Use MSGT_DECVIDEO in a video decoder.
[mplayer/glamo.git] / libmpcodecs / vd_vfw.c
blobc87f5ef5d9db23dd1261ab0748cbdea913201a6d
1 /*
2 * This file is part of MPlayer.
4 * MPlayer is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * MPlayer 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. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #include <stdio.h>
20 #include <stdlib.h>
22 #include "config.h"
23 #include "mp_msg.h"
24 #include "help_mp.h"
26 #include "vd_internal.h"
27 #include "libmpdemux/aviprint.h"
28 #include "loader/wine/driver.h"
29 #include "loader/wine/vfw.h"
31 static const vd_info_t info = {
32 #ifdef BUILD_VFWEX
33 "Win32/VfWex video codecs",
34 "vfwex",
35 #else
36 "Win32/VfW video codecs",
37 "vfw",
38 #endif
39 "A'rpi & Alex",
40 "avifile.sf.net",
41 "win32 codecs"
44 #ifdef BUILD_VFWEX
45 LIBVD_EXTERN(vfwex)
46 #else
47 LIBVD_EXTERN(vfw)
48 #endif
50 typedef struct {
51 BITMAPINFOHEADER *o_bih;
52 HIC handle;
53 unsigned char *palette;
54 } vd_vfw_ctx;
56 static int vfw_set_postproc(sh_video_t* sh, int quality)
58 vd_vfw_ctx *priv = sh->context;
59 // Works only with opendivx/divx4 based DLL
60 return ICSendMessage(priv->handle, ICM_USER+80, (long)(&quality), 0);
63 static void set_csp(BITMAPINFOHEADER *o_bih,unsigned int outfmt){
64 int yuv = 0;
66 switch (outfmt)
68 /* planar format */
69 case IMGFMT_YV12:
70 case IMGFMT_I420:
71 case IMGFMT_IYUV:
72 o_bih->biBitCount=12;
73 yuv=1;
74 break;
75 case IMGFMT_YVU9:
76 case IMGFMT_IF09:
77 o_bih->biBitCount=9;
78 yuv=1;
79 break;
80 /* packed format */
81 case IMGFMT_YUY2:
82 case IMGFMT_UYVY:
83 case IMGFMT_YVYU:
84 o_bih->biBitCount=16;
85 yuv=1;
86 break;
87 /* rgb/bgr format */
88 case IMGFMT_RGB8:
89 case IMGFMT_BGR8:
90 o_bih->biBitCount=8;
91 break;
92 case IMGFMT_RGB15:
93 case IMGFMT_RGB16:
94 case IMGFMT_BGR15:
95 case IMGFMT_BGR16:
96 o_bih->biBitCount=16;
97 break;
98 case IMGFMT_RGB24:
99 case IMGFMT_BGR24:
100 o_bih->biBitCount=24;
101 break;
102 case IMGFMT_RGB32:
103 case IMGFMT_BGR32:
104 o_bih->biBitCount=32;
105 break;
106 default:
107 mp_msg(MSGT_WIN32,MSGL_ERR,"Unsupported image format: %s\n", vo_format_name(outfmt));
108 return;
111 o_bih->biSizeImage = abs(o_bih->biWidth * o_bih->biHeight * (o_bih->biBitCount/8));
113 // Note: we cannot rely on sh->outfmtidx here, it's undefined at this stage!!!
114 // if (yuv && !(sh->codec->outflags[sh->outfmtidx] & CODECS_FLAG_YUVHACK))
115 if (yuv)
116 o_bih->biCompression = outfmt;
117 else
118 o_bih->biCompression = 0;
121 // to set/get/query special features/parameters
122 static int control(sh_video_t *sh,int cmd,void* arg,...){
123 vd_vfw_ctx *priv = sh->context;
124 switch(cmd){
125 case VDCTRL_QUERY_MAX_PP_LEVEL:
126 return 9;
127 case VDCTRL_SET_PP_LEVEL:
128 vfw_set_postproc(sh,10*(*((int*)arg)));
129 return CONTROL_OK;
130 // FIXME: make this optional...
131 case VDCTRL_QUERY_FORMAT:
133 HRESULT ret;
134 if(!(sh->codec->outflags[sh->outfmtidx]&CODECS_FLAG_QUERY))
135 return CONTROL_UNKNOWN; // do not query!
136 set_csp(priv->o_bih,*((int*)arg));
137 #ifdef BUILD_VFWEX
138 ret = ICDecompressQueryEx(priv->handle, sh->bih, priv->o_bih);
139 #else
140 ret = ICDecompressQuery(priv->handle, sh->bih, priv->o_bih);
141 #endif
142 if (ret)
144 mp_msg(MSGT_WIN32, MSGL_DBG2, "ICDecompressQuery failed:: Error %d\n", (int)ret);
145 return CONTROL_FALSE;
147 return CONTROL_TRUE;
150 return CONTROL_UNKNOWN;
153 // init driver
154 static int init(sh_video_t *sh){
155 HRESULT ret;
156 // unsigned int outfmt=sh->codec->outfmt[sh->outfmtidx];
157 int i, o_bih_len;
158 vd_vfw_ctx *priv;
160 /* Hack for VSSH codec: new dll can't decode old files
161 * In my samples old files have no extradata, so use that info
162 * to decide what dll should be used (here and in vd_dshow).
164 if (!strcmp(sh->codec->dll, "vssh264.dll") && (sh->bih->biSize > 40))
165 return 0;
167 priv = malloc(sizeof(vd_vfw_ctx));
168 if (!priv)
169 return 0;
170 memset(priv, 0, sizeof(vd_vfw_ctx));
171 sh->context = priv;
173 mp_msg(MSGT_WIN32,MSGL_V,"======= Win32 (VFW) VIDEO Codec init =======\n");
176 // win32_codec_name = sh->codec->dll;
177 // sh->hic = ICOpen( 0x63646976, sh->bih->biCompression, ICMODE_FASTDECOMPRESS);
178 // priv->handle = ICOpen( 0x63646976, sh->bih->biCompression, ICMODE_DECOMPRESS);
179 priv->handle = ICOpen( (long)(sh->codec->dll), sh->bih->biCompression, ICMODE_DECOMPRESS);
180 if(!priv->handle){
181 mp_msg(MSGT_WIN32,MSGL_ERR,"ICOpen failed! unknown codec / wrong parameters?\n");
182 return 0;
185 // sh->bih->biBitCount=32;
187 o_bih_len = ICDecompressGetFormatSize(priv->handle, sh->bih);
189 if(o_bih_len < sizeof(BITMAPINFOHEADER)){
190 mp_msg(MSGT_WIN32,MSGL_ERR,"ICDecompressGetFormatSize returned a bogus value: %d\n", o_bih_len);
191 return 0;
194 priv->o_bih = malloc(o_bih_len);
195 memset(priv->o_bih, 0, o_bih_len);
197 mp_msg(MSGT_WIN32,MSGL_V,"ICDecompressGetFormatSize ret: %d\n", o_bih_len);
199 ret = ICDecompressGetFormat(priv->handle, sh->bih, priv->o_bih);
200 if(ret < 0){
201 mp_msg(MSGT_WIN32,MSGL_ERR,"ICDecompressGetFormat failed: Error %d\n", (int)ret);
202 for (i=0; i < o_bih_len; i++) mp_msg(MSGT_WIN32, MSGL_DBG2, "%02x ", priv->o_bih[i]);
203 return 0;
205 mp_msg(MSGT_WIN32,MSGL_V,"ICDecompressGetFormat OK\n");
207 #if 0
208 // workaround for pegasus MJPEG:
209 if(!sh_video->o_bih.biWidth) sh_video->o_bih.biWidth=sh_video->bih->biWidth;
210 if(!sh_video->o_bih.biHeight) sh_video->o_bih.biHeight=sh_video->bih->biHeight;
211 if(!sh_video->o_bih.biPlanes) sh_video->o_bih.biPlanes=sh_video->bih->biPlanes;
212 #endif
214 // ok let libvo and vd core to handshake and decide the optimal csp:
215 if(!mpcodecs_config_vo(sh,sh->disp_w,sh->disp_h,IMGFMT_YUY2)) return 0;
217 if (!(sh->codec->outflags[sh->outfmtidx]&CODECS_FLAG_FLIP)) {
218 priv->o_bih->biHeight=-sh->bih->biHeight; // flip image!
221 // ok, let's set the choosen colorspace:
222 set_csp(priv->o_bih,sh->codec->outfmt[sh->outfmtidx]);
224 // fake it to RGB for broken DLLs (divx3)
225 if(sh->codec->outflags[sh->outfmtidx] & CODECS_FLAG_YUVHACK)
226 priv->o_bih->biCompression = 0;
228 // sanity check:
229 #ifdef BUILD_VFWEX
230 ret = ICDecompressQueryEx(priv->handle, sh->bih, priv->o_bih);
231 #else
232 ret = ICDecompressQuery(priv->handle, sh->bih, priv->o_bih);
233 #endif
234 if (ret)
236 mp_msg(MSGT_WIN32,MSGL_WARN,"ICDecompressQuery failed: Error %d\n", (int)ret);
237 // return 0;
238 } else
239 mp_msg(MSGT_WIN32,MSGL_V,"ICDecompressQuery OK\n");
241 #ifdef BUILD_VFWEX
242 ret = ICDecompressBeginEx(priv->handle, sh->bih, priv->o_bih);
243 #else
244 ret = ICDecompressBegin(priv->handle, sh->bih, priv->o_bih);
245 #endif
246 if (ret)
248 mp_msg(MSGT_WIN32,MSGL_WARN,"ICDecompressBegin failed: Error %d\n", (int)ret);
249 // return 0;
252 // for broken codecs set it again:
253 if(sh->codec->outflags[sh->outfmtidx] & CODECS_FLAG_YUVHACK)
254 set_csp(priv->o_bih,sh->codec->outfmt[sh->outfmtidx]);
256 mp_msg(MSGT_WIN32, MSGL_V, "Input format:\n");
257 if( mp_msg_test(MSGT_HEADER,MSGL_V) ) print_video_header(sh->bih,MSGL_V);
258 mp_msg(MSGT_WIN32, MSGL_V, "Output format:\n");
259 if( mp_msg_test(MSGT_HEADER,MSGL_V) ) print_video_header(priv->o_bih,MSGL_V);
261 // set postprocessing level in xvid/divx4 .dll
262 ICSendMessage(priv->handle, ICM_USER+80, (long)(&divx_quality), 0);
264 // don't do this palette mess always, it makes div3 dll crashing...
265 if(sh->codec->outfmt[sh->outfmtidx]==IMGFMT_BGR8){
266 if(ICDecompressGetPalette(priv->handle, sh->bih, priv->o_bih)){
267 priv->palette = (unsigned char*)(priv->o_bih+1);
268 mp_msg(MSGT_WIN32,MSGL_V,"ICDecompressGetPalette OK\n");
269 } else {
270 if(sh->bih->biSize>=40+4*4)
271 priv->palette = (unsigned char*)(sh->bih+1);
275 mp_msg(MSGT_DECVIDEO,MSGL_V,"INFO: Win32 video codec init OK!\n");
276 return 1;
279 // uninit driver
280 static void uninit(sh_video_t *sh){
281 HRESULT ret;
282 vd_vfw_ctx *priv = sh->context;
284 #ifdef BUILD_VFWEX
285 ret = ICDecompressEndEx(priv->handle);
286 #else
287 ret = ICDecompressEnd(priv->handle);
288 #endif
289 if (ret)
291 mp_msg(MSGT_WIN32, MSGL_WARN, "ICDecompressEnd failed: %ld\n", ret);
292 return;
295 ret = ICClose(priv->handle);
296 if (ret)
298 mp_msg(MSGT_WIN32, MSGL_WARN, "ICClose failed: %ld\n", ret);
299 return;
302 free(priv->o_bih);
303 free(priv);
306 // decode a frame
307 static mp_image_t* decode(sh_video_t *sh,void* data,int len,int flags){
308 vd_vfw_ctx *priv = sh->context;
309 mp_image_t* mpi;
310 HRESULT ret;
312 if(len<=0) return NULL; // skipped frame
314 mpi=mpcodecs_get_image(sh,
315 (sh->codec->outflags[sh->outfmtidx] & CODECS_FLAG_STATIC) ?
316 MP_IMGTYPE_STATIC : MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_WIDTH,
317 sh->disp_w, sh->disp_h);
318 if(!mpi){ // temporary!
319 mp_msg(MSGT_DECVIDEO,MSGL_WARN,MSGTR_MPCODECS_CouldntAllocateImageForCinepakCodec);
320 return NULL;
323 // set stride: (trick discovered by Andreas Ackermann - thanx!)
324 sh->bih->biWidth=mpi->width; //mpi->stride[0]/(mpi->bpp/8);
325 priv->o_bih->biWidth=mpi->width; //mpi->stride[0]/(mpi->bpp/8);
327 sh->bih->biSizeImage = len;
329 #ifdef BUILD_VFWEX
330 ret = ICDecompressEx(priv->handle,
331 #else
332 ret = ICDecompress(priv->handle,
333 #endif
334 ( (sh->ds->flags&1) ? 0 : ICDECOMPRESS_NOTKEYFRAME ) |
335 ( ((flags&3)==2 && !(sh->ds->flags&1))?(ICDECOMPRESS_HURRYUP|ICDECOMPRESS_PREROL):0 ),
336 sh->bih, data, priv->o_bih, (flags&3) ? 0 : mpi->planes[0]);
338 if ((int)ret){
339 mp_msg(MSGT_DECVIDEO,MSGL_WARN,"Error decompressing frame, err=%ld\n",ret);
340 return NULL;
343 // export palette:
344 if(mpi->imgfmt==IMGFMT_RGB8 || mpi->imgfmt==IMGFMT_BGR8){
345 if (priv->palette)
347 mpi->planes[1] = priv->palette;
348 mp_dbg(MSGT_DECVIDEO, MSGL_DBG2, "Found and copied palette\n");
350 else
351 mpi->planes[1]=NULL;
354 return mpi;