Added video player and .duk video decoder

(video playback support phase 2)


git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@1248 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
avolkov
2003-09-20 01:15:03 +00:00
parent d8a815db68
commit 1e08b8a527
12 changed files with 1877 additions and 1 deletions
+2 -1
View File
@@ -1 +1,2 @@
uqm_CFILES="vfileins.c"
uqm_CFILES="vfileins.c video.c videodec.c vidplayer.c dukvid.c"
uqm_SUBDIRS="sdl"
+687
View File
@@ -0,0 +1,687 @@
/* DUCK video player
*
* Status: as raw as it gets
*
*/
#include "video.h"
#include "libs/sndlib.h"
#include "libs/sound/sound.h"
#include "dukvid.h"
#include "endian_uqm.h"
#include <stdio.h>
#define _THIS TFB_VideoDecoder* This
int dukv_GetError (_THIS);
bool dukv_Init (_THIS, TFB_VideoFormat* fmt);
void dukv_Term (_THIS);
bool dukv_Open (_THIS, uio_DirHandle *dir, const char *filename);
void dukv_Close (_THIS);
int dukv_DecodeNext (_THIS);
uint32 dukv_SeekFrame (_THIS, uint32 frame);
float dukv_SeekTime (_THIS, float time);
uint32 dukv_GetFrame (_THIS);
float dukv_GetTime (_THIS);
TFB_VideoDecoderFuncs dukv_DecoderVtbl =
{
dukv_GetError,
dukv_Init,
dukv_Term,
dukv_Open,
dukv_Close,
dukv_DecodeNext,
dukv_SeekFrame,
dukv_SeekTime,
dukv_GetFrame,
dukv_GetTime,
};
typedef struct tfb_duckvideoheader
{
uint32 version;
uint32 scrn_x_ofs; // horz screen offset in pixels
uint32 scrn_y_ofs; // vert screen offset in pixels
uint16 wb, hb; // width + height in blocks
sint16 lumas[8]; // future luminance deltas
sint16 chromas[8]; // future chrominance deltas
} TFB_DuckVideoHeader;
#define NUM_VEC_ITEMS 0x010
#define NUM_VECTORS 0x100
typedef struct tfb_duckvideodeltas
{
sint32 lumas[NUM_VECTORS][NUM_VEC_ITEMS];
sint32 chromas[NUM_VECTORS][NUM_VEC_ITEMS];
} TFB_DuckVideoDeltas;
typedef struct tfb_duckvideo
{
sint32 last_error;
uio_DirHandle* basedir;
char* basename;
uio_Stream *stream;
// loaded from disk
uint32* frames;
uint32 cframes;
uint32 iframe;
uint32 version;
uint32 wb, hb; // width + height in blocks
uint32 w, h;
// generated
TFB_DuckVideoDeltas d;
uint8* inbuf;
uint32* decbuf;
} TFB_DuckVideo;
#define DUCK_GENERAL_FPS 14.622f
#define DUCK_MAX_FRAME_SIZE 0x8000U
#define DUCK_END_OF_SEQUENCE 1
void
dukv_DecodeFrame (uint8* src_p, uint32* dst_p, uint32 wb, uint32 hb,
TFB_DuckVideoDeltas* deltas)
{
int iVec;
int iSeq;
uint32 x, y;
sint32 w;
uint32 *d_p0, *d_p1;
int i;
w = wb * 4;
iVec = *(src_p++);
iSeq = 0;
for (y = 0; y < hb; ++y)
{
sint32 accum0, accum1, corr, corr0, corr1, delta;
sint32 pix[4];
d_p0 = dst_p + y * w * 2;
d_p1 = d_p0 + w;
accum0 = 0;
accum1 = 0;
corr0 = 0;
corr1 = 0;
for (x = 0; x < wb; ++x)
{
if (y == 0)
{
pix[0] = pix[1] = pix[2] = pix[3] = 0;
}
else
{
uint32* p_p = d_p0 - w;
pix[0] = p_p[0];
pix[1] = p_p[1];
pix[2] = p_p[2];
pix[3] = p_p[3];
}
// start with chroma delta
delta = deltas->chromas[iVec][iSeq++];
iSeq++; // correctors ignored
accum0 += delta >> 1;
if (delta & 1)
{
iVec = *(src_p++);
iSeq = 0;
}
// line 0
for (i = 0; i < 4; ++i, ++d_p0)
{
delta = deltas->lumas[iVec][iSeq++];
corr = deltas->lumas[iVec][iSeq++];
accum0 += delta >> 1;
corr0 ^= corr;
pix[i] += accum0;
pix[i] ^= corr0;
if (delta & 1)
{
iVec = *(src_p++);
iSeq = 0;
}
*d_p0 = pix[i];
}
// line 1
for (i = 0; i < 4; ++i, ++d_p1)
{
delta = deltas->lumas[iVec][iSeq++];
corr = deltas->lumas[iVec][iSeq++];
accum1 += delta >> 1;
corr1 ^= corr;
pix[i] += accum1;
pix[i] ^= corr1;
if (delta & 1)
{
iVec = *(src_p++);
iSeq = 0;
}
*d_p1 = pix[i];
}
}
}
}
void
dukv_DecodeFrameV3 (uint8* src_p, uint32* dst_p, uint32 wb, uint32 hb,
TFB_DuckVideoDeltas* deltas)
{
int iVec;
int iSeq;
uint32 x, y;
sint32 w;
uint32* d_p;
int i;
iVec = *(src_p++);
iSeq = 0;
hb *= 2;
w = wb * 4;
for (y = 0; y < hb; ++y)
{
sint32 accum, delta, pix;
d_p = dst_p + y * w;
accum = 0;
for (x = 0; x < wb; ++x)
{
// start with chroma delta
delta = deltas->chromas[iVec][iSeq];
iSeq += 2; // correctors ignored
accum += delta >> 1;
if (delta & DUCK_END_OF_SEQUENCE)
{
iVec = *(src_p++);
iSeq = 0;
}
for (i = 0; i < 4; ++i, ++d_p)
{
if (y == 0)
pix = 0;
else
pix = d_p[-w];
// get next luma delta
delta = deltas->lumas[iVec][iSeq];
iSeq += 2; // correctors ignored
accum += delta >> 1;
pix += accum;
if (delta & DUCK_END_OF_SEQUENCE)
{
iVec = *(src_p++);
iSeq = 0;
}
*d_p = pix;
}
}
}
}
bool
dukv_OpenStream (TFB_DuckVideo* dukv)
{
char filename[280];
strcat (strcpy (filename, dukv->basename), ".duk");
return (dukv->stream =
res_OpenResFile (dukv->basedir, filename, "rb")) != NULL;
}
bool
dukv_ReadFrames (TFB_DuckVideo* dukv)
{
char filename[280];
uint32 i;
uio_Stream *fp;
strcat (strcpy (filename, dukv->basename), ".frm");
if (!(fp = res_OpenResFile (dukv->basedir, filename, "rb")))
return false;
dukv->cframes = LengthResFile (fp) / sizeof (uint32);
dukv->frames = (uint32*) HMalloc (dukv->cframes * sizeof (uint32));
if ((uint32)ReadResFile (dukv->frames, sizeof (uint32), dukv->cframes, fp)
!= dukv->cframes)
{
HFree (dukv->frames);
dukv->frames = 0;
return 0;
}
res_CloseResFile (fp);
for (i = 0; i < dukv->cframes; ++i)
dukv->frames[i] = UQM_SwapBE32 (dukv->frames[i]);
return true;
}
bool
dukv_ReadVectors (TFB_DuckVideo* dukv, uint8* vectors)
{
uio_Stream *fp;
char filename[280];
int ret;
strcat (strcpy (filename, dukv->basename), ".tbl");
if (!(fp = res_OpenResFile (dukv->basedir, filename, "rb")))
return false;
ret = ReadResFile (vectors, NUM_VEC_ITEMS * NUM_VECTORS, 1, fp);
res_CloseResFile (fp);
return ret;
}
bool
dukv_ReadHeader (TFB_DuckVideo* dukv, sint32* pl, sint32* pc)
{
uio_Stream *fp;
char filename[280];
int ret;
int i;
TFB_DuckVideoHeader hdr;
strcat (strcpy (filename, dukv->basename), ".hdr");
if (!(fp = res_OpenResFile (dukv->basedir, filename, "rb")))
return false;
ret = ReadResFile (&hdr, sizeof (hdr), 1, fp);
res_CloseResFile (fp);
if (!ret)
return false;
dukv->version = UQM_SwapBE32 (hdr.version);
dukv->wb = UQM_SwapBE16 (hdr.wb);
dukv->hb = UQM_SwapBE16 (hdr.hb);
for (i = 0; i < 8; ++i)
{
pl[i] = (sint16) UQM_SwapBE16 (hdr.lumas[i]);
pc[i] = (sint16) UQM_SwapBE16 (hdr.chromas[i]);
}
dukv->w = dukv->wb * 4;
dukv->h = dukv->hb * 4;
return true;
}
sint32
dukv_make_delta (sint32* protos, bool is_chroma, int i1, int i2)
{
sint32 d1, d2;
if (!is_chroma)
{
// 0x421 is (r,g,b)=(1,1,1) in 15bit pixel coding
d1 = (protos[i1] >> 1) * 0x421;
d2 = (protos[i2] >> 1) * 0x421;
return ((d1 << 16) + d2) << 1;
}
else
{
d1 = (protos[i1] << 10) + protos[i2];
return ((d1 << 16) + d1) << 1;
}
}
sint32
dukv_make_corr (sint32* protos, bool is_chroma, int i1, int i2)
{
sint32 d1, d2;
if (!is_chroma)
{
d1 = (protos[i1] & 1) << 15;
d2 = (protos[i2] & 1) << 15;
return (d1 << 16) + d2;
}
else
{
return (i1 << 3) + i2;
}
}
void
dukv_DecodeVector (uint8* vec, sint32* p, bool is_chroma, sint32* deltas)
{
int citems = vec[0];
int i;
for (i = 0; i < citems; i += 2, vec += 2, deltas += 2)
{
sint32 d = dukv_make_delta (p, is_chroma, vec[1], vec[2]);
if (i == citems - 2)
d |= DUCK_END_OF_SEQUENCE;
deltas[0] = d;
deltas[1] = dukv_make_corr (p, is_chroma, vec[1], vec[2]);
}
}
void
dukv_InitDeltas (TFB_DuckVideo* dukv, uint8* vectors, sint32* pl, sint32* pc)
{
int i;
for (i = 0; i < NUM_VECTORS; ++i)
{
uint8* vector = vectors + i * NUM_VEC_ITEMS;
dukv_DecodeVector (vector, pl, false, dukv->d.lumas[i]);
dukv_DecodeVector (vector, pc, true, dukv->d.chromas[i]);
}
}
__inline__ uint32
dukv_PixelConv (uint16 pix, const TFB_VideoFormat* fmt)
{
uint32 r, g, b;
r = (pix >> 7) & 0xf8;
g = (pix >> 2) & 0xf8;
b = (pix << 3) & 0xf8;
return
((r >> fmt->Rloss) << fmt->Rshift) |
((g >> fmt->Gloss) << fmt->Gshift) |
((b >> fmt->Bloss) << fmt->Bshift);
}
void
dukv_RenderFrame (_THIS)
{
TFB_DuckVideo* dukv = This->dec_data;
const TFB_VideoFormat* fmt = This->format;
uint32 h, x, y;
uint32* dec = dukv->decbuf;
h = dukv->h / 2;
// separate bpp versions for speed
switch (fmt->BytesPerPixel)
{
case 2:
{
for (y = 0; y < h; ++y)
{
uint16 *dst0, *dst1;
dst0 = (uint16*) This->callbacks.GetCanvasLine (This, y * 2);
dst1 = (uint16*) This->callbacks.GetCanvasLine (This, y * 2 + 1);
for (x = 0; x < dukv->w; ++x, ++dec, ++dst0, ++dst1)
{
uint32 pair = *dec;
*dst0 = dukv_PixelConv ((uint16)(pair >> 16), fmt);
*dst1 = dukv_PixelConv ((uint16)(pair & 0xffff), fmt);
}
}
break;
}
case 3:
{
for (y = 0; y < h; ++y)
{
uint8 *dst0, *dst1;
dst0 = (uint8*) This->callbacks.GetCanvasLine (This, y * 2);
dst1 = (uint8*) This->callbacks.GetCanvasLine (This, y * 2 + 1);
for (x = 0; x < dukv->w; ++x, ++dec, dst0 += 3, dst1 += 3)
{
uint32 pair = *dec;
*(uint32*)dst0 =
dukv_PixelConv ((uint16)(pair >> 16), fmt);
*(uint32*)dst1 =
dukv_PixelConv ((uint16)(pair & 0xffff), fmt);
}
}
break;
}
case 4:
{
for (y = 0; y < h; ++y)
{
uint32 *dst0, *dst1;
dst0 = (uint32*) This->callbacks.GetCanvasLine (This, y * 2);
dst1 = (uint32*) This->callbacks.GetCanvasLine (This, y * 2 + 1);
for (x = 0; x < dukv->w; ++x, ++dec, ++dst0, ++dst1)
{
uint32 pair = *dec;
*dst0 = dukv_PixelConv ((uint16)(pair >> 16), fmt);
*dst1 = dukv_PixelConv ((uint16)(pair & 0xffff), fmt);
}
}
break;
}
default:
;
}
}
int dukv_GetError (_THIS)
{
return This->error;
}
bool
dukv_Init (_THIS, TFB_VideoFormat* fmt)
{
This->format = fmt;
This->audio_synced = 1;
This->dec_data = HCalloc (sizeof (TFB_DuckVideo));
return true;
}
void
dukv_Term (_THIS)
{
//TFB_DuckVideo* dukv = This->dec_data;
dukv_Close (This);
HFree (This->dec_data);
}
bool
dukv_Open (_THIS, uio_DirHandle *dir, const char *filename)
{
TFB_DuckVideo* dukv = This->dec_data;
char* pext;
sint32 lumas[8], chromas[8];
uint8* vectors;
dukv->basedir = dir;
dukv->basename = HMalloc (strlen (filename) + 1);
strcpy (dukv->basename, filename);
pext = strrchr (dukv->basename, '.');
if (pext) // strip extension
*pext = 0;
vectors = HMalloc (NUM_VEC_ITEMS * NUM_VECTORS);
if (!dukv_OpenStream (dukv)
|| !dukv_ReadFrames (dukv)
|| !dukv_ReadHeader (dukv, lumas, chromas)
|| !dukv_ReadVectors (dukv, vectors))
{
HFree (vectors);
dukv_Close (This);
dukv->last_error = dukve_BadFile;
return false;
}
dukv_InitDeltas (dukv, vectors, lumas, chromas);
HFree (vectors);
This->w = dukv->w;
This->h = dukv->h;
This->length = (float) dukv->cframes / DUCK_GENERAL_FPS;
This->frame_count = dukv->cframes;
This->max_frame_wait =
(uint32) (1000.0f / DUCK_GENERAL_FPS * 1.1);
dukv->inbuf = HMalloc (DUCK_MAX_FRAME_SIZE);
dukv->decbuf = HMalloc (dukv->w * dukv->h * sizeof (uint16));
return true;
}
void
dukv_Close (_THIS)
{
TFB_DuckVideo* dukv = This->dec_data;
if (dukv->basename)
{
HFree (dukv->basename);
dukv->basename = NULL;
}
if (dukv->frames)
{
HFree (dukv->frames);
dukv->frames = NULL;
}
if (dukv->stream)
{
res_CloseResFile (dukv->stream);
dukv->stream = NULL;
}
if (dukv->inbuf)
{
HFree (dukv->inbuf);
dukv->inbuf = NULL;
}
if (dukv->decbuf)
{
HFree (dukv->decbuf);
dukv->decbuf = NULL;
}
}
int
dukv_DecodeNext (_THIS)
{
TFB_DuckVideo* dukv = This->dec_data;
uint32 fh[2];
uint32 vofs;
uint32 vsize;
uint16 ver;
if (!dukv->stream || dukv->iframe >= dukv->cframes)
return 0;
SeekResFile (dukv->stream, dukv->frames[dukv->iframe], SEEK_SET);
if (ReadResFile (&fh, sizeof (fh), 1, dukv->stream) != 1)
{
dukv->last_error = dukve_EOF;
return 0;
}
vofs = UQM_SwapBE32 (fh[0]);
vsize = UQM_SwapBE32 (fh[1]);
if (vsize > DUCK_MAX_FRAME_SIZE)
{
dukv->last_error = dukve_OutOfBuf;
return -1;
}
SeekResFile (dukv->stream, vofs, SEEK_CUR);
if ((uint32)ReadResFile (dukv->inbuf, 1, vsize, dukv->stream) != vsize)
{
dukv->last_error = dukve_EOF;
return 0;
}
ver = UQM_SwapBE16 (*(uint16*)dukv->inbuf);
if (ver == 0x0300)
dukv_DecodeFrameV3 (dukv->inbuf + 0x10, dukv->decbuf,
dukv->wb, dukv->hb, &dukv->d);
else
dukv_DecodeFrame (dukv->inbuf + 0x10, dukv->decbuf,
dukv->wb, dukv->hb, &dukv->d);
dukv->iframe++;
dukv_RenderFrame (This);
return 1;
}
uint32
dukv_SeekFrame (_THIS, uint32 frame)
{
TFB_DuckVideo* dukv = This->dec_data;
if (frame > dukv->cframes)
frame = dukv->cframes; // EOS
return dukv->iframe = frame;
}
float
dukv_SeekTime (_THIS, float time)
{
//TFB_DuckVideo* dukv = This->dec_data;
uint32 frame = (uint32) (time * DUCK_GENERAL_FPS);
return (float) dukv_SeekFrame (This, frame) / DUCK_GENERAL_FPS;
}
uint32
dukv_GetFrame (_THIS)
{
TFB_DuckVideo* dukv = This->dec_data;
return dukv->iframe;
}
float
dukv_GetTime (_THIS)
{
TFB_DuckVideo* dukv = This->dec_data;
return (float) dukv->iframe / DUCK_GENERAL_FPS;
}
+36
View File
@@ -0,0 +1,36 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _DUKVID_H
#define _DUKVID_H
#include "libs/video/videodec.h"
extern TFB_VideoDecoderFuncs dukv_DecoderVtbl;
typedef enum
{
// positive values are the same as in errno
dukve_None = 0,
dukve_Unknown = -1,
dukve_BadFile = -2,
dukve_BadArg = -3,
dukve_OutOfBuf = -4,
dukve_EOF = -5,
dukve_Other = -1000,
} DukVid_Error;
#endif // _DUKVID_H
+1
View File
@@ -0,0 +1 @@
uqm_CFILES="sdlvideo.c"
+58
View File
@@ -0,0 +1,58 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "libs/graphics/sdl/sdl_common.h"
#include "libs/video/video.h"
#include "sdlvideo.h"
void
TFB_GetScreenFormat (TFB_VideoFormat *fmt)
{
SDL_PixelFormat *sdl = SDL_Video->format;
fmt->BitsPerPixel = sdl->BitsPerPixel;
fmt->Rmask = sdl->Rmask;
fmt->Gmask = sdl->Gmask;
fmt->Bmask = sdl->Bmask;
fmt->Amask = 0; // no alpha support for now
}
TFB_Image*
TFB_CreateVideoImage (int w, int h)
{
TFB_Image* img;
SDL_PixelFormat* fmt = SDL_Video->format;
img = HMalloc (sizeof (TFB_Image));
img->mutex = CreateMutex ();
img->ScaledImg = NULL;
img->MipmapImg = NULL;
img->colormap_index = -1;
img->last_scale_type = -1;
img->Palette = NULL;
img->NormalImg = SDL_CreateRGBSurface (SDL_SWSURFACE, w, h,
fmt->BitsPerPixel, fmt->Rmask, fmt->Gmask, fmt->Bmask, 0);
return img;
}
void*
TFB_GetVideoLine (TFB_Image* img, uint32 line)
{
SDL_Surface* surf = img->NormalImg;
return (uint8*)surf->pixels + surf->pitch * line;
}
+28
View File
@@ -0,0 +1,28 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _SDLVIDEO_H
#define _SDLVIDEO_H
#include "libs/graphics/gfx_common.h"
#include "libs/graphics/tfb_draw.h"
#include "libs/gfxlib.h"
void TFB_GetScreenFormat (TFB_VideoFormat *fmt);
TFB_Image* TFB_CreateVideoImage (int w, int h);
void* TFB_GetVideoLine (TFB_Image* img, uint32 line);
#endif // _SDLVIDEO_H
+150
View File
@@ -0,0 +1,150 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "video.h"
#include "sdl/sdlvideo.h"
#include "vidplayer.h"
#define NULL_VIDEO_REF (0)
static VIDEO_REF _cur_video = NULL_VIDEO_REF;
BOOLEAN
InitVideo (BOOLEAN useCDROM)
//useCDROM doesn't really apply to us
{
TFB_VideoFormat fmt;
TFB_GetScreenFormat (&fmt);
return VideoDecoder_Init (0, fmt.BitsPerPixel, fmt.Rmask,
fmt.Gmask, fmt.Bmask, fmt.Amask);
(void)useCDROM; /* dodge compiler warning */
}
void
UninitVideo ()
{
VideoDecoder_Uninit ();
}
void
VidStop ()
{
if (_cur_video)
{
TFB_StopVideo (_cur_video);
TFB_FadeClearScreen ();
}
_cur_video = NULL_VIDEO_REF;
}
VIDEO_REF
VidPlaying ()
// this should just probably return BOOLEAN
{
if (!_cur_video)
return NULL_VIDEO_REF;
if (TFB_VideoPlaying (_cur_video))
return _cur_video;
return NULL_VIDEO_REF;
}
VIDEO_TYPE
VidPlay (VIDEO_REF VidRef, char *loopname, BOOLEAN uninit)
// uninit was used to uninit the game kernel
// before spawning duck exe
{
VIDEO_TYPE ret;
TFB_VideoClip* vid = (TFB_VideoClip*) VidRef;
if (!vid)
return NO_FMV;
if (_cur_video)
TFB_StopVideo (_cur_video);
_cur_video = NULL_VIDEO_REF;
TFB_FadeClearScreen ();
FlushInput ();
LockCrossThreadMutex (GraphicsLock);
SetContext (ScreenContext);
// play video in the center of the screen
if (TFB_PlayVideo (VidRef, (SCREEN_WIDTH - vid->w) / 2,
(SCREEN_HEIGHT - vid->h) / 2))
{
_cur_video = VidRef;
ret = SOFTWARE_FMV;
}
else
{
ret = NO_FMV;
}
UnlockCrossThreadMutex (GraphicsLock);
/* dodge compiler warnings */
(void) loopname;
(void) uninit;
return ret;
}
void
VidDoInput (void)
{
if (_cur_video)
TFB_VideoInput (_cur_video);
}
VIDEO_REF
_init_video_file(PVOID pStr)
{
TFB_VideoClip* vid;
TFB_VideoDecoder* dec;
dec = VideoDecoder_Load (contentDir, (const char*)pStr);
if (!dec)
return NULL_VIDEO_REF;
vid = (TFB_VideoClip*) HCalloc (sizeof (*vid));
vid->decoder = dec;
vid->length = dec->length;
vid->w = vid->decoder->w;
vid->h = vid->decoder->h;
vid->guard = CreateMutex ();
vid->frame_lock = CreateCondVar ();
return (VIDEO_REF) vid;
}
BOOLEAN
DestroyVideo (VIDEO_REF VideoRef)
{
TFB_VideoClip* vid = (TFB_VideoClip*) VideoRef;
if (!vid)
return FALSE;
VideoDecoder_Free (vid->decoder);
DestroyMutex (vid->guard);
DestroyCondVar (vid->frame_lock);
HFree (vid);
return TRUE;
}
+52
View File
@@ -0,0 +1,52 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _UQM_VIDEO_H
#define _UQM_VIDEO_H
#include "starcon.h"
#include "options.h"
#include "misc.h"
#include "vidlib.h"
#include "libs/graphics/tfb_draw.h"
#include "videodec.h"
#include "libs/sound/sound.h"
typedef struct tfb_videoclip
{
TFB_VideoDecoder *decoder; // decoder to read from
float length; // total length of clip seconds
uint32 w, h;
RECT dst_rect; // destination screen rect
RECT src_rect; // source rect
MUSIC_REF hAudio;
Task play_task;
uint32 frame_time; // time when next frame should be rendered
TFB_Image* frame;
uint32 cur_frame;
uint32 max_frame_wait;
bool playing;
Mutex guard;
CondVar frame_lock;
uint32 want_frame;
void* data; // user-defined data
} TFB_VideoClip;
#endif // _UQM_VIDEO_H
+224
View File
@@ -0,0 +1,224 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "video.h"
#include "videodec.h"
#include "dukvid.h"
static bool vd_inited = 0;
static TFB_VideoFormat vd_vidfmt;
static struct vd_DecoderInfo
{
const char* ext;
const char* name;
TFB_VideoDecoderFuncs* funcs;
}
vd_decoders[] =
{
{"duk", "DukVid", &dukv_DecoderVtbl},
{NULL, NULL, NULL} // null term
};
static void vd_computeMasks (uint32 mask, uint32* shift, uint32* loss);
bool
VideoDecoder_Init (int flags, int depth, uint32 Rmask, uint32 Gmask,
uint32 Bmask, uint32 Amask)
{
vd_inited = 0;
if (depth < 15 || depth > 32)
{
fprintf (stderr, "VideoDecoder_Init: Unsupported video depth %d\n", depth);
return false;
}
if ((Rmask & Gmask) || (Rmask & Bmask) || (Rmask & Amask) ||
(Gmask & Bmask) || (Gmask & Amask) || (Bmask & Amask))
{
fprintf (stderr, "VideoDecoder_Init: Invalid channel masks\n");
return false;
}
// BEGIN: adapted from SDL
vd_vidfmt.BitsPerPixel = depth;
vd_vidfmt.BytesPerPixel = (depth + 7) / 8;
vd_vidfmt.Rmask = Rmask;
vd_vidfmt.Gmask = Gmask;
vd_vidfmt.Bmask = Bmask;
vd_vidfmt.Amask = Amask;
vd_computeMasks (Rmask, &vd_vidfmt.Rshift, &vd_vidfmt.Rloss);
vd_computeMasks (Gmask, &vd_vidfmt.Gshift, &vd_vidfmt.Gloss);
vd_computeMasks (Bmask, &vd_vidfmt.Bshift, &vd_vidfmt.Bloss);
vd_computeMasks (Amask, &vd_vidfmt.Ashift, &vd_vidfmt.Aloss);
// END: adapted from SDL
vd_inited = 1;
(void)flags; // dodge compiler warning
return 1;
}
void
VideoDecoder_Uninit (void)
{
vd_inited = 0;
// go for a strall in a park
}
TFB_VideoDecoder*
VideoDecoder_Load (uio_DirHandle *dir, const char *filename)
{
const char* pext;
struct vd_DecoderInfo* dinfo;
TFB_VideoDecoder* decoder;
if (!vd_inited)
return NULL;
pext = strrchr (filename, '.');
if (!pext)
{
fprintf (stderr, "VideoDecoder_Load: Unknown file type\n");
return NULL;
}
++pext;
for (dinfo = vd_decoders;
dinfo->ext && strcmp(dinfo->ext, pext) != 0;
++dinfo)
;
if (!dinfo->ext)
{
fprintf (stderr, "VideoDecoder_Load: Unsupported file type\n");
return NULL;
}
decoder = (TFB_VideoDecoder*) HCalloc (sizeof (*decoder));
decoder->funcs = dinfo->funcs;
if (!decoder->funcs->Init (decoder, &vd_vidfmt))
{
fprintf (stderr, "VideoDecoder_Load: Cannot init '%s' decoder, code %d\n",
dinfo->name, decoder->funcs->GetError (decoder));
HFree (decoder);
return NULL;
}
decoder->decoder_info = dinfo->name;
decoder->dir = dir;
decoder->filename = (char *) HMalloc (strlen (filename) + 1);
strcpy (decoder->filename, filename);
decoder->error = VIDEODECODER_OK;
if (!decoder->funcs->Open (decoder, dir, filename))
{
fprintf (stderr, "VideoDecoder_Load: '%s' decoder did not load %s, code %d\n",
dinfo->name, filename, decoder->funcs->GetError (decoder));
VideoDecoder_Free (decoder);
return NULL;
}
return decoder;
}
// return: >0 = OK, 0 = EOF, <0 = Error
int
VideoDecoder_Decode (TFB_VideoDecoder *decoder)
{
int ret;
if (!decoder)
return 0;
decoder->cur_frame = decoder->funcs->GetFrame (decoder);
decoder->pos = decoder->funcs->GetTime (decoder);
ret = decoder->funcs->DecodeNext (decoder);
if (ret == 0)
decoder->error = VIDEODECODER_EOF;
else if (ret < 0)
decoder->error = VIDEODECODER_ERROR;
else
decoder->error = VIDEODECODER_OK;
return ret;
}
float
VideoDecoder_Seek (TFB_VideoDecoder *decoder, float pos)
{
if (!decoder)
return 0.0;
decoder->pos = decoder->funcs->SeekTime (decoder, pos);
decoder->cur_frame = decoder->funcs->GetFrame (decoder);
return decoder->pos;
}
uint32
VideoDecoder_SeekFrame (TFB_VideoDecoder *decoder, uint32 frame)
{
if (!decoder)
return 0;
decoder->cur_frame = decoder->funcs->SeekFrame (decoder, frame);
decoder->pos = decoder->funcs->GetTime (decoder);
return decoder->cur_frame;
}
void
VideoDecoder_Rewind (TFB_VideoDecoder *decoder)
{
if (!decoder)
return;
VideoDecoder_Seek (decoder, 0);
}
void
VideoDecoder_Free (TFB_VideoDecoder *decoder)
{
if (!decoder)
return;
decoder->funcs->Close (decoder);
decoder->funcs->Term (decoder);
HFree (decoder->filename);
HFree (decoder);
}
// BEGIN: adapted from SDL
static void
vd_computeMasks (uint32 mask, uint32* shift, uint32* loss)
{
*shift = 0;
*loss = 8;
if (mask)
{
for (; !(mask & 1); mask >>= 1 )
++*shift;
for (; (mask & 1); mask >>= 1 )
--*loss;
}
}
// END: adapted from SDL
+124
View File
@@ -0,0 +1,124 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _VIDEODEC_H
#define _VIDEODEC_H
#include "vidlib.h"
#include "libs/video/video.h"
#include "reslib.h"
// forward-declare
typedef struct tfb_videodecoder TFB_VideoDecoder;
// we do not support paletted format for now
typedef struct tfb_videoformat
{
uint32 BitsPerPixel;
uint32 BytesPerPixel;
uint32 Rmask, Gmask, Bmask, Amask;
uint32 Rshift, Gshift, Bshift, Ashift;
uint32 Rloss, Gloss, Bloss, Aloss;
} TFB_VideoFormat;
#define _THIS TFB_VideoDecoder*
typedef struct tfb_videodecoderfunc
{
int (* GetError) (_THIS);
bool (* Init) (_THIS, TFB_VideoFormat* fmt);
void (* Term) (_THIS);
bool (* Open) (_THIS, uio_DirHandle *dir, const char *filename);
void (* Close) (_THIS);
int (* DecodeNext) (_THIS);
uint32 (* SeekFrame) (_THIS, uint32 frame);
float (* SeekTime) (_THIS, float time);
uint32 (* GetFrame) (_THIS);
float (* GetTime) (_THIS);
} TFB_VideoDecoderFuncs;
// decoder will call these to get info
// from the player
typedef struct tfb_videocallbacks
{
// any decoder calls this
void* (* GetCanvasLine) (_THIS, uint32 line);
// non-audio-driven decoders call this to figure out
// when the next frame should be drawn
uint32 (* GetTicks) (_THIS);
// non-audio-driven decoders call this to inform
// the player when the next frame should be drawn
bool (* SetTimer) (_THIS, uint32 msecs);
} TFB_VideoCallbacks;
#undef _THIS
struct tfb_videodecoder
{
// decoder virtual funcs - R/O
const TFB_VideoDecoderFuncs *funcs;
// video formats - R/O
const TFB_VideoFormat *format;
// decoder-set data - R/O
uint32 w, h;
float length; // total length in seconds
uint32 frame_count;
uint32 max_frame_wait; // maximum interframe delay in msecs
bool audio_synced;
// decoder callbacks
TFB_VideoCallbacks callbacks;
// decoder-defined data - don't mess with
void *dec_data;
// other - public
bool looping;
void* data; // user-defined data
// info - public R/O
sint32 error;
float pos; // position in seconds
uint32 cur_frame;
const char *decoder_info;
// semi-private
uio_DirHandle *dir;
char *filename;
};
// return values
enum
{
VIDEODECODER_OK,
VIDEODECODER_ERROR,
VIDEODECODER_EOF,
};
bool VideoDecoder_Init (int flags, int depth, uint32 Rmask, uint32 Gmask,
uint32 Bmask, uint32 Amask);
void VideoDecoder_Uninit (void);
TFB_VideoDecoder* VideoDecoder_Load (uio_DirHandle *dir,
const char *filename);
int VideoDecoder_Decode (TFB_VideoDecoder *decoder);
float VideoDecoder_Seek (TFB_VideoDecoder *decoder, float time_pos);
uint32 VideoDecoder_SeekFrame (TFB_VideoDecoder *decoder, uint32 frame_pos);
void VideoDecoder_Rewind (TFB_VideoDecoder *decoder);
void VideoDecoder_Free (TFB_VideoDecoder *decoder);
#endif // _VIDEODEC_H
+486
View File
@@ -0,0 +1,486 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "vidplayer.h"
#include "sdl/sdlvideo.h"
// video callbacks
static void* vp_GetCanvasLine (TFB_VideoDecoder*, uint32 line);
static uint32 vp_GetTicks (TFB_VideoDecoder*);
static bool vp_SetTimer (TFB_VideoDecoder*, uint32 msecs);
TFB_VideoCallbacks vp_DecoderCBs =
{
vp_GetCanvasLine,
vp_GetTicks,
vp_SetTimer
};
// audio stream callbacks
static bool vp_AudioStart (TFB_SoundSample* sample);
static void vp_AudioEnd (TFB_SoundSample* sample);
static void vp_BufferTag (TFB_SoundSample* sample, TFB_SoundTag* tag);
static void vp_QueueBuffer (TFB_SoundSample* sample, TFBSound_Object buffer);
static TFB_SoundCallbacks vp_AudioCBs =
{
vp_AudioStart,
NULL,
vp_AudioEnd,
vp_BufferTag,
vp_QueueBuffer
};
// inter-thread param guarded by mutex
static Semaphore vp_interthread_lock = 0;
void* vp_interthread_clip = NULL;
typedef struct
{
// standard state required by DoInput
BOOLEAN (*InputFunc) (PVOID pInputState);
COUNT MenuRepeatDelay;
VIDEO_REF CurVideo;
} VIDEO_INPUT_STATE;
void
TFB_FadeClearScreen ()
{
BYTE xform_buf[1];
RECT r = {{0, 0}, {SCREEN_WIDTH, SCREEN_HEIGHT}};
xform_buf[0] = FadeAllToBlack;
SleepThreadUntil (XFormColorMap (
(COLORMAPPTR) xform_buf, ONE_SECOND / 2));
// paint black rect over screen
LockCrossThreadMutex (GraphicsLock);
SetContext (ScreenContext);
SetContextForeGroundColor (BUILD_COLOR (
MAKE_RGB15 (0x0, 0x0, 0x0), 0x00));
DrawFilledRectangle (&r);
UnlockCrossThreadMutex (GraphicsLock);
// fade in black rect instantly
xform_buf[0] = FadeAllToColor;
XFormColorMap ((COLORMAPPTR) xform_buf, 0);
}
int
ac_video_play_task (void* data)
{
Task task = (Task) data;
volatile TFB_VideoClip* vid;
int ret;
uint32 want_frame;
TimeCount TimeOut;
int bTerm;
uint32 clagged;
// snatch the clip pointer and release
vid = vp_interthread_clip;
vp_interthread_clip = NULL;
ClearSemaphore (vp_interthread_lock);
LockMutex (vid->guard);
want_frame = vid->want_frame;
PlayMusic (vid->hAudio, FALSE, 1);
UnlockMutex (vid->guard);
clagged = 0;
ret = VideoDecoder_Decode (vid->decoder);
TimeOut = GetTimeCounter () + vid->decoder->max_frame_wait *
ONE_SECOND / 1000;
while (!(bTerm = Task_ReadState (task, TASK_EXIT)) && ret > 0)
{
// wait till its time to render next frame
while (!(bTerm = Task_ReadState (task, TASK_EXIT))
&& want_frame == vid->cur_frame - clagged
&& TimeOut > GetTimeCounter ())
{
TaskSwitch ();
LockMutex (vid->guard);
want_frame = vid->want_frame;
UnlockMutex (vid->guard);
}
if (bTerm)
break;
if (want_frame == vid->cur_frame - clagged)
{ // timed out - draw the next frame
++clagged;
}
else if (want_frame > vid->cur_frame - clagged
&& want_frame <= vid->cur_frame)
{
// catching up
clagged = vid->cur_frame - want_frame;
// try again
continue;
}
else if (want_frame != vid->cur_frame + 1)
{ // out of sequence frame, let's get it
vid->cur_frame = VideoDecoder_SeekFrame (
vid->decoder, want_frame);
ret = VideoDecoder_Decode (vid->decoder);
clagged = 0;
}
else
{
clagged = 0;
}
vid->cur_frame = vid->decoder->cur_frame;
// draw the frame
if (ret > 0)
{
LockCrossThreadMutex (GraphicsLock);
SetContext (ScreenContext);
TFB_DrawScreen_Image (vid->frame,
vid->dst_rect.corner.x, vid->dst_rect.corner.y,
GSCALE_IDENTITY, NULL, TFB_SCREEN_MAIN);
UnlockCrossThreadMutex (GraphicsLock);
FlushGraphics (); // needed to prevent half-frame updates
}
// increase timeout with lag-count to allow audio to catch up
TimeOut = GetTimeCounter () + vid->decoder->max_frame_wait *
ONE_SECOND / 1000 + clagged * ONE_SECOND / 100;
ret = VideoDecoder_Decode (vid->decoder);
}
StopMusic ();
vid->playing = false;
FinishTask (task);
return 0;
}
int
video_play_task (void* data)
{
Task task = (Task) data;
TFB_VideoClip* vid;
int ret;
// snatch the clip pointer and release
vid = vp_interthread_clip;
vp_interthread_clip = NULL;
ClearSemaphore (vp_interthread_lock);
LockMutex (vid->guard);
if (vid->hAudio)
PlayMusic (vid->hAudio, FALSE, 1);
UnlockMutex (vid->guard);
// this works like so:
// 1. you call VideoDecoder_Seek() [when necessary] and
// VideoDecoder_Decode()
// 2. the decoder calls back vp_GetTicks() and vp_SetTimer()
// to figure out and tell you when to render the frame
// being decoded
// On a seek operation, the decoder should reset its internal
// clock and call vp_GetTicks() again
//
ret = VideoDecoder_Decode (vid->decoder);
while (!Task_ReadState (task, TASK_EXIT) && ret > 0)
{
// wait till its time to render next frame
SleepThreadUntil (vid->frame_time);
vid->cur_frame = vid->decoder->cur_frame;
LockCrossThreadMutex (GraphicsLock);
SetContext (ScreenContext);
TFB_DrawScreen_Image (vid->frame,
vid->dst_rect.corner.x, vid->dst_rect.corner.y,
GSCALE_IDENTITY, NULL, TFB_SCREEN_MAIN);
UnlockCrossThreadMutex (GraphicsLock);
FlushGraphics (); // needed to prevent half-frame updates
ret = VideoDecoder_Decode (vid->decoder);
}
vid->playing = false;
if (vid->hAudio)
StopMusic ();
FinishTask (task);
return 0;
}
bool
TFB_PlayVideo (VIDEO_REF VidRef, uint32 x, uint32 y)
{
TFB_VideoClip* vid = (TFB_VideoClip*) VidRef;
RECT scrn_r;
RECT clip_r = {{0, 0}, {vid->w, vid->h}};
RECT vid_r = {{0, 0}, {SCREEN_WIDTH, SCREEN_HEIGHT}};
RECT dr = {{x, y}, {vid->w, vid->h}};
RECT sr;
if (!vid)
return false;
// calculate the frame-source and screen-destination rects
GetContextClipRect (&scrn_r);
if (scrn_r.extent.width <= 0 || scrn_r.extent.height <= 0)
{ // bad or empty rect
scrn_r = vid_r;
}
else if (!BoxIntersect(&scrn_r, &vid_r, &scrn_r))
return false; // drawing outside visible
sr = dr;
sr.corner.x = -sr.corner.x;
sr.corner.y = -sr.corner.y;
if (!BoxIntersect (&clip_r, &sr, &sr))
return false; // drawing outside visible
dr.corner.x += scrn_r.corner.x;
dr.corner.y += scrn_r.corner.y;
if (!BoxIntersect (&scrn_r, &dr, &vid->dst_rect))
return false; // drawing outside visible
vid->src_rect = vid->dst_rect;
vid->src_rect.corner.x = sr.corner.x;
vid->src_rect.corner.y = sr.corner.y;
vid->decoder->callbacks = vp_DecoderCBs;
vid->decoder->data = vid;
vid->frame = TFB_CreateVideoImage (vid->w, vid->h);
vid->cur_frame = -1;
vid->want_frame = -1;
vid->hAudio = LoadMusicFile (vid->decoder->filename);
StopMusic ();
if (vid->decoder->audio_synced)
{
TFB_SoundSample **pmus;
if (!vid->hAudio)
{
fprintf (stderr, "TFB_PlayVideo: Cannot load sound-track for audio-synced video\n");
return false;
}
// nasty hack for now
LockMusicData (vid->hAudio, &pmus);
(*pmus)->buffer_tag = HCalloc (sizeof (TFB_SoundTag) * (*pmus)->num_buffers);
(*pmus)->callbacks = vp_AudioCBs;
(*pmus)->data = vid; // hijack data ;)
UnlockMusicData (vid->hAudio);
}
// creation probably needs better handling
if (!vp_interthread_lock)
vp_interthread_lock = CreateSemaphore (1, "inter-thread param lock");
SetSemaphore (vp_interthread_lock);
vp_interthread_clip = vid;
vid->playing = true;
if (vid->decoder->audio_synced)
vid->play_task = AssignTask (ac_video_play_task, 4096, "a/c video player");
else
vid->play_task = AssignTask (video_play_task, 4096, "video player");
if (!vid->play_task)
{
vid->playing = false;
//UnlockCrossThreadMutex (vid->frame_lock);
ClearSemaphore (vp_interthread_lock);
TFB_StopVideo (VidRef);
return false;
}
return true;
}
void
TFB_StopVideo (VIDEO_REF VidRef)
{
TFB_VideoClip* vid = (TFB_VideoClip*) VidRef;
if (!vid)
return;
vid->playing = false;
if (vid->play_task)
ConcludeTask (vid->play_task);
if (vid->hAudio)
{
StopMusic ();
DestroyMusic (vid->hAudio);
vid->hAudio = 0;
}
if (vid->frame)
{
TFB_DrawScreen_DeleteImage (vid->frame);
vid->frame = NULL;
}
}
bool
TFB_VideoPlaying (VIDEO_REF VidRef)
{
TFB_VideoClip* vid = (TFB_VideoClip*) VidRef;
if (!vid)
return false;
return vid->playing;
}
BOOLEAN
TFB_DoVideoInput (PVOID pIS)
{
VIDEO_INPUT_STATE* pVIS = (VIDEO_INPUT_STATE*) pIS;
TFB_VideoClip* vid = (TFB_VideoClip*) pVIS->CurVideo;
if (!pVIS->CurVideo || !TFB_VideoPlaying (pVIS->CurVideo))
return FALSE;
if (CurrentMenuState.select
|| CurrentMenuState.cancel
|| CurrentMenuState.special)
{ // abort movie
TFB_StopVideo (pVIS->CurVideo);
return FALSE;
}
else if (CurrentMenuState.left || CurrentMenuState.right)
{
if (vid->decoder->audio_synced)
{
float newpos;
LockMutex (vid->guard);
newpos = vid->decoder->pos;
UnlockMutex (vid->guard);
if (CurrentMenuState.left)
newpos -= 2;
else if (CurrentMenuState.right)
newpos += 1;
if (newpos < 0)
newpos = 0;
LockMutex (soundSource[MUSIC_SOURCE].stream_mutex);
SeekStream (MUSIC_SOURCE, (uint32) (newpos * 1000));
UnlockMutex (soundSource[MUSIC_SOURCE].stream_mutex);
TaskSwitch ();
}
// non a/c decoder seeking is not supported yet
}
return TRUE;
}
void
TFB_VideoInput (VIDEO_REF VidRef)
{
VIDEO_INPUT_STATE vis;
vis.MenuRepeatDelay = 0;
vis.InputFunc = TFB_DoVideoInput;
vis.CurVideo = VidRef;
DoInput (&vis, TRUE);
}
static void*
vp_GetCanvasLine (TFB_VideoDecoder* decoder, uint32 line)
{
TFB_VideoClip* vid = (TFB_VideoClip*) decoder->data;
if (!vid)
return NULL;
return TFB_GetVideoLine (vid->frame, line);
}
static uint32
vp_GetTicks (TFB_VideoDecoder* decoder)
{
return GetTimeCounter () * 1000 / ONE_SECOND;
(void)decoder; // gobble up compiler warning
}
static bool
vp_SetTimer (TFB_VideoDecoder* decoder, uint32 msecs)
{
TFB_VideoClip* vid = (TFB_VideoClip*) decoder->data;
if (!vid)
return false;
// time when next frame should be displayed
vid->frame_time = GetTimeCounter () + msecs * ONE_SECOND / 1000;
return true;
}
static bool
vp_AudioStart (TFB_SoundSample* sample)
{
TFB_VideoClip* vid = sample->data;
LockMutex (vid->guard);
vid->want_frame = SoundDecoder_GetFrame (sample->decoder);
UnlockMutex (vid->guard);
return true;
}
static void
vp_AudioEnd (TFB_SoundSample* sample)
{
TFB_VideoClip* vid = sample->data;
LockMutex (vid->guard);
vid->want_frame = vid->decoder->frame_count; // end it
UnlockMutex (vid->guard);
}
static void
vp_BufferTag (TFB_SoundSample* sample, TFB_SoundTag* tag)
{
TFB_VideoClip* vid = sample->data;
uint32 frame = (uint32) tag->data;
LockMutex (vid->guard);
vid->want_frame = frame; // let it go!
UnlockMutex (vid->guard);
}
static void
vp_QueueBuffer (TFB_SoundSample* sample, TFBSound_Object buffer)
{
//TFB_VideoClip* vid = sample->data;
TFB_TagBuffer (sample, buffer,
(void*) SoundDecoder_GetFrame (sample->decoder));
}
+29
View File
@@ -0,0 +1,29 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _VIDPLAYER_H
#define _VIDPLAYER_H
#include "video.h"
void TFB_FadeClearScreen ();
bool TFB_PlayVideo (VIDEO_REF VidRef, uint32 x, uint32 y);
void TFB_StopVideo (VIDEO_REF VidRef);
bool TFB_VideoPlaying (VIDEO_REF VidRef);
void TFB_VideoInput (VIDEO_REF VidRef);
#endif // _VIDPLAYER_H