mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-11-10 14:52:01 +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];
|
||||
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_detail; // may be NULL even if codec error
|
||||
|
@ -74,7 +74,7 @@ typedef struct
|
|||
int32_t numframes;
|
||||
int32_t sumtimes[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);
|
||||
|
@ -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);
|
||||
#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
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include "v_draw.h"
|
||||
#include "v_video.h"
|
||||
#include "texturemanager.h"
|
||||
#include "animtexture.h"
|
||||
|
||||
#undef UNUSED
|
||||
#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);
|
||||
|
||||
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 err;
|
||||
|
@ -44,14 +59,14 @@ int32_t animvpx_read_ivf_header(FileReader & inhandle, animvpx_ivf_header_t *hdr
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
hdr->hdrlen = B_LITTLE16(hdr->hdrlen);
|
||||
hdr->hdrlen = LittleShort(hdr->hdrlen);
|
||||
|
||||
hdr->width = B_LITTLE16(hdr->width);
|
||||
hdr->height = B_LITTLE16(hdr->height);
|
||||
hdr->fpsnumer = B_LITTLE32(hdr->fpsnumer);
|
||||
hdr->fpsdenom = B_LITTLE32(hdr->fpsdenom);
|
||||
hdr->width = LittleShort(hdr->width);
|
||||
hdr->height = LittleShort(hdr->height);
|
||||
hdr->fpsnumer = LittleLong(hdr->fpsnumer);
|
||||
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()
|
||||
|
||||
|
@ -338,89 +353,4 @@ read_ivf_frame:
|
|||
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
|
||||
|
|
|
@ -44,19 +44,44 @@
|
|||
|
||||
void AnimTexture::SetFrameSize(int format, int width, int height)
|
||||
{
|
||||
pixelformat = format;
|
||||
FTexture::SetSize(width, height);
|
||||
Image.Resize(width * height * (format == Paletted ? 1 : 3));
|
||||
memset(Image.Data(), 0, Image.Size());
|
||||
CleanHardwareTextures();
|
||||
pixelformat = format;
|
||||
}
|
||||
|
||||
void AnimTexture::SetFrame(const uint8_t* palette, const void* data_)
|
||||
{
|
||||
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();
|
||||
pixelformat = Paletted;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
@ -85,40 +110,18 @@ FBitmap AnimTexture::GetBgraBitmap(const PalEntry* remap, int* trans)
|
|||
dpix[p + 3] = 255;
|
||||
}
|
||||
}
|
||||
else if (pixelformat == RGB)
|
||||
else if (pixelformat == RGB || pixelformat == YUV)
|
||||
{
|
||||
for (int i = 0; i < Width * Height; i++)
|
||||
{
|
||||
int p = i * 4;
|
||||
dpix[p + 0] = spix[p + 2];
|
||||
dpix[p + 1] = spix[p + 1];
|
||||
dpix[p + 2] = spix[p];
|
||||
int q = i * 3;
|
||||
dpix[p + 0] = spix[q + 2];
|
||||
dpix[p + 1] = spix[q + 1];
|
||||
dpix[p + 2] = spix[q];
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -95,13 +95,13 @@ FString MusicFileExists(const char* fn)
|
|||
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);
|
||||
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);
|
||||
}
|
||||
|
@ -131,20 +131,20 @@ FileReader OpenMusic(const char* musicname)
|
|||
}
|
||||
if (!reader.isOpen())
|
||||
{
|
||||
int lumpnum = LookupMusicLump(musicname);
|
||||
int lumpnum = LookupMusic(musicname);
|
||||
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.
|
||||
auto rfn = fileSystem.GetResourceFileName(fileSystem.GetFileContainer(lumpnum));
|
||||
auto rfbase = ExtractFileBase(rfn);
|
||||
FStringf aliasMusicname("music/%s/%s", rfbase.GetChars(), musicname);
|
||||
lumpnum = LookupMusicLump(aliasMusicname);
|
||||
lumpnum = LookupMusic(aliasMusicname);
|
||||
}
|
||||
if (lumpnum == -1)
|
||||
{
|
||||
// Always look in the 'music' subfolder as well. This gets used by multiple setups to store ripped CD tracks.
|
||||
FStringf aliasMusicname("music/%s", musicname);
|
||||
lumpnum = LookupMusicLump(aliasMusicname);
|
||||
lumpnum = LookupMusic(aliasMusicname);
|
||||
}
|
||||
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.
|
||||
FName* aliasp = MusicAliases.CheckKey(musicname);
|
||||
|
@ -270,7 +270,7 @@ void Mus_InitMusic()
|
|||
I_InitMusic();
|
||||
static MusicCallbacks mus_cb =
|
||||
{
|
||||
LookupMusic,
|
||||
LookupMusicCB,
|
||||
OpenMusic
|
||||
};
|
||||
S_SetMusicCallbacks(&mus_cb);
|
||||
|
|
|
@ -18,3 +18,4 @@ void Mus_ResumeSaved();
|
|||
FString G_SetupFilenameBasedMusic(const char* fileName, const char *defaultfn);
|
||||
class FSerializer;
|
||||
void Mus_Serialize(FSerializer& arc);
|
||||
int LookupMusic(const char* fn, bool onlyextended = false);
|
||||
|
|
|
@ -48,6 +48,8 @@
|
|||
#include "SmackerDecoder.h"
|
||||
#include "movie/playmve.h"
|
||||
#include "gamecontrol.h"
|
||||
#include "animvpx.h"
|
||||
#include "raze_music.h"
|
||||
|
||||
|
||||
IMPLEMENT_CLASS(DScreenJob, true, false)
|
||||
|
@ -134,7 +136,7 @@ public:
|
|||
|
||||
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();
|
||||
return -1;
|
||||
}
|
||||
|
@ -232,6 +234,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);
|
||||
}
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
class DSmkPlayer : public DScreenJob
|
||||
{
|
||||
SmackerHandle hSMK{};
|
||||
|
@ -337,7 +469,16 @@ DScreenJob* PlayVideo(const char* filename, const AnimSound* ans, const int* fra
|
|||
{
|
||||
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())
|
||||
{
|
||||
int nLen = strlen(filename);
|
||||
|
@ -349,7 +490,7 @@ DScreenJob* PlayVideo(const char* filename, const AnimSound* ans, const int* fra
|
|||
}
|
||||
if (!fr.isOpen())
|
||||
{
|
||||
Printf("%s: Unable to open video\n", filename);
|
||||
Printf(PRINT_BOLD, "%s: Unable to open video\n", filename);
|
||||
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);
|
||||
if (!anm->isvalid())
|
||||
{
|
||||
Printf("%s: invalid ANM file.\n", filename);
|
||||
Printf(PRINT_BOLD, "%s: invalid ANM file.\n", filename);
|
||||
anm->Destroy();
|
||||
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.
|
||||
if (!anm->isvalid())
|
||||
{
|
||||
Printf("%s: invalid SMK file.\n", filename);
|
||||
Printf(PRINT_BOLD, "%s: invalid SMK file.\n", filename);
|
||||
anm->Destroy();
|
||||
return nothing();
|
||||
}
|
||||
|
@ -391,10 +532,21 @@ DScreenJob* PlayVideo(const char* filename, const AnimSound* ans, const int* fra
|
|||
}
|
||||
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.
|
||||
else
|
||||
{
|
||||
Printf("%s: Unknown video format\n", filename);
|
||||
Printf(PRINT_BOLD, "%s: Unknown video format\n", filename);
|
||||
}
|
||||
return nothing();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue