Introducing LibAvW - a wrapper DLL to play videos using libav. Basic support includes...
authorvortex <vortex@d7cf8633-e32d-0410-b094-e92efae38249>
Tue, 20 Mar 2012 20:56:05 +0000 (20:56 +0000)
committervortex <vortex@d7cf8633-e32d-0410-b094-e92efae38249>
Tue, 20 Mar 2012 20:56:05 +0000 (20:56 +0000)
git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@11766 d7cf8633-e32d-0410-b094-e92efae38249

cl_video.c
cl_video.h
cl_video_jamdecode.c
cl_video_libavw.c [new file with mode: 0644]
dpvsimpledecode.c
dpvsimpledecode.h

index 08db058..f23dc92 100644 (file)
@@ -2,13 +2,6 @@
 #include "quakedef.h"
 #include "cl_dyntexture.h"
 #include "cl_video.h"
-#include "dpvsimpledecode.h"
-
-// VorteX: JAM video module used by Blood Omnicide
-#define USEJAM
-#ifdef USEJAM
-  #include "cl_video_jamdecode.c"
-#endif
 
 // cvars
 cvar_t cl_video_subtitles = {CVAR_SAVE, "cl_video_subtitles", "0", "show subtitles for videos (if they are present)"};
@@ -22,6 +15,19 @@ cvar_t cl_video_keepaspectratio = {CVAR_SAVE, "cl_video_keepaspectratio", "0", "
 cvar_t cl_video_fadein = {CVAR_SAVE, "cl_video_fadein", "0", "fading-from-black effect once video is started, in seconds"};
 cvar_t cl_video_fadeout = {CVAR_SAVE, "cl_video_fadeout", "0", "fading-to-black effect once video is ended, in seconds"};
 
+cvar_t v_glslgamma_video = {CVAR_SAVE, "v_glslgamma_video", "1", "applies GLSL gamma to played video, could be a fraction, requires r_glslgamma_2d 1."};
+
+// DPV stream decoder
+#include "dpvsimpledecode.h"
+
+// VorteX: libavcodec implementation
+#include "cl_video_libavw.c"
+
+// JAM video decoder used by Blood Omnicide
+#ifdef JAMVIDEO
+#include "cl_video_jamdecode.c"
+#endif
+
 // constants (and semi-constants)
 static int  cl_videormask;
 static int  cl_videobmask;
@@ -44,18 +50,23 @@ static clvideo_t *FindUnusedVid( void )
 static qboolean OpenStream( clvideo_t * video )
 {
        const char *errorstring;
+
        video->stream = dpvsimpledecode_open( video, video->filename, &errorstring);
-       if (!video->stream )
-       {
-#ifdef USEJAM
-               video->stream = jam_open( video, video->filename, &errorstring);
-               if (video->stream)
-                       return true;
+       if (video->stream)
+               return true;
+
+#ifdef JAMVIDEO
+       video->stream = jam_open( video, video->filename, &errorstring);
+       if (video->stream)
+               return true;
 #endif
-               Con_Printf("unable to open \"%s\", error: %s\n", video->filename, errorstring);
-               return false;
-       }
-       return true;
+
+       video->stream = LibAvW_OpenVideo( video, video->filename, &errorstring);
+       if (video->stream)
+               return true;
+
+       Con_Printf("unable to open \"%s\", error: %s\n", video->filename, errorstring);
+       return false;
 }
 
 static void VideoUpdateCallback(rtexture_t *rt, void *data)
@@ -89,7 +100,11 @@ static void SuspendVideo( clvideo_t * video )
        UnlinkVideoTexture(video);
        // if we are in firstframe mode, also close the stream
        if (video->state == CLVIDEO_FIRSTFRAME)
-               video->close(video->stream);
+       {
+               if (video->stream)
+                       video->close(video->stream);
+               video->stream = NULL;
+       }
 }
 
 static qboolean WakeVideo( clvideo_t * video )
@@ -129,7 +144,7 @@ static void LoadSubtitles( clvideo_t *video, const char *subtitlesfile )
                subtitle_text = NULL;
                if (langcvar)
                {
-                       dpsnprintf(overridename, sizeof(overridename), "script/locale/%s/%s", langcvar->string, subtitlesfile);
+                       dpsnprintf(overridename, sizeof(overridename), "locale/%s/%s", langcvar->string, subtitlesfile);
                        subtitle_text = (char *)FS_LoadFile(overridename, cls.permanentmempool, false, NULL);
                }
                if (!subtitle_text)
@@ -303,7 +318,9 @@ void CL_RestartVideo(clvideo_t *video)
        video->framenum = -1;
 
        // reopen stream
-       video->close(video->stream);
+       if (video->stream)
+               video->close(video->stream);
+       video->stream = NULL;
        if (!OpenStream(video))
                video->state = CLVIDEO_UNUSED;
 }
@@ -318,7 +335,11 @@ void CL_CloseVideo(clvideo_t * video)
 
        // close stream
        if (!video->suspended || video->state != CLVIDEO_FIRSTFRAME)
-               video->close(video->stream);
+       {
+               if (video->stream)
+                       video->close(video->stream);
+               video->stream = NULL;
+       }
        // unlink texture
        if (!video->suspended)
                UnlinkVideoTexture(video);
@@ -389,13 +410,6 @@ void CL_Video_Frame(void)
                cl_num_videos--;
 }
 
