2 Libavcodec integration for Darkplaces by Timofeyev Pavel
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to:
18 Free Software Foundation, Inc.
19 59 Temple Place - Suite 330
20 Boston, MA 02111-1307, USA
24 // LadyHavoc: for some reason this is being #include'd rather than treated as its own file...
29 #include "cl_video_libavw.h"
32 #define LIBAVW_SCALER_BILINEAR 0
33 #define LIBAVW_SCALER_BICUBIC 1
34 #define LIBAVW_SCALER_X 2
35 #define LIBAVW_SCALER_POINT 3
36 #define LIBAVW_SCALER_AREA 4
37 #define LIBAVW_SCALER_BICUBLIN 5
38 #define LIBAVW_SCALER_GAUSS 6
39 #define LIBAVW_SCALER_SINC 7
40 #define LIBAVW_SCALER_LANCZOS 8
41 #define LIBAVW_SCALER_SPLINE 9
43 #define LIBAVW_PIXEL_FORMAT_BGR 0
44 #define LIBAVW_PIXEL_FORMAT_BGRA 1
46 #define LIBAVW_PRINT_WARNING 1
47 #define LIBAVW_PRINT_ERROR 2
48 #define LIBAVW_PRINT_FATAL 3
49 #define LIBAVW_PRINT_PANIC 4
50 // exported callback functions:
51 typedef void avwCallbackPrint(int, const char *);
52 typedef int avwCallbackIoRead(void *, uint8_t *, int);
53 typedef uint64_t avwCallbackIoSeek(void *, uint64_t, int);
54 typedef uint64_t avwCallbackIoSeekSize(void *);
55 // exported functions:
56 int (*qLibAvW_Init)(avwCallbackPrint *printfunction); // init library, returns error code
57 const char *(*qLibAvW_ErrorString)(int errorcode); // get string for error code
58 const char *(*qLibAvW_AvcVersion)(void); // get a string containing libavcodec version wrapper was built for
59 float (*qLibAvW_Version)(void); // get wrapper version
60 int (*qLibAvW_CreateStream)(void **stream); // create stream, returns error code
61 void (*qLibAvW_RemoveStream)(void *stream); // flush and remove stream
62 int (*qLibAvW_StreamGetVideoWidth)(void *stream); // get video parameters of stream
63 int (*qLibAvW_StreamGetVideoHeight)(void *stream);
64 double (*qLibAvW_StreamGetFramerate)(void *stream);
65 int (*qLibAvW_StreamGetError)(void *stream); // get last function errorcode from stream
66 // simple API to play video
67 int (*qLibAvW_PlayVideo)(void *stream, void *file, avwCallbackIoRead *IoRead, avwCallbackIoSeek *IoSeek, avwCallbackIoSeekSize *IoSeekSize);
68 int (*qLibAvW_PlaySeekNextFrame)(void *stream);
69 int (*qLibAvW_PlayGetFrameImage)(void *stream, int pixel_format, void *imagedata, int imagewidth, int imageheight, int scaler);
71 static dllfunction_t libavwfuncs[] =
73 {"LibAvW_Init", (void **) &qLibAvW_Init },
74 {"LibAvW_ErrorString", (void **) &qLibAvW_ErrorString },
75 {"LibAvW_AvcVersion", (void **) &qLibAvW_AvcVersion },
76 {"LibAvW_Version", (void **) &qLibAvW_Version },
77 {"LibAvW_CreateStream", (void **) &qLibAvW_CreateStream },
78 {"LibAvW_RemoveStream", (void **) &qLibAvW_RemoveStream },
79 {"LibAvW_StreamGetVideoWidth", (void **) &qLibAvW_StreamGetVideoWidth },
80 {"LibAvW_StreamGetVideoHeight",(void **) &qLibAvW_StreamGetVideoHeight },
81 {"LibAvW_StreamGetFramerate", (void **) &qLibAvW_StreamGetFramerate },
82 {"LibAvW_StreamGetError", (void **) &qLibAvW_StreamGetError },
83 {"LibAvW_PlayVideo", (void **) &qLibAvW_PlayVideo },
84 {"LibAvW_PlaySeekNextFrame", (void **) &qLibAvW_PlaySeekNextFrame },
85 {"LibAvW_PlayGetFrameImage", (void **) &qLibAvW_PlayGetFrameImage },
89 const char* dllnames_libavw[] =
101 static dllhandle_t libavw_dll = NULL;
104 typedef struct libavwstream_s
107 double info_framerate;
108 unsigned int info_imagewidth;
109 unsigned int info_imageheight;
110 double info_aspectratio;
113 // channel the sound file is being played on
120 cvar_t cl_video_libavw_minwidth = {CF_ARCHIVE, "cl_video_libavw_minwidth", "0", "if videos width is lesser than minimal, thay will be upscaled"};
121 cvar_t cl_video_libavw_minheight = {CF_ARCHIVE, "cl_video_libavw_minheight", "0", "if videos height is lesser than minimal, thay will be upscaled"};
122 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."};
125 const char* libavw_extensions[] =
144 =================================================================
147 a features that is not supported yet and likely to be done
148 - streaming audio from videofiles
149 - streaming subtitles
151 =================================================================
154 unsigned int libavw_getwidth(void *stream);
155 unsigned int libavw_getheight(void *stream);
156 double libavw_getframerate(void *stream);
157 double libavw_getaspectratio(void *stream);
158 void libavw_close(void *stream);
160 static int libavw_decodeframe(void *stream, void *imagedata, unsigned int Rmask, unsigned int Gmask, unsigned int Bmask, unsigned int bytesperpixel, int imagebytesperrow)
162 int pixel_format = LIBAVW_PIXEL_FORMAT_BGR;
165 libavwstream_t *s = (libavwstream_t *)stream;
171 s->sndchan = S_StartSound(-1, 0, s->sfx, vec3_origin, 1.0f, 0);
176 if (!qLibAvW_PlaySeekNextFrame(s->stream))
178 // got error or file end
179 errorcode = qLibAvW_StreamGetError(s->stream);
181 Con_Printf(CON_ERROR "LibAvW: %s\n", qLibAvW_ErrorString(errorcode));
185 // decode into bgr texture
186 if (bytesperpixel == 4)
187 pixel_format = LIBAVW_PIXEL_FORMAT_BGRA;
188 else if (bytesperpixel == 3)
189 pixel_format = LIBAVW_PIXEL_FORMAT_BGR;
192 Con_Printf(CON_ERROR "LibAvW: cannot determine pixel format for bpp %i\n", bytesperpixel);
195 if (!qLibAvW_PlayGetFrameImage(s->stream, pixel_format, imagedata, s->info_imagewidth, s->info_imageheight, min(9, max(0, cl_video_libavw_scaler.integer))))
196 Con_Printf(CON_ERROR "LibAvW: %s\n", qLibAvW_ErrorString(qLibAvW_StreamGetError(s->stream)));
201 unsigned int libavw_getwidth(void *stream)
203 return ((libavwstream_t *)stream)->info_imagewidth;
206 unsigned int libavw_getheight(void *stream)
208 return ((libavwstream_t *)stream)->info_imageheight;
211 double libavw_getframerate(void *stream)
213 return ((libavwstream_t *)stream)->info_framerate;
216 double libavw_getaspectratio(void *stream)
218 return ((libavwstream_t *)stream)->info_aspectratio;
222 void libavw_close(void *stream)
224 libavwstream_t *s = (libavwstream_t *)stream;
227 qLibAvW_RemoveStream(s->stream);
233 S_StopChannel(s->sndchan, true, true);
238 static int LibAvW_FS_Read(void *opaque, uint8_t *buf, int buf_size)
240 return FS_Read((qfile_t *)opaque, buf, buf_size);
242 static uint64_t LibAvW_FS_Seek(void *opaque, uint64_t pos, int whence)
244 return (uint64_t)FS_Seek((qfile_t *)opaque, pos, whence);
246 static uint64_t LibAvW_FS_SeekSize(void *opaque)
248 return (uint64_t)FS_FileSize((qfile_t *)opaque);
251 // open as DP video stream
252 void *LibAvW_OpenVideo(clvideo_t *video, char *filename, const char **errorstring)
255 char filebase[MAX_OSPATH], check[MAX_OSPATH];
265 s = (libavwstream_t *)Z_Malloc(sizeof(libavwstream_t));
268 *errorstring = "unable to allocate memory for stream info structure";
271 memset(s, 0, sizeof(libavwstream_t));
275 s->file = FS_OpenVirtualFile(filename, true);
278 FS_StripExtension(filename, filebase, sizeof(filebase));
279 // we tried .dpv, try another extensions
280 for (i = 0; libavw_extensions[i] != NULL; i++)
282 dpsnprintf(check, sizeof(check), "%s.%s", filebase, libavw_extensions[i]);
283 s->file = FS_OpenVirtualFile(check, true);
289 *errorstring = "unable to open videofile";
296 // allocate libavw stream
297 if ((errorcode = qLibAvW_CreateStream(&s->stream)))
299 *errorstring = qLibAvW_ErrorString(errorcode);
305 // open video for playing
306 if (!qLibAvW_PlayVideo(s->stream, s->file, &LibAvW_FS_Read, &LibAvW_FS_Seek, &LibAvW_FS_SeekSize))
308 *errorstring = qLibAvW_ErrorString(qLibAvW_StreamGetError(s->stream));
314 // all right, start codec
315 s->info_imagewidth = qLibAvW_StreamGetVideoWidth(s->stream);
316 s->info_imageheight = qLibAvW_StreamGetVideoHeight(s->stream);
317 s->info_framerate = qLibAvW_StreamGetFramerate(s->stream);
318 s->info_aspectratio = (double)s->info_imagewidth / (double)s->info_imageheight;
319 video->close = libavw_close;
320 video->getwidth = libavw_getwidth;
321 video->getheight = libavw_getheight;
322 video->getframerate = libavw_getframerate;
323 video->decodeframe = libavw_decodeframe;
324 video->getaspectratio = libavw_getaspectratio;
326 // apply min-width, min-height, keep aspect rate
327 if (cl_video_libavw_minwidth.integer > 0)
328 s->info_imagewidth = max(s->info_imagewidth, (unsigned int)cl_video_libavw_minwidth.integer);
329 if (cl_video_libavw_minheight.integer > 0)
330 s->info_imageheight = max(s->info_imageheight, (unsigned int)cl_video_libavw_minheight.integer);
332 // provide sound in separate .wav
333 len = strlen(filename) + 10;
334 wavename = (char *)Z_Malloc(len);
337 FS_StripExtension(filename, wavename, len-1);
338 dp_strlcat(wavename, ".wav", len);
339 s->sfx = S_PrecacheSound(wavename, false, false);
346 static void libavw_message(int level, const char *message)
348 if (level == LIBAVW_PRINT_WARNING)
349 Con_Printf(CON_WARN "LibAvcodec warning: %s\n", message);
350 else if (level == LIBAVW_PRINT_ERROR)
351 Con_Printf(CON_ERROR "LibAvcodec error: %s\n", message);
352 else if (level == LIBAVW_PRINT_FATAL)
353 Con_Printf(CON_ERROR "LibAvcodec fatal error: %s\n", message);
355 Con_Printf(CON_ERROR "LibAvcodec panic: %s\n", message);
358 qbool LibAvW_OpenLibrary(void)
362 // COMMANDLINEOPTION: Video: -nolibavw disables libavcodec wrapper support
363 if (Sys_CheckParm("-nolibavw"))
367 Sys_LoadDependency(dllnames_libavw, &libavw_dll, libavwfuncs);
371 // initialize libav wrapper
372 if ((errorcode = qLibAvW_Init(&libavw_message)))
374 Con_Printf(CON_ERROR "LibAvW failed to initialize: %s\n", qLibAvW_ErrorString(errorcode));
375 Sys_FreeLibrary(&libavw_dll);
378 Cvar_RegisterVariable(&cl_video_libavw_minwidth);
379 Cvar_RegisterVariable(&cl_video_libavw_minheight);
380 Cvar_RegisterVariable(&cl_video_libavw_scaler);
385 void LibAvW_CloseLibrary(void)
387 Sys_FreeLibrary(&libavw_dll);