Update to MPlayer SVN rev 30134 and FFmpeg SVN rev 20947.
[vaapi:mplayer.git] / libmpcodecs / .svn / text-base / vd_vfw.c.svn-base
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 #include "config.h"
5 #include "mp_msg.h"
6 #include "help_mp.h"
7
8 #include "vd_internal.h"
9
10 #include "loader/wine/driver.h"
11 #include "loader/wine/vfw.h"
12
13 static vd_info_t info = {
14 #ifdef BUILD_VFWEX
15         "Win32/VfWex video codecs",
16         "vfwex",
17 #else
18         "Win32/VfW video codecs",
19         "vfw",
20 #endif
21         "A'rpi & Alex",
22         "avifile.sf.net",
23         "win32 codecs"
24 };
25
26 #ifdef BUILD_VFWEX
27 LIBVD_EXTERN(vfwex)
28 #else
29 LIBVD_EXTERN(vfw)
30 #endif
31
32 typedef struct {
33     BITMAPINFOHEADER *o_bih;
34     HIC handle;
35     unsigned char *palette;
36 } vd_vfw_ctx;
37
38 static int vfw_set_postproc(sh_video_t* sh, int quality)
39 {
40     vd_vfw_ctx *priv = sh->context;
41     // Works only with opendivx/divx4 based DLL
42     return ICSendMessage(priv->handle, ICM_USER+80, (long)(&quality), 0);
43 }
44
45 static void set_csp(BITMAPINFOHEADER *o_bih,unsigned int outfmt){
46     int yuv = 0;
47
48         switch (outfmt)
49         {
50         /* planar format */
51         case IMGFMT_YV12:
52         case IMGFMT_I420:
53         case IMGFMT_IYUV:
54             o_bih->biBitCount=12;
55             yuv=1;
56             break;
57         case IMGFMT_YVU9:
58         case IMGFMT_IF09:
59             o_bih->biBitCount=9;
60             yuv=1;
61             break;
62         /* packed format */
63         case IMGFMT_YUY2:
64         case IMGFMT_UYVY:
65         case IMGFMT_YVYU:
66             o_bih->biBitCount=16;
67             yuv=1;
68             break;
69         /* rgb/bgr format */
70         case IMGFMT_RGB8:
71         case IMGFMT_BGR8:
72             o_bih->biBitCount=8;
73             break;
74         case IMGFMT_RGB15:
75         case IMGFMT_RGB16:
76         case IMGFMT_BGR15:
77         case IMGFMT_BGR16:
78             o_bih->biBitCount=16;
79             break;
80         case IMGFMT_RGB24:
81         case IMGFMT_BGR24:
82             o_bih->biBitCount=24;
83             break;
84         case IMGFMT_RGB32:
85         case IMGFMT_BGR32:
86             o_bih->biBitCount=32;
87             break;
88         default:
89             mp_msg(MSGT_WIN32,MSGL_ERR,"Unsupported image format: %s\n", vo_format_name(outfmt));
90             return;
91         }
92
93         o_bih->biSizeImage = abs(o_bih->biWidth * o_bih->biHeight * (o_bih->biBitCount/8));
94
95 // Note: we cannot rely on sh->outfmtidx here, it's undefined at this stage!!!
96 //      if (yuv && !(sh->codec->outflags[sh->outfmtidx] & CODECS_FLAG_YUVHACK))
97         if (yuv)
98             o_bih->biCompression = outfmt;
99         else
100             o_bih->biCompression = 0;
101 }
102
103 // to set/get/query special features/parameters
104 static int control(sh_video_t *sh,int cmd,void* arg,...){
105     vd_vfw_ctx *priv = sh->context;
106     switch(cmd){
107     case VDCTRL_QUERY_MAX_PP_LEVEL:
108         return 9;
109     case VDCTRL_SET_PP_LEVEL:
110         vfw_set_postproc(sh,10*(*((int*)arg)));
111         return CONTROL_OK;
112 #if 1
113     // FIXME: make this optional...
114     case VDCTRL_QUERY_FORMAT:
115       {
116         HRESULT ret;
117         if(!(sh->codec->outflags[sh->outfmtidx]&CODECS_FLAG_QUERY))
118             return CONTROL_UNKNOWN;     // do not query!
119         set_csp(priv->o_bih,*((int*)arg));
120 #ifdef BUILD_VFWEX
121         ret = ICDecompressQueryEx(priv->handle, sh->bih, priv->o_bih);
122 #else
123         ret = ICDecompressQuery(priv->handle, sh->bih, priv->o_bih);
124 #endif
125         if (ret)
126         {
127             mp_msg(MSGT_WIN32, MSGL_DBG2, "ICDecompressQuery failed:: Error %d\n", (int)ret);
128             return CONTROL_FALSE;
129         }
130         return CONTROL_TRUE;
131       }
132 #endif
133     }
134     return CONTROL_UNKNOWN;
135 }
136
137 void print_video_header(BITMAPINFOHEADER *h, int verbose_level);
138
139 // init driver
140 static int init(sh_video_t *sh){
141     HRESULT ret;
142 //    unsigned int outfmt=sh->codec->outfmt[sh->outfmtidx];
143     int i, o_bih_len;
144     vd_vfw_ctx *priv;
145
146     /* Hack for VSSH codec: new dll can't decode old files
147      * In my samples old files have no extradata, so use that info
148      * to decide what dll should be used (here and in vd_dshow).
149      */
150     if (!strcmp(sh->codec->dll, "vssh264.dll") && (sh->bih->biSize > 40))
151       return 0;
152
153     priv = malloc(sizeof(vd_vfw_ctx));
154     if (!priv)
155         return 0;
156     memset(priv, 0, sizeof(vd_vfw_ctx));
157     sh->context = priv;
158
159     mp_msg(MSGT_WIN32,MSGL_V,"======= Win32 (VFW) VIDEO Codec init =======\n");
160
161
162 //    win32_codec_name = sh->codec->dll;
163 //    sh->hic = ICOpen( 0x63646976, sh->bih->biCompression, ICMODE_FASTDECOMPRESS);
164 //    priv->handle = ICOpen( 0x63646976, sh->bih->biCompression, ICMODE_DECOMPRESS);
165     priv->handle = ICOpen( (long)(sh->codec->dll), sh->bih->biCompression, ICMODE_DECOMPRESS);
166     if(!priv->handle){
167         mp_msg(MSGT_WIN32,MSGL_ERR,"ICOpen failed! unknown codec / wrong parameters?\n");
168         return 0;
169     }
170
171 //    sh->bih->biBitCount=32;
172
173     o_bih_len = ICDecompressGetFormatSize(priv->handle, sh->bih);
174
175     if(o_bih_len < sizeof(BITMAPINFOHEADER)){
176        mp_msg(MSGT_WIN32,MSGL_ERR,"ICDecompressGetFormatSize returned a bogus value: %d\n", o_bih_len);
177        return 0;
178     }
179
180     priv->o_bih = malloc(o_bih_len);
181     memset(priv->o_bih, 0, o_bih_len);
182
183     mp_msg(MSGT_WIN32,MSGL_V,"ICDecompressGetFormatSize ret: %d\n", o_bih_len);
184
185     ret = ICDecompressGetFormat(priv->handle, sh->bih, priv->o_bih);
186     if(ret < 0){
187         mp_msg(MSGT_WIN32,MSGL_ERR,"ICDecompressGetFormat failed: Error %d\n", (int)ret);
188         for (i=0; i < o_bih_len; i++) mp_msg(MSGT_WIN32, MSGL_DBG2, "%02x ", priv->o_bih[i]);
189         return 0;
190     }
191     mp_msg(MSGT_WIN32,MSGL_V,"ICDecompressGetFormat OK\n");
192
193 #if 0
194     // workaround for pegasus MJPEG:
195     if(!sh_video->o_bih.biWidth) sh_video->o_bih.biWidth=sh_video->bih->biWidth;
196     if(!sh_video->o_bih.biHeight) sh_video->o_bih.biHeight=sh_video->bih->biHeight;
197     if(!sh_video->o_bih.biPlanes) sh_video->o_bih.biPlanes=sh_video->bih->biPlanes;
198 #endif
199
200     // ok let libvo and vd core to handshake and decide the optimal csp:
201     if(!mpcodecs_config_vo(sh,sh->disp_w,sh->disp_h,IMGFMT_YUY2)) return 0;
202
203     if (!(sh->codec->outflags[sh->outfmtidx]&CODECS_FLAG_FLIP)) {
204         priv->o_bih->biHeight=-sh->bih->biHeight; // flip image!
205     }
206
207     // ok, let's set the choosen colorspace:
208     set_csp(priv->o_bih,sh->codec->outfmt[sh->outfmtidx]);
209
210     // fake it to RGB for broken DLLs (divx3)
211     if(sh->codec->outflags[sh->outfmtidx] & CODECS_FLAG_YUVHACK)
212         priv->o_bih->biCompression = 0;
213
214     // sanity check:
215 #if 1
216 #ifdef BUILD_VFWEX
217     ret = ICDecompressQueryEx(priv->handle, sh->bih, priv->o_bih);
218 #else
219     ret = ICDecompressQuery(priv->handle, sh->bih, priv->o_bih);
220 #endif
221     if (ret)
222     {
223         mp_msg(MSGT_WIN32,MSGL_WARN,"ICDecompressQuery failed: Error %d\n", (int)ret);
224 //      return 0;
225     } else
226         mp_msg(MSGT_WIN32,MSGL_V,"ICDecompressQuery OK\n");
227 #endif
228
229 #ifdef BUILD_VFWEX
230     ret = ICDecompressBeginEx(priv->handle, sh->bih, priv->o_bih);
231 #else
232     ret = ICDecompressBegin(priv->handle, sh->bih, priv->o_bih);
233 #endif
234     if (ret)
235     {
236         mp_msg(MSGT_WIN32,MSGL_WARN,"ICDecompressBegin failed: Error %d\n", (int)ret);
237 //      return 0;
238     }
239
240     // for broken codecs set it again:
241     if(sh->codec->outflags[sh->outfmtidx] & CODECS_FLAG_YUVHACK)
242         set_csp(priv->o_bih,sh->codec->outfmt[sh->outfmtidx]);
243
244     mp_msg(MSGT_WIN32, MSGL_V, "Input format:\n");
245     if( mp_msg_test(MSGT_HEADER,MSGL_V) ) print_video_header(sh->bih,MSGL_V);
246     mp_msg(MSGT_WIN32, MSGL_V, "Output format:\n");
247     if( mp_msg_test(MSGT_HEADER,MSGL_V) ) print_video_header(priv->o_bih,MSGL_V);
248
249     // set postprocessing level in xvid/divx4 .dll
250     ICSendMessage(priv->handle, ICM_USER+80, (long)(&divx_quality), 0);
251
252     // don't do this palette mess always, it makes div3 dll crashing...
253     if(sh->codec->outfmt[sh->outfmtidx]==IMGFMT_BGR8){
254         if(ICDecompressGetPalette(priv->handle, sh->bih, priv->o_bih)){
255             priv->palette = (unsigned char*)(priv->o_bih+1);
256             mp_msg(MSGT_WIN32,MSGL_V,"ICDecompressGetPalette OK\n");
257         } else {
258             if(sh->bih->biSize>=40+4*4)
259                 priv->palette = (unsigned char*)(sh->bih+1);
260         }
261     }
262
263     mp_msg(MSGT_DECVIDEO,MSGL_V,"INFO: Win32 video codec init OK!\n");
264     return 1;
265 }
266
267 // uninit driver
268 static void uninit(sh_video_t *sh){
269     HRESULT ret;
270     vd_vfw_ctx *priv = sh->context;
271
272 #ifdef BUILD_VFWEX
273     ret = ICDecompressEndEx(priv->handle);
274 #else
275     ret = ICDecompressEnd(priv->handle);
276 #endif
277     if (ret)
278     {
279         mp_msg(MSGT_WIN32, MSGL_WARN, "ICDecompressEnd failed: %ld\n", ret);
280         return;
281     }
282
283     ret = ICClose(priv->handle);
284     if (ret)
285     {
286         mp_msg(MSGT_WIN32, MSGL_WARN, "ICClose failed: %ld\n", ret);
287         return;
288     }
289
290     free(priv->o_bih);
291     free(priv);
292 }
293
294 // decode a frame
295 static mp_image_t* decode(sh_video_t *sh,void* data,int len,int flags){
296     vd_vfw_ctx *priv = sh->context;
297     mp_image_t* mpi;
298     HRESULT ret;
299
300     if(len<=0) return NULL; // skipped frame
301
302     mpi=mpcodecs_get_image(sh,
303         (sh->codec->outflags[sh->outfmtidx] & CODECS_FLAG_STATIC) ?
304         MP_IMGTYPE_STATIC : MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_WIDTH,
305         sh->disp_w, sh->disp_h);
306     if(!mpi){   // temporary!
307         mp_msg(MSGT_DECVIDEO,MSGL_WARN,MSGTR_MPCODECS_CouldntAllocateImageForCinepakCodec);
308         return NULL;
309     }
310
311     // set stride:  (trick discovered by Andreas Ackermann - thanx!)
312     sh->bih->biWidth=mpi->width; //mpi->stride[0]/(mpi->bpp/8);
313     priv->o_bih->biWidth=mpi->width; //mpi->stride[0]/(mpi->bpp/8);
314
315     sh->bih->biSizeImage = len;
316
317 #ifdef BUILD_VFWEX
318     ret = ICDecompressEx(priv->handle,
319 #else
320     ret = ICDecompress(priv->handle,
321 #endif
322           ( (sh->ds->flags&1) ? 0 : ICDECOMPRESS_NOTKEYFRAME ) |
323           ( ((flags&3)==2 && !(sh->ds->flags&1))?(ICDECOMPRESS_HURRYUP|ICDECOMPRESS_PREROL):0 ),
324            sh->bih, data, priv->o_bih, (flags&3) ? 0 : mpi->planes[0]);
325
326     if ((int)ret){
327       mp_msg(MSGT_DECVIDEO,MSGL_WARN,"Error decompressing frame, err=%ld\n",ret);
328       return NULL;
329     }
330
331     // export palette:
332     if(mpi->imgfmt==IMGFMT_RGB8 || mpi->imgfmt==IMGFMT_BGR8){
333         if (priv->palette)
334         {
335             mpi->planes[1] = priv->palette;
336             mp_dbg(MSGT_DECVIDEO, MSGL_DBG2, "Found and copied palette\n");
337         }
338         else
339             mpi->planes[1]=NULL;
340     }
341
342     return mpi;
343 }