-void CL_Video_Shutdown( void )
-{
-       int i;
-       for (i = 0 ; i < cl_num_videos ; i++)
-               CL_CloseVideo(&cl_videos[ i ]);
-}
-
 void CL_PurgeOwner( int owner )
 {
        int i;
@@ -474,7 +488,7 @@ void CL_DrawVideo(void)
        st[6] = 1.0; st[7] = 1.0; 
        if (cl_video_keepaspectratio.integer)
        {
-               float a = ((float)video->cpif.width / (float)video->cpif.height) / ((float)vid.width / (float)vid.height);
+               float a = video->getaspectratio(video->stream) / ((float)vid.width / (float)vid.height);
                if (cl_video_keepaspectratio.integer >= 2)
                {
                        // clip instead of scale
@@ -542,7 +556,14 @@ void CL_DrawVideo(void)
 #endif
 
        // draw video
-       DrawQ_SuperPic(px, py, &video->cpif, sx, sy, st[0], st[1], b, b, b, 1, st[2], st[3], b, b, b, 1, st[4], st[5], b, b, b, 1, st[6], st[7], b, b, b, 1, 0);
+       if (v_glslgamma_video.value >= 1)
+               DrawQ_SuperPic(px, py, &video->cpif, sx, sy, st[0], st[1], b, b, b, 1, st[2], st[3], b, b, b, 1, st[4], st[5], b, b, b, 1, st[6], st[7], b, b, b, 1, 0);
+       else
+       {
+               DrawQ_SuperPic(px, py, &video->cpif, sx, sy, st[0], st[1], b, b, b, 1, st[2], st[3], b, b, b, 1, st[4], st[5], b, b, b, 1, st[6], st[7], b, b, b, 1, DRAWFLAG_NOGAMMA);
+               if (v_glslgamma_video.value > 0.0)
+                       DrawQ_SuperPic(px, py, &video->cpif, sx, sy, st[0], st[1], b, b, b, v_glslgamma_video.value, st[2], st[3], b, b, b, v_glslgamma_video.value, st[4], st[5], b, b, b, v_glslgamma_video.value, st[6], st[7], b, b, b, v_glslgamma_video.value, 0);
+       }
 
 #ifndef USE_GLES2
        // disable video-only stipple
@@ -704,5 +725,19 @@ void CL_Video_Init( void )
        Cvar_RegisterVariable(&cl_video_fadein);
        Cvar_RegisterVariable(&cl_video_fadeout);
 
+       Cvar_RegisterVariable(&v_glslgamma_video);
+
        R_RegisterModule( "CL_Video", cl_video_start, cl_video_shutdown, cl_video_newmap, NULL, NULL );
-}
\ No newline at end of file
+
+       LibAvW_OpenLibrary();
+}
+
+void CL_Video_Shutdown( void )
+{
+       int i;
+
+       for (i = 0 ; i < cl_num_videos ; i++)
+               CL_CloseVideo(&cl_videos[ i ]);
+
+       LibAvW_CloseLibrary();
+}
index 4277124..97960b8 100644 (file)
@@ -59,6 +59,7 @@ typedef struct clvideo_s
        unsigned int (*getwidth) (void *stream);
        unsigned int (*getheight) (void *stream);
        double (*getframerate) (void *stream);
+       double (*getaspectratio) (void *stream);
        int (*decodeframe) (void *stream, void *imagedata, unsigned int Rmask, unsigned int Gmask, unsigned int Bmask, unsigned int bytesperpixel, int imagebytesperrow);
 
        // if a video is suspended, it is automatically paused (else we'd still have to process the frames)
index da65ef2..475f1f7 100644 (file)
 // JAM format decoder, used by Blood Omnicide
 
+#ifdef LIBAVCODEC
+//#define JAM_USELIBAVCODECSCALE
+#endif
+
 typedef struct jamdecodestream_s
 {
-       int error;
+       qfile_t       *file;
+       double         info_framerate;
+       unsigned int   info_frames;
+       unsigned int   info_imagewidth;
+       unsigned int   info_imageheight;
+       double         info_aspectratio;
+       float          colorscale;
+       unsigned char  colorsub;
 
-       qfile_t *file;
-       double info_framerate;
-       unsigned int info_frames;
-       unsigned int info_imagewidth;
-       unsigned int info_imageheight;
-       int doubleres;
-       float colorscale;
-       unsigned char colorsub;
-       float stipple;
+       // info used during decoding
+       unsigned char *frame;
+       unsigned char *frame_prev;
+       unsigned char  frame_palette[768];
+       unsigned char *frame_compressed;
+       unsigned int   framesize;
+       unsigned int   framenum;
 
-       // info used durign decoding
-       unsigned char *videopixels;
-       unsigned char *compressed;
-       unsigned char *framedata;
-       unsigned char *prevframedata;
-       unsigned char colormap[768];
-       unsigned int framesize;
-       unsigned int framenum;
+       // libavcodec scaling
+#ifdef JAM_USELIBAVCODECSCALE
+       unsigned char *frame_output_buffer;
+       AVFrame       *frame_output;
+       AVFrame       *frame_output_scale;
+       unsigned int   framewidth;
+       unsigned int   frameheight;
+#endif
 
        // channel the sound file is being played on
        int sndchan;
 }
 jamdecodestream_t;
 
-#define JAMDECODEERROR_NONE                0
-#define JAMDECODEERROR_EOF                 1
-#define JAMDECODEERROR_READERROR           2
-#define JAMDECODEERROR_BAD_FRAME_HEADER    3
-#define JAMDECODEERROR_BAD_OUTPUT_SIZE     4
-#define JAMDECODEERROR_BAD_COLORMAP        5
-
 // opens a stream
 void jam_close(void *stream);
 unsigned int jam_getwidth(void *stream);
 unsigned int jam_getheight(void *stream);
 double jam_getframerate(void *stream);
+double jam_getaspectratio(void *stream);
 int jam_video(void *stream, void *imagedata, unsigned int Rmask, unsigned int Gmask, unsigned int Bmask, unsigned int bytesperpixel, int imagebytesperrow);
-static void *jam_open(clvideo_t *video, char *filename, const char **errorstring)
+void *jam_open(clvideo_t *video, char *filename, const char **errorstring)
 {
-       unsigned char jamHead[16];
-       char *wavename;
+       char jamHead[16];
        jamdecodestream_t *s;
-       qfile_t *file;
+       char *wavename;
 
+       // allocate stream structure
        s = (jamdecodestream_t *)Z_Malloc(sizeof(jamdecodestream_t));
-       if (s != NULL)
+       memset(s, 0, sizeof(jamdecodestream_t));
+       s->sndchan = -1;
+       if (s == NULL)
        {
-               if ((file = FS_OpenVirtualFile(filename, false)))
-               {
-                       s->file = file;
-                       if (FS_Read(s->file, &jamHead, 16))
-                       {
-                               if (!memcmp(jamHead, "JAM", 3))
-                               {
-                                       s->info_imagewidth = LittleLong(*(jamHead + 4));
-                                       s->info_imageheight = LittleLong(*(jamHead + 8));
-                                       s->info_frames = LittleLong(*(jamHead + 12));
-                                       s->info_framerate = 15;
-                                       s->doubleres = 0;
-                                       s->colorscale = 0.70;
-                                       s->colorsub = 8;
-                                       s->stipple = 0.4;
-                                       s->framesize = s->info_imagewidth * s->info_imageheight;
-                                       if (s->framesize > 0)
-                                       {
-                                               s->compressed = (unsigned char *)Z_Malloc(s->framesize);
-                                               s->framedata = (unsigned char *)Z_Malloc(s->framesize * 2);
-                                               s->prevframedata = (unsigned char *)Z_Malloc(s->framesize * 2);
-                                               s->videopixels = (unsigned char *)Z_Malloc(s->framesize * 4); // bgra, doubleres
-                                               if (s->compressed != NULL && s->framedata != NULL && s->prevframedata != NULL && s->videopixels != NULL)
-                                               {
-                                                       size_t namelen;
+               *errorstring = "unable to allocate memory for stream info structure";
+               return NULL;
+       }
 
-                                                       namelen = strlen(filename) + 10;
-                                                       wavename = (char *)Z_Malloc(namelen);
-                                                       if (wavename)
-                                                       {
-                                                               sfx_t* sfx;
+       // open file
+       s->file = FS_OpenVirtualFile(filename, true);
+       if (!s->file)
+       {
+               *errorstring = "unable to open videofile";
+               jam_close(s);
+               return NULL;
+       }
 
-                                                               FS_StripExtension(filename, wavename, namelen);
-                                                               strlcat(wavename, ".wav", namelen);
-                                                               sfx = S_PrecacheSound(wavename, false, false);
-                                                               if (sfx != NULL)
-                                                                       s->sndchan = S_StartSound (-1, 0, sfx, vec3_origin, 1.0f, 0);
-                                                               else
-                                                                       s->sndchan = -1;
-                                                               Z_Free(wavename);
-                                                       }
-                                                       // all is well...
-                                                       // set the module functions
-                                                       s->framenum = 0;
-                                                       video->close = jam_close;
-                                                       video->getwidth = jam_getwidth;
-                                                       video->getheight = jam_getheight;
-                                                       video->getframerate = jam_getframerate;
-                                                       video->decodeframe = jam_video;
-                                                       return s;
-                                               }
-                                               else if (errorstring != NULL)
-                                                       *errorstring = "unable to allocate memory for stream info structure";
-                                               if (s->compressed != NULL)
-                                                       Z_Free(s->compressed);
-                                               if (s->framedata != NULL)
-                                                       Z_Free(s->framedata);
-                                               if (s->prevframedata != NULL)
-                                                       Z_Free(s->prevframedata);
-                                               if (s->videopixels != NULL)
-                                                       Z_Free(s->videopixels);
-                                       }
-                                       else if (errorstring != NULL)
-                                               *errorstring = "bad framesize";
-                               }
-                               else if (errorstring != NULL)
-                                       *errorstring = "not JAM videofile";
-                       }
-                       else if (errorstring != NULL)
-                               *errorstring = "unexpected EOF";
-                       FS_Close(file);
-               }
-               else if (errorstring != NULL)
-                       *errorstring = "unable to open videofile";
+       // read header
+       if (!FS_Read(s->file, jamHead, 16))
+       {
+               *errorstring = "JamDecoder: unexpected EOF reading header";
+               jam_close(s);
+               return NULL;
+       }
+       if (memcmp(jamHead, "JAM", 4))
+       {
+               *errorstring = "JamDecoder: not a JAM file";
+               jam_close(s);
+               return NULL;
+       }
+
+       s->info_imagewidth = LittleLong(*(jamHead + 4));
+       s->info_imageheight = LittleLong(*(jamHead + 8));
+       s->info_frames = LittleLong(*(jamHead + 12)) - 1;
+       s->info_framerate = 15;
+       s->info_aspectratio = (double)s->info_imagewidth / (double)s->info_imageheight;
+       s->colorscale = 0.90;
+       s->colorsub = 4;
+       s->framesize = s->info_imagewidth * s->info_imageheight;
+
+       // allocate frame input/output
+       if (s->framesize < 0)
+       {
+               *errorstring = "JamDecoder: bad framesize";
+               jam_close(s);
+               return NULL;
+       }
+       s->frame = (unsigned char *)Z_Malloc(s->framesize * 2);
+       s->frame_prev = (unsigned char *)Z_Malloc(s->framesize * 2);
+       s->frame_compressed = (unsigned char *)Z_Malloc(s->framesize);
+       if (s->frame_compressed == NULL || s->frame == NULL || s->frame_prev == NULL)
+       {
+               *errorstring = "JamDecoder: unable to allocate memory for video decoder";
+               jam_close(s);
+               return NULL;
+       }
+
+       // scale support provided by libavcodec
+#ifdef JAM_USELIBAVCODECSCALE
+       s->framewidth = s->info_imagewidth;
+       s->frameheight = s->info_imageheight;
+
+       // min size
+       if (cl_video_libavcodec_minwidth.integer > 0)
+               s->info_imagewidth = max(s->info_imagewidth, (unsigned int)cl_video_libavcodec_minwidth.integer);
+       if (cl_video_libavcodec_minheight.integer > 0)
+               s->info_imageheight = max(s->info_imageheight, (unsigned int)cl_video_libavcodec_minheight.integer);
+
+       // allocate output
+       s->frame_output_buffer = (unsigned char *)Z_Malloc(s->framesize * 4);
+       s->frame_output = AvCodec_AllocFrame();
+       s->frame_output_scale = AvCodec_AllocFrame();
+       if (!s->frame_output_buffer || !s->frame_output || !s->frame_output_scale)
+    {
+               *errorstring = "JamDecoder: failed to allocate LibAvcodec frame";
+               jam_close(s);
                Z_Free(s);
+        return NULL;
        }
-       else if (errorstring != NULL)
-               *errorstring = "unable to allocate memory for stream info structure";
-       return NULL;
+#endif
+
+       // everything is ok
+       // set the module functions
+       s->framenum = 0;
+       video->close = jam_close;
+       video->getwidth = jam_getwidth;
+       video->getheight = jam_getheight;
+       video->getframerate = jam_getframerate;
+       video->decodeframe = jam_video;
+       video->getaspectratio = jam_getaspectratio;
+
+       // set sound
+       size_t namelen;
+       namelen = strlen(filename) + 10;
+       wavename = (char *)Z_Malloc(namelen);
+       if (wavename)
+       {
+               sfx_t* sfx;
+               FS_StripExtension(filename, wavename, namelen);
+               strlcat(wavename, ".wav", namelen);
+               sfx = S_PrecacheSound(wavename, false, false);
+               if (sfx != NULL)
+                       s->sndchan = S_StartSound (-1, 0, sfx, vec3_origin, 1.0f, 0);
+               else
+                       s->sndchan = -1;
+               Z_Free(wavename);
+       }
+
+       return s;
 }
 
 // closes a stream
@@ -138,14 +169,32 @@ void jam_close(void *stream)
        jamdecodestream_t *s = (jamdecodestream_t *)stream;
        if (s == NULL)
                return;
-       Z_Free(s->compressed);
-       Z_Free(s->framedata);
-       Z_Free(s->prevframedata);
-       Z_Free(s->videopixels);
+       if (s->frame_compressed)
+               Z_Free(s->frame_compressed);
+       s->frame_compressed = NULL;
+       if (s->frame)
+               Z_Free(s->frame);
+       s->frame = NULL;
+       if (s->frame_prev)
+               Z_Free(s->frame_prev);
+       s->frame_prev = NULL;
        if (s->sndchan != -1)
                S_StopChannel(s->sndchan, true, true);
+       s->sndchan = -1;
        if (s->file)
                FS_Close(s->file);
+       s->file = NULL;
+#ifdef JAM_USELIBAVCODECSCALE
+       if (s->frame_output_buffer)
+               Z_Free(s->frame_output_buffer);
+       s->frame_output_buffer = NULL;
+       if (s->frame_output)
+               AvUtil_Free(s->frame_output);
+       s->frame_output = NULL;
+       if (s->frame_output_scale)
+               AvUtil_Free(s->frame_output_scale);
+       s->frame_output_scale = NULL;
+#endif
        Z_Free(s);
 }
 
