mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-12-28 12:30:46 +00:00
- re-implemented VP8 support.
Since the decoder cannot handle sound, there's two options: 1: Use the same sounds as the video it replaces. 2: If an identifiable streamable sound with the same base name is found, it will be played along with the video. Fixes #133
This commit is contained in:
parent
80cea90854
commit
b23424485a
6 changed files with 224 additions and 152 deletions
|
@ -36,7 +36,7 @@ typedef struct
|
||||||
extern const char *animvpx_read_ivf_header_errmsg[7];
|
extern const char *animvpx_read_ivf_header_errmsg[7];
|
||||||
int32_t animvpx_read_ivf_header(FileReader & inhandle, animvpx_ivf_header_t *hdr);
|
int32_t animvpx_read_ivf_header(FileReader & inhandle, animvpx_ivf_header_t *hdr);
|
||||||
|
|
||||||
typedef struct
|
struct animvpx_codec_ctx
|
||||||
{
|
{
|
||||||
const char *errmsg; // non-NULL if codec error? better always check...
|
const char *errmsg; // non-NULL if codec error? better always check...
|
||||||
const char *errmsg_detail; // may be NULL even if codec error
|
const char *errmsg_detail; // may be NULL even if codec error
|
||||||
|
@ -74,7 +74,7 @@ typedef struct
|
||||||
int32_t numframes;
|
int32_t numframes;
|
||||||
int32_t sumtimes[3];
|
int32_t sumtimes[3];
|
||||||
int32_t maxtimes[3];
|
int32_t maxtimes[3];
|
||||||
} animvpx_codec_ctx;
|
};
|
||||||
|
|
||||||
|
|
||||||
int32_t animvpx_init_codec(const animvpx_ivf_header_t *info, FileReader & inhandle, animvpx_codec_ctx *codec);
|
int32_t animvpx_init_codec(const animvpx_ivf_header_t *info, FileReader & inhandle, animvpx_codec_ctx *codec);
|
||||||
|
@ -90,19 +90,5 @@ int32_t animvpx_render_frame(animvpx_codec_ctx *codec, double animvpx_aspect);
|
||||||
void animvpx_print_stats(const animvpx_codec_ctx *codec);
|
void animvpx_print_stats(const animvpx_codec_ctx *codec);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline int32_t animvpx_check_header(const animvpx_ivf_header_t *hdr)
|
|
||||||
{
|
|
||||||
if (memcmp(hdr->magic,"DKIF",4))
|
|
||||||
return 2; // "not an IVF file"
|
|
||||||
|
|
||||||
if (hdr->version != 0)
|
|
||||||
return 3; // "unrecognized IVF version"
|
|
||||||
|
|
||||||
// fourcc is left as-is
|
|
||||||
if (memcmp(hdr->fourcc, "VP80", 4))
|
|
||||||
return 4; // "only VP8 supported"
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // !defined ANIM_VPX_H
|
#endif // !defined ANIM_VPX_H
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
#include "v_draw.h"
|
#include "v_draw.h"
|
||||||
#include "v_video.h"
|
#include "v_video.h"
|
||||||
#include "texturemanager.h"
|
#include "texturemanager.h"
|
||||||
#include "animtexture.h"
|
|
||||||
|
|
||||||
#undef UNUSED
|
#undef UNUSED
|
||||||
#define VPX_CODEC_DISABLE_COMPAT 1
|
#define VPX_CODEC_DISABLE_COMPAT 1
|
||||||
|
@ -33,6 +32,22 @@ const char *animvpx_read_ivf_header_errmsg[] = {
|
||||||
|
|
||||||
static_assert(sizeof(animvpx_ivf_header_t) == 32);
|
static_assert(sizeof(animvpx_ivf_header_t) == 32);
|
||||||
|
|
||||||
|
inline int32_t animvpx_check_header(const animvpx_ivf_header_t* hdr)
|
||||||
|
{
|
||||||
|
if (memcmp(hdr->magic, "DKIF", 4))
|
||||||
|
return 2; // "not an IVF file"
|
||||||
|
|
||||||
|
if (hdr->version != 0)
|
||||||
|
return 3; // "unrecognized IVF version"
|
||||||
|
|
||||||
|
// fourcc is left as-is
|
||||||
|
if (memcmp(hdr->fourcc, "VP80", 4))
|
||||||
|
return 4; // "only VP8 supported"
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int32_t animvpx_read_ivf_header(FileReader & inhandle, animvpx_ivf_header_t *hdr)
|
int32_t animvpx_read_ivf_header(FileReader & inhandle, animvpx_ivf_header_t *hdr)
|
||||||
{
|
{
|
||||||
int32_t err;
|
int32_t err;
|
||||||
|
@ -44,14 +59,14 @@ int32_t animvpx_read_ivf_header(FileReader & inhandle, animvpx_ivf_header_t *hdr
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
hdr->hdrlen = B_LITTLE16(hdr->hdrlen);
|
hdr->hdrlen = LittleShort(hdr->hdrlen);
|
||||||
|
|
||||||
hdr->width = B_LITTLE16(hdr->width);
|
hdr->width = LittleShort(hdr->width);
|
||||||
hdr->height = B_LITTLE16(hdr->height);
|
hdr->height = LittleShort(hdr->height);
|
||||||
hdr->fpsnumer = B_LITTLE32(hdr->fpsnumer);
|
hdr->fpsnumer = LittleLong(hdr->fpsnumer);
|
||||||
hdr->fpsdenom = B_LITTLE32(hdr->fpsdenom);
|
hdr->fpsdenom = LittleLong(hdr->fpsdenom);
|
||||||
|
|
||||||
hdr->numframes = B_LITTLE32(hdr->numframes);
|
hdr->numframes = LittleLong(hdr->numframes);
|
||||||
|
|
||||||
// the rest is based on vpxdec.c --> file_is_ivf()
|
// the rest is based on vpxdec.c --> file_is_ivf()
|
||||||
|
|
||||||
|
@ -338,89 +353,4 @@ read_ivf_frame:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/////////////// DRAWING! ///////////////
|
|
||||||
static int sampler;
|
|
||||||
static FGameTexture* vpxtex[2];
|
|
||||||
static int which;
|
|
||||||
|
|
||||||
void animvpx_setup_glstate(int32_t animvpx_flags)
|
|
||||||
{
|
|
||||||
////////// GL STATE //////////
|
|
||||||
vpxtex[0] = TexMan.FindGameTexture("AnimTextureFrame1", ETextureType::Override);
|
|
||||||
vpxtex[1] = TexMan.FindGameTexture("AnimTextureFrame2", ETextureType::Override);
|
|
||||||
|
|
||||||
sampler = CLAMP_XY;
|
|
||||||
GLInterface.ClearScreen(0, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void animvpx_restore_glstate(void)
|
|
||||||
{
|
|
||||||
vpxtex[0]->CleanHardwareData();
|
|
||||||
vpxtex[0] = nullptr;
|
|
||||||
vpxtex[1]->CleanHardwareData();
|
|
||||||
vpxtex[1] = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t animvpx_render_frame(animvpx_codec_ctx *codec, double animvpx_aspect)
|
|
||||||
{
|
|
||||||
int32_t t = I_msTime();
|
|
||||||
|
|
||||||
if (codec->initstate <= 0) // not inited or error
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (codec->pic == NULL)
|
|
||||||
return 2; // shouldn't happen
|
|
||||||
|
|
||||||
which ^= 1;
|
|
||||||
static_cast<AnimTexture*>(vpxtex[which]->GetTexture())->SetFrameSize(AnimTexture::YUV, codec->width, codec->height);
|
|
||||||
static_cast<AnimTexture*>(vpxtex[which]->GetTexture())->SetFrame(nullptr, codec->pic);
|
|
||||||
|
|
||||||
float vid_wbyh = ((float)codec->width)/codec->height;
|
|
||||||
if (animvpx_aspect > 0)
|
|
||||||
vid_wbyh = animvpx_aspect;
|
|
||||||
float scr_wbyh = ((float)xdim)/ydim;
|
|
||||||
|
|
||||||
float x=1.0, y=1.0;
|
|
||||||
#if 1
|
|
||||||
// aspect correction by pillarboxing/letterboxing
|
|
||||||
// TODO: fullscreen? can't assume square pixels there
|
|
||||||
if (vid_wbyh != scr_wbyh)
|
|
||||||
{
|
|
||||||
if (vid_wbyh < scr_wbyh)
|
|
||||||
x = vid_wbyh/scr_wbyh;
|
|
||||||
else
|
|
||||||
y = scr_wbyh/vid_wbyh;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
x *= screen->GetWidth() / 2;
|
|
||||||
y *= screen->GetHeight() / 2;
|
|
||||||
DrawTexture(twod, vpxtex[which], screen->GetWidth() / 2 - int(x), screen->GetHeight()/2 - int(y), DTA_DestWidth, 2*int(x), DTA_DestHeight, 2*int(y),
|
|
||||||
DTA_Masked, false, DTA_KeepRatio, true, DTA_LegacyRenderStyle, STYLE_Normal, TAG_DONE);
|
|
||||||
|
|
||||||
t = I_msTime()-t;
|
|
||||||
codec->sumtimes[2] += t;
|
|
||||||
codec->maxtimes[2] = max(codec->maxtimes[2], t);
|
|
||||||
codec->numframes++;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void animvpx_print_stats(const animvpx_codec_ctx *codec)
|
|
||||||
{
|
|
||||||
if (codec->numframes != 0)
|
|
||||||
{
|
|
||||||
const int32_t *s = codec->sumtimes;
|
|
||||||
const int32_t *m = codec->maxtimes;
|
|
||||||
int32_t n = codec->numframes;
|
|
||||||
|
|
||||||
Printf("VP8 timing stats (mean, max) [ms] for %d frames:\n"
|
|
||||||
" read and decode frame: %.02f, %d\n"
|
|
||||||
" 3 planes -> packed conversion: %.02f, %d\n"
|
|
||||||
" upload and display: %.02f, %d\n",
|
|
||||||
n, (double)s[0]/n, m[0], (double)s[1]/n, m[1], (double)s[2]/n, m[2]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -44,19 +44,44 @@
|
||||||
|
|
||||||
void AnimTexture::SetFrameSize(int format, int width, int height)
|
void AnimTexture::SetFrameSize(int format, int width, int height)
|
||||||
{
|
{
|
||||||
|
pixelformat = format;
|
||||||
FTexture::SetSize(width, height);
|
FTexture::SetSize(width, height);
|
||||||
Image.Resize(width * height * (format == Paletted ? 1 : 3));
|
Image.Resize(width * height * (format == Paletted ? 1 : 3));
|
||||||
memset(Image.Data(), 0, Image.Size());
|
memset(Image.Data(), 0, Image.Size());
|
||||||
CleanHardwareTextures();
|
CleanHardwareTextures();
|
||||||
pixelformat = format;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimTexture::SetFrame(const uint8_t* palette, const void* data_)
|
void AnimTexture::SetFrame(const uint8_t* palette, const void* data_)
|
||||||
{
|
{
|
||||||
if (palette) memcpy(Palette, palette, 768);
|
if (palette) memcpy(Palette, palette, 768);
|
||||||
if (data_) memcpy(Image.Data(), data_, Width * Height * (pixelformat == Paletted ? 1 : 3));
|
if (data_)
|
||||||
|
{
|
||||||
|
if (pixelformat == YUV)
|
||||||
|
{
|
||||||
|
auto spix = (const uint8_t*)data_;
|
||||||
|
auto dpix = Image.Data();
|
||||||
|
for (int i = 0; i < Width * Height; i++)
|
||||||
|
{
|
||||||
|
int p = i * 4;
|
||||||
|
int q = i * 3;
|
||||||
|
float y = spix[p] * (1 / 255.f);
|
||||||
|
float u = spix[p + 1] * (1 / 255.f) - 0.5f;
|
||||||
|
float v = spix[p + 2] * (1 / 255.f) - 0.5f;
|
||||||
|
|
||||||
|
y = 1.1643f * (y - 0.0625f);
|
||||||
|
|
||||||
|
float r = y + 1.5958f * v;
|
||||||
|
float g = y - 0.39173f * u - 0.81290f * v;
|
||||||
|
float b = y + 2.017f * u;
|
||||||
|
|
||||||
|
dpix[q + 0] = (uint8_t)(clamp(r, 0.f, 1.f) * 255);
|
||||||
|
dpix[q + 1] = (uint8_t)(clamp(g, 0.f, 1.f) * 255);
|
||||||
|
dpix[q + 2] = (uint8_t)(clamp(b, 0.f, 1.f) * 255);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else memcpy(Image.Data(), data_, Width * Height * (pixelformat == Paletted ? 1 : 3));
|
||||||
|
}
|
||||||
CleanHardwareTextures();
|
CleanHardwareTextures();
|
||||||
pixelformat = Paletted;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
@ -85,40 +110,18 @@ FBitmap AnimTexture::GetBgraBitmap(const PalEntry* remap, int* trans)
|
||||||
dpix[p + 3] = 255;
|
dpix[p + 3] = 255;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (pixelformat == RGB)
|
else if (pixelformat == RGB || pixelformat == YUV)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < Width * Height; i++)
|
for (int i = 0; i < Width * Height; i++)
|
||||||
{
|
{
|
||||||
int p = i * 4;
|
int p = i * 4;
|
||||||
dpix[p + 0] = spix[p + 2];
|
int q = i * 3;
|
||||||
dpix[p + 1] = spix[p + 1];
|
dpix[p + 0] = spix[q + 2];
|
||||||
dpix[p + 2] = spix[p];
|
dpix[p + 1] = spix[q + 1];
|
||||||
|
dpix[p + 2] = spix[q];
|
||||||
dpix[p + 3] = 255;
|
dpix[p + 3] = 255;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (pixelformat == YUV)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < Width * Height; i++)
|
|
||||||
{
|
|
||||||
int p = i * 4;
|
|
||||||
float y = spix[p] * (1 / 255.f);
|
|
||||||
float u = spix[p + 1] * (1 / 255.f) - 0.5f;
|
|
||||||
float v = spix[p + 2] * (1 / 255.f) - 0.5f;
|
|
||||||
|
|
||||||
y = 1.1643f * (y - 0.0625f);
|
|
||||||
|
|
||||||
float r = y + 1.5958f * v;
|
|
||||||
float g = y - 0.39173f * u - 0.81290f * v;
|
|
||||||
float b = y + 2.017f * u;
|
|
||||||
|
|
||||||
dpix[p + 0] = (uint8_t)(clamp(b, 0.f, 1.f) * 255);
|
|
||||||
dpix[p + 1] = (uint8_t)(clamp(g, 0.f, 1.f) * 255);
|
|
||||||
dpix[p + 2] = (uint8_t)(clamp(r, 0.f, 1.f) * 255);
|
|
||||||
dpix[p + 3] = 255;
|
|
||||||
}
|
|
||||||
return bmp;
|
|
||||||
|
|
||||||
}
|
|
||||||
return bmp;
|
return bmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,13 +95,13 @@ FString MusicFileExists(const char* fn)
|
||||||
return FString();
|
return FString();
|
||||||
}
|
}
|
||||||
|
|
||||||
int LookupMusicLump(const char* fn)
|
int LookupMusic(const char* fn, bool onlyextended)
|
||||||
{
|
{
|
||||||
if (mus_extendedlookup)
|
if (mus_extendedlookup || onlyextended)
|
||||||
{
|
{
|
||||||
FString name = StripExtension(fn);
|
FString name = StripExtension(fn);
|
||||||
int l = fileSystem.FindFileWithExtensions(name, knownMusicExts, countof(knownMusicExts));
|
int l = fileSystem.FindFileWithExtensions(name, knownMusicExts, countof(knownMusicExts));
|
||||||
if (l >= 0) return l;
|
if (l >= 0 || onlyextended) return l;
|
||||||
}
|
}
|
||||||
return fileSystem.CheckNumForFullName(fn, true, ns_music);
|
return fileSystem.CheckNumForFullName(fn, true, ns_music);
|
||||||
}
|
}
|
||||||
|
@ -131,20 +131,20 @@ FileReader OpenMusic(const char* musicname)
|
||||||
}
|
}
|
||||||
if (!reader.isOpen())
|
if (!reader.isOpen())
|
||||||
{
|
{
|
||||||
int lumpnum = LookupMusicLump(musicname);
|
int lumpnum = LookupMusic(musicname);
|
||||||
if (mus_extendedlookup && lumpnum >= 0)
|
if (mus_extendedlookup && lumpnum >= 0)
|
||||||
{
|
{
|
||||||
// EDuke also looks in a subfolder named after the main game resource. Do this as well if extended lookup is active.
|
// EDuke also looks in a subfolder named after the main game resource. Do this as well if extended lookup is active.
|
||||||
auto rfn = fileSystem.GetResourceFileName(fileSystem.GetFileContainer(lumpnum));
|
auto rfn = fileSystem.GetResourceFileName(fileSystem.GetFileContainer(lumpnum));
|
||||||
auto rfbase = ExtractFileBase(rfn);
|
auto rfbase = ExtractFileBase(rfn);
|
||||||
FStringf aliasMusicname("music/%s/%s", rfbase.GetChars(), musicname);
|
FStringf aliasMusicname("music/%s/%s", rfbase.GetChars(), musicname);
|
||||||
lumpnum = LookupMusicLump(aliasMusicname);
|
lumpnum = LookupMusic(aliasMusicname);
|
||||||
}
|
}
|
||||||
if (lumpnum == -1)
|
if (lumpnum == -1)
|
||||||
{
|
{
|
||||||
// Always look in the 'music' subfolder as well. This gets used by multiple setups to store ripped CD tracks.
|
// Always look in the 'music' subfolder as well. This gets used by multiple setups to store ripped CD tracks.
|
||||||
FStringf aliasMusicname("music/%s", musicname);
|
FStringf aliasMusicname("music/%s", musicname);
|
||||||
lumpnum = LookupMusicLump(aliasMusicname);
|
lumpnum = LookupMusic(aliasMusicname);
|
||||||
}
|
}
|
||||||
if (lumpnum == -1 && (g_gameType & GAMEFLAG_SW))
|
if (lumpnum == -1 && (g_gameType & GAMEFLAG_SW))
|
||||||
{
|
{
|
||||||
|
@ -170,7 +170,7 @@ FileReader OpenMusic(const char* musicname)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static FString LookupMusic(const char* musicname, int& order)
|
static FString LookupMusicCB(const char* musicname, int& order)
|
||||||
{
|
{
|
||||||
// Now perform music aliasing. This also needs to be done before checking identities because multiple names can map to the same song.
|
// Now perform music aliasing. This also needs to be done before checking identities because multiple names can map to the same song.
|
||||||
FName* aliasp = MusicAliases.CheckKey(musicname);
|
FName* aliasp = MusicAliases.CheckKey(musicname);
|
||||||
|
@ -270,7 +270,7 @@ void Mus_InitMusic()
|
||||||
I_InitMusic();
|
I_InitMusic();
|
||||||
static MusicCallbacks mus_cb =
|
static MusicCallbacks mus_cb =
|
||||||
{
|
{
|
||||||
LookupMusic,
|
LookupMusicCB,
|
||||||
OpenMusic
|
OpenMusic
|
||||||
};
|
};
|
||||||
S_SetMusicCallbacks(&mus_cb);
|
S_SetMusicCallbacks(&mus_cb);
|
||||||
|
|
|
@ -18,3 +18,4 @@ void Mus_ResumeSaved();
|
||||||
FString G_SetupFilenameBasedMusic(const char* fileName, const char *defaultfn);
|
FString G_SetupFilenameBasedMusic(const char* fileName, const char *defaultfn);
|
||||||
class FSerializer;
|
class FSerializer;
|
||||||
void Mus_Serialize(FSerializer& arc);
|
void Mus_Serialize(FSerializer& arc);
|
||||||
|
int LookupMusic(const char* fn, bool onlyextended = false);
|
||||||
|
|
|
@ -48,6 +48,8 @@
|
||||||
#include "SmackerDecoder.h"
|
#include "SmackerDecoder.h"
|
||||||
#include "movie/playmve.h"
|
#include "movie/playmve.h"
|
||||||
#include "gamecontrol.h"
|
#include "gamecontrol.h"
|
||||||
|
#include "animvpx.h"
|
||||||
|
#include "raze_music.h"
|
||||||
|
|
||||||
|
|
||||||
IMPLEMENT_CLASS(DScreenJob, true, false)
|
IMPLEMENT_CLASS(DScreenJob, true, false)
|
||||||
|
@ -134,7 +136,7 @@ public:
|
||||||
|
|
||||||
if (curframe > 4 && currentclock > frametime + 60)
|
if (curframe > 4 && currentclock > frametime + 60)
|
||||||
{
|
{
|
||||||
Printf("WARNING: slowdown in video playback, aborting\n");
|
Printf(PRINT_BOLD, "WARNING: slowdown in video playback, aborting\n");
|
||||||
soundEngine->StopAllChannels();
|
soundEngine->StopAllChannels();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -226,6 +228,136 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class DVpxPlayer : public DScreenJob
|
||||||
|
{
|
||||||
|
bool failed = false;
|
||||||
|
FileReader fr;
|
||||||
|
AnimTextures animtex;
|
||||||
|
animvpx_codec_ctx codec;
|
||||||
|
const AnimSound* animSnd;
|
||||||
|
|
||||||
|
uint32_t convnumer;
|
||||||
|
uint32_t convdenom;
|
||||||
|
|
||||||
|
uint32_t msecsperframe;
|
||||||
|
uint64_t nextframetime;
|
||||||
|
|
||||||
|
int framenum = 0;
|
||||||
|
int lastsoundframe = -1;
|
||||||
|
public:
|
||||||
|
int soundtrack = -1;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool isvalid() { return !failed; }
|
||||||
|
|
||||||
|
DVpxPlayer(FileReader& fr_, const AnimSound* animSnd_, int origframedelay)
|
||||||
|
{
|
||||||
|
fr = std::move(fr_);
|
||||||
|
animSnd = animSnd_;
|
||||||
|
|
||||||
|
animvpx_ivf_header_t info;
|
||||||
|
|
||||||
|
int err = animvpx_read_ivf_header(fr, &info);
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
Printf(PRINT_BOLD, "Failed reading IVF file: %s\n", animvpx_read_ivf_header_errmsg[err]);
|
||||||
|
failed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (animvpx_init_codec(&info, fr, &codec))
|
||||||
|
{
|
||||||
|
Printf(PRINT_BOLD, "Error initializing VPX codec.\n");
|
||||||
|
failed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
convnumer = 120 * info.fpsdenom;
|
||||||
|
convdenom = info.fpsnumer * origframedelay;
|
||||||
|
|
||||||
|
msecsperframe = scale(info.fpsdenom, 1000, info.fpsnumer);
|
||||||
|
nextframetime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
int Frame(uint64_t clock, bool skiprequest) override
|
||||||
|
{
|
||||||
|
if (clock == 0)
|
||||||
|
{
|
||||||
|
if (soundtrack > 0)
|
||||||
|
{
|
||||||
|
Mus_Play(nullptr, fileSystem.GetFileFullName(soundtrack, false), false);
|
||||||
|
}
|
||||||
|
animtex.SetSize(AnimTexture::YUV, codec.width, codec.height);
|
||||||
|
}
|
||||||
|
bool stop = false;
|
||||||
|
if (clock > nextframetime)
|
||||||
|
{
|
||||||
|
nextframetime += 1'000'000 * msecsperframe;
|
||||||
|
|
||||||
|
uint8_t* pic;
|
||||||
|
int i = animvpx_nextpic(&codec, &pic);
|
||||||
|
if (i)
|
||||||
|
{
|
||||||
|
Printf(PRINT_BOLD, "Failed getting next pic: %s\n", animvpx_nextpic_errmsg[i]);
|
||||||
|
if (codec.errmsg)
|
||||||
|
{
|
||||||
|
Printf(PRINT_BOLD, " %s\n", codec.errmsg);
|
||||||
|
if (codec.errmsg_detail)
|
||||||
|
Printf(PRINT_BOLD, " detail: %s\n", codec.errmsg_detail);
|
||||||
|
}
|
||||||
|
stop = true;
|
||||||
|
}
|
||||||
|
if (!pic) stop = true;
|
||||||
|
|
||||||
|
if (!stop)
|
||||||
|
{
|
||||||
|
animtex.SetFrame(nullptr, pic);
|
||||||
|
}
|
||||||
|
|
||||||
|
framenum++;
|
||||||
|
|
||||||
|
int soundframe = convdenom ? scale(framenum, convnumer, convdenom) : framenum;
|
||||||
|
if (soundframe > lastsoundframe)
|
||||||
|
{
|
||||||
|
if (animSnd && soundtrack == -1) for (int i = 0; animSnd[i].framenum >= 0; i++)
|
||||||
|
{
|
||||||
|
if (animSnd[i].framenum == soundframe)
|
||||||
|
{
|
||||||
|
int sound = animSnd[i].soundnum;
|
||||||
|
if (sound == -1)
|
||||||
|
soundEngine->StopAllChannels();
|
||||||
|
else if (SoundEnabled())
|
||||||
|
soundEngine->StartSound(SOURCE_None, nullptr, nullptr, CHAN_AUTO, CHANF_UI, sound, 1.f, ATTN_NONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastsoundframe = soundframe;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DrawTexture(twod, animtex.GetFrame(), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit, TAG_DONE);
|
||||||
|
if (stop || skiprequest) Mus_Stop();
|
||||||
|
if (stop) return 0;
|
||||||
|
return skiprequest ? -1 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnDestroy() override
|
||||||
|
{
|
||||||
|
animvpx_uninit_codec(&codec);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
@ -337,7 +469,16 @@ DScreenJob* PlayVideo(const char* filename, const AnimSound* ans, const int* fra
|
||||||
{
|
{
|
||||||
return nothing();
|
return nothing();
|
||||||
}
|
}
|
||||||
auto fr = fileSystem.OpenFileReader(filename);
|
FileReader fr;
|
||||||
|
// first try as .ivf - but only if sounds are provided - the decoder is video only.
|
||||||
|
if (ans)
|
||||||
|
{
|
||||||
|
auto fn = StripExtension(filename);
|
||||||
|
DefaultExtension(fn, ".ivf");
|
||||||
|
fr = fileSystem.OpenFileReader(fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fr.isOpen()) fr = fileSystem.OpenFileReader(filename);
|
||||||
if (!fr.isOpen())
|
if (!fr.isOpen())
|
||||||
{
|
{
|
||||||
int nLen = strlen(filename);
|
int nLen = strlen(filename);
|
||||||
|
@ -349,7 +490,7 @@ DScreenJob* PlayVideo(const char* filename, const AnimSound* ans, const int* fra
|
||||||
}
|
}
|
||||||
if (!fr.isOpen())
|
if (!fr.isOpen())
|
||||||
{
|
{
|
||||||
Printf("%s: Unable to open video\n", filename);
|
Printf(PRINT_BOLD, "%s: Unable to open video\n", filename);
|
||||||
return nothing();
|
return nothing();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -363,7 +504,7 @@ DScreenJob* PlayVideo(const char* filename, const AnimSound* ans, const int* fra
|
||||||
auto anm = Create<DAnmPlayer>(fr, ans, frameticks, nosoundcutoff);
|
auto anm = Create<DAnmPlayer>(fr, ans, frameticks, nosoundcutoff);
|
||||||
if (!anm->isvalid())
|
if (!anm->isvalid())
|
||||||
{
|
{
|
||||||
Printf("%s: invalid ANM file.\n", filename);
|
Printf(PRINT_BOLD, "%s: invalid ANM file.\n", filename);
|
||||||
anm->Destroy();
|
anm->Destroy();
|
||||||
return nothing();
|
return nothing();
|
||||||
}
|
}
|
||||||
|
@ -375,7 +516,7 @@ DScreenJob* PlayVideo(const char* filename, const AnimSound* ans, const int* fra
|
||||||
auto anm = Create<DSmkPlayer>(filename, ans, true); // Fixme: Handle Blood's video scaling behavior more intelligently.
|
auto anm = Create<DSmkPlayer>(filename, ans, true); // Fixme: Handle Blood's video scaling behavior more intelligently.
|
||||||
if (!anm->isvalid())
|
if (!anm->isvalid())
|
||||||
{
|
{
|
||||||
Printf("%s: invalid SMK file.\n", filename);
|
Printf(PRINT_BOLD, "%s: invalid SMK file.\n", filename);
|
||||||
anm->Destroy();
|
anm->Destroy();
|
||||||
return nothing();
|
return nothing();
|
||||||
}
|
}
|
||||||
|
@ -391,10 +532,21 @@ DScreenJob* PlayVideo(const char* filename, const AnimSound* ans, const int* fra
|
||||||
}
|
}
|
||||||
return anm;
|
return anm;
|
||||||
}
|
}
|
||||||
|
else if (!memcmp(id, "DKIF\0\0 \0VP80", 12))
|
||||||
|
{
|
||||||
|
auto anm = Create<DVpxPlayer>(fr, ans, frameticks? frameticks[1] : 0 );
|
||||||
|
if (!anm->isvalid())
|
||||||
|
{
|
||||||
|
anm->Destroy();
|
||||||
|
return nothing();
|
||||||
|
}
|
||||||
|
anm->soundtrack = LookupMusic(filename, true);
|
||||||
|
return anm;
|
||||||
|
}
|
||||||
// add more formats here.
|
// add more formats here.
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Printf("%s: Unknown video format\n", filename);
|
Printf(PRINT_BOLD, "%s: Unknown video format\n", filename);
|
||||||
}
|
}
|
||||||
return nothing();
|
return nothing();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue