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.
26 #include "vd_internal.h"
28 #ifdef CONFIG_QUICKTIME
29 #include <QuickTime/ImageCodec.h>
30 #define dump_ImageDescription(x)
32 #include "loader/ldt_keeper.h"
33 #include "loader/qtx/qtxsdk/components.h"
34 #include "loader/wine/winbase.h"
35 #include "loader/wine/windef.h"
38 static const vd_info_t info
= {
39 "Quicktime Video decoder",
48 static mp_image_t
* mpi
;
49 static Rect OutBufferRect
; //the dimensions of our GWorld
51 static GWorldPtr OutBufferGWorld
= NULL
;//a GWorld is some kind of description for a drawing environment
52 static ImageDescriptionHandle framedescHandle
;
53 static ImageSequence imageSeq
;
55 #ifndef CONFIG_QUICKTIME
56 static HINSTANCE qtime_qts
; // handle to the preloaded quicktime.qts
57 static HMODULE handler
;
58 static OSErr (*InitializeQTML
)(long flags
);
59 static OSErr (*EnterMovies
)(void);
60 static void (*ExitMovies
)(void);
61 static OSErr (*DecompressSequenceBegin
)(ImageSequence
*seqID
,
62 ImageDescriptionHandle desc
,
64 /*GDHandle*/void* gdh
,
66 MatrixRecordPtr matrix
,
71 DecompressorComponent codec
);
72 static OSErr (*DecompressSequenceFrameS
)(ImageSequence seqID
,
77 ICMCompletionProcRecordPtr asyncCompletionProc
);
78 static PixMapHandle (*GetGWorldPixMap
)(GWorldPtr offscreenGWorld
);
79 static OSErr (*QTNewGWorldFromPtr
)(GWorldPtr
*gw
,
81 const Rect
*boundsRect
,
83 /*GDHandle*/void* aGDevice
, //unused anyway
87 static Handle (*NewHandleClear
)(Size byteCount
);
88 static void (*DisposeHandle
)(Handle h
);
89 static void (*DisposeGWorld
)(GWorldPtr offscreenGWorld
);
90 static OSErr (*CDSequenceEnd
)(ImageSequence seqID
);
91 #endif /* #ifndef CONFIG_QUICKTIME */
93 // to set/get/query special features/parameters
94 static int control(sh_video_t
*sh
,int cmd
,void* arg
,...){
95 return CONTROL_UNKNOWN
;
99 static int init(sh_video_t
*sh
){
101 int extradata_size
= sh
->bih
? sh
->bih
->biSize
- sizeof(BITMAPINFOHEADER
) : 0;
102 void *extradata
= sh
->bih
+ 1;
105 mp_msg(MSGT_DECVIDEO
,MSGL_ERR
,"sh->ImageDesc not set, try -demuxer mov if this fails.\n");
107 #ifndef CONFIG_QUICKTIME
112 //preload quicktime.qts to avoid the problems caused by the hardcoded path inside the dll
113 qtime_qts
= LoadLibraryA("QuickTime.qts");
115 mp_msg(MSGT_DECVIDEO
,MSGL_ERR
,"unable to load QuickTime.qts\n" );
119 handler
= LoadLibraryA("qtmlClient.dll");
121 mp_msg(MSGT_DECVIDEO
,MSGL_ERR
,"unable to load qtmlClient.dll\n");
125 InitializeQTML
= (OSErr (*)(long))GetProcAddress(handler
, "InitializeQTML");
126 EnterMovies
= (OSErr (*)(void))GetProcAddress(handler
, "EnterMovies");
127 ExitMovies
= (void (*)(void))GetProcAddress(handler
, "ExitMovies");
128 DecompressSequenceBegin
= (OSErr (*)(ImageSequence
*,ImageDescriptionHandle
,CGrafPtr
,void *,const Rect
*,MatrixRecordPtr
,short,RgnHandle
,CodecFlags
,CodecQ
,DecompressorComponent
))GetProcAddress(handler
, "DecompressSequenceBegin");
129 DecompressSequenceFrameS
= (OSErr (*)(ImageSequence
,Ptr
,long,CodecFlags
,CodecFlags
*,ICMCompletionProcRecordPtr
))GetProcAddress(handler
, "DecompressSequenceFrameS");
130 GetGWorldPixMap
= (PixMapHandle (*)(GWorldPtr
))GetProcAddress(handler
, "GetGWorldPixMap");
131 QTNewGWorldFromPtr
= (OSErr(*)(GWorldPtr
*,OSType
,const Rect
*,CTabHandle
,void*,GWorldFlags
,void *,long))GetProcAddress(handler
, "QTNewGWorldFromPtr");
132 NewHandleClear
= (OSErr(*)(Size
))GetProcAddress(handler
, "NewHandleClear");
133 DisposeHandle
= (void (*)(Handle
))GetProcAddress(handler
, "DisposeHandle");
134 DisposeGWorld
= (void (*)(GWorldPtr
))GetProcAddress(handler
, "DisposeGWorld");
135 CDSequenceEnd
= (OSErr (*)(ImageSequence
))GetProcAddress(handler
, "CDSequenceEnd");
137 if(!InitializeQTML
|| !EnterMovies
|| !DecompressSequenceBegin
|| !DecompressSequenceFrameS
){
138 mp_msg(MSGT_DECVIDEO
,MSGL_ERR
,"invalid qtmlClient.dll!\n");
142 result
=InitializeQTML(kInitializeQTMLDisableDirectSound
|
143 kInitializeQTMLUseGDIFlag
|
144 kInitializeQTMLDisableDDClippers
);
145 mp_msg(MSGT_DECVIDEO
,MSGL_DBG2
,"InitializeQTML returned %d\n",result
);
146 #endif /* CONFIG_QUICKTIME */
148 result
=EnterMovies();
149 mp_msg(MSGT_DECVIDEO
,MSGL_DBG2
,"EnterMovies returned %d\n",result
);
153 OutBufferRect
.left
=0;
154 OutBufferRect
.right
=sh
->disp_w
;
155 OutBufferRect
.bottom
=sh
->disp_h
;
157 //Fill the imagedescription for our SVQ3 frame
158 //we can probably get this from Demuxer
159 if (!sh
->ImageDesc
&& extradata_size
>= sizeof(ImageDescription
) &&
160 ((ImageDescription
*)extradata
)->idSize
<= extradata_size
)
161 sh
->ImageDesc
= extradata
;
163 mp_msg(MSGT_DECVIDEO
,MSGL_DBG2
,"ImageDescription size: %d\n",((ImageDescription
*)(sh
->ImageDesc
))->idSize
);
164 framedescHandle
=(ImageDescriptionHandle
)NewHandleClear(((ImageDescription
*)(sh
->ImageDesc
))->idSize
);
165 memcpy(*framedescHandle
,sh
->ImageDesc
,((ImageDescription
*)(sh
->ImageDesc
))->idSize
);
167 // assume extradata consists only of the atoms, build the other parts
168 ImageDescription
*idesc
;
169 int size
= sizeof(*idesc
) + extradata_size
;
170 mp_msg(MSGT_DECVIDEO
, MSGL_V
, "Generating a ImageDescription\n");
171 framedescHandle
=(ImageDescriptionHandle
)NewHandleClear(size
);
172 idesc
= *framedescHandle
;
173 memcpy(idesc
+ 1, extradata
, extradata_size
);
174 idesc
->idSize
= size
;
175 idesc
->width
= sh
->disp_w
;
176 idesc
->height
= sh
->disp_h
;
178 dump_ImageDescription(*framedescHandle
);
180 (**framedescHandle
).cType
= bswap_32(sh
->format
);
181 sh
->context
= (void *)kYUVSPixelFormat
;
183 int imgfmt
= sh
->codec
->outfmt
[sh
->outfmtidx
];
188 qt_imgfmt
= kYUVSPixelFormat
;
191 qt_imgfmt
= 0x73797639; //kYVU9PixelFormat;
194 qt_imgfmt
= 0x79343230;
197 qt_imgfmt
= k2vuyPixelFormat
;
200 qt_imgfmt
= kYVYU422PixelFormat
;
201 imgfmt
= IMGFMT_YUY2
;
204 qt_imgfmt
= k16LE555PixelFormat
;
207 qt_imgfmt
= k24BGRPixelFormat
;
210 qt_imgfmt
= k32BGRAPixelFormat
;
213 qt_imgfmt
= k32RGBAPixelFormat
;
216 mp_msg(MSGT_DECVIDEO
,MSGL_ERR
,"Unknown requested csp\n");
219 mp_msg(MSGT_DECVIDEO
,MSGL_DBG2
,"imgfmt: %s qt_imgfmt: %.4s\n", vo_format_name(imgfmt
), (char *)&qt_imgfmt
);
220 sh
->context
= (void *)qt_imgfmt
;
221 if(!mpcodecs_config_vo(sh
,sh
->disp_w
,sh
->disp_h
,imgfmt
)) return 0;
224 mpi
=mpcodecs_get_image(sh
, MP_IMGTYPE_STATIC
, MP_IMGFLAG_PRESERVE
,
225 sh
->disp_w
, sh
->disp_h
);
228 result
= QTNewGWorldFromPtr(
231 &OutBufferRect
, //we should benchmark if yvu9 is faster for svq3, too
238 mp_msg(MSGT_DECVIDEO
,MSGL_ERR
,"QTNewGWorldFromPtr result=%d\n",result
);
242 result
= DecompressSequenceBegin(&imageSeq
, framedescHandle
, (CGrafPtr
)OutBufferGWorld
,
243 NULL
, NULL
, NULL
, srcCopy
, NULL
, 0,
244 codecNormalQuality
, 0);
246 mp_msg(MSGT_DECVIDEO
,MSGL_ERR
,"DecompressSequenceBegin result=%d\n",result
);
254 static void uninit(sh_video_t
*sh
){
255 if(OutBufferGWorld
) {
256 DisposeGWorld(OutBufferGWorld
);
257 OutBufferGWorld
= NULL
;
259 if(framedescHandle
) {
260 DisposeHandle((Handle
)framedescHandle
);
261 framedescHandle
= NULL
;
264 CDSequenceEnd(imageSeq
);
271 static mp_image_t
* decode(sh_video_t
*sh
,void* data
,int len
,int flags
){
275 if(len
<=0) return NULL
; // skipped frame
281 result
= DecompressSequenceFrameS(imageSeq
, data
, len
, 0, &ignore
, NULL
);
283 mp_msg(MSGT_DECVIDEO
,MSGL_ERR
,"DecompressSequenceFrameS result=0x%d\n",result
);
287 if((int)sh
->context
==0x73797639){ // Sorenson 16-bit YUV -> std YVU9
290 PixMap dstPixMap
= **GetGWorldPixMap(OutBufferGWorld
);
291 short *src0
=(short *)((char*)dstPixMap
.baseAddr
+0x20);
293 for(i
=0;i
<mpi
->h
;i
++){
295 unsigned char* dst
=mpi
->planes
[0]+i
*mpi
->stride
[0];
296 unsigned short* src
=src0
+i
*((mpi
->w
+15)&(~15));
297 for(x
=0;x
<mpi
->w
;x
++) dst
[x
]=src
[x
];
299 src0
+=((mpi
->w
+15)&(~15))*((mpi
->h
+15)&(~15));
300 for(i
=0;i
<mpi
->h
/4;i
++){
302 unsigned char* dst
=mpi
->planes
[1]+i
*mpi
->stride
[1];
303 unsigned short* src
=src0
+i
*(((mpi
->w
+63)&(~63))/4);
304 for(x
=0;x
<mpi
->w
/4;x
++) dst
[x
]=src
[x
];
305 src
+=((mpi
->w
+63)&(~63))/4;
307 src0
+=(((mpi
->w
+63)&(~63))/4)*(((mpi
->h
+63)&(~63))/4);
308 for(i
=0;i
<mpi
->h
/4;i
++){
310 unsigned char* dst
=mpi
->planes
[2]+i
*mpi
->stride
[2];
311 unsigned short* src
=src0
+i
*(((mpi
->w
+63)&(~63))/4);
312 for(x
=0;x
<mpi
->w
/4;x
++) dst
[x
]=src
[x
];
313 src
+=((mpi
->w
+63)&(~63))/4;