@@ -153,8 +202,6 @@ void jam_close(void *stream)
 unsigned int jam_getwidth(void *stream)
 {
        jamdecodestream_t *s = (jamdecodestream_t *)stream;
-       if (s->doubleres)
-               return s->info_imagewidth * 2;
        return s->info_imagewidth;
 }
 
@@ -162,8 +209,6 @@ unsigned int jam_getwidth(void *stream)
 unsigned int jam_getheight(void *stream)
 {
        jamdecodestream_t *s = (jamdecodestream_t *)stream;
-       if (s->doubleres)
-               return s->info_imageheight * 2;
        return s->info_imageheight;
 }
 
@@ -174,6 +219,12 @@ double jam_getframerate(void *stream)
        return s->info_framerate;
 }
 
+// returns aspect ration of the stream
+double jam_getaspectratio(void *stream)
+{
+       jamdecodestream_t *s = (jamdecodestream_t *)stream;
+       return s->info_aspectratio;
+}
 
 // decode JAM frame
 static void jam_decodeframe(unsigned char *inbuf, unsigned char *outbuf, unsigned char *prevbuf, int outsize, int frametype)
@@ -239,117 +290,89 @@ static void jam_decodeframe(unsigned char *inbuf, unsigned char *outbuf, unsigne
 int jam_video(void *stream, void *imagedata, unsigned int Rmask, unsigned int Gmask, unsigned int Bmask, unsigned int bytesperpixel, int imagebytesperrow)
 {
        unsigned char frameHead[16], *b;
-       unsigned int compsize, outsize, i, j;
+       unsigned int compsize, outsize, i;
        jamdecodestream_t *s = (jamdecodestream_t *)stream;
 
-       s->error = DPVSIMPLEDECODEERROR_NONE;
-       if (s->framenum < s->info_frames)
-       {
+       // EOF
+       if (s->framenum >= s->info_frames)
+               return 1;
+       s->framenum++;
+
 readframe:
-               if (FS_Read(s->file, &frameHead, 16))
-               {
-                       compsize = LittleLong(*(frameHead + 8)) - 16;
-                       outsize = LittleLong(*(frameHead + 12));
-                       if (compsize > s->framesize || outsize > s->framesize)
-                               s->error = JAMDECODEERROR_BAD_FRAME_HEADER;
-                       else if (FS_Read(s->file, s->compressed, compsize))
-                       {
-                               // palette goes interleaved with special flag
-                               if (frameHead[0] == 2)
-                               {
-                                       if (compsize == 768)
-                                       {
-                                               memcpy(s->colormap, s->compressed, 768);
-                                               for(i = 0; i < 768; i++)
-                                                       s->colormap[i] = (unsigned char)(bound(0, (s->colormap[i] * s->colorscale) - s->colorsub, 255));
-                                               goto readframe;
-                                       }
-                                       //else
-                                       //      s->error = JAMDECODEERROR_BAD_COLORMAP;
-                               }
-                               else
-                               {
-                                       // decode frame
-                                       // shift buffers to provide current and previous one, decode
-                                       b = s->prevframedata;
-                                       s->prevframedata = s->framedata;
-                                       s->framedata = b;
-                                       jam_decodeframe(s->compressed, s->framedata, s->prevframedata, outsize, frameHead[4]);
-                                       // make 32bit imagepixels from 8bit palettized frame
-                                       if (s->doubleres)
-                                               b = s->videopixels;
-                                       else
-                                               b = (unsigned char *)imagedata;
-                                       for(i = 0; i < s->framesize; i++)
-                                       {
-                                               // bgra
-                                               *b++ = s->colormap[s->framedata[i]*3 + 2];
-                                               *b++ = s->colormap[s->framedata[i]*3 + 1];
-                                               *b++ = s->colormap[s->framedata[i]*3];
-                                               *b++ = 255;
-                                       }
-                                       // nearest 2x
-                                       if (s->doubleres)
-                                       {
-                                               for (i = 0; i < s->info_imageheight; i++)
-                                               {
-                                                       b = (unsigned char *)imagedata + (s->info_imagewidth*2*4)*(i*2);
-                                                       for (j = 0; j < s->info_imagewidth; j++)
-                                                       {
-                                                               *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4];
-                                                               *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 1];
-                                                               *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 2];
-                                                               *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 3];
-                                                               //
-                                                               *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4];
-                                                               *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 1];
-                                                               *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 2];
-                                                               *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 3];
-                                                       }
-                                                       b = (unsigned char *)imagedata + (s->info_imagewidth*2*4)*(i*2 + 1);
-                                                       for (j = 0; j < s->info_imagewidth; j++)
-                                                       {
-                                                               *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4];
-                                                               *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 1];
-                                                               *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 2];
-                                                               *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 3];
-                                                               //
-                                                               *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4];
-                                                               *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 1];
-                                                               *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 2];
-                                                               *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 3];
-                                                       }
-                                               }
-                                               // do stippling
-                                               if (s->stipple)
-                                               {
-                                                       for (i = 0; i < s->info_imageheight; i++)
-                                                       {
-                                                               b = (unsigned char *)imagedata + (s->info_imagewidth * 4 * 2 * 2 * i);
-                                                               for (j = 0; j < s->info_imagewidth; j++)
-                                                               {
-                                                                       b[0] = b[0] * s->stipple;
-                                                                       b[1] = b[1] * s->stipple;
-                                                                       b[2] = b[2] * s->stipple;
-                                                                       b += 4;
-                                                                       b[0] = b[0] * s->stipple;
-                                                                       b[1] = b[1] * s->stipple;
-                                                                       b[2] = b[2] * s->stipple;
-                                                                       b += 4;
-                                                               }
-                                                       }
-                                               }
-                                       }
+       // read frame header
+       if (!FS_Read(s->file, &frameHead, 16))
+       {
+               Con_Printf("JamDecoder: unexpected EOF on frame %i\n", s->framenum);
+               return 1;
+       }
+       compsize = LittleLong(*(frameHead + 8)) - 16;
+       outsize = LittleLong(*(frameHead + 12));
+       if (compsize > s->framesize || outsize > s->framesize)
+       {
+               Con_Printf("JamDecoder: got bogus header on frame %i\n", s->framenum);
+               return 1;
+       }
 
