2 Libavcodec integration for Darkplaces by Timofeyev Pavel
\r
4 This program is free software; you can redistribute it and/or
\r
5 modify it under the terms of the GNU General Public License
\r
6 as published by the Free Software Foundation; either version 2
\r
7 of the License, or (at your option) any later version.
\r
9 This program is distributed in the hope that it will be useful,
\r
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
\r
13 See the GNU General Public License for more details.
\r
15 You should have received a copy of the GNU General Public License
\r
16 along with this program; if not, write to:
\r
18 Free Software Foundation, Inc.
\r
19 59 Temple Place - Suite 330
\r
20 Boston, MA 02111-1307, USA
\r
24 // LordHavoc: for some reason this is being #include'd rather than treated as its own file...
\r
25 // LordHavoc: adapted to not require stdint.h as this is not available on MSVC++, using unsigned char instead of uint8_t and fs_offset_t instead of int64_t.
\r
28 #define LIBAVW_SCALER_BILINEAR 0
\r
29 #define LIBAVW_SCALER_BICUBIC 1
\r
30 #define LIBAVW_SCALER_X 2
\r
31 #define LIBAVW_SCALER_POINT 3
\r
32 #define LIBAVW_SCALER_AREA 4
\r
33 #define LIBAVW_SCALER_BICUBLIN 5
\r
34 #define LIBAVW_SCALER_GAUSS 6
\r
35 #define LIBAVW_SCALER_SINC 7
\r
36 #define LIBAVW_SCALER_LANCZOS 8
\r
37 #define LIBAVW_SCALER_SPLINE 9
\r
39 #define LIBAVW_PIXEL_FORMAT_BGR 0
\r
40 #define LIBAVW_PIXEL_FORMAT_BGRA 1
\r
42 #define LIBAVW_PRINT_WARNING 1
\r
43 #define LIBAVW_PRINT_ERROR 2
\r
44 #define LIBAVW_PRINT_FATAL 3
\r
45 #define LIBAVW_PRINT_PANIC 4
\r
46 // exported callback functions:
\r
47 typedef void avwCallbackPrint(int, const char *);
\r
48 typedef int avwCallbackIoRead(void *, unsigned char *, int);
\r
49 typedef fs_offset_t avwCallbackIoSeek(void *, fs_offset_t, int);
\r
50 typedef fs_offset_t avwCallbackIoSeekSize(void *);
\r
51 // exported functions:
\r
52 int (*qLibAvW_Init)(avwCallbackPrint *printfunction); // init library, returns error code
\r
53 const char *(*qLibAvW_ErrorString)(int errorcode); // get string for error code
\r
54 const char *(*qLibAvW_AvcVersion)(void); // get a string containing libavcodec version wrapper was built for
\r
55 float (*qLibAvW_Version)(void); // get wrapper version
\r
56 int (*qLibAvW_CreateStream)(void **stream); // create stream, returns error code
\r
57 void (*qLibAvW_RemoveStream)(void *stream); // flush and remove stream
\r
58 int (*qLibAvW_StreamGetVideoWidth)(void *stream); // get video parameters of stream
\r
59 int (*qLibAvW_StreamGetVideoHeight)(void *stream);
\r
60 double (*qLibAvW_StreamGetFramerate)(void *stream);
\r
61 int (*qLibAvW_StreamGetError)(void *stream); // get last function errorcode from stream
\r
62 // simple API to play video
\r
63 int (*qLibAvW_PlayVideo)(void *stream, void *file, avwCallbackIoRead *IoRead, avwCallbackIoSeek *IoSeek, avwCallbackIoSeekSize *IoSeekSize);
\r
64 int (*qLibAvW_PlaySeekNextFrame)(void *stream);
\r
65 int (*qLibAvW_PlayGetFrameImage)(void *stream, int pixel_format, void *imagedata, int imagewidth, int imageheight, int scaler);
\r
67 static dllfunction_t libavwfuncs[] =
\r
69 {"LibAvW_Init", (void **) &qLibAvW_Init },
\r
70 {"LibAvW_ErrorString", (void **) &qLibAvW_ErrorString },
\r
71 {"LibAvW_AvcVersion", (void **) &qLibAvW_AvcVersion },
\r
72 {"LibAvW_Version", (void **) &qLibAvW_Version },
\r
73 {"LibAvW_CreateStream", (void **) &qLibAvW_CreateStream },
\r
74 {"LibAvW_RemoveStream", (void **) &qLibAvW_RemoveStream },
\r
75 {"LibAvW_StreamGetVideoWidth", (void **) &qLibAvW_StreamGetVideoWidth },
\r
76 {"LibAvW_StreamGetVideoHeight",(void **) &qLibAvW_StreamGetVideoHeight },
\r
77 {"LibAvW_StreamGetFramerate", (void **) &qLibAvW_StreamGetFramerate },
\r
78 {"LibAvW_StreamGetError", (void **) &qLibAvW_StreamGetError },
\r
79 {"LibAvW_PlayVideo", (void **) &qLibAvW_PlayVideo },
\r
80 {"LibAvW_PlaySeekNextFrame", (void **) &qLibAvW_PlaySeekNextFrame },
\r
81 {"LibAvW_PlayGetFrameImage", (void **) &qLibAvW_PlayGetFrameImage },
\r
85 const char* dllnames_libavw[] =
\r
89 #elif defined(MACOSX)
\r
98 static dllhandle_t libavw_dll = NULL;
\r
101 typedef struct libavwstream_s
\r
104 double info_framerate;
\r
105 unsigned int info_imagewidth;
\r
106 unsigned int info_imageheight;
\r
107 double info_aspectratio;
\r
110 // channel the sound file is being played on
\r
117 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
118 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
119 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
121 // video extensions
\r
122 const char* libavw_extensions[] =
\r
141 =================================================================
\r
144 a features that is not supported yet and likely to be done
\r
145 - streaming audio from videofiles
\r
146 - streaming subtitles
\r
148 =================================================================
\r
151 unsigned int libavw_getwidth(void *stream);
\r
152 unsigned int libavw_getheight(void *stream);
\r
153 double libavw_getframerate(void *stream);
\r
154 double libavw_getaspectratio(void *stream);
\r
155 void libavw_close(void *stream);
\r
157 int libavw_decodeframe(void *stream, void *imagedata, unsigned int Rmask, unsigned int Gmask, unsigned int Bmask, unsigned int bytesperpixel, int imagebytesperrow)
\r
159 int pixel_format = LIBAVW_PIXEL_FORMAT_BGR;
\r
162 libavwstream_t *s = (libavwstream_t *)stream;
\r
165 if (!s->sndstarted)
\r
167 if (s->sfx != NULL)
\r
168 s->sndchan = S_StartSound(-1, 0, s->sfx, vec3_origin, 1.0f, 0);
\r
173 if (!qLibAvW_PlaySeekNextFrame(s->stream))
\r
175 // got error or file end
\r
176 errorcode = qLibAvW_StreamGetError(s->stream);
\r
178 Con_Printf("LibAvW: %s\n", qLibAvW_ErrorString(errorcode));
\r
182 // decode into bgr texture
\r
183 if (bytesperpixel == 4)
\r
184 pixel_format = LIBAVW_PIXEL_FORMAT_BGRA;
\r
185 else if (bytesperpixel == 3)
\r
186 pixel_format = LIBAVW_PIXEL_FORMAT_BGR;
\r
189 Con_Printf("LibAvW: cannot determine pixel format for bpp %i\n", bytesperpixel);
\r
192 if (!qLibAvW_PlayGetFrameImage(s->stream, pixel_format, imagedata, s->info_imagewidth, s->info_imageheight, min(9, max(0, cl_video_libavw_scaler.integer))))
\r
193 Con_Printf("LibAvW: %s\n", qLibAvW_ErrorString(qLibAvW_StreamGetError(s->stream)));
\r
198 unsigned int libavw_getwidth(void *stream)
\r
200 return ((libavwstream_t *)stream)->info_imagewidth;
\r
203 unsigned int libavw_getheight(void *stream)
\r
205 return ((libavwstream_t *)stream)->info_imageheight;
\r
208 double libavw_getframerate(void *stream)
\r
210 return ((libavwstream_t *)stream)->info_framerate;
\r
213 double libavw_getaspectratio(void *stream)
\r
215 return ((libavwstream_t *)stream)->info_aspectratio;
\r
219 void libavw_close(void *stream)
\r
221 libavwstream_t *s = (libavwstream_t *)stream;
\r
224 qLibAvW_RemoveStream(s->stream);
\r
229 if (s->sndchan >= 0)
\r
230 S_StopChannel(s->sndchan, true, true);
\r
235 int LibAvW_FS_Read(void *opaque, unsigned char *buf, int buf_size)
\r
237 return FS_Read((qfile_t *)opaque, buf, buf_size);
\r
239 fs_offset_t LibAvW_FS_Seek(void *opaque, fs_offset_t pos, int whence)
\r
241 return (fs_offset_t)FS_Seek((qfile_t *)opaque, pos, whence);
\r
243 fs_offset_t LibAvW_FS_SeekSize(void *opaque)
\r
245 return (fs_offset_t)FS_FileSize((qfile_t *)opaque);
\r
248 // open as DP video stream
\r
249 void *LibAvW_OpenVideo(clvideo_t *video, char *filename, const char **errorstring)
\r
252 char filebase[MAX_OSPATH], check[MAX_OSPATH];
\r
262 s = (libavwstream_t *)Z_Malloc(sizeof(libavwstream_t));
\r
264 memset(s, 0, sizeof(libavwstream_t));
\r
267 *errorstring = "unable to allocate memory for stream info structure";
\r
272 s->file = FS_OpenVirtualFile(filename, true);
\r
275 FS_StripExtension(filename, filebase, sizeof(filebase));
\r
276 // we tried .dpv, try another extensions
\r
277 for (i = 0; libavw_extensions[i] != NULL; i++)
\r
279 dpsnprintf(check, sizeof(check), "%s.%s", filebase, libavw_extensions[i]);
\r
280 s->file = FS_OpenVirtualFile(check, true);
\r
286 *errorstring = "unable to open videofile";
\r
293 // allocate libavw stream
\r
294 if ((errorcode = qLibAvW_CreateStream(&s->stream)))
\r
296 *errorstring = qLibAvW_ErrorString(errorcode);
\r
302 // open video for playing
\r
303 if (!qLibAvW_PlayVideo(s->stream, s->file, &LibAvW_FS_Read, &LibAvW_FS_Seek, &LibAvW_FS_SeekSize))
\r
305 *errorstring = qLibAvW_ErrorString(qLibAvW_StreamGetError(s->stream));
\r
311 // all right, start codec
\r
312 s->info_imagewidth = qLibAvW_StreamGetVideoWidth(s->stream);
\r
313 s->info_imageheight = qLibAvW_StreamGetVideoHeight(s->stream);
\r
314 s->info_framerate = qLibAvW_StreamGetFramerate(s->stream);
\r
315 s->info_aspectratio = (double)s->info_imagewidth / (double)s->info_imageheight;
\r
316 video->close = libavw_close;
\r
317 video->getwidth = libavw_getwidth;
\r
318 video->getheight = libavw_getheight;
\r
319 video->getframerate = libavw_getframerate;
\r
320 video->decodeframe = libavw_decodeframe;
\r
321 video->getaspectratio = libavw_getaspectratio;
\r
323 // apply min-width, min-height, keep aspect rate
\r
324 if (cl_video_libavw_minwidth.integer > 0)
\r
325 s->info_imagewidth = max(s->info_imagewidth, (unsigned int)cl_video_libavw_minwidth.integer);
\r
326 if (cl_video_libavw_minheight.integer > 0)
\r
327 s->info_imageheight = max(s->info_imageheight, (unsigned int)cl_video_libavw_minheight.integer);
\r
329 // provide sound in separate .wav
\r
330 len = strlen(filename) + 10;
\r
331 wavename = (char *)Z_Malloc(len);
\r
334 FS_StripExtension(filename, wavename, len-1);
\r
335 strlcat(wavename, ".wav", len);
\r
336 s->sfx = S_PrecacheSound(wavename, false, false);
\r
343 void libavw_message(int level, const char *message)
\r
345 if (level == LIBAVW_PRINT_WARNING)
\r
346 Con_Printf("LibAvcodec warning: %s\n", message);
\r
347 else if (level == LIBAVW_PRINT_ERROR)
\r
348 Con_Printf("LibAvcodec error: %s\n", message);
\r
349 else if (level == LIBAVW_PRINT_FATAL)
\r
350 Con_Printf("LibAvcodec fatal error: %s\n", message);
\r
352 Con_Printf("LibAvcodec panic: %s\n", message);
\r
355 qboolean LibAvW_OpenLibrary(void)
\r
359 // COMMANDLINEOPTION: Video: -nolibavw disables libavcodec wrapper support
\r
360 if (COM_CheckParm("-nolibavw"))
\r
364 Sys_LoadLibrary(dllnames_libavw, &libavw_dll, libavwfuncs);
\r
368 // initialize libav wrapper
\r
369 if ((errorcode = qLibAvW_Init(&libavw_message)))
\r
371 Con_Printf("LibAvW failed to initialize: %s\n", qLibAvW_ErrorString(errorcode));
\r
372 Sys_UnloadLibrary(&libavw_dll);
\r
375 Cvar_RegisterVariable(&cl_video_libavw_minwidth);
\r
376 Cvar_RegisterVariable(&cl_video_libavw_minheight);
\r
377 Cvar_RegisterVariable(&cl_video_libavw_scaler);
\r
382 void LibAvW_CloseLibrary(void)
\r
384 Sys_UnloadLibrary(&libavw_dll);
\r