Tizen 2.0 Release
[framework/multimedia/gst-plugins-bad0.10.git] / sys / qtwrapper / videodecoders.c
1 /*
2  * GStreamer QuickTime video decoder codecs wrapper
3  * Copyright <2006, 2007> Fluendo <gstreamer@fluendo.com>
4  * Copyright <2006, 2007> Pioneers of the Inevitable <songbird@songbirdnest.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  *
24  * Alternatively, the contents of this file may be used under the
25  * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
26  * which case the following provisions apply instead of the ones
27  * mentioned above:
28  *
29  * This library is free software; you can redistribute it and/or
30  * modify it under the terms of the GNU Library General Public
31  * License as published by the Free Software Foundation; either
32  * version 2 of the License, or (at your option) any later version.
33  *
34  * This library is distributed in the hope that it will be useful,
35  * but WITHOUT ANY WARRANTY; without even the implied warranty of
36  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
37  * Library General Public License for more details.
38  *
39  * You should have received a copy of the GNU Library General Public
40  * License along with this library; if not, write to the
41  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
42  * Boston, MA 02111-1307, USA.
43  */
44
45 #ifdef HAVE_CONFIG_H
46 #include "config.h"
47 #endif
48
49 #include <string.h>
50
51 #include "qtwrapper.h"
52 #include "codecmapping.h"
53 #include "qtutils.h"
54 #include "imagedescription.h"
55
56 #define QTWRAPPER_VDEC_PARAMS_QDATA g_quark_from_static_string("qtwrapper-vdec-params")
57
58 static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
59     GST_PAD_SRC,
60     GST_PAD_ALWAYS,
61     GST_STATIC_CAPS ("video/x-raw-yuv"));
62
63 typedef struct _QTWrapperVideoDecoder QTWrapperVideoDecoder;
64 typedef struct _QTWrapperVideoDecoderClass QTWrapperVideoDecoderClass;
65
66 #define MAC_LOCK(qtwrapper) g_mutex_lock (qtwrapper->lock)
67 #define MAC_UNLOCK(qtwrapper) g_mutex_unlock (qtwrapper->lock)
68
69 struct _QTWrapperVideoDecoder
70 {
71   GstElement parent;
72
73   GstPad *sinkpad;
74   GstPad *srcpad;
75
76   GMutex *lock;
77   ComponentInstance instance;
78   CodecInfo codecinfo;
79   ImageDescriptionHandle idesc;
80   CodecDecompressParams *dparams;
81   CodecCapabilities codeccaps;
82   guint64 frameNumber;
83   ICMDecompressionSessionRef decsession;
84   GstFlowReturn lastret;
85   guint64 outsize;
86   guint width, height;
87   GstClockTime last_ts;
88   GstClockTime last_duration;
89   GstBuffer *prevbuf;
90   gboolean flushing;
91   gboolean framebuffering;
92
93   /* width/height of output buffer */
94   Rect rect;
95 };
96
97 struct _QTWrapperVideoDecoderClass
98 {
99   GstElementClass parent_class;
100
101   Component component;
102   guint32 componentType;
103   guint32 componentSubType;
104
105   GstPadTemplate *sinktempl;
106 };
107
108 typedef struct _QTWrapperVideoDecoderParams QTWrapperVideoDecoderParams;
109
110 struct _QTWrapperVideoDecoderParams
111 {
112   Component component;
113   GstCaps *sinkcaps;
114 };
115
116 static GstElementClass *parent_class = NULL;
117
118 static gboolean
119 qtwrapper_video_decoder_sink_setcaps (GstPad * pad, GstCaps * caps);
120 static GstFlowReturn qtwrapper_video_decoder_chain (GstPad * pad,
121     GstBuffer * buf);
122 static gboolean qtwrapper_video_decoder_sink_event (GstPad * pad,
123     GstEvent * event);
124
125 static void qtwrapper_video_decoder_finalize (GObject * object);
126 static void decompressCb (void *decompressionTrackingRefCon,
127     OSStatus result,
128     ICMDecompressionTrackingFlags decompressionTrackingFlags,
129     CVPixelBufferRef pixelBuffer,
130     TimeValue64 displayTime,
131     TimeValue64 displayDuration,
132     ICMValidTimeFlags validTimeFlags, void *reserved, void *sourceFrameRefCon);
133
134 /*
135  * Class setup
136  */
137
138 static void
139 qtwrapper_video_decoder_base_init (QTWrapperVideoDecoderClass * klass)
140 {
141   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
142   gchar *name = NULL;
143   gchar *info = NULL;
144   char *longname, *description;
145   ComponentDescription desc;
146   QTWrapperVideoDecoderParams *params;
147
148   params = (QTWrapperVideoDecoderParams *)
149       g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass),
150       QTWRAPPER_VDEC_PARAMS_QDATA);
151   g_assert (params);
152
153   get_name_info_from_component (params->component, &desc, &name, &info);
154
155   /* Fill in details */
156   longname =
157       g_strdup_printf ("QTWrapper Video Decoder : %s", GST_STR_NULL (name));
158   description =
159       g_strdup_printf ("QTWrapper SCAudio wrapper for decoder: %s",
160       GST_STR_NULL (info));
161   gst_element_class_set_details_simple (element_class, longname,
162       "Codec/Decoder/Video", description,
163       "Fluendo <gstreamer@fluendo.com>, "
164       "Pioneers of the Inevitable <songbird@songbirdnest.com>");
165   g_free (longname);
166   g_free (description);
167   g_free (name);
168   g_free (info);
169
170   klass->sinktempl = gst_pad_template_new ("sink", GST_PAD_SINK,
171       GST_PAD_ALWAYS, params->sinkcaps);
172
173   gst_element_class_add_pad_template (element_class, klass->sinktempl);
174   gst_element_class_add_static_pad_template (element_class, &src_templ);
175
176   /* Store class-global values */
177   klass->component = params->component;
178   klass->componentType = desc.componentType;
179   klass->componentSubType = desc.componentSubType;
180 }
181
182 static void
183 qtwrapper_video_decoder_class_init (QTWrapperVideoDecoderClass * klass)
184 {
185   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
186
187   parent_class = g_type_class_peek_parent (klass);
188
189   gobject_class->finalize =
190       GST_DEBUG_FUNCPTR (qtwrapper_video_decoder_finalize);
191 }
192
193 static void
194 qtwrapper_video_decoder_init (QTWrapperVideoDecoder * qtwrapper)
195 {
196   QTWrapperVideoDecoderClass *oclass;
197   ImageSubCodecDecompressCapabilities capabs;
198
199   GST_LOG ("...");
200   oclass = (QTWrapperVideoDecoderClass *) (G_OBJECT_GET_CLASS (qtwrapper));
201
202   /* 1. Create a ocmponent instance */
203   if (!(qtwrapper->instance = OpenComponent (oclass->component))) {
204     GST_ERROR_OBJECT (qtwrapper, "Couldn't create a component instance !");
205     return;
206   }
207
208   /* 2. Initialize decoder */
209   memset (&capabs, 0, sizeof (ImageSubCodecDecompressCapabilities));
210   if (ImageCodecInitialize (qtwrapper->instance, &capabs) != noErr) {
211     GST_ERROR_OBJECT (qtwrapper, "Couldn't initialize the QT component !");
212     return;
213   }
214
215   /* 3. Get codec info */
216   memset (&qtwrapper->codecinfo, 0, sizeof (CodecInfo));
217   if (ImageCodecGetCodecInfo (qtwrapper->instance,
218           &qtwrapper->codecinfo) != noErr) {
219     GST_ERROR_OBJECT (qtwrapper, "Couldn't get Codec Information !");
220     return;
221   }
222
223   /* sink pad */
224   qtwrapper->sinkpad = gst_pad_new_from_template (oclass->sinktempl, "sink");
225   gst_pad_set_setcaps_function (qtwrapper->sinkpad,
226       GST_DEBUG_FUNCPTR (qtwrapper_video_decoder_sink_setcaps));
227   gst_pad_set_chain_function (qtwrapper->sinkpad,
228       GST_DEBUG_FUNCPTR (qtwrapper_video_decoder_chain));
229   gst_pad_set_event_function (qtwrapper->sinkpad,
230       GST_DEBUG_FUNCPTR (qtwrapper_video_decoder_sink_event));
231   gst_element_add_pad (GST_ELEMENT (qtwrapper), qtwrapper->sinkpad);
232
233   /* src pad */
234   qtwrapper->srcpad = gst_pad_new_from_static_template (&src_templ, "src");
235   gst_element_add_pad (GST_ELEMENT (qtwrapper), qtwrapper->srcpad);
236
237   qtwrapper->lock = g_mutex_new ();
238 }
239
240 static void
241 qtwrapper_video_decoder_finalize (GObject * object)
242 {
243   QTWrapperVideoDecoder *qtwrapper;
244
245   qtwrapper = (QTWrapperVideoDecoder *) object;
246
247   if (qtwrapper->lock)
248     g_mutex_free (qtwrapper->lock);
249
250   if (G_OBJECT_CLASS (parent_class)->finalize)
251     G_OBJECT_CLASS (parent_class)->finalize (object);
252 }
253
254 /* fill_image_description
255  * Fills an ImageDescription with codec-specific values
256  *
257  * Doesn't fill in the idSize, width and height.
258  */
259
260 static void
261 fill_image_description (QTWrapperVideoDecoder * qtwrapper,
262     ImageDescription * desc)
263 {
264   QTWrapperVideoDecoderClass *oclass;
265
266   oclass = (QTWrapperVideoDecoderClass *) (G_OBJECT_GET_CLASS (qtwrapper));
267
268   desc->cType = oclass->componentSubType;
269   desc->version = qtwrapper->codecinfo.version;
270   desc->revisionLevel = qtwrapper->codecinfo.revisionLevel;
271   desc->vendor = qtwrapper->codecinfo.vendor;
272   desc->temporalQuality = codecMaxQuality;
273   desc->spatialQuality = codecNormalQuality;
274   desc->hRes = Long2Fix (72);
275   desc->vRes = Long2Fix (72);
276   desc->frameCount = 1;
277   /* The following is a pure empiric calculation ... so there's are chances it
278    * might not work. To be fixed when we can figure out what the exact value should
279    * be. */
280   desc->depth = 24;
281   /* no color table */
282   desc->clutID = -1;
283 }
284
285
286 /* new_image_description
287  *
288  * Create an ImageDescription for the given 'codec_data' buffer.
289  */
290
291 static ImageDescription *
292 new_image_description (QTWrapperVideoDecoder * qtwrapper, GstBuffer * buf,
293     guint width, guint height)
294 {
295   QTWrapperVideoDecoderClass *oclass;
296   ImageDescription *desc = NULL;
297
298   oclass = (QTWrapperVideoDecoderClass *) (G_OBJECT_GET_CLASS (qtwrapper));
299
300   if (buf) {
301     GST_LOG ("buf %p , size:%d", buf, GST_BUFFER_SIZE (buf));
302 #if DEBUG_DUMP
303     gst_util_dump_mem (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
304 #endif
305   }
306
307   if (!buf) {
308     /* standard case, no codec data */
309     desc = g_new0 (ImageDescription, 1);
310     desc->idSize = sizeof (ImageDescription);
311     fill_image_description (qtwrapper, desc);
312   } else {
313     if ((desc =
314             image_description_from_codec_data (buf, oclass->componentSubType)))
315       fill_image_description (qtwrapper, desc);
316     else
317       goto beach;
318   }
319
320   /* Fix up values */
321   desc->width = width;
322   desc->height = height;
323   desc->hRes = Long2Fix (72);
324   desc->vRes = Long2Fix (72);
325
326   /* if we have h264, we need frame buffering */
327   if ((oclass->componentSubType == QT_MAKE_FOURCC_LE ('a', 'v', 'c', '1')))
328     qtwrapper->framebuffering = TRUE;
329   else
330     qtwrapper->framebuffering = FALSE;
331
332 beach:
333   return desc;
334 }
335
336 /* close_decoder
337  *
338  * Close and free decoder
339  */
340 #if 0
341 static void
342 close_decoder (QTWrapperVideoDecoder * qtwrapper)
343 {
344   if (qtwrapper->idesc) {
345     DisposeHandle ((Handle) qtwrapper->idesc);
346     qtwrapper->idesc = NULL;
347   }
348
349   if (qtwrapper->prevbuf) {
350     gst_buffer_unref (qtwrapper->prevbuf);
351     qtwrapper->prevbuf = NULL;
352   }
353
354   if (qtwrapper->dparams) {
355     g_free (qtwrapper->dparams);
356     qtwrapper->dparams = NULL;
357   }
358
359 }
360 #endif
361 /* open_decoder
362  *
363  * Attempt to initialize the ImageDecompressorComponent with the given
364  * caps.
365  *
366  * Returns TRUE and fills *outcaps if the decoder was properly initialized
367  * Returns FALSE if something went wrong.
368  */
369
370 static gboolean
371 open_decoder (QTWrapperVideoDecoder * qtwrapper, GstCaps * caps,
372     GstCaps ** outcaps)
373 {
374   ImageDescription *desc;
375   gint width, height;
376   GstStructure *s;
377   const GValue *par = NULL;
378   const GValue *rate = NULL;
379   const GValue *cdata = NULL;
380   OSStatus status;
381   gboolean res = FALSE;
382   guint32 outformat;
383
384   ICMDecompressionSessionOptionsRef sessionoptions = NULL;
385   ICMDecompressionTrackingCallbackRecord cbrecord;
386   CFMutableDictionaryRef pixelBufferAttributes = NULL;
387
388
389   s = gst_caps_get_structure (caps, 0);
390
391   /* 1. Extract information from incoming caps */
392   if ((!gst_structure_get_int (s, "width", &width)) ||
393       (!gst_structure_get_int (s, "height", &height)) ||
394       (!(rate = gst_structure_get_value (s, "framerate"))))
395     goto beach;
396   par = gst_structure_get_value (s, "pixel-aspect-ratio");
397   cdata = gst_structure_get_value (s, "codec_data");
398
399   /* 2. Create ImageDescription */
400   if (cdata) {
401     GstBuffer *cdatabuf;
402
403     cdatabuf = gst_value_get_buffer (cdata);
404     desc = new_image_description (qtwrapper, cdatabuf, width, height);
405   } else {
406     desc = new_image_description (qtwrapper, NULL, width, height);
407   }
408
409 #if DEBUG_DUMP
410   dump_image_description (desc);
411 #endif
412
413   /* 3.a. Create a handle to receive the ImageDescription */
414   GST_LOG_OBJECT (qtwrapper,
415       "Creating a new ImageDescriptionHandle of %" G_GSIZE_FORMAT " bytes",
416       desc->idSize);
417   qtwrapper->idesc = (ImageDescriptionHandle) NewHandleClear (desc->idSize);
418   if (G_UNLIKELY (qtwrapper->idesc == NULL)) {
419     GST_WARNING_OBJECT (qtwrapper,
420         "Failed to create an ImageDescriptionHandle of size %" G_GSIZE_FORMAT,
421         desc->idSize);
422     g_free (desc);
423     goto beach;
424   }
425
426   /* 3.b. Copy the ImageDescription to the handle */
427   GST_LOG_OBJECT (qtwrapper,
428       "Copying %" G_GSIZE_FORMAT
429       " bytes from desc [%p] to *qtwrapper->video [%p]", desc->idSize, desc,
430       *qtwrapper->idesc);
431   memcpy (*qtwrapper->idesc, desc, desc->idSize);
432   g_free (desc);
433
434 #if G_BYTE_ORDER == G_BIG_ENDIAN
435   outformat = kYUVSPixelFormat;
436 #else
437   outformat = k2vuyPixelFormat;
438 #endif
439
440   /* 4. Put output pixel info in dictionnnary */
441   pixelBufferAttributes =
442       CFDictionaryCreateMutable (NULL, 0, &kCFTypeDictionaryKeyCallBacks,
443       &kCFTypeDictionaryValueCallBacks);
444
445   addSInt32ToDictionary (pixelBufferAttributes, kCVPixelBufferWidthKey, width);
446   addSInt32ToDictionary (pixelBufferAttributes, kCVPixelBufferHeightKey,
447       height);
448   addSInt32ToDictionary (pixelBufferAttributes,
449       kCVPixelBufferPixelFormatTypeKey, outformat);
450
451   /* 5. fill in callback structure */
452
453   cbrecord.decompressionTrackingCallback = decompressCb;
454   cbrecord.decompressionTrackingRefCon = qtwrapper;
455
456   /* 6. create decompressionsession */
457   status = ICMDecompressionSessionCreate (NULL,
458       qtwrapper->idesc,
459       sessionoptions, pixelBufferAttributes, &cbrecord, &qtwrapper->decsession);
460
461   qtwrapper->outsize = width * height * 2;
462   qtwrapper->width = width;
463   qtwrapper->height = height;
464
465   if (status) {
466     GST_DEBUG_OBJECT (qtwrapper,
467         "Error when Calling ICMDecompressionSessionCreate : %ld", status);
468     goto beach;
469   }
470 #if G_BYTE_ORDER == G_BIG_ENDIAN
471   outformat = GST_MAKE_FOURCC ('Y', 'U', 'Y', '2');
472 #else
473   outformat = GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y');
474 #endif
475
476   /* 9. Create output caps */
477   *outcaps = gst_caps_new_simple ("video/x-raw-yuv",
478       "format", GST_TYPE_FOURCC, outformat,
479       "width", G_TYPE_INT, width,
480       "height", G_TYPE_INT, height,
481       "framerate", GST_TYPE_FRACTION,
482       gst_value_get_fraction_numerator (rate),
483       gst_value_get_fraction_denominator (rate), NULL);
484   if (par)
485     gst_structure_set_value (gst_caps_get_structure (*outcaps, 0),
486         "pixel-aspect-ratio", par);
487   res = TRUE;
488
489 beach:
490   return res;
491 }
492
493 static gboolean
494 qtwrapper_video_decoder_sink_setcaps (GstPad * pad, GstCaps * caps)
495 {
496   QTWrapperVideoDecoder *qtwrapper;
497   gboolean ret = FALSE;
498   GstCaps *othercaps = NULL;
499
500   qtwrapper = (QTWrapperVideoDecoder *) gst_pad_get_parent (pad);
501
502   GST_LOG_OBJECT (qtwrapper, "caps:%" GST_PTR_FORMAT, caps);
503
504   /* Setup the decoder with the given input caps */
505   if (!(open_decoder (qtwrapper, caps, &othercaps))) {
506     goto beach;
507   }
508
509   ret = gst_pad_set_caps (qtwrapper->srcpad, othercaps);
510   if (!ret)
511     goto beach;
512
513 beach:
514   if (othercaps)
515     gst_caps_unref (othercaps);
516   gst_object_unref (qtwrapper);
517   return ret;
518 }
519
520 static void
521 decompressCb (void *decompressionTrackingRefCon,
522     OSStatus result,
523     ICMDecompressionTrackingFlags decompressionTrackingFlags,
524     CVPixelBufferRef pixelBuffer,
525     TimeValue64 displayTime,
526     TimeValue64 displayDuration,
527     ICMValidTimeFlags validTimeFlags, void *reserved, void *sourceFrameRefCon)
528 {
529   QTWrapperVideoDecoder *qtwrapper;
530   GstBuffer *origbuf = (GstBuffer *) sourceFrameRefCon;
531
532   qtwrapper = (QTWrapperVideoDecoder *) decompressionTrackingRefCon;
533
534   GST_LOG_OBJECT (qtwrapper,
535       "result:%d, flags:0x%x, pixelBuffer:%p, displayTime:%lld, displayDuration:%lld",
536       (guint32) result, (guint32) decompressionTrackingFlags, pixelBuffer,
537       displayTime, displayDuration);
538
539   GST_LOG_OBJECT (qtwrapper,
540       "validTimeFlags:0x%x, reserved:%p, sourceFrameRefCon:%p",
541       (guint32) validTimeFlags, reserved, sourceFrameRefCon);
542
543   if (decompressionTrackingFlags & kICMDecompressionTracking_ReleaseSourceData) {
544     GST_LOG ("removing previous buffer : %p", origbuf);
545     gst_buffer_unref (origbuf);
546   }
547
548   if (decompressionTrackingFlags & kICMDecompressionTracking_EmittingFrame)
549     GST_LOG ("EMITTING FRAME");
550   if (decompressionTrackingFlags & kICMDecompressionTracking_FrameDecoded)
551     GST_LOG ("FRAME DECODED");
552   if (decompressionTrackingFlags & kICMDecompressionTracking_FrameDropped)
553     GST_LOG ("FRAME DROPPED");
554   if (decompressionTrackingFlags &
555       kICMDecompressionTracking_FrameNeedsRequeueing)
556     GST_LOG ("FRAME NEEDS REQUEUING");
557
558   if ((decompressionTrackingFlags & kICMDecompressionTracking_EmittingFrame)
559       && pixelBuffer) {
560     guint8 *addr;
561     GstBuffer *outbuf;
562     size_t size;
563     GstClockTime outtime;
564
565     size = CVPixelBufferGetDataSize (pixelBuffer);
566     outtime = gst_util_uint64_scale (displayTime, GST_SECOND, 600);
567
568     GST_LOG ("Got a buffer ready outtime : %" GST_TIME_FORMAT,
569         GST_TIME_ARGS (outtime));
570
571     if (qtwrapper->flushing) {
572       CVPixelBufferRelease (pixelBuffer);
573       goto beach;
574     }
575
576     dump_cvpixel_buffer (pixelBuffer);
577
578     CVPixelBufferRetain (pixelBuffer);
579     if (CVPixelBufferLockBaseAddress (pixelBuffer, 0))
580       GST_WARNING ("Couldn't lock base adress on pixel buffer !");
581     addr = CVPixelBufferGetBaseAddress (pixelBuffer);
582
583     /* allocate buffer */
584     qtwrapper->lastret =
585         gst_pad_alloc_buffer (qtwrapper->srcpad, GST_BUFFER_OFFSET_NONE,
586         (gint) qtwrapper->outsize, GST_PAD_CAPS (qtwrapper->srcpad), &outbuf);
587     if (G_UNLIKELY (qtwrapper->lastret != GST_FLOW_OK)) {
588       GST_LOG ("gst_pad_alloc_buffer() returned %s",
589           gst_flow_get_name (qtwrapper->lastret));
590       goto beach;
591     }
592
593     /* copy data */
594     GST_LOG ("copying data in buffer from %p to %p",
595         addr, GST_BUFFER_DATA (outbuf));
596     if (G_UNLIKELY ((qtwrapper->width * 2) !=
597             CVPixelBufferGetBytesPerRow (pixelBuffer))) {
598       guint i;
599       gulong realpixels;
600       size_t stride;
601
602       stride = CVPixelBufferGetBytesPerRow (pixelBuffer);
603       realpixels = qtwrapper->width * 2;
604
605       /* special copy for stride handling */
606       for (i = 0; i < qtwrapper->height; i++)
607         g_memmove (GST_BUFFER_DATA (outbuf) + realpixels * i,
608             addr + stride * i, realpixels);
609
610     } else
611       g_memmove (GST_BUFFER_DATA (outbuf), addr, (int) qtwrapper->outsize);
612
613     /* Release CVPixelBuffer */
614     CVPixelBufferUnlockBaseAddress (pixelBuffer, 0);
615     CVPixelBufferRelease (pixelBuffer);
616
617     /* Set proper timestamp ! */
618     gst_buffer_set_caps (outbuf, GST_PAD_CAPS (qtwrapper->srcpad));
619     GST_BUFFER_TIMESTAMP (outbuf) = qtwrapper->last_ts;
620     GST_BUFFER_DURATION (outbuf) = qtwrapper->last_duration;
621     GST_BUFFER_SIZE (outbuf) = (int) qtwrapper->outsize;
622
623     /* See if we push buffer downstream */
624     if (G_LIKELY (!qtwrapper->framebuffering)) {
625       GST_LOG ("No buffering needed, pushing buffer downstream");
626       MAC_UNLOCK (qtwrapper);
627       qtwrapper->lastret = gst_pad_push (qtwrapper->srcpad, outbuf);
628       MAC_LOCK (qtwrapper);
629     } else {
630       /* Check if we push the current buffer or the stored buffer */
631       if (!qtwrapper->prevbuf) {
632         GST_LOG ("Storing buffer");
633         qtwrapper->prevbuf = outbuf;
634         qtwrapper->lastret = GST_FLOW_OK;
635       } else if (GST_BUFFER_TIMESTAMP (qtwrapper->prevbuf) >
636           GST_BUFFER_TIMESTAMP (outbuf)) {
637         GST_LOG ("Newly decoded buffer is earliest, pushing that one !");
638         MAC_UNLOCK (qtwrapper);
639         qtwrapper->lastret = gst_pad_push (qtwrapper->srcpad, outbuf);
640         MAC_LOCK (qtwrapper);
641       } else {
642         GstBuffer *tmp;
643
644         tmp = qtwrapper->prevbuf;
645         qtwrapper->prevbuf = outbuf;
646         GST_LOG ("Stored buffer is earliest, pushing that one !");
647         MAC_UNLOCK (qtwrapper);
648         qtwrapper->lastret = gst_pad_push (qtwrapper->srcpad, tmp);
649         MAC_LOCK (qtwrapper);
650       }
651     }
652   } else {
653     qtwrapper->lastret = GST_FLOW_OK;
654   }
655
656 beach:
657   return;
658 }
659
660 /* _chain
661  *
662  * Here we feed the data to the decoder and ask to decode frames.
663  *
664  * Known issues/questions are:
665  *  * How can we be guaranteed that one frame in automatically gives one output
666  *    frame ?
667  *  * PTS/DTS timestamp issues. With mpeg-derivate formats, the incoming order is
668  *    different from the output order.
669  */
670
671 static GstFlowReturn
672 qtwrapper_video_decoder_chain (GstPad * pad, GstBuffer * buf)
673 {
674   QTWrapperVideoDecoder *qtwrapper;
675   GstFlowReturn ret = GST_FLOW_OK;
676   ICMFrameTimeRecord frameTime = { {0} };
677   OSStatus status;
678   guint64 intime;
679
680   qtwrapper = (QTWrapperVideoDecoder *) gst_pad_get_parent (pad);
681
682   intime = gst_util_uint64_scale (GST_BUFFER_TIMESTAMP (buf), 600, GST_SECOND);
683
684   GST_DEBUG_OBJECT (qtwrapper,
685       "buffer:%p timestamp:%" GST_TIME_FORMAT " intime:%llu Size:%d", buf,
686       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), intime,
687       GST_BUFFER_SIZE (buf));
688
689   frameTime.recordSize = sizeof (ICMFrameTimeRecord);
690 /*   *(TimeValue64 *)&frameTime.value = intime; */
691   frameTime.value.lo = (guint32) (intime & 0xffffffff);
692   frameTime.value.hi = (guint32) (intime >> 32);
693   frameTime.base = 0;
694   frameTime.scale = 600;
695   frameTime.rate = fixed1;
696   frameTime.duration = 1;
697   frameTime.flags = icmFrameTimeDecodeImmediately;
698 /*   frameTime.flags = icmFrameTimeIsNonScheduledDisplayTime; */
699   frameTime.frameNumber = (long) (++qtwrapper->frameNumber);
700
701   MAC_LOCK (qtwrapper);
702
703   qtwrapper->last_ts = GST_BUFFER_TIMESTAMP (buf);
704   qtwrapper->last_duration = GST_BUFFER_DURATION (buf);
705
706   status = ICMDecompressionSessionDecodeFrame (qtwrapper->decsession,
707       GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf), NULL, &frameTime, buf);
708   MAC_UNLOCK (qtwrapper);
709
710   if (status) {
711     GST_WARNING_OBJECT (qtwrapper, "Error when Calling DecodeFrame() : %ld",
712         status);
713     ret = GST_FLOW_ERROR;
714     goto beach;
715   }
716
717 beach:
718   gst_object_unref (qtwrapper);
719   return qtwrapper->lastret;
720 }
721
722 static gboolean
723 qtwrapper_video_decoder_sink_event (GstPad * pad, GstEvent * event)
724 {
725   gboolean res;
726   QTWrapperVideoDecoder *qtwrapper;
727
728   qtwrapper = (QTWrapperVideoDecoder *) gst_pad_get_parent (pad);
729
730   GST_LOG_OBJECT (pad, "event : %s", GST_EVENT_TYPE_NAME (event));
731
732   switch (GST_EVENT_TYPE (event)) {
733     case GST_EVENT_FLUSH_START:
734       MAC_LOCK (qtwrapper);
735       qtwrapper->flushing = TRUE;
736       if (qtwrapper->prevbuf) {
737         GST_LOG ("About to unref buffer %p", qtwrapper->prevbuf);
738         gst_buffer_unref (qtwrapper->prevbuf);
739         qtwrapper->prevbuf = NULL;
740       }
741       ICMDecompressionSessionFlush (qtwrapper->decsession);
742       MAC_UNLOCK (qtwrapper);
743       break;
744     case GST_EVENT_FLUSH_STOP:
745       MAC_LOCK (qtwrapper);
746       qtwrapper->flushing = FALSE;
747       qtwrapper->prevbuf = NULL;
748       MAC_UNLOCK (qtwrapper);
749       break;
750     default:
751       break;
752   }
753
754   res = gst_pad_push_event (qtwrapper->srcpad, event);
755
756   gst_object_unref (qtwrapper);
757   return res;
758 }
759
760 /* _register
761  *
762  * Scan through all available Image Decompressor components to find the ones we
763  * can handle and wrap in this plugin.
764  */
765
766 gboolean
767 qtwrapper_video_decoders_register (GstPlugin * plugin)
768 {
769   gboolean res = TRUE;
770   Component componentID = NULL;
771   ComponentDescription desc = {
772     'imdc', 0, 0, 0, 0
773   };
774   GTypeInfo typeinfo = {
775     sizeof (QTWrapperVideoDecoderClass),
776     (GBaseInitFunc) qtwrapper_video_decoder_base_init,
777     NULL,
778     (GClassInitFunc) qtwrapper_video_decoder_class_init,
779     NULL,
780     NULL,
781     sizeof (QTWrapperVideoDecoder),
782     0,
783     (GInstanceInitFunc) qtwrapper_video_decoder_init,
784   };
785
786   /* Find all ImageDecoders ! */
787   GST_DEBUG ("There are %ld decompressors available", CountComponents (&desc));
788
789   /* loop over ImageDecoders */
790   do {
791     componentID = FindNextComponent (componentID, &desc);
792
793     GST_LOG ("componentID : %p", componentID);
794
795     if (componentID) {
796       ComponentDescription thisdesc;
797       gchar *name = NULL, *info = NULL;
798       GstCaps *caps = NULL;
799       gchar *type_name = NULL;
800       GType type;
801       QTWrapperVideoDecoderParams *params = NULL;
802
803       if (!(get_name_info_from_component (componentID, &thisdesc, &name,
804                   &info)))
805         goto next;
806
807       if (!get_output_info_from_component (componentID)) {
808         GST_WARNING ("Couldn't get output info from component");
809         goto next;
810       }
811
812       GST_LOG (" name:%s", GST_STR_NULL (name));
813       GST_LOG (" info:%s", GST_STR_NULL (info));
814
815       GST_LOG (" type:%" GST_FOURCC_FORMAT,
816           QT_FOURCC_ARGS (thisdesc.componentType));
817       GST_LOG (" subtype:%" GST_FOURCC_FORMAT,
818           QT_FOURCC_ARGS (thisdesc.componentSubType));
819       GST_LOG (" manufacturer:%" GST_FOURCC_FORMAT,
820           QT_FOURCC_ARGS (thisdesc.componentManufacturer));
821
822       if (!(caps = fourcc_to_caps (thisdesc.componentSubType))) {
823         GST_LOG
824             ("We can't find caps for this component, switching to the next one !");
825         goto next;
826       }
827
828       type_name = g_strdup_printf ("qtwrappervideodec_%" GST_FOURCC_FORMAT,
829           QT_FOURCC_ARGS (thisdesc.componentSubType));
830       g_strdelimit (type_name, " ", '_');
831
832       if (g_type_from_name (type_name)) {
833         GST_WARNING ("We already have a registered plugin for %s", type_name);
834         goto next;
835       }
836
837       params = g_new0 (QTWrapperVideoDecoderParams, 1);
838       params->component = componentID;
839       params->sinkcaps = gst_caps_ref (caps);
840
841       GST_INFO ("Registering g_type for type_name: %s", type_name);
842       type = g_type_register_static (GST_TYPE_ELEMENT, type_name, &typeinfo, 0);
843       /* Store params in type qdata */
844       g_type_set_qdata (type, QTWRAPPER_VDEC_PARAMS_QDATA, (gpointer) params);
845
846       /* register type */
847       if (!gst_element_register (plugin, type_name, GST_RANK_MARGINAL, type)) {
848         g_warning ("Failed to register %s", type_name);;
849         g_type_set_qdata (type, QTWRAPPER_VDEC_PARAMS_QDATA, NULL);
850         g_free (params);
851         res = FALSE;
852         goto next;
853       } else {
854         GST_LOG ("Reigstered video plugin %s", type_name);
855       }
856
857     next:
858       if (name)
859         g_free (name);
860       if (info)
861         g_free (info);
862       if (type_name)
863         g_free (type_name);
864       if (caps)
865         gst_caps_unref (caps);
866     }
867
868   } while (componentID && res);
869
870   return res;
871 }