-                               }
-                       }
-                       else
-                               s->error = JAMDECODEERROR_READERROR;
+       // read frame contents
+       if (!FS_Read(s->file, s->frame_compressed, compsize))
+       {
+               Con_Printf("JamDecoder: unexpected EOF on frame %i\n", s->framenum);
+               return 1;
+       }
+
+       // palette goes interleaved with special flag
+       if (frameHead[0] == 2)
+       {
+               if (compsize == 768)
+               {
+                       memcpy(s->frame_palette, s->frame_compressed, 768);
+                       for(i = 0; i < 768; i++)
+                               s->frame_palette[i] = (unsigned char)(bound(0, (s->frame_palette[i] * s->colorscale) - s->colorsub, 255));
+                       goto readframe;
                }
-               else
-                       s->error = JAMDECODEERROR_READERROR;
        }
        else
-               s->error = DPVSIMPLEDECODEERROR_EOF;
-       return s->error;
-}
+       {
+               // decode frame
+               // shift buffers to provide current and previous one, decode
+               b = s->frame_prev;
+               s->frame_prev = s->frame;
+               s->frame = b;
+               jam_decodeframe(s->frame_compressed, s->frame, s->frame_prev, outsize, frameHead[4]);
+#ifdef JAM_USELIBAVCODECSCALE
+               // make BGRA imagepixels from 8bit palettized frame
+               b = (unsigned char *)s->frame_output_buffer;
+               for(i = 0; i < s->framesize; i++)
+               {
+                       *b++ = s->frame_palette[s->frame[i]*3 + 2];
+                       *b++ = s->frame_palette[s->frame[i]*3 + 1];
+                       *b++ = s->frame_palette[s->frame[i]*3];
+                       *b++ = 255;
+               }
+               // scale
+               AvCodec_FillPicture((AVPicture *)s->frame_output, (uint8_t *)s->frame_output_buffer, PIX_FMT_BGRA, s->framewidth, s->frameheight);
+               AvCodec_FillPicture((AVPicture *)s->frame_output_scale, (uint8_t *)imagedata, PIX_FMT_BGRA, s->info_imagewidth, s->info_imageheight);
+               SwsContext *scale_context = SwScale_GetCachedContext(NULL, s->framewidth, s->frameheight, PIX_FMT_BGRA, s->info_imagewidth, s->info_imageheight, PIX_FMT_BGRA, libavcodec_scalers[max(0, min(LIBAVCODEC_SCALERS, cl_video_libavcodec_scaler.integer))], NULL, NULL, NULL); 
+               if (!scale_context)
+               {
+                       Con_Printf("JamDecoder: LibAvcodec: error creating scale context frame %i\n", s->framenum);
+                       return 1;
+               }
+               if (!SwScale_Scale(scale_context, s->frame_output->data, s->frame_output->linesize, 0, s->frameheight, s->frame_output_scale->data, s->frame_output_scale->linesize))
+                       Con_Printf("JamDecoder: LibAvcodec : error scaling frame\n", s->framenum);
+               SwScale_FreeContext(scale_context); 
+#else
+               // make BGRA imagepixels from 8bit palettized frame
+               b = (unsigned char *)imagedata;
+               for(i = 0; i < s->framesize; i++)
+               {
+                       // bgra
+                       *b++ = s->frame_palette[s->frame[i]*3 + 2];
+                       *b++ = s->frame_palette[s->frame[i]*3 + 1];
+                       *b++ = s->frame_palette[s->frame[i]*3];
+                       *b++ = 255;
+               }
+#endif
+       }
+       return 0;
+}
\ No newline at end of file
diff --git a/cl_video_libavw.c b/cl_video_libavw.c
new file mode 100644 (file)
index 0000000..5423897
--- /dev/null
@@ -0,0 +1,390 @@
+/*\r
+       Libavcodec integration for Darkplaces by Timofeyev Pavel\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\r
+\r
+       See the GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to:\r
+\r
+               Free Software Foundation, Inc.\r
+               59 Temple Place - Suite 330\r
+               Boston, MA  02111-1307, USA\r
+\r
+*/\r
+\r
+#include "common.h"\r
+#ifdef _MSC_VERSION\r
+#include "stdint.h"\r
+#else\r
+#include <stdint.h>\r
+#endif\r
+\r
+// scaler type\r
+#define LIBAVW_SCALER_BILINEAR  0\r
+#define LIBAVW_SCALER_BICUBIC   1\r
+#define LIBAVW_SCALER_X         2\r
+#define LIBAVW_SCALER_POINT     3\r
+#define LIBAVW_SCALER_AREA      4\r
+#define LIBAVW_SCALER_BICUBLIN  5\r
+#define LIBAVW_SCALER_GAUSS     6\r
+#define LIBAVW_SCALER_SINC      7\r
+#define LIBAVW_SCALER_LANCZOS   8\r
+#define LIBAVW_SCALER_SPLINE    9\r
+// output format\r
+#define LIBAVW_PIXEL_FORMAT_BGR   0\r
+#define LIBAVW_PIXEL_FORMAT_BGRA  1\r
+// print levels\r
+#define LIBAVW_PRINT_WARNING 1\r
+#define LIBAVW_PRINT_ERROR   2\r
+#define LIBAVW_PRINT_FATAL   3\r
+#define LIBAVW_PRINT_PANIC   4\r
+// exported callback functions:\r
+typedef void    avwCallbackPrint(int, const char *);\r
+typedef int     avwCallbackIoRead(void *, uint8_t *, int);\r
+typedef int64_t avwCallbackIoSeek(void *, int64_t, int);\r
+typedef int64_t avwCallbackIoSeekSize(void *);\r
+// exported functions:\r
+int         (*qLibAvW_Init)(avwCallbackPrint *printfunction); // init library, returns error code\r
+const char *(*qLibAvW_ErrorString)(int errorcode); // get string for error code\r
+const char *(*qLibAvW_AvcVersion)(void); // get a string containing libavcodec version wrapper was built for\r
+float       (*qLibAvW_Version)(void); // get wrapper version\r
+int         (*qLibAvW_CreateStream)(void **stream); // create stream, returns error code\r
+void        (*qLibAvW_RemoveStream)(void *stream); // flush and remove stream\r
+int         (*qLibAvW_StreamGetVideoWidth)(void *stream); // get video parameters of stream\r
+int         (*qLibAvW_StreamGetVideoHeight)(void *stream);\r
+double      (*qLibAvW_StreamGetFramerate)(void *stream);\r
+int         (*qLibAvW_StreamGetError)(void *stream); // get last function errorcode from stream\r
+// simple API to play video\r
+int (*qLibAvW_PlayVideo)(void *stream, void *file, avwCallbackIoRead *IoRead, avwCallbackIoSeek *IoSeek, avwCallbackIoSeekSize *IoSeekSize);\r
+int (*qLibAvW_PlaySeekNextFrame)(void *stream);\r
+int (*qLibAvW_PlayGetFrameImage)(void *stream, int pixel_format, void *imagedata, int imagewidth, int imageheight, int scaler);\r
+\r
+static dllfunction_t libavwfuncs[] =\r
+{\r
+       {"LibAvW_Init",                (void **) &qLibAvW_Init },\r
+       {"LibAvW_ErrorString",         (void **) &qLibAvW_ErrorString },\r
+       {"LibAvW_AvcVersion",          (void **) &qLibAvW_AvcVersion },\r
+       {"LibAvW_Version",             (void **) &qLibAvW_Version },\r
+       {"LibAvW_CreateStream",        (void **) &qLibAvW_CreateStream },\r
+       {"LibAvW_RemoveStream",        (void **) &qLibAvW_RemoveStream },\r
+       {"LibAvW_StreamGetVideoWidth", (void **) &qLibAvW_StreamGetVideoWidth },\r
+       {"LibAvW_StreamGetVideoHeight",(void **) &qLibAvW_StreamGetVideoHeight },\r
+       {"LibAvW_StreamGetFramerate",  (void **) &qLibAvW_StreamGetFramerate },\r
+       {"LibAvW_StreamGetError",      (void **) &qLibAvW_StreamGetError },\r
+       {"LibAvW_PlayVideo",           (void **) &qLibAvW_PlayVideo },\r
+       {"LibAvW_PlaySeekNextFrame",   (void **) &qLibAvW_PlaySeekNextFrame },\r
+       {"LibAvW_PlayGetFrameImage",   (void **) &qLibAvW_PlayGetFrameImage },\r
+       {NULL, NULL}\r
+};\r
+\r
+const char* dllnames_libavw[] =\r
+{\r
+#if defined(WIN32)\r
+               "libavw.dll",\r
+#elif defined(MACOSX)\r
+               "libavw.dylib",\r
+#else\r
+               "libavw.so.1",\r
+               "libavw.so",\r
+#endif\r
+               NULL\r
+};\r
+\r
+static dllhandle_t libavw_dll = NULL;\r
+\r
+// DP videostream\r
+typedef struct libavwstream_s\r
+{\r
+       qfile_t     *file;\r
+       double       info_framerate;\r
+       unsigned int info_imagewidth;\r
+       unsigned int info_imageheight;\r
+       double       info_aspectratio;\r
+       void        *stream;\r
+\r
+       // channel the sound file is being played on\r
+       sfx_t *sfx;\r
+       int    sndchan;\r
+       int    sndstarted;\r
+}\r
+libavwstream_t;\r
+\r
+cvar_t cl_video_libavw_minwidth  = {CVAR_SAVE, "cl_video_libavw_minwidth", "0", "if videos width is lesser than minimal, thay will be upscaled"};\r
+cvar_t cl_video_libavw_minheight = {CVAR_SAVE, "cl_video_libavw_minheight", "0", "if videos height is lesser than minimal, thay will be upscaled"};\r
+cvar_t cl_video_libavw_scaler    = {CVAR_SAVE, "cl_video_libavw_scaler", "1", "selects a scaler for libavcode played videos. Scalers are: 0 - bilinear, 1 - bicubic, 2 - x, 3 - point, 4 - area, 5 - bicublin, 6 - gauss, 7 - sinc, 8 - lanczos, 9 - spline."};\r
+\r
+// video extensions\r
+const char* libavw_extensions[] =\r
+{\r
+       "ogv",\r
+       "avi",\r
+       "mpg",\r
+       "mp4",\r
+       "mkv",\r
+       "webm",\r
+       "bik",\r
+       "roq",\r
+       "flv",\r
+       "wmv",\r
+       "mpeg",\r
+       "mjpeg",\r
+       "mpeg4",\r
+       NULL\r
+};\r
+\r
+/*\r
+=================================================================\r
+\r
+  Video decoding\r
+  a features that is not supported yet and likely to be done\r
+  - streaming audio from videofiles\r
+  - streaming subtitles\r
+\r
+=================================================================\r
+*/\r
+\r
+unsigned int libavw_getwidth(void *stream);\r
+unsigned int libavw_getheight(void *stream);\r
+double libavw_getframerate(void *stream);\r
+double libavw_getaspectratio(void *stream);\r
+void libavw_close(void *stream);\r
+\r
+int libavw_decodeframe(void *stream, void *imagedata, unsigned int Rmask, unsigned int Gmask, unsigned int Bmask, unsigned int bytesperpixel, int imagebytesperrow)\r
+{\r
+       int pixel_format = LIBAVW_PIXEL_FORMAT_BGR;\r
+       int errorcode;\r
+\r
+       libavwstream_t *s = (libavwstream_t *)stream;\r
+\r
+       // start sound\r
+       if (!s->sndstarted)\r
+       {\r
+               if (s->sfx != NULL)\r
+                       s->sndchan = S_StartSound(-1, 0, s->sfx, vec3_origin, 1.0f, 0);\r
+               s->sndstarted = 1;\r
+       }\r
+\r
+       // read frame\r
+       if (!qLibAvW_PlaySeekNextFrame(s->stream))\r
+       {\r
+               // got error or file end\r
+               errorcode = qLibAvW_StreamGetError(s->stream);\r
+               if (errorcode)\r
+                       Con_Printf("LibAvW: %s\n", qLibAvW_ErrorString(errorcode));\r
+               return 1;\r
+       }\r
+\r
+       // decode into bgr texture\r
+       if (bytesperpixel == 4)\r
+               pixel_format = LIBAVW_PIXEL_FORMAT_BGRA;\r
+       else if (bytesperpixel == 3)\r
+               pixel_format = LIBAVW_PIXEL_FORMAT_BGR;\r
+       else\r
+       {\r
+               Con_Printf("LibAvW: cannot determine pixel format for bpp %i\n", bytesperpixel);\r
+               return 1;\r
+       }\r
+       if (!qLibAvW_PlayGetFrameImage(s->stream, pixel_format, imagedata, s->info_imagewidth, s->info_imageheight, min(9, max(0, cl_video_libavw_scaler.integer))))\r
+               Con_Printf("LibAvW: %s\n", qLibAvW_ErrorString(qLibAvW_StreamGetError(s->stream)));\r
+       return 0;\r
+}\r
+\r
+// get stream info\r
+unsigned int libavw_getwidth(void *stream)\r
+{\r
+       return ((libavwstream_t *)stream)->info_imagewidth;\r
+}\r
+\r
+unsigned int libavw_getheight(void *stream)\r
+{\r
+       return ((libavwstream_t *)stream)->info_imageheight;\r
+}\r
+\r
+double libavw_getframerate(void *stream)\r
+{\r
+       return ((libavwstream_t *)stream)->info_framerate;\r
+}\r
+\r
+double libavw_getaspectratio(void *stream)\r
+{\r
+       return ((libavwstream_t *)stream)->info_aspectratio;\r
+}\r
+\r
+// close stream\r
+void libavw_close(void *stream)\r
+{\r
+       libavwstream_t *s = (libavwstream_t *)stream;\r
+\r
+       if (s->stream)\r
+               qLibAvW_RemoveStream(s->stream);\r
+       s->stream = NULL;\r
+       if (s->file)\r
+               FS_Close(s->file);\r
+       s->file = NULL;\r
+       if (s->sndchan >= 0)\r
+               S_StopChannel(s->sndchan, true, true);\r
+       s->sndchan = -1;\r
+}\r
+\r
+// IO wrapper\r
+int LibAvW_FS_Read(void *opaque, uint8_t *buf, int buf_size)\r
+{\r
+       return FS_Read((qfile_t *)opaque, buf, buf_size);\r
+}\r
+int64_t LibAvW_FS_Seek(void *opaque, int64_t pos, int whence)\r
+{\r
+       return (int64_t)FS_Seek((qfile_t *)opaque, pos, whence);\r
+}\r
+int64_t LibAvW_FS_SeekSize(void *opaque)\r
+{\r
+       return (int64_t)FS_FileSize((qfile_t *)opaque);\r
+}\r
+\r
+// open as DP video stream\r
+void *LibAvW_OpenVideo(clvideo_t *video, char *filename, const char **errorstring)\r
+{\r
+       libavwstream_t *s;\r
+       char filebase[MAX_OSPATH], check[MAX_OSPATH];\r
+       unsigned int i;\r
+       int errorcode;\r
+       char *wavename;\r
+       size_t len;\r
+\r
+       if (!libavw_dll)\r
+               return NULL;\r
+\r
+       // allocate stream\r
+       s = (libavwstream_t *)Z_Malloc(sizeof(libavwstream_t));\r
+       s->sndchan = -1;\r
+       memset(s, 0, sizeof(libavwstream_t));\r
+       if (s == NULL)\r
+       {\r
+               *errorstring = "unable to allocate memory for stream info structure";\r
+               return NULL;\r
+       }\r
+\r
+       // open file\r
+       s->file = FS_OpenVirtualFile(filename, true);\r
+       if (!s->file)\r
+       {\r
+               FS_StripExtension(filename, filebase, sizeof(filebase));\r
+               // we tried .dpv, try another extensions\r
+               for (i = 0; libavw_extensions[i] != NULL; i++)\r
+               {\r
+                       dpsnprintf(check, sizeof(check), "%s.%s", filebase, libavw_extensions[i]);\r
+                       s->file = FS_OpenVirtualFile(check, true);\r
+                       if (s->file)\r
+                               break;\r
+               }\r
+               if (!s->file)\r
+               {\r
+                       *errorstring = "unable to open videofile";\r
+                       libavw_close(s);\r
+                       Z_Free(s);\r
+                        return NULL;\r
+               }\r
+       }\r
+\r
+       // allocate libavw stream\r
+       if ((errorcode = qLibAvW_CreateStream(&s->stream)))\r
+       {\r
+               *errorstring = qLibAvW_ErrorString(errorcode);\r
+               libavw_close(s);\r
+               Z_Free(s);\r
+        return NULL;\r
+       }\r
+\r
+       // open video for playing\r
+       if (!qLibAvW_PlayVideo(s->stream, s->file, &LibAvW_FS_Read, &LibAvW_FS_Seek, &LibAvW_FS_SeekSize))\r
+       {\r
+               *errorstring = qLibAvW_ErrorString(qLibAvW_StreamGetError(s->stream));\r
+               libavw_close(s);\r
+               Z_Free(s);\r
+        return NULL;\r
+       }\r
+\r
+       // all right, start codec\r
+       s->info_imagewidth = qLibAvW_StreamGetVideoWidth(s->stream);\r
+       s->info_imageheight = qLibAvW_StreamGetVideoHeight(s->stream);\r
+       s->info_framerate = qLibAvW_StreamGetFramerate(s->stream);\r
+       s->info_aspectratio = (double)s->info_imagewidth / (double)s->info_imageheight;\r
+       video->close = libavw_close;\r
+       video->getwidth = libavw_getwidth;\r
+       video->getheight = libavw_getheight;\r
+       video->getframerate = libavw_getframerate;\r
+       video->decodeframe = libavw_decodeframe;\r
+       video->getaspectratio = libavw_getaspectratio;\r
+\r
+       // apply min-width, min-height, keep aspect rate\r
+       if (cl_video_libavw_minwidth.integer > 0)\r
+               s->info_imagewidth = max(s->info_imagewidth, (unsigned int)cl_video_libavw_minwidth.integer);\r
+       if (cl_video_libavw_minheight.integer > 0)\r
+               s->info_imageheight = max(s->info_imageheight, (unsigned int)cl_video_libavw_minheight.integer);\r
+       \r
+       // provide sound in separate .wav\r
+       len = strlen(filename) + 10;\r
+       wavename = (char *)Z_Malloc(len);\r
+       if (wavename)\r
+       {\r
+               FS_StripExtension(filename, wavename, len-1);\r
+               strlcat(wavename, ".wav", len);\r
+               s->sfx = S_PrecacheSound(wavename, false, false);\r
+               s->sndchan = -1;\r
+               Z_Free(wavename);\r
+       }\r
+       return s;\r
+}\r
+\r
+void libavw_message(int level, const char *message)\r
+{\r
+       if (level == LIBAVW_PRINT_WARNING)\r
+               Con_Printf("LibAvcodec warning: %s\n", message);\r
+       else if (level == LIBAVW_PRINT_ERROR)\r
+               Con_Printf("LibAvcodec error: %s\n", message);\r
+       else if (level == LIBAVW_PRINT_FATAL)\r
+               Con_Printf("LibAvcodec fatal error: %s\n", message);\r
+       else\r
+               Con_Printf("LibAvcodec panic: %s\n", message);\r
+}\r
+\r
+qboolean LibAvW_OpenLibrary(void)\r
+{\r
+       int errorcode;\r
+\r
+       // COMMANDLINEOPTION: Video: -nolibavw disables libavcodec wrapper support\r
+       if (COM_CheckParm("-nolibavw"))\r
+               return false;\r
+\r
+       // load DLL's\r
+       Sys_LoadLibrary(dllnames_libavw, &libavw_dll, libavwfuncs);\r
+       if (!libavw_dll)\r
+               return false;\r
+\r
+       // initialize libav wrapper\r
+       if ((errorcode = qLibAvW_Init(&libavw_message)))\r
+       {\r
+               Con_Printf("LibAvW failed to initialize: %s\n", qLibAvW_ErrorString(errorcode));\r
+               Sys_UnloadLibrary(&libavw_dll);\r
+       }\r
+\r
+       Cvar_RegisterVariable(&cl_video_libavw_minwidth);\r
+       Cvar_RegisterVariable(&cl_video_libavw_minheight);\r
+       Cvar_RegisterVariable(&cl_video_libavw_scaler);\r
+\r
+       return true;\r
+}\r
+\r
+void LibAvW_CloseLibrary(void)\r
+{\r
+       Sys_UnloadLibrary(&libavw_dll);\r
+}\r
+\r
index a72bf36..ed89260 100644 (file)
@@ -230,6 +230,7 @@ typedef struct dpvsimpledecodestream_s
        unsigned int info_imageBmask;
        unsigned int info_imageBshift;
        unsigned int info_imagesize;
