X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=cl_video_libavw.c;h=83f4921c35677005afeb608254a0697add198831;hb=819ea19a0017f7af07baf3e65824d81379818d7b;hp=54238973258e9c4de28a1a6c00d2be4afb1d0075;hpb=e42e4168dcbbade766cfa8ad980e7975a14fa1bb;p=xonotic%2Fdarkplaces.git diff --git a/cl_video_libavw.c b/cl_video_libavw.c index 54238973..83f4921c 100644 --- a/cl_video_libavw.c +++ b/cl_video_libavw.c @@ -1,390 +1,388 @@ -/* - Libavcodec integration for Darkplaces by Timofeyev Pavel - - 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: - - Free Software Foundation, Inc. - 59 Temple Place - Suite 330 - Boston, MA 02111-1307, USA - -*/ - -#include "common.h" -#ifdef _MSC_VERSION -#include "stdint.h" -#else -#include -#endif - -// scaler type -#define LIBAVW_SCALER_BILINEAR 0 -#define LIBAVW_SCALER_BICUBIC 1 -#define LIBAVW_SCALER_X 2 -#define LIBAVW_SCALER_POINT 3 -#define LIBAVW_SCALER_AREA 4 -#define LIBAVW_SCALER_BICUBLIN 5 -#define LIBAVW_SCALER_GAUSS 6 -#define LIBAVW_SCALER_SINC 7 -#define LIBAVW_SCALER_LANCZOS 8 -#define LIBAVW_SCALER_SPLINE 9 -// output format -#define LIBAVW_PIXEL_FORMAT_BGR 0 -#define LIBAVW_PIXEL_FORMAT_BGRA 1 -// print levels -#define LIBAVW_PRINT_WARNING 1 -#define LIBAVW_PRINT_ERROR 2 -#define LIBAVW_PRINT_FATAL 3 -#define LIBAVW_PRINT_PANIC 4 -// exported callback functions: -typedef void avwCallbackPrint(int, const char *); -typedef int avwCallbackIoRead(void *, uint8_t *, int); -typedef int64_t avwCallbackIoSeek(void *, int64_t, int); -typedef int64_t avwCallbackIoSeekSize(void *); -// exported functions: -int (*qLibAvW_Init)(avwCallbackPrint *printfunction); // init library, returns error code -const char *(*qLibAvW_ErrorString)(int errorcode); // get string for error code -const char *(*qLibAvW_AvcVersion)(void); // get a string containing libavcodec version wrapper was built for -float (*qLibAvW_Version)(void); // get wrapper version -int (*qLibAvW_CreateStream)(void **stream); // create stream, returns error code -void (*qLibAvW_RemoveStream)(void *stream); // flush and remove stream -int (*qLibAvW_StreamGetVideoWidth)(void *stream); // get video parameters of stream -int (*qLibAvW_StreamGetVideoHeight)(void *stream); -double (*qLibAvW_StreamGetFramerate)(void *stream); -int (*qLibAvW_StreamGetError)(void *stream); // get last function errorcode from stream -// simple API to play video -int (*qLibAvW_PlayVideo)(void *stream, void *file, avwCallbackIoRead *IoRead, avwCallbackIoSeek *IoSeek, avwCallbackIoSeekSize *IoSeekSize); -int (*qLibAvW_PlaySeekNextFrame)(void *stream); -int (*qLibAvW_PlayGetFrameImage)(void *stream, int pixel_format, void *imagedata, int imagewidth, int imageheight, int scaler); - -static dllfunction_t libavwfuncs[] = -{ - {"LibAvW_Init", (void **) &qLibAvW_Init }, - {"LibAvW_ErrorString", (void **) &qLibAvW_ErrorString }, - {"LibAvW_AvcVersion", (void **) &qLibAvW_AvcVersion }, - {"LibAvW_Version", (void **) &qLibAvW_Version }, - {"LibAvW_CreateStream", (void **) &qLibAvW_CreateStream }, - {"LibAvW_RemoveStream", (void **) &qLibAvW_RemoveStream }, - {"LibAvW_StreamGetVideoWidth", (void **) &qLibAvW_StreamGetVideoWidth }, - {"LibAvW_StreamGetVideoHeight",(void **) &qLibAvW_StreamGetVideoHeight }, - {"LibAvW_StreamGetFramerate", (void **) &qLibAvW_StreamGetFramerate }, - {"LibAvW_StreamGetError", (void **) &qLibAvW_StreamGetError }, - {"LibAvW_PlayVideo", (void **) &qLibAvW_PlayVideo }, - {"LibAvW_PlaySeekNextFrame", (void **) &qLibAvW_PlaySeekNextFrame }, - {"LibAvW_PlayGetFrameImage", (void **) &qLibAvW_PlayGetFrameImage }, - {NULL, NULL} -}; - -const char* dllnames_libavw[] = -{ -#if defined(WIN32) - "libavw.dll", -#elif defined(MACOSX) - "libavw.dylib", -#else - "libavw.so.1", - "libavw.so", -#endif - NULL -}; - -static dllhandle_t libavw_dll = NULL; - -// DP videostream -typedef struct libavwstream_s -{ - qfile_t *file; - double info_framerate; - unsigned int info_imagewidth; - unsigned int info_imageheight; - double info_aspectratio; - void *stream; - - // channel the sound file is being played on - sfx_t *sfx; - int sndchan; - int sndstarted; -} -libavwstream_t; - -cvar_t cl_video_libavw_minwidth = {CVAR_SAVE, "cl_video_libavw_minwidth", "0", "if videos width is lesser than minimal, thay will be upscaled"}; -cvar_t cl_video_libavw_minheight = {CVAR_SAVE, "cl_video_libavw_minheight", "0", "if videos height is lesser than minimal, thay will be upscaled"}; -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."}; - -// video extensions -const char* libavw_extensions[] = -{ - "ogv", - "avi", - "mpg", - "mp4", - "mkv", - "webm", - "bik", - "roq", - "flv", - "wmv", - "mpeg", - "mjpeg", - "mpeg4", - NULL -}; - -/* -================================================================= - - Video decoding - a features that is not supported yet and likely to be done - - streaming audio from videofiles - - streaming subtitles - -================================================================= -*/ - -unsigned int libavw_getwidth(void *stream); -unsigned int libavw_getheight(void *stream); -double libavw_getframerate(void *stream); -double libavw_getaspectratio(void *stream); -void libavw_close(void *stream); - -int libavw_decodeframe(void *stream, void *imagedata, unsigned int Rmask, unsigned int Gmask, unsigned int Bmask, unsigned int bytesperpixel, int imagebytesperrow) -{ - int pixel_format = LIBAVW_PIXEL_FORMAT_BGR; - int errorcode; - - libavwstream_t *s = (libavwstream_t *)stream; - - // start sound - if (!s->sndstarted) - { - if (s->sfx != NULL) - s->sndchan = S_StartSound(-1, 0, s->sfx, vec3_origin, 1.0f, 0); - s->sndstarted = 1; - } - - // read frame - if (!qLibAvW_PlaySeekNextFrame(s->stream)) - { - // got error or file end - errorcode = qLibAvW_StreamGetError(s->stream); - if (errorcode) - Con_Printf("LibAvW: %s\n", qLibAvW_ErrorString(errorcode)); - return 1; - } - - // decode into bgr texture - if (bytesperpixel == 4) - pixel_format = LIBAVW_PIXEL_FORMAT_BGRA; - else if (bytesperpixel == 3) - pixel_format = LIBAVW_PIXEL_FORMAT_BGR; - else - { - Con_Printf("LibAvW: cannot determine pixel format for bpp %i\n", bytesperpixel); - return 1; - } - if (!qLibAvW_PlayGetFrameImage(s->stream, pixel_format, imagedata, s->info_imagewidth, s->info_imageheight, min(9, max(0, cl_video_libavw_scaler.integer)))) - Con_Printf("LibAvW: %s\n", qLibAvW_ErrorString(qLibAvW_StreamGetError(s->stream))); - return 0; -} - -// get stream info -unsigned int libavw_getwidth(void *stream) -{ - return ((libavwstream_t *)stream)->info_imagewidth; -} - -unsigned int libavw_getheight(void *stream) -{ - return ((libavwstream_t *)stream)->info_imageheight; -} - -double libavw_getframerate(void *stream) -{ - return ((libavwstream_t *)stream)->info_framerate; -} - -double libavw_getaspectratio(void *stream) -{ - return ((libavwstream_t *)stream)->info_aspectratio; -} - -// close stream -void libavw_close(void *stream) -{ - libavwstream_t *s = (libavwstream_t *)stream; - - if (s->stream) - qLibAvW_RemoveStream(s->stream); - s->stream = NULL; - if (s->file) - FS_Close(s->file); - s->file = NULL; - if (s->sndchan >= 0) - S_StopChannel(s->sndchan, true, true); - s->sndchan = -1; -} - -// IO wrapper -int LibAvW_FS_Read(void *opaque, uint8_t *buf, int buf_size) -{ - return FS_Read((qfile_t *)opaque, buf, buf_size); -} -int64_t LibAvW_FS_Seek(void *opaque, int64_t pos, int whence) -{ - return (int64_t)FS_Seek((qfile_t *)opaque, pos, whence); -} -int64_t LibAvW_FS_SeekSize(void *opaque) -{ - return (int64_t)FS_FileSize((qfile_t *)opaque); -} - -// open as DP video stream -void *LibAvW_OpenVideo(clvideo_t *video, char *filename, const char **errorstring) -{ - libavwstream_t *s; - char filebase[MAX_OSPATH], check[MAX_OSPATH]; - unsigned int i; - int errorcode; - char *wavename; - size_t len; - - if (!libavw_dll) - return NULL; - - // allocate stream - s = (libavwstream_t *)Z_Malloc(sizeof(libavwstream_t)); - s->sndchan = -1; - memset(s, 0, sizeof(libavwstream_t)); - if (s == NULL) - { - *errorstring = "unable to allocate memory for stream info structure"; - return NULL; - } - - // open file - s->file = FS_OpenVirtualFile(filename, true); - if (!s->file) - { - FS_StripExtension(filename, filebase, sizeof(filebase)); - // we tried .dpv, try another extensions - for (i = 0; libavw_extensions[i] != NULL; i++) - { - dpsnprintf(check, sizeof(check), "%s.%s", filebase, libavw_extensions[i]); - s->file = FS_OpenVirtualFile(check, true); - if (s->file) - break; - } - if (!s->file) - { - *errorstring = "unable to open videofile"; - libavw_close(s); - Z_Free(s); - return NULL; - } - } - - // allocate libavw stream - if ((errorcode = qLibAvW_CreateStream(&s->stream))) - { - *errorstring = qLibAvW_ErrorString(errorcode); - libavw_close(s); - Z_Free(s); - return NULL; - } - - // open video for playing - if (!qLibAvW_PlayVideo(s->stream, s->file, &LibAvW_FS_Read, &LibAvW_FS_Seek, &LibAvW_FS_SeekSize)) - { - *errorstring = qLibAvW_ErrorString(qLibAvW_StreamGetError(s->stream)); - libavw_close(s); - Z_Free(s); - return NULL; - } - - // all right, start codec - s->info_imagewidth = qLibAvW_StreamGetVideoWidth(s->stream); - s->info_imageheight = qLibAvW_StreamGetVideoHeight(s->stream); - s->info_framerate = qLibAvW_StreamGetFramerate(s->stream); - s->info_aspectratio = (double)s->info_imagewidth / (double)s->info_imageheight; - video->close = libavw_close; - video->getwidth = libavw_getwidth; - video->getheight = libavw_getheight; - video->getframerate = libavw_getframerate; - video->decodeframe = libavw_decodeframe; - video->getaspectratio = libavw_getaspectratio; - - // apply min-width, min-height, keep aspect rate - if (cl_video_libavw_minwidth.integer > 0) - s->info_imagewidth = max(s->info_imagewidth, (unsigned int)cl_video_libavw_minwidth.integer); - if (cl_video_libavw_minheight.integer > 0) - s->info_imageheight = max(s->info_imageheight, (unsigned int)cl_video_libavw_minheight.integer); - - // provide sound in separate .wav - len = strlen(filename) + 10; - wavename = (char *)Z_Malloc(len); - if (wavename) - { - FS_StripExtension(filename, wavename, len-1); - strlcat(wavename, ".wav", len); - s->sfx = S_PrecacheSound(wavename, false, false); - s->sndchan = -1; - Z_Free(wavename); - } - return s; -} - -void libavw_message(int level, const char *message) -{ - if (level == LIBAVW_PRINT_WARNING) - Con_Printf("LibAvcodec warning: %s\n", message); - else if (level == LIBAVW_PRINT_ERROR) - Con_Printf("LibAvcodec error: %s\n", message); - else if (level == LIBAVW_PRINT_FATAL) - Con_Printf("LibAvcodec fatal error: %s\n", message); - else - Con_Printf("LibAvcodec panic: %s\n", message); -} - -qboolean LibAvW_OpenLibrary(void) -{ - int errorcode; - - // COMMANDLINEOPTION: Video: -nolibavw disables libavcodec wrapper support - if (COM_CheckParm("-nolibavw")) - return false; - - // load DLL's - Sys_LoadLibrary(dllnames_libavw, &libavw_dll, libavwfuncs); - if (!libavw_dll) - return false; - - // initialize libav wrapper - if ((errorcode = qLibAvW_Init(&libavw_message))) - { - Con_Printf("LibAvW failed to initialize: %s\n", qLibAvW_ErrorString(errorcode)); - Sys_UnloadLibrary(&libavw_dll); - } - - Cvar_RegisterVariable(&cl_video_libavw_minwidth); - Cvar_RegisterVariable(&cl_video_libavw_minheight); - Cvar_RegisterVariable(&cl_video_libavw_scaler); - - return true; -} - -void LibAvW_CloseLibrary(void) -{ - Sys_UnloadLibrary(&libavw_dll); -} - +/* + Libavcodec integration for Darkplaces by Timofeyev Pavel + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +// LadyHavoc: for some reason this is being #include'd rather than treated as its own file... + +#include "quakedef.h" +#include "client.h" +#include "cl_video.h" +#include "cl_video_libavw.h" + +// scaler type +#define LIBAVW_SCALER_BILINEAR 0 +#define LIBAVW_SCALER_BICUBIC 1 +#define LIBAVW_SCALER_X 2 +#define LIBAVW_SCALER_POINT 3 +#define LIBAVW_SCALER_AREA 4 +#define LIBAVW_SCALER_BICUBLIN 5 +#define LIBAVW_SCALER_GAUSS 6 +#define LIBAVW_SCALER_SINC 7 +#define LIBAVW_SCALER_LANCZOS 8 +#define LIBAVW_SCALER_SPLINE 9 +// output format +#define LIBAVW_PIXEL_FORMAT_BGR 0 +#define LIBAVW_PIXEL_FORMAT_BGRA 1 +// print levels +#define LIBAVW_PRINT_WARNING 1 +#define LIBAVW_PRINT_ERROR 2 +#define LIBAVW_PRINT_FATAL 3 +#define LIBAVW_PRINT_PANIC 4 +// exported callback functions: +typedef void avwCallbackPrint(int, const char *); +typedef int avwCallbackIoRead(void *, uint8_t *, int); +typedef uint64_t avwCallbackIoSeek(void *, uint64_t, int); +typedef uint64_t avwCallbackIoSeekSize(void *); +// exported functions: +int (*qLibAvW_Init)(avwCallbackPrint *printfunction); // init library, returns error code +const char *(*qLibAvW_ErrorString)(int errorcode); // get string for error code +const char *(*qLibAvW_AvcVersion)(void); // get a string containing libavcodec version wrapper was built for +float (*qLibAvW_Version)(void); // get wrapper version +int (*qLibAvW_CreateStream)(void **stream); // create stream, returns error code +void (*qLibAvW_RemoveStream)(void *stream); // flush and remove stream +int (*qLibAvW_StreamGetVideoWidth)(void *stream); // get video parameters of stream +int (*qLibAvW_StreamGetVideoHeight)(void *stream); +double (*qLibAvW_StreamGetFramerate)(void *stream); +int (*qLibAvW_StreamGetError)(void *stream); // get last function errorcode from stream +// simple API to play video +int (*qLibAvW_PlayVideo)(void *stream, void *file, avwCallbackIoRead *IoRead, avwCallbackIoSeek *IoSeek, avwCallbackIoSeekSize *IoSeekSize); +int (*qLibAvW_PlaySeekNextFrame)(void *stream); +int (*qLibAvW_PlayGetFrameImage)(void *stream, int pixel_format, void *imagedata, int imagewidth, int imageheight, int scaler); + +static dllfunction_t libavwfuncs[] = +{ + {"LibAvW_Init", (void **) &qLibAvW_Init }, + {"LibAvW_ErrorString", (void **) &qLibAvW_ErrorString }, + {"LibAvW_AvcVersion", (void **) &qLibAvW_AvcVersion }, + {"LibAvW_Version", (void **) &qLibAvW_Version }, + {"LibAvW_CreateStream", (void **) &qLibAvW_CreateStream }, + {"LibAvW_RemoveStream", (void **) &qLibAvW_RemoveStream }, + {"LibAvW_StreamGetVideoWidth", (void **) &qLibAvW_StreamGetVideoWidth }, + {"LibAvW_StreamGetVideoHeight",(void **) &qLibAvW_StreamGetVideoHeight }, + {"LibAvW_StreamGetFramerate", (void **) &qLibAvW_StreamGetFramerate }, + {"LibAvW_StreamGetError", (void **) &qLibAvW_StreamGetError }, + {"LibAvW_PlayVideo", (void **) &qLibAvW_PlayVideo }, + {"LibAvW_PlaySeekNextFrame", (void **) &qLibAvW_PlaySeekNextFrame }, + {"LibAvW_PlayGetFrameImage", (void **) &qLibAvW_PlayGetFrameImage }, + {NULL, NULL} +}; + +const char* dllnames_libavw[] = +{ +#if defined(WIN32) + "libavcodec.dll", +#elif defined(MACOSX) + "libavcodec.dylib", +#else + "libavcodec.so", +#endif + NULL +}; + +static dllhandle_t libavw_dll = NULL; + +// DP videostream +typedef struct libavwstream_s +{ + qfile_t *file; + double info_framerate; + unsigned int info_imagewidth; + unsigned int info_imageheight; + double info_aspectratio; + void *stream; + + // channel the sound file is being played on + sfx_t *sfx; + int sndchan; + int sndstarted; +} +libavwstream_t; + +cvar_t cl_video_libavw_minwidth = {CF_ARCHIVE, "cl_video_libavw_minwidth", "0", "if videos width is lesser than minimal, thay will be upscaled"}; +cvar_t cl_video_libavw_minheight = {CF_ARCHIVE, "cl_video_libavw_minheight", "0", "if videos height is lesser than minimal, thay will be upscaled"}; +cvar_t cl_video_libavw_scaler = {CF_ARCHIVE, "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."}; + +// video extensions +const char* libavw_extensions[] = +{ + "ogv", + "avi", + "mpg", + "mp4", + "mkv", + "webm", + "bik", + "roq", + "flv", + "wmv", + "mpeg", + "mjpeg", + "mpeg4", + NULL +}; + +/* +================================================================= + + Video decoding + a features that is not supported yet and likely to be done + - streaming audio from videofiles + - streaming subtitles + +================================================================= +*/ + +unsigned int libavw_getwidth(void *stream); +unsigned int libavw_getheight(void *stream); +double libavw_getframerate(void *stream); +double libavw_getaspectratio(void *stream); +void libavw_close(void *stream); + +static int libavw_decodeframe(void *stream, void *imagedata, unsigned int Rmask, unsigned int Gmask, unsigned int Bmask, unsigned int bytesperpixel, int imagebytesperrow) +{ + int pixel_format = LIBAVW_PIXEL_FORMAT_BGR; + int errorcode; + + libavwstream_t *s = (libavwstream_t *)stream; + + // start sound + if (!s->sndstarted) + { + if (s->sfx != NULL) + s->sndchan = S_StartSound(-1, 0, s->sfx, vec3_origin, 1.0f, 0); + s->sndstarted = 1; + } + + // read frame + if (!qLibAvW_PlaySeekNextFrame(s->stream)) + { + // got error or file end + errorcode = qLibAvW_StreamGetError(s->stream); + if (errorcode) + Con_Printf(CON_ERROR "LibAvW: %s\n", qLibAvW_ErrorString(errorcode)); + return 1; + } + + // decode into bgr texture + if (bytesperpixel == 4) + pixel_format = LIBAVW_PIXEL_FORMAT_BGRA; + else if (bytesperpixel == 3) + pixel_format = LIBAVW_PIXEL_FORMAT_BGR; + else + { + Con_Printf(CON_ERROR "LibAvW: cannot determine pixel format for bpp %i\n", bytesperpixel); + return 1; + } + if (!qLibAvW_PlayGetFrameImage(s->stream, pixel_format, imagedata, s->info_imagewidth, s->info_imageheight, min(9, max(0, cl_video_libavw_scaler.integer)))) + Con_Printf(CON_ERROR "LibAvW: %s\n", qLibAvW_ErrorString(qLibAvW_StreamGetError(s->stream))); + return 0; +} + +// get stream info +unsigned int libavw_getwidth(void *stream) +{ + return ((libavwstream_t *)stream)->info_imagewidth; +} + +unsigned int libavw_getheight(void *stream) +{ + return ((libavwstream_t *)stream)->info_imageheight; +} + +double libavw_getframerate(void *stream) +{ + return ((libavwstream_t *)stream)->info_framerate; +} + +double libavw_getaspectratio(void *stream) +{ + return ((libavwstream_t *)stream)->info_aspectratio; +} + +// close stream +void libavw_close(void *stream) +{ + libavwstream_t *s = (libavwstream_t *)stream; + + if (s->stream) + qLibAvW_RemoveStream(s->stream); + s->stream = NULL; + if (s->file) + FS_Close(s->file); + s->file = NULL; + if (s->sndchan >= 0) + S_StopChannel(s->sndchan, true, true); + s->sndchan = -1; +} + +// IO wrapper +static int LibAvW_FS_Read(void *opaque, uint8_t *buf, int buf_size) +{ + return FS_Read((qfile_t *)opaque, buf, buf_size); +} +static uint64_t LibAvW_FS_Seek(void *opaque, uint64_t pos, int whence) +{ + return (uint64_t)FS_Seek((qfile_t *)opaque, pos, whence); +} +static uint64_t LibAvW_FS_SeekSize(void *opaque) +{ + return (uint64_t)FS_FileSize((qfile_t *)opaque); +} + +// open as DP video stream +void *LibAvW_OpenVideo(clvideo_t *video, char *filename, const char **errorstring) +{ + libavwstream_t *s; + char filebase[MAX_OSPATH], check[MAX_OSPATH]; + unsigned int i; + int errorcode; + char *wavename; + size_t len; + + if (!libavw_dll) + return NULL; + + // allocate stream + s = (libavwstream_t *)Z_Malloc(sizeof(libavwstream_t)); + if (s == NULL) + { + *errorstring = "unable to allocate memory for stream info structure"; + return NULL; + } + memset(s, 0, sizeof(libavwstream_t)); + s->sndchan = -1; + + // open file + s->file = FS_OpenVirtualFile(filename, true); + if (!s->file) + { + FS_StripExtension(filename, filebase, sizeof(filebase)); + // we tried .dpv, try another extensions + for (i = 0; libavw_extensions[i] != NULL; i++) + { + dpsnprintf(check, sizeof(check), "%s.%s", filebase, libavw_extensions[i]); + s->file = FS_OpenVirtualFile(check, true); + if (s->file) + break; + } + if (!s->file) + { + *errorstring = "unable to open videofile"; + libavw_close(s); + Z_Free(s); + return NULL; + } + } + + // allocate libavw stream + if ((errorcode = qLibAvW_CreateStream(&s->stream))) + { + *errorstring = qLibAvW_ErrorString(errorcode); + libavw_close(s); + Z_Free(s); + return NULL; + } + + // open video for playing + if (!qLibAvW_PlayVideo(s->stream, s->file, &LibAvW_FS_Read, &LibAvW_FS_Seek, &LibAvW_FS_SeekSize)) + { + *errorstring = qLibAvW_ErrorString(qLibAvW_StreamGetError(s->stream)); + libavw_close(s); + Z_Free(s); + return NULL; + } + + // all right, start codec + s->info_imagewidth = qLibAvW_StreamGetVideoWidth(s->stream); + s->info_imageheight = qLibAvW_StreamGetVideoHeight(s->stream); + s->info_framerate = qLibAvW_StreamGetFramerate(s->stream); + s->info_aspectratio = (double)s->info_imagewidth / (double)s->info_imageheight; + video->close = libavw_close; + video->getwidth = libavw_getwidth; + video->getheight = libavw_getheight; + video->getframerate = libavw_getframerate; + video->decodeframe = libavw_decodeframe; + video->getaspectratio = libavw_getaspectratio; + + // apply min-width, min-height, keep aspect rate + if (cl_video_libavw_minwidth.integer > 0) + s->info_imagewidth = max(s->info_imagewidth, (unsigned int)cl_video_libavw_minwidth.integer); + if (cl_video_libavw_minheight.integer > 0) + s->info_imageheight = max(s->info_imageheight, (unsigned int)cl_video_libavw_minheight.integer); + + // provide sound in separate .wav + len = strlen(filename) + 10; + wavename = (char *)Z_Malloc(len); + if (wavename) + { + FS_StripExtension(filename, wavename, len-1); + strlcat(wavename, ".wav", len); + s->sfx = S_PrecacheSound(wavename, false, false); + s->sndchan = -1; + Z_Free(wavename); + } + return s; +} + +static void libavw_message(int level, const char *message) +{ + if (level == LIBAVW_PRINT_WARNING) + Con_Printf(CON_WARN "LibAvcodec warning: %s\n", message); + else if (level == LIBAVW_PRINT_ERROR) + Con_Printf(CON_ERROR "LibAvcodec error: %s\n", message); + else if (level == LIBAVW_PRINT_FATAL) + Con_Printf(CON_ERROR "LibAvcodec fatal error: %s\n", message); + else + Con_Printf(CON_ERROR "LibAvcodec panic: %s\n", message); +} + +qbool LibAvW_OpenLibrary(void) +{ + int errorcode; + + // COMMANDLINEOPTION: Video: -nolibavw disables libavcodec wrapper support + if (Sys_CheckParm("-nolibavw")) + return false; + + // load DLL's + Sys_LoadDependency(dllnames_libavw, &libavw_dll, libavwfuncs); + if (!libavw_dll) + return false; + + // initialize libav wrapper + if ((errorcode = qLibAvW_Init(&libavw_message))) + { + Con_Printf(CON_ERROR "LibAvW failed to initialize: %s\n", qLibAvW_ErrorString(errorcode)); + Sys_FreeLibrary(&libavw_dll); + } + + Cvar_RegisterVariable(&cl_video_libavw_minwidth); + Cvar_RegisterVariable(&cl_video_libavw_minheight); + Cvar_RegisterVariable(&cl_video_libavw_scaler); + + return true; +} + +void LibAvW_CloseLibrary(void) +{ + Sys_FreeLibrary(&libavw_dll); +}