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>
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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.
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
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.
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.
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.
51 #include "qtwrapper.h"
52 #include "codecmapping.h"
54 #include "imagedescription.h"
56 #define QTWRAPPER_VDEC_PARAMS_QDATA g_quark_from_static_string("qtwrapper-vdec-params")
58 static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
61 GST_STATIC_CAPS ("video/x-raw-yuv"));
63 typedef struct _QTWrapperVideoDecoder QTWrapperVideoDecoder;
64 typedef struct _QTWrapperVideoDecoderClass QTWrapperVideoDecoderClass;
66 #define MAC_LOCK(qtwrapper) g_mutex_lock (qtwrapper->lock)
67 #define MAC_UNLOCK(qtwrapper) g_mutex_unlock (qtwrapper->lock)
69 struct _QTWrapperVideoDecoder
77 ComponentInstance instance;
79 ImageDescriptionHandle idesc;
80 CodecDecompressParams *dparams;
81 CodecCapabilities codeccaps;
83 ICMDecompressionSessionRef decsession;
84 GstFlowReturn lastret;
88 GstClockTime last_duration;
91 gboolean framebuffering;
93 /* width/height of output buffer */
97 struct _QTWrapperVideoDecoderClass
99 GstElementClass parent_class;
102 guint32 componentType;
103 guint32 componentSubType;
105 GstPadTemplate *sinktempl;
108 typedef struct _QTWrapperVideoDecoderParams QTWrapperVideoDecoderParams;
110 struct _QTWrapperVideoDecoderParams
116 static GstElementClass *parent_class = NULL;
119 qtwrapper_video_decoder_sink_setcaps (GstPad * pad, GstCaps * caps);
120 static GstFlowReturn qtwrapper_video_decoder_chain (GstPad * pad,
122 static gboolean qtwrapper_video_decoder_sink_event (GstPad * pad,
125 static void qtwrapper_video_decoder_finalize (GObject * object);
126 static void decompressCb (void *decompressionTrackingRefCon,
128 ICMDecompressionTrackingFlags decompressionTrackingFlags,
129 CVPixelBufferRef pixelBuffer,
130 TimeValue64 displayTime,
131 TimeValue64 displayDuration,
132 ICMValidTimeFlags validTimeFlags, void *reserved, void *sourceFrameRefCon);
139 qtwrapper_video_decoder_base_init (QTWrapperVideoDecoderClass * klass)
141 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
144 char *longname, *description;
145 ComponentDescription desc;
146 QTWrapperVideoDecoderParams *params;
148 params = (QTWrapperVideoDecoderParams *)
149 g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass),
150 QTWRAPPER_VDEC_PARAMS_QDATA);
153 get_name_info_from_component (params->component, &desc, &name, &info);
155 /* Fill in details */
157 g_strdup_printf ("QTWrapper Video Decoder : %s", GST_STR_NULL (name));
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>");
166 g_free (description);
170 klass->sinktempl = gst_pad_template_new ("sink", GST_PAD_SINK,
171 GST_PAD_ALWAYS, params->sinkcaps);
173 gst_element_class_add_pad_template (element_class, klass->sinktempl);
174 gst_element_class_add_static_pad_template (element_class, &src_templ);
176 /* Store class-global values */
177 klass->component = params->component;
178 klass->componentType = desc.componentType;
179 klass->componentSubType = desc.componentSubType;
183 qtwrapper_video_decoder_class_init (QTWrapperVideoDecoderClass * klass)
185 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
187 parent_class = g_type_class_peek_parent (klass);
189 gobject_class->finalize =
190 GST_DEBUG_FUNCPTR (qtwrapper_video_decoder_finalize);
194 qtwrapper_video_decoder_init (QTWrapperVideoDecoder * qtwrapper)
196 QTWrapperVideoDecoderClass *oclass;
197 ImageSubCodecDecompressCapabilities capabs;
200 oclass = (QTWrapperVideoDecoderClass *) (G_OBJECT_GET_CLASS (qtwrapper));
202 /* 1. Create a ocmponent instance */
203 if (!(qtwrapper->instance = OpenComponent (oclass->component))) {
204 GST_ERROR_OBJECT (qtwrapper, "Couldn't create a component instance !");
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 !");
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 !");
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);
234 qtwrapper->srcpad = gst_pad_new_from_static_template (&src_templ, "src");
235 gst_element_add_pad (GST_ELEMENT (qtwrapper), qtwrapper->srcpad);
237 qtwrapper->lock = g_mutex_new ();
241 qtwrapper_video_decoder_finalize (GObject * object)
243 QTWrapperVideoDecoder *qtwrapper;
245 qtwrapper = (QTWrapperVideoDecoder *) object;
248 g_mutex_free (qtwrapper->lock);
250 if (G_OBJECT_CLASS (parent_class)->finalize)
251 G_OBJECT_CLASS (parent_class)->finalize (object);
254 /* fill_image_description
255 * Fills an ImageDescription with codec-specific values
257 * Doesn't fill in the idSize, width and height.
261 fill_image_description (QTWrapperVideoDecoder * qtwrapper,
262 ImageDescription * desc)
264 QTWrapperVideoDecoderClass *oclass;
266 oclass = (QTWrapperVideoDecoderClass *) (G_OBJECT_GET_CLASS (qtwrapper));
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
286 /* new_image_description
288 * Create an ImageDescription for the given 'codec_data' buffer.
291 static ImageDescription *
292 new_image_description (QTWrapperVideoDecoder * qtwrapper, GstBuffer * buf,
293 guint width, guint height)
295 QTWrapperVideoDecoderClass *oclass;
296 ImageDescription *desc = NULL;
298 oclass = (QTWrapperVideoDecoderClass *) (G_OBJECT_GET_CLASS (qtwrapper));
301 GST_LOG ("buf %p , size:%d", buf, GST_BUFFER_SIZE (buf));
303 gst_util_dump_mem (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
308 /* standard case, no codec data */
309 desc = g_new0 (ImageDescription, 1);
310 desc->idSize = sizeof (ImageDescription);
311 fill_image_description (qtwrapper, desc);
314 image_description_from_codec_data (buf, oclass->componentSubType)))
315 fill_image_description (qtwrapper, desc);
322 desc->height = height;
323 desc->hRes = Long2Fix (72);
324 desc->vRes = Long2Fix (72);
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;
330 qtwrapper->framebuffering = FALSE;
338 * Close and free decoder
342 close_decoder (QTWrapperVideoDecoder * qtwrapper)
344 if (qtwrapper->idesc) {
345 DisposeHandle ((Handle) qtwrapper->idesc);
346 qtwrapper->idesc = NULL;
349 if (qtwrapper->prevbuf) {
350 gst_buffer_unref (qtwrapper->prevbuf);
351 qtwrapper->prevbuf = NULL;
354 if (qtwrapper->dparams) {
355 g_free (qtwrapper->dparams);
356 qtwrapper->dparams = NULL;
363 * Attempt to initialize the ImageDecompressorComponent with the given
366 * Returns TRUE and fills *outcaps if the decoder was properly initialized
367 * Returns FALSE if something went wrong.
371 open_decoder (QTWrapperVideoDecoder * qtwrapper, GstCaps * caps,
374 ImageDescription *desc;
377 const GValue *par = NULL;
378 const GValue *rate = NULL;
379 const GValue *cdata = NULL;
381 gboolean res = FALSE;
384 ICMDecompressionSessionOptionsRef sessionoptions = NULL;
385 ICMDecompressionTrackingCallbackRecord cbrecord;
386 CFMutableDictionaryRef pixelBufferAttributes = NULL;
389 s = gst_caps_get_structure (caps, 0);
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"))))
396 par = gst_structure_get_value (s, "pixel-aspect-ratio");
397 cdata = gst_structure_get_value (s, "codec_data");
399 /* 2. Create ImageDescription */
403 cdatabuf = gst_value_get_buffer (cdata);
404 desc = new_image_description (qtwrapper, cdatabuf, width, height);
406 desc = new_image_description (qtwrapper, NULL, width, height);
410 dump_image_description (desc);
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",
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,
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,
431 memcpy (*qtwrapper->idesc, desc, desc->idSize);
434 #if G_BYTE_ORDER == G_BIG_ENDIAN
435 outformat = kYUVSPixelFormat;
437 outformat = k2vuyPixelFormat;
440 /* 4. Put output pixel info in dictionnnary */
441 pixelBufferAttributes =
442 CFDictionaryCreateMutable (NULL, 0, &kCFTypeDictionaryKeyCallBacks,
443 &kCFTypeDictionaryValueCallBacks);
445 addSInt32ToDictionary (pixelBufferAttributes, kCVPixelBufferWidthKey, width);
446 addSInt32ToDictionary (pixelBufferAttributes, kCVPixelBufferHeightKey,
448 addSInt32ToDictionary (pixelBufferAttributes,
449 kCVPixelBufferPixelFormatTypeKey, outformat);
451 /* 5. fill in callback structure */
453 cbrecord.decompressionTrackingCallback = decompressCb;
454 cbrecord.decompressionTrackingRefCon = qtwrapper;
456 /* 6. create decompressionsession */
457 status = ICMDecompressionSessionCreate (NULL,
459 sessionoptions, pixelBufferAttributes, &cbrecord, &qtwrapper->decsession);
461 qtwrapper->outsize = width * height * 2;
462 qtwrapper->width = width;
463 qtwrapper->height = height;
466 GST_DEBUG_OBJECT (qtwrapper,
467 "Error when Calling ICMDecompressionSessionCreate : %ld", status);
470 #if G_BYTE_ORDER == G_BIG_ENDIAN
471 outformat = GST_MAKE_FOURCC ('Y', 'U', 'Y', '2');
473 outformat = GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y');
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);
485 gst_structure_set_value (gst_caps_get_structure (*outcaps, 0),
486 "pixel-aspect-ratio", par);
494 qtwrapper_video_decoder_sink_setcaps (GstPad * pad, GstCaps * caps)
496 QTWrapperVideoDecoder *qtwrapper;
497 gboolean ret = FALSE;
498 GstCaps *othercaps = NULL;
500 qtwrapper = (QTWrapperVideoDecoder *) gst_pad_get_parent (pad);
502 GST_LOG_OBJECT (qtwrapper, "caps:%" GST_PTR_FORMAT, caps);
504 /* Setup the decoder with the given input caps */
505 if (!(open_decoder (qtwrapper, caps, &othercaps))) {
509 ret = gst_pad_set_caps (qtwrapper->srcpad, othercaps);
515 gst_caps_unref (othercaps);
516 gst_object_unref (qtwrapper);
521 decompressCb (void *decompressionTrackingRefCon,
523 ICMDecompressionTrackingFlags decompressionTrackingFlags,
524 CVPixelBufferRef pixelBuffer,
525 TimeValue64 displayTime,
526 TimeValue64 displayDuration,
527 ICMValidTimeFlags validTimeFlags, void *reserved, void *sourceFrameRefCon)
529 QTWrapperVideoDecoder *qtwrapper;
530 GstBuffer *origbuf = (GstBuffer *) sourceFrameRefCon;
532 qtwrapper = (QTWrapperVideoDecoder *) decompressionTrackingRefCon;
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);
539 GST_LOG_OBJECT (qtwrapper,
540 "validTimeFlags:0x%x, reserved:%p, sourceFrameRefCon:%p",
541 (guint32) validTimeFlags, reserved, sourceFrameRefCon);
543 if (decompressionTrackingFlags & kICMDecompressionTracking_ReleaseSourceData) {
544 GST_LOG ("removing previous buffer : %p", origbuf);
545 gst_buffer_unref (origbuf);
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");
558 if ((decompressionTrackingFlags & kICMDecompressionTracking_EmittingFrame)
563 GstClockTime outtime;
565 size = CVPixelBufferGetDataSize (pixelBuffer);
566 outtime = gst_util_uint64_scale (displayTime, GST_SECOND, 600);
568 GST_LOG ("Got a buffer ready outtime : %" GST_TIME_FORMAT,
569 GST_TIME_ARGS (outtime));
571 if (qtwrapper->flushing) {
572 CVPixelBufferRelease (pixelBuffer);
576 dump_cvpixel_buffer (pixelBuffer);
578 CVPixelBufferRetain (pixelBuffer);
579 if (CVPixelBufferLockBaseAddress (pixelBuffer, 0))
580 GST_WARNING ("Couldn't lock base adress on pixel buffer !");
581 addr = CVPixelBufferGetBaseAddress (pixelBuffer);
583 /* allocate buffer */
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));
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))) {
602 stride = CVPixelBufferGetBytesPerRow (pixelBuffer);
603 realpixels = qtwrapper->width * 2;
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);
611 g_memmove (GST_BUFFER_DATA (outbuf), addr, (int) qtwrapper->outsize);
613 /* Release CVPixelBuffer */
614 CVPixelBufferUnlockBaseAddress (pixelBuffer, 0);
615 CVPixelBufferRelease (pixelBuffer);
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;
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);
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);
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);
653 qtwrapper->lastret = GST_FLOW_OK;
662 * Here we feed the data to the decoder and ask to decode frames.
664 * Known issues/questions are:
665 * * How can we be guaranteed that one frame in automatically gives one output
667 * * PTS/DTS timestamp issues. With mpeg-derivate formats, the incoming order is
668 * different from the output order.
672 qtwrapper_video_decoder_chain (GstPad * pad, GstBuffer * buf)
674 QTWrapperVideoDecoder *qtwrapper;
675 GstFlowReturn ret = GST_FLOW_OK;
676 ICMFrameTimeRecord frameTime = { {0} };
680 qtwrapper = (QTWrapperVideoDecoder *) gst_pad_get_parent (pad);
682 intime = gst_util_uint64_scale (GST_BUFFER_TIMESTAMP (buf), 600, GST_SECOND);
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));
689 frameTime.recordSize = sizeof (ICMFrameTimeRecord);
690 /* *(TimeValue64 *)&frameTime.value = intime; */
691 frameTime.value.lo = (guint32) (intime & 0xffffffff);
692 frameTime.value.hi = (guint32) (intime >> 32);
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);
701 MAC_LOCK (qtwrapper);
703 qtwrapper->last_ts = GST_BUFFER_TIMESTAMP (buf);
704 qtwrapper->last_duration = GST_BUFFER_DURATION (buf);
706 status = ICMDecompressionSessionDecodeFrame (qtwrapper->decsession,
707 GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf), NULL, &frameTime, buf);
708 MAC_UNLOCK (qtwrapper);
711 GST_WARNING_OBJECT (qtwrapper, "Error when Calling DecodeFrame() : %ld",
713 ret = GST_FLOW_ERROR;
718 gst_object_unref (qtwrapper);
719 return qtwrapper->lastret;
723 qtwrapper_video_decoder_sink_event (GstPad * pad, GstEvent * event)
726 QTWrapperVideoDecoder *qtwrapper;
728 qtwrapper = (QTWrapperVideoDecoder *) gst_pad_get_parent (pad);
730 GST_LOG_OBJECT (pad, "event : %s", GST_EVENT_TYPE_NAME (event));
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;
741 ICMDecompressionSessionFlush (qtwrapper->decsession);
742 MAC_UNLOCK (qtwrapper);
744 case GST_EVENT_FLUSH_STOP:
745 MAC_LOCK (qtwrapper);
746 qtwrapper->flushing = FALSE;
747 qtwrapper->prevbuf = NULL;
748 MAC_UNLOCK (qtwrapper);
754 res = gst_pad_push_event (qtwrapper->srcpad, event);
756 gst_object_unref (qtwrapper);
762 * Scan through all available Image Decompressor components to find the ones we
763 * can handle and wrap in this plugin.
767 qtwrapper_video_decoders_register (GstPlugin * plugin)
770 Component componentID = NULL;
771 ComponentDescription desc = {
774 GTypeInfo typeinfo = {
775 sizeof (QTWrapperVideoDecoderClass),
776 (GBaseInitFunc) qtwrapper_video_decoder_base_init,
778 (GClassInitFunc) qtwrapper_video_decoder_class_init,
781 sizeof (QTWrapperVideoDecoder),
783 (GInstanceInitFunc) qtwrapper_video_decoder_init,
786 /* Find all ImageDecoders ! */
787 GST_DEBUG ("There are %ld decompressors available", CountComponents (&desc));
789 /* loop over ImageDecoders */
791 componentID = FindNextComponent (componentID, &desc);
793 GST_LOG ("componentID : %p", componentID);
796 ComponentDescription thisdesc;
797 gchar *name = NULL, *info = NULL;
798 GstCaps *caps = NULL;
799 gchar *type_name = NULL;
801 QTWrapperVideoDecoderParams *params = NULL;
803 if (!(get_name_info_from_component (componentID, &thisdesc, &name,
807 if (!get_output_info_from_component (componentID)) {
808 GST_WARNING ("Couldn't get output info from component");
812 GST_LOG (" name:%s", GST_STR_NULL (name));
813 GST_LOG (" info:%s", GST_STR_NULL (info));
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));
822 if (!(caps = fourcc_to_caps (thisdesc.componentSubType))) {
824 ("We can't find caps for this component, switching to the next one !");
828 type_name = g_strdup_printf ("qtwrappervideodec_%" GST_FOURCC_FORMAT,
829 QT_FOURCC_ARGS (thisdesc.componentSubType));
830 g_strdelimit (type_name, " ", '_');
832 if (g_type_from_name (type_name)) {
833 GST_WARNING ("We already have a registered plugin for %s", type_name);
837 params = g_new0 (QTWrapperVideoDecoderParams, 1);
838 params->component = componentID;
839 params->sinkcaps = gst_caps_ref (caps);
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);
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);
854 GST_LOG ("Reigstered video plugin %s", type_name);
865 gst_caps_unref (caps);
868 } while (componentID && res);