+       double info_aspectratio;
 
        // current video frame (needed because of delta compression)
        int videoframenum;
@@ -360,6 +361,7 @@ void *dpvsimpledecode_open(clvideo_t *video, char *filename, const char **errors
                                                s->info_imagewidth = hz_bitstream_read_short(s->framedatablocks);
                                                s->info_imageheight = hz_bitstream_read_short(s->framedatablocks);
                                                s->info_framerate = (double) hz_bitstream_read_int(s->framedatablocks) * (1.0 / 65536.0);
+                                               s->info_aspectratio = (double)s->info_imagewidth / (double)s->info_imageheight;
 
                                                if (s->info_framerate > 0.0)
                                                {
@@ -391,6 +393,7 @@ void *dpvsimpledecode_open(clvideo_t *video, char *filename, const char **errors
                                                                video->getheight = dpvsimpledecode_getheight;
                                                                video->getframerate = dpvsimpledecode_getframerate;
                                                                video->decodeframe = dpvsimpledecode_video;
+                                                               video->getaspectratio = dpvsimpledecode_getaspectratio;
 
                                                                return s;
                                                        }
@@ -512,6 +515,13 @@ double dpvsimpledecode_getframerate(void *stream)
        return s->info_framerate;
 }
 
+// return aspect ratio of the stream
+double dpvsimpledecode_getaspectratio(void *stream)
+{
+       dpvsimpledecodestream_t *s = (dpvsimpledecodestream_t *)stream;
+       return s->info_aspectratio;
+}
+
 static int dpvsimpledecode_convertpixels(dpvsimpledecodestream_t *s, void *imagedata, int imagebytesperrow)
 {
        unsigned int a, x, y, width, height;
index 621b001..0b0ac35 100644 (file)
@@ -40,6 +40,9 @@ unsigned int dpvsimpledecode_getheight(void *stream);
 // returns the framerate of the stream
 double dpvsimpledecode_getframerate(void *stream);
 
+// returns aspect ratio of the stream
+double dpvsimpledecode_getaspectratio(void *stream);
+
 // decodes a video frame to the supplied output pixels
 int dpvsimpledecode_video(void *stream, void *imagedata, unsigned int Rmask, unsigned int Gmask, unsigned int Bmask, unsigned int bytesperpixel, int imagebytesperrow);