commands: Allow cycling subtitles backwards with 'J'
[mplayer/glamo.git] / libmpcodecs / vd_qtvideo.c
blobd3dbeacc454813dcaf012ba5adada9573f220129
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>
21 #include <inttypes.h>
23 #include "config.h"
24 #include "mp_msg.h"
25 #include "mpbswap.h"
26 #include "vd_internal.h"
28 #ifdef CONFIG_QUICKTIME
29 #include <QuickTime/ImageCodec.h>
30 #define dump_ImageDescription(x)
31 #else
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"
36 #endif
38 static const vd_info_t info = {
39 "Quicktime Video decoder",
40 "qtvideo",
41 "A'rpi",
42 "Sascha Sommer",
43 "win32"
46 LIBVD_EXTERN(qtvideo)
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,
63 CGrafPtr port,
64 /*GDHandle*/void* gdh,
65 const Rect *srcRect,
66 MatrixRecordPtr matrix,
67 short mode,
68 RgnHandle mask,
69 CodecFlags flags,
70 CodecQ accuracy,
71 DecompressorComponent codec);
72 static OSErr (*DecompressSequenceFrameS)(ImageSequence seqID,
73 Ptr data,
74 long dataSize,
75 CodecFlags inFlags,
76 CodecFlags *outFlags,
77 ICMCompletionProcRecordPtr asyncCompletionProc);
78 static PixMapHandle (*GetGWorldPixMap)(GWorldPtr offscreenGWorld);
79 static OSErr (*QTNewGWorldFromPtr)(GWorldPtr *gw,
80 OSType pixelFormat,
81 const Rect *boundsRect,
82 CTabHandle cTable,
83 /*GDHandle*/void* aGDevice, //unused anyway
84 GWorldFlags flags,
85 void *baseAddr,
86 long rowBytes);
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;
98 // init driver
99 static int init(sh_video_t *sh){
100 OSErr result = 1;
101 int extradata_size = sh->bih ? sh->bih->biSize - sizeof(*sh->bih) : 0;
102 void *extradata = sh->bih + 1;
104 if (!sh->ImageDesc)
105 mp_msg(MSGT_DECVIDEO,MSGL_ERR,"sh->ImageDesc not set, try -demuxer mov if this fails.\n");
107 #ifndef CONFIG_QUICKTIME
108 #ifdef WIN32_LOADER
109 Setup_LDT_Keeper();
110 #endif
112 //preload quicktime.qts to avoid the problems caused by the hardcoded path inside the dll
113 qtime_qts = LoadLibraryA("QuickTime.qts");
114 if(!qtime_qts){
115 mp_msg(MSGT_DECVIDEO,MSGL_ERR,"unable to load QuickTime.qts\n" );
116 return 0;
119 handler = LoadLibraryA("qtmlClient.dll");
120 if(!handler){
121 mp_msg(MSGT_DECVIDEO,MSGL_ERR,"unable to load qtmlClient.dll\n");
122 return 0;
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");
139 return 0;
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);
151 //make a yuy2 gworld
152 OutBufferRect.top=0;
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;
162 if (sh->ImageDesc) {
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);
166 } else {
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 if (mp_msg_test(MSGT_DECVIDEO, MSGL_V))
179 dump_ImageDescription(*framedescHandle);
181 (**framedescHandle).cType = bswap_32(sh->format);
182 sh->context = (void *)kYUVSPixelFormat;
184 int imgfmt = sh->codec->outfmt[sh->outfmtidx];
185 int qt_imgfmt;
186 switch(imgfmt)
188 case IMGFMT_YUY2:
189 qt_imgfmt = kYUVSPixelFormat;
190 break;
191 case IMGFMT_YVU9:
192 qt_imgfmt = 0x73797639; //kYVU9PixelFormat;
193 break;
194 case IMGFMT_YV12:
195 qt_imgfmt = 0x79343230;
196 break;
197 case IMGFMT_UYVY:
198 qt_imgfmt = k2vuyPixelFormat;
199 break;
200 case IMGFMT_YVYU:
201 qt_imgfmt = kYVYU422PixelFormat;
202 imgfmt = IMGFMT_YUY2;
203 break;
204 case IMGFMT_RGB16:
205 qt_imgfmt = k16LE555PixelFormat;
206 break;
207 case IMGFMT_BGR24:
208 qt_imgfmt = k24BGRPixelFormat;
209 break;
210 case IMGFMT_BGR32:
211 qt_imgfmt = k32BGRAPixelFormat;
212 break;
213 case IMGFMT_RGB32:
214 qt_imgfmt = k32RGBAPixelFormat;
215 break;
216 default:
217 mp_msg(MSGT_DECVIDEO,MSGL_ERR,"Unknown requested csp\n");
218 return 0;
220 mp_msg(MSGT_DECVIDEO,MSGL_DBG2,"imgfmt: %s qt_imgfmt: %.4s\n", vo_format_name(imgfmt), (char *)&qt_imgfmt);
221 sh->context = (void *)qt_imgfmt;
222 if(!mpcodecs_config_vo(sh,sh->disp_w,sh->disp_h,imgfmt)) return 0;
225 mpi=mpcodecs_get_image(sh, MP_IMGTYPE_STATIC, MP_IMGFLAG_PRESERVE,
226 sh->disp_w, sh->disp_h);
227 if(!mpi) return 0;
229 result = QTNewGWorldFromPtr(
230 &OutBufferGWorld,
231 (OSType)sh->context,
232 &OutBufferRect, //we should benchmark if yvu9 is faster for svq3, too
236 mpi->planes[0],
237 mpi->stride[0]);
238 if (result) {
239 mp_msg(MSGT_DECVIDEO,MSGL_ERR,"QTNewGWorldFromPtr result=%d\n",result);
240 return 0;
243 result = DecompressSequenceBegin(&imageSeq, framedescHandle, (CGrafPtr)OutBufferGWorld,
244 NULL, NULL, NULL, srcCopy, NULL, 0,
245 codecNormalQuality, 0);
246 if(result) {
247 mp_msg(MSGT_DECVIDEO,MSGL_ERR,"DecompressSequenceBegin result=%d\n",result);
248 return 0;
251 return 1;
254 // uninit driver
255 static void uninit(sh_video_t *sh){
256 if(OutBufferGWorld) {
257 DisposeGWorld(OutBufferGWorld);
258 OutBufferGWorld = NULL;
260 if(framedescHandle) {
261 DisposeHandle((Handle)framedescHandle);
262 framedescHandle = NULL;
264 if(imageSeq) {
265 CDSequenceEnd(imageSeq);
266 imageSeq = 0;
268 ExitMovies();
271 // decode a frame
272 static mp_image_t* decode(sh_video_t *sh,void* data,int len,int flags){
273 OSErr result = 1;
274 CodecFlags ignore;
276 if(len<=0) return NULL; // skipped frame
278 #if defined(WIN32_LOADER) && !defined(CONFIG_QUICKTIME)
279 Setup_FS_Segment();
280 #endif
282 result = DecompressSequenceFrameS(imageSeq, data, len, 0, &ignore, NULL);
283 if(result) {
284 mp_msg(MSGT_DECVIDEO,MSGL_ERR,"DecompressSequenceFrameS result=0x%d\n",result);
285 return NULL;
288 if((int)sh->context==0x73797639){ // Sorenson 16-bit YUV -> std YVU9
289 int i;
291 PixMap dstPixMap = **GetGWorldPixMap(OutBufferGWorld);
292 short *src0=(short *)((char*)dstPixMap.baseAddr+0x20);
294 for(i=0;i<mpi->h;i++){
295 int x;
296 unsigned char* dst=mpi->planes[0]+i*mpi->stride[0];
297 unsigned short* src=src0+i*((mpi->w+15)&(~15));
298 for(x=0;x<mpi->w;x++) dst[x]=src[x];
300 src0+=((mpi->w+15)&(~15))*((mpi->h+15)&(~15));
301 for(i=0;i<mpi->h/4;i++){
302 int x;
303 unsigned char* dst=mpi->planes[1]+i*mpi->stride[1];
304 unsigned short* src=src0+i*(((mpi->w+63)&(~63))/4);
305 for(x=0;x<mpi->w/4;x++) dst[x]=src[x];
306 src+=((mpi->w+63)&(~63))/4;
308 src0+=(((mpi->w+63)&(~63))/4)*(((mpi->h+63)&(~63))/4);
309 for(i=0;i<mpi->h/4;i++){
310 int x;
311 unsigned char* dst=mpi->planes[2]+i*mpi->stride[2];
312 unsigned short* src=src0+i*(((mpi->w+63)&(~63))/4);
313 for(x=0;x<mpi->w/4;x++) dst[x]=src[x];
314 src+=((mpi->w+63)&(~63))/4;
320 return mpi;