configure.ac: Add QuickTime Wrapper plug-in.
authorJulien Moutte <julien@moutte.net>
Mon, 26 Nov 2007 13:19:48 +0000 (13:19 +0000)
committerJulien Moutte <julien@moutte.net>
Mon, 26 Nov 2007 13:19:48 +0000 (13:19 +0000)
Original commit message from CVS:
2007-11-26  Julien Moutte  <julien@fluendo.com>

* configure.ac: Add QuickTime Wrapper plug-in.
* gst/speexresample/gstspeexresample.c:
(gst_speex_resample_push_drain), (gst_speex_resample_process): Fix
build on Mac OS X Leopard. Incorrect printf format arguments.
* sys/Makefile.am:
* sys/qtwrapper/Makefile.am:
* sys/qtwrapper/audiodecoders.c:
(qtwrapper_audio_decoder_base_init),
(qtwrapper_audio_decoder_class_init),
(qtwrapper_audio_decoder_init),
(clear_AudioStreamBasicDescription), (fill_indesc_mp3),
(fill_indesc_aac), (fill_indesc_samr), (fill_indesc_generic),
(make_samr_magic_cookie), (open_decoder),
(qtwrapper_audio_decoder_sink_setcaps), (process_buffer_cb),
(qtwrapper_audio_decoder_chain),
(qtwrapper_audio_decoder_sink_event),
(qtwrapper_audio_decoders_register):
* sys/qtwrapper/codecmapping.c: (audio_caps_from_string),
(fourcc_to_caps):
* sys/qtwrapper/codecmapping.h:
* sys/qtwrapper/imagedescription.c: (image_description_for_avc1),
(image_description_for_mp4v), (image_description_from_stsd_buffer),
(image_description_from_codec_data):
* sys/qtwrapper/imagedescription.h:
* sys/qtwrapper/qtutils.c: (get_name_info_from_component),
(get_output_info_from_component), (dump_avcc_atom),
(dump_image_description), (dump_codec_decompress_params),
(addSInt32ToDictionary), (dump_cvpixel_buffer),
(DestroyAudioBufferList), (AllocateAudioBufferList):
* sys/qtwrapper/qtutils.h:
* sys/qtwrapper/qtwrapper.c: (plugin_init):
* sys/qtwrapper/qtwrapper.h:
* sys/qtwrapper/videodecoders.c:
(qtwrapper_video_decoder_base_init),
(qtwrapper_video_decoder_class_init),
(qtwrapper_video_decoder_init), (qtwrapper_video_decoder_finalize),
(fill_image_description), (new_image_description), (close_decoder),
(open_decoder), (qtwrapper_video_decoder_sink_setcaps),
(decompressCb), (qtwrapper_video_decoder_chain),
(qtwrapper_video_decoder_sink_event),
(qtwrapper_video_decoders_register): Initial import of QuickTime
wrapper jointly developped by Songbird authors (Pioneers of the
Inevitable) and Fluendo.

15 files changed:
ChangeLog
configure.ac
gst/speexresample/gstspeexresample.c
sys/Makefile.am
sys/qtwrapper/Makefile.am [new file with mode: 0644]
sys/qtwrapper/audiodecoders.c [new file with mode: 0644]
sys/qtwrapper/codecmapping.c [new file with mode: 0644]
sys/qtwrapper/codecmapping.h [new file with mode: 0644]
sys/qtwrapper/imagedescription.c [new file with mode: 0644]
sys/qtwrapper/imagedescription.h [new file with mode: 0644]
sys/qtwrapper/qtutils.c [new file with mode: 0644]
sys/qtwrapper/qtutils.h [new file with mode: 0644]
sys/qtwrapper/qtwrapper.c [new file with mode: 0644]
sys/qtwrapper/qtwrapper.h [new file with mode: 0644]
sys/qtwrapper/videodecoders.c [new file with mode: 0644]

index 1d06831..58b70b9 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,49 @@
+2007-11-26  Julien Moutte  <julien@fluendo.com>
+
+       * configure.ac: Add QuickTime Wrapper plug-in.
+       * gst/speexresample/gstspeexresample.c:
+       (gst_speex_resample_push_drain), (gst_speex_resample_process): Fix
+       build on Mac OS X Leopard. Incorrect printf format arguments.
+       * sys/Makefile.am:
+       * sys/qtwrapper/Makefile.am:
+       * sys/qtwrapper/audiodecoders.c:
+       (qtwrapper_audio_decoder_base_init),
+       (qtwrapper_audio_decoder_class_init),
+       (qtwrapper_audio_decoder_init),
+       (clear_AudioStreamBasicDescription), (fill_indesc_mp3),
+       (fill_indesc_aac), (fill_indesc_samr), (fill_indesc_generic),
+       (make_samr_magic_cookie), (open_decoder),
+       (qtwrapper_audio_decoder_sink_setcaps), (process_buffer_cb),
+       (qtwrapper_audio_decoder_chain),
+       (qtwrapper_audio_decoder_sink_event),
+       (qtwrapper_audio_decoders_register):
+       * sys/qtwrapper/codecmapping.c: (audio_caps_from_string),
+       (fourcc_to_caps):
+       * sys/qtwrapper/codecmapping.h:
+       * sys/qtwrapper/imagedescription.c: (image_description_for_avc1),
+       (image_description_for_mp4v), (image_description_from_stsd_buffer),
+       (image_description_from_codec_data):
+       * sys/qtwrapper/imagedescription.h:
+       * sys/qtwrapper/qtutils.c: (get_name_info_from_component),
+       (get_output_info_from_component), (dump_avcc_atom),
+       (dump_image_description), (dump_codec_decompress_params),
+       (addSInt32ToDictionary), (dump_cvpixel_buffer),
+       (DestroyAudioBufferList), (AllocateAudioBufferList):
+       * sys/qtwrapper/qtutils.h:
+       * sys/qtwrapper/qtwrapper.c: (plugin_init):
+       * sys/qtwrapper/qtwrapper.h:
+       * sys/qtwrapper/videodecoders.c:
+       (qtwrapper_video_decoder_base_init),
+       (qtwrapper_video_decoder_class_init),
+       (qtwrapper_video_decoder_init), (qtwrapper_video_decoder_finalize),
+       (fill_image_description), (new_image_description), (close_decoder),
+       (open_decoder), (qtwrapper_video_decoder_sink_setcaps),
+       (decompressCb), (qtwrapper_video_decoder_chain),
+       (qtwrapper_video_decoder_sink_event),
+       (qtwrapper_video_decoders_register): Initial import of QuickTime
+       wrapper jointly developped by Songbird authors (Pioneers of the
+       Inevitable) and Fluendo.
+
 2007-11-26  Stefan Kost  <ensonic@users.sf.net>
 
        * gst/spectrum/gstspectrum.c:
index dcf4b35..82b1736 100644 (file)
@@ -298,6 +298,12 @@ AG_GST_CHECK_FEATURE(OPENGL, [Open GL], glsink, [
 CPPFLAGS="$save_CPPFLAGS"
 LIBS="$save_LIBS"
 
+dnl check for QuickTime
+translit(dnm, m, l) AM_CONDITIONAL(USE_QUICKTIME, true)
+AG_GST_CHECK_FEATURE(QUICKTIME, [QuickTime wrapper], qtwrapper, [
+  AC_CHECK_HEADER(QuickTime/Movies.h, HAVE_QUICKTIME="yes", HAVE_QUICKTIME="no")
+])
+
 dnl check for Video CD
 translit(dnm, m, l) AM_CONDITIONAL(USE_VCD, true)
 AG_GST_CHECK_FEATURE(VCD, [Video CD], vcdsrc, [
@@ -955,6 +961,7 @@ dnl not building plugins with external dependencies,
 dnl but we still need to set the conditionals
 
 AM_CONDITIONAL(USE_OPENGL, false)
+AM_CONDITIONAL(USE_QUICKTIME, false)
 AM_CONDITIONAL(USE_VCD, false)
 AM_CONDITIONAL(USE_X, false)
 AM_CONDITIONAL(USE_ALSA, false)
@@ -1086,6 +1093,7 @@ gst-libs/gst/app/Makefile
 sys/Makefile
 sys/glsink/Makefile
 sys/dvb/Makefile
+sys/qtwrapper/Makefile
 sys/vcd/Makefile
 examples/Makefile
 examples/app/Makefile
index e6765a0..77fb8e2 100644 (file)
@@ -594,8 +594,9 @@ gst_speex_resample_push_drain (GstSpeexResample * resample)
         GST_FRAMES_TO_CLOCK_TIME (out_processed, resample->outrate);
   }
 
-  GST_LOG ("Pushing drain buffer of %ld bytes with timestamp %" GST_TIME_FORMAT
-      " duration %" GST_TIME_FORMAT " offset %lld offset_end %lld",
+  GST_LOG ("Pushing drain buffer of %u bytes with timestamp %" GST_TIME_FORMAT
+      " duration %" GST_TIME_FORMAT " offset %" G_GUINT64_FORMAT
+      " offset_end %" G_GUINT64_FORMAT,
       GST_BUFFER_SIZE (buf),
       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
       GST_TIME_ARGS (GST_BUFFER_DURATION (buf)),
@@ -752,8 +753,9 @@ gst_speex_resample_process (GstSpeexResample * resample, GstBuffer * inbuf,
     GST_ERROR ("Failed to convert data: %s", resample_resampler_strerror (err));
     return GST_FLOW_ERROR;
   } else {
-    GST_LOG ("Converted to buffer of %ld bytes with timestamp %" GST_TIME_FORMAT
-        ", duration %" GST_TIME_FORMAT ", offset %lld, offset_end %lld",
+    GST_LOG ("Converted to buffer of %u bytes with timestamp %" GST_TIME_FORMAT
+        ", duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT
+        ", offset_end %" G_GUINT64_FORMAT,
         GST_BUFFER_SIZE (outbuf),
         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
         GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
index 106c729..564771e 100644 (file)
@@ -34,6 +34,12 @@ else
 DVB_DIR=
 endif
 
-SUBDIRS = $(GL_DIR) $(DVB_DIR) $(VCD_DIR)
+if USE_QUICKTIME
+QT_DIR=qtwrapper
+else
+QT_DIR=
+endif
+
+SUBDIRS = $(GL_DIR) $(DVB_DIR) $(VCD_DIR) $(QT_DIR)
 
-DIST_SUBDIRS = glsink dvb vcd
+DIST_SUBDIRS = glsink dvb vcd qtwrapper
diff --git a/sys/qtwrapper/Makefile.am b/sys/qtwrapper/Makefile.am
new file mode 100644 (file)
index 0000000..db08647
--- /dev/null
@@ -0,0 +1,24 @@
+plugin_LTLIBRARIES = libgstqtwrapper.la
+
+# sources used to compile this plug-in
+libgstqtwrapper_la_SOURCES = \
+       qtwrapper.c             \
+       qtutils.c               \
+       codecmapping.c          \
+       audiodecoders.c         \
+       videodecoders.c         \
+       imagedescription.c
+
+# flags used to compile this plugin
+# add other _CFLAGS and _LIBS as needed
+libgstqtwrapper_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS)
+libgstqtwrapper_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS)
+libgstqtwrapper_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -Wl,-framework,CoreAudio,-framework,AudioToolbox,-framework,Carbon,-framework,QuickTime,-framework,QuartzCore
+
+
+# headers we need but don't want installed
+noinst_HEADERS =               \
+       codecmapping.h          \
+       qtwrapper.h             \
+       qtutils.h               \
+       imagedescription.h
diff --git a/sys/qtwrapper/audiodecoders.c b/sys/qtwrapper/audiodecoders.c
new file mode 100644 (file)
index 0000000..2efd5ae
--- /dev/null
@@ -0,0 +1,799 @@
+/*
+ * GStreamer QuickTime audio decoder codecs wrapper
+ * Copyright <2006, 2007> Fluendo <gstreamer@fluendo.com>
+ * Copyright <2006, 2007> Pioneers of the Inevitable <songbird@songbirdnest.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <QuickTime/Movies.h>
+#include <AudioToolbox/AudioToolbox.h>
+
+#include <gst/base/gstadapter.h>
+#include "qtwrapper.h"
+#include "codecmapping.h"
+#include "qtutils.h"
+
+#define QTWRAPPER_ADEC_PARAMS_QDATA g_quark_from_static_string("qtwrapper-adec-params")
+
+static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw-float, "
+        "endianness = (int) {" G_STRINGIFY (G_BYTE_ORDER) " }, "
+        "signed = (boolean) { TRUE }, "
+        "width = (int) 32, "
+        "depth = (int) 32, " "rate = (int) 44100, " "channels = (int) 2")
+    );
+
+typedef struct _QTWrapperAudioDecoder QTWrapperAudioDecoder;
+typedef struct _QTWrapperAudioDecoderClass QTWrapperAudioDecoderClass;
+
+struct _QTWrapperAudioDecoder
+{
+  GstElement parent;
+
+  GstPad *sinkpad;
+  GstPad *srcpad;
+
+  /* FIXME : all following should be protected by a mutex */
+  AudioConverterRef aconv;
+  AudioStreamBasicDescription indesc, outdesc;
+
+  guint samplerate;
+  guint channels;
+  AudioBufferList *bufferlist;
+
+  /* first time received after NEWSEGMENT */
+  GstClockTime initial_time;
+  /* offset in samples from the initial time */
+  guint64 cur_offset;
+  /* TRUE just after receiving a NEWSEGMENT */
+  gboolean gotnewsegment;
+
+  /* temporary output data */
+  gpointer tmpdata;
+
+  /* buffer previously used by the decoder */
+  gpointer prevdata;
+
+  GstAdapter *adapter;
+};
+
+struct _QTWrapperAudioDecoderClass
+{
+  GstElementClass parent_class;
+
+  /* fourcc of the format */
+  guint32 componentSubType;
+
+  GstPadTemplate *sinktempl;
+};
+
+typedef struct _QTWrapperAudioDecoderParams QTWrapperAudioDecoderParams;
+
+struct _QTWrapperAudioDecoderParams
+{
+  Component component;
+  GstCaps *sinkcaps;
+};
+
+static gboolean qtwrapper_audio_decoder_sink_setcaps (GstPad * pad,
+    GstCaps * caps);
+static GstFlowReturn qtwrapper_audio_decoder_chain (GstPad * pad,
+    GstBuffer * buf);
+static gboolean qtwrapper_audio_decoder_sink_event (GstPad * pad,
+    GstEvent * event);
+
+static void
+qtwrapper_audio_decoder_base_init (QTWrapperAudioDecoderClass * klass)
+{
+  GstElementDetails details;
+  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+  gchar *name = NULL;
+  gchar *info = NULL;
+  ComponentDescription desc;
+  QTWrapperAudioDecoderParams *params;
+
+  params = (QTWrapperAudioDecoderParams *)
+      g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass),
+      QTWRAPPER_ADEC_PARAMS_QDATA);
+  g_assert (params);
+
+  get_name_info_from_component (params->component, &desc, &name, &info);
+
+  /* Fill in details */
+  details.longname = g_strdup_printf ("QTWrapper Audio Decoder : %s", name);
+  details.klass = "Codec/Decoder/Audio";
+  details.description = info;
+  details.author = "Fluendo <gstreamer@fluendo.com>, "
+      "Pioneers of the Inevitable <songbird@songbirdnest.com>";
+  gst_element_class_set_details (element_class, &details);
+
+  g_free (details.longname);
+  g_free (name);
+  g_free (info);
+
+  /* Add pad templates */
+  klass->sinktempl = gst_pad_template_new ("sink", GST_PAD_SINK,
+      GST_PAD_ALWAYS, params->sinkcaps);
+  gst_element_class_add_pad_template (element_class, klass->sinktempl);
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&src_templ));
+
+  /* Store class-global values */
+  klass->componentSubType = desc.componentSubType;
+}
+
+static void
+qtwrapper_audio_decoder_class_init (QTWrapperAudioDecoderClass * klass)
+{
+  /* FIXME : don't we need some vmethod implementations here ?? */
+}
+
+static void
+qtwrapper_audio_decoder_init (QTWrapperAudioDecoder * qtwrapper)
+{
+  QTWrapperAudioDecoderClass *oclass;
+
+  oclass = (QTWrapperAudioDecoderClass *) (G_OBJECT_GET_CLASS (qtwrapper));
+
+  /* Sink pad */
+  qtwrapper->sinkpad = gst_pad_new_from_template (oclass->sinktempl, "sink");
+  gst_pad_set_setcaps_function (qtwrapper->sinkpad,
+      GST_DEBUG_FUNCPTR (qtwrapper_audio_decoder_sink_setcaps));
+  gst_pad_set_chain_function (qtwrapper->sinkpad,
+      GST_DEBUG_FUNCPTR (qtwrapper_audio_decoder_chain));
+  gst_pad_set_event_function (qtwrapper->sinkpad,
+      GST_DEBUG_FUNCPTR (qtwrapper_audio_decoder_sink_event));
+  gst_element_add_pad (GST_ELEMENT (qtwrapper), qtwrapper->sinkpad);
+
+  /* Source pad */
+  qtwrapper->srcpad = gst_pad_new_from_static_template (&src_templ, "src");
+  gst_element_add_pad (GST_ELEMENT (qtwrapper), qtwrapper->srcpad);
+
+  qtwrapper->adapter = gst_adapter_new ();
+}
+
+static void
+clear_AudioStreamBasicDescription (AudioStreamBasicDescription * desc)
+{
+  desc->mSampleRate = 0;
+  desc->mFormatID = 0;
+  desc->mFormatFlags = 0;
+  desc->mBytesPerPacket = 0;
+  desc->mFramesPerPacket = 0;
+  desc->mBytesPerFrame = 0;
+  desc->mChannelsPerFrame = 0;
+  desc->mBitsPerChannel = 0;
+
+}
+
+static void
+fill_indesc_mp3 (QTWrapperAudioDecoder * qtwrapper, guint32 fourcc, gint rate,
+    gint channels)
+{
+  GST_LOG ("...");
+  clear_AudioStreamBasicDescription (&qtwrapper->indesc);
+  /* only the samplerate is needed apparently */
+  qtwrapper->indesc.mSampleRate = rate;
+  qtwrapper->indesc.mFormatID = kAudioFormatMPEGLayer3;
+  qtwrapper->indesc.mChannelsPerFrame = channels;
+}
+
+static void
+fill_indesc_aac (QTWrapperAudioDecoder * qtwrapper, guint32 fourcc, gint rate,
+    gint channels)
+{
+  clear_AudioStreamBasicDescription (&qtwrapper->indesc);
+  qtwrapper->indesc.mSampleRate = rate;
+  qtwrapper->indesc.mFormatID = kAudioFormatMPEG4AAC;
+  /* aac always has 1024 bytes per packet */
+  qtwrapper->indesc.mBytesPerPacket = 1024;
+  qtwrapper->indesc.mChannelsPerFrame = channels;
+}
+
+static void
+fill_indesc_samr (QTWrapperAudioDecoder * qtwrapper, guint32 fourcc,
+    gint channels)
+{
+  clear_AudioStreamBasicDescription (&qtwrapper->indesc);
+  qtwrapper->indesc.mSampleRate = 8000;
+  qtwrapper->indesc.mFormatID = fourcc;
+  qtwrapper->indesc.mChannelsPerFrame = 1;
+  qtwrapper->indesc.mFramesPerPacket = 160;
+}
+
+static void
+fill_indesc_generic (QTWrapperAudioDecoder * qtwrapper, guint32 fourcc,
+    gint rate, gint channels)
+{
+  clear_AudioStreamBasicDescription (&qtwrapper->indesc);
+  qtwrapper->indesc.mSampleRate = rate;
+  qtwrapper->indesc.mFormatID = fourcc;
+  qtwrapper->indesc.mChannelsPerFrame = channels;
+}
+
+static gpointer
+make_samr_magic_cookie (GstBuffer * codec_data, gsize * len)
+{
+  gpointer res;
+
+  *len = 48;
+  res = g_malloc0 (0x30);
+
+  /* 12 first bytes are 'frma' (format) atom with 'samr' value */
+  GST_WRITE_UINT32_BE (res, 0xc);
+  GST_WRITE_UINT32_LE (res + 4, QT_MAKE_FOURCC_BE ('f', 'r', 'm', 'a'));
+  GST_WRITE_UINT32_LE (res + 8, QT_MAKE_FOURCC_BE ('s', 'a', 'm', 'r'));
+
+  /* 10 bytes for 'enda' atom with 0 */
+  GST_WRITE_UINT32_BE (res + 12, 10);
+  GST_WRITE_UINT32_LE (res + 16, QT_MAKE_FOURCC_BE ('e', 'n', 'd', 'a'));
+
+  /* 17(+1) bytes for the codec_data contents */
+  GST_WRITE_UINT32_BE (res + 22, 18);
+  memcpy (res + 26, GST_BUFFER_DATA (codec_data) + 4, 17);
+
+  /* yes... we need to replace 'damr' by 'samr'. Blame Apple ! */
+  GST_WRITE_UINT8 (res + 26, 's');
+
+  /* padding 8 bytes */
+  GST_WRITE_UINT32_BE (res + 40, 8);
+
+#if DEBUG_DUMP
+  gst_util_dump_mem (res, 48);
+#endif
+
+  return res;
+}
+
+static gboolean
+open_decoder (QTWrapperAudioDecoder * qtwrapper, GstCaps * caps,
+    GstCaps ** othercaps)
+{
+  gboolean ret = FALSE;
+  QTWrapperAudioDecoderClass *oclass;
+  gint channels = 2;
+  gint rate = 44100;
+  gint depth = 32;
+  OSErr oserr;
+  OSStatus status;
+  GstStructure *s;
+  gchar *tmp;
+  const GValue *value;
+  GstBuffer *codec_data = NULL;
+
+  tmp = gst_caps_to_string (caps);
+  GST_LOG_OBJECT (qtwrapper, "caps: %s", tmp);
+  g_free (tmp);
+
+  /* extract rate/channels information from the caps */
+  s = gst_caps_get_structure (caps, 0);
+  gst_structure_get_int (s, "rate", &rate);
+  gst_structure_get_int (s, "channels", &channels);
+
+  /* depth isn't compulsory */
+  if (!(gst_structure_get_int (s, "depth", &depth)))
+    gst_structure_get_int (s, "samplesize", &depth);
+
+  /* get codec_data */
+  if ((value = gst_structure_get_value (s, "codec_data"))) {
+    codec_data = GST_BUFFER_CAST (gst_value_get_mini_object (value));
+  }
+
+  /* If the quicktime demuxer gives us a full esds atom, use that instead of the codec_data */
+  if ((value = gst_structure_get_value (s, "quicktime_esds"))) {
+    codec_data = GST_BUFFER_CAST (gst_value_get_mini_object (value));
+  }
+#if DEBUG_DUMP
+  if (codec_data)
+    gst_util_dump_mem (GST_BUFFER_DATA (codec_data),
+        GST_BUFFER_SIZE (codec_data));
+#endif
+
+
+  GST_LOG ("rate:%d, channels:%d, depth:%d", rate, channels, depth);
+
+  oclass = (QTWrapperAudioDecoderClass *) (G_OBJECT_GET_CLASS (qtwrapper));
+
+  /* Setup the input format description, some format require special handling */
+  switch (oclass->componentSubType) {
+    case QT_MAKE_FOURCC_LE ('.', 'm', 'p', '3'):
+      fill_indesc_mp3 (qtwrapper, oclass->componentSubType, rate, channels);
+      break;
+    case QT_MAKE_FOURCC_LE ('m', 'p', '4', 'a'):
+      fill_indesc_aac (qtwrapper, oclass->componentSubType, rate, channels);
+      break;
+    case QT_MAKE_FOURCC_LE ('s', 'a', 'm', 'r'):
+      fill_indesc_samr (qtwrapper, oclass->componentSubType, channels);
+      rate = 8000;
+      break;
+    default:
+      fill_indesc_generic (qtwrapper, oclass->componentSubType, rate, channels);
+      break;
+  }
+
+#if DEBUG_DUMP
+  gst_util_dump_mem (&qtwrapper->indesc, sizeof (AudioStreamBasicDescription));
+#endif
+
+  /* we're forcing output to stereo 44.1kHz */
+  rate = 44100;
+  channels = 2;
+
+  qtwrapper->samplerate = rate;
+  qtwrapper->channels = channels;
+
+  /* Setup the output format description */
+  qtwrapper->outdesc.mSampleRate = rate;
+  qtwrapper->outdesc.mFormatID = kAudioFormatLinearPCM;
+  qtwrapper->outdesc.mFormatFlags = kAudioFormatFlagIsFloat;
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+  qtwrapper->outdesc.mFormatFlags |= kAudioFormatFlagIsBigEndian;
+#endif
+  qtwrapper->outdesc.mBytesPerPacket = channels * 4;    /* ?? */
+  qtwrapper->outdesc.mFramesPerPacket = 1;
+  qtwrapper->outdesc.mBytesPerFrame = channels * 4;     /* channels * bytes-per-samples */
+  qtwrapper->outdesc.mChannelsPerFrame = channels;
+  qtwrapper->outdesc.mBitsPerChannel = 32;
+
+  /* Create an AudioConverter */
+  status = AudioConverterNew (&qtwrapper->indesc,
+      &qtwrapper->outdesc, &qtwrapper->aconv);
+  if (status != noErr) {
+    GST_WARNING_OBJECT (qtwrapper,
+        "Error when calling AudioConverterNew() : %" GST_FOURCC_FORMAT,
+        QT_FOURCC_ARGS (status));
+    goto beach;
+  }
+
+  /* if we have codec_data, give it to the converter ! */
+  if (codec_data) {
+    gsize len;
+    gpointer magiccookie;
+
+    if (oclass->componentSubType == QT_MAKE_FOURCC_LE ('s', 'a', 'm', 'r')) {
+      magiccookie = make_samr_magic_cookie (codec_data, &len);
+    } else {
+      len = GST_BUFFER_SIZE (codec_data);
+      magiccookie = GST_BUFFER_DATA (codec_data);
+    }
+    GST_LOG_OBJECT (qtwrapper, "Setting magic cookie %p of size %"
+        G_GSIZE_FORMAT, magiccookie, len);
+    oserr = AudioConverterSetProperty (qtwrapper->aconv,
+        kAudioConverterDecompressionMagicCookie, len, magiccookie);
+    if (oserr != noErr) {
+      GST_WARNING_OBJECT (qtwrapper, "Error setting extra codec data !");
+      goto beach;
+    }
+  }
+
+  /* Create output bufferlist */
+  qtwrapper->bufferlist = AllocateAudioBufferList (channels,
+      rate * channels * 4 / 20);
+
+  /* Create output caps */
+  *othercaps = gst_caps_new_simple ("audio/x-raw-float",
+      "endianness", G_TYPE_INT, G_BYTE_ORDER,
+      "signed", G_TYPE_BOOLEAN, TRUE,
+      "width", G_TYPE_INT, 32,
+      "depth", G_TYPE_INT, 32,
+      "rate", G_TYPE_INT, rate, "channels", G_TYPE_INT, channels, NULL);
+
+  ret = TRUE;
+
+beach:
+  return ret;
+}
+
+static gboolean
+qtwrapper_audio_decoder_sink_setcaps (GstPad * pad, GstCaps * caps)
+{
+  QTWrapperAudioDecoder *qtwrapper;
+  gboolean ret = FALSE;
+  GstCaps *othercaps = NULL;
+
+  qtwrapper = (QTWrapperAudioDecoder *) gst_pad_get_parent (pad);
+
+  GST_LOG_OBJECT (qtwrapper, "caps:%" GST_PTR_FORMAT, caps);
+
+  /* 1. open decoder */
+  if (!(open_decoder (qtwrapper, caps, &othercaps)))
+    goto beach;
+
+  /* 2. set caps downstream */
+  ret = gst_pad_set_caps (qtwrapper->srcpad, othercaps);
+
+beach:
+  if (othercaps)
+    gst_caps_unref (othercaps);
+  gst_object_unref (qtwrapper);
+  return ret;
+}
+
+static OSStatus
+process_buffer_cb (AudioConverterRef inAudioConverter,
+    UInt32 * ioNumberDataPackets,
+    AudioBufferList * ioData,
+    AudioStreamPacketDescription ** outDataPacketDescription,
+    QTWrapperAudioDecoder * qtwrapper)
+{
+  gint len;
+  AudioStreamPacketDescription aspd[200];
+
+  GST_LOG_OBJECT (qtwrapper,
+      "ioNumberDataPackets:%lu, iodata:%p, outDataPacketDescription:%p",
+      *ioNumberDataPackets, ioData, outDataPacketDescription);
+  if (outDataPacketDescription)
+    GST_LOG ("*outDataPacketDescription:%p", *outDataPacketDescription);
+
+  GST_LOG ("mNumberBuffers : %u", (guint32) ioData->mNumberBuffers);
+  GST_LOG ("mData:%p , mDataByteSize:%u",
+      ioData->mBuffers[0].mData, (guint32) ioData->mBuffers[0].mDataByteSize);
+
+  ioData->mBuffers[0].mData = NULL;
+  ioData->mBuffers[0].mDataByteSize = 0;
+  if (qtwrapper->prevdata)
+    g_free (qtwrapper->prevdata);
+
+  len = gst_adapter_available (qtwrapper->adapter);
+
+  if (len) {
+    ioData->mBuffers[0].mData = gst_adapter_take (qtwrapper->adapter, len);
+    qtwrapper->prevdata = ioData->mBuffers[0].mData;
+
+    /* if we have a valid outDataPacketDescription, we need to fill it */
+    if (outDataPacketDescription) {
+      /* mStartOffset : the number of bytes from the start of the buffer to the
+       * beginning of the packet. */
+      aspd[0].mStartOffset = 0;
+      aspd[1].mStartOffset = 0;
+      /* mVariableFramesInPacket : the number of samples frames of data in the
+       * packet. For formats with a constant number of frames per packet, this
+       * field is set to 0. */
+      aspd[0].mVariableFramesInPacket = 0;
+      aspd[1].mVariableFramesInPacket = 0;
+      /* mDataByteSize : The number of bytes in the packet. */
+      aspd[0].mDataByteSize = len;
+      aspd[1].mDataByteSize = 0;
+      GST_LOG ("ASPD: mStartOffset:%lld, mVariableFramesInPacket:%u, "
+          "mDataByteSize:%u", aspd[0].mStartOffset,
+          (guint32) aspd[0].mVariableFramesInPacket,
+          (guint32) aspd[0].mDataByteSize);
+      *outDataPacketDescription = (AudioStreamPacketDescription *) & aspd;
+    }
+
+  } else {
+    qtwrapper->prevdata = NULL;
+  }
+
+  ioData->mBuffers[0].mDataByteSize = len;
+
+  GST_LOG_OBJECT (qtwrapper, "returning %d bytes at %p",
+      len, ioData->mBuffers[0].mData);
+
+  if (!len)
+    return 42;
+  return noErr;
+}
+
+static GstFlowReturn
+qtwrapper_audio_decoder_chain (GstPad * pad, GstBuffer * buf)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  QTWrapperAudioDecoder *qtwrapper;
+
+  qtwrapper = (QTWrapperAudioDecoder *) gst_pad_get_parent (pad);
+
+  GST_LOG_OBJECT (qtwrapper,
+      "buffer:%p , timestamp:%" GST_TIME_FORMAT " ,size:%d", buf,
+      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), GST_BUFFER_SIZE (buf));
+
+#if DEBUG_DUMP
+  gst_util_dump_mem (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
+#endif
+
+  if (qtwrapper->gotnewsegment) {
+
+    GST_DEBUG_OBJECT (qtwrapper, "AudioConverterReset()");
+
+    AudioConverterReset (qtwrapper->aconv);
+
+    /* some formats can give us a better initial time using the buffer
+     * timestamp. */
+    if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buf)))
+      qtwrapper->initial_time = GST_BUFFER_TIMESTAMP (buf);
+
+    qtwrapper->gotnewsegment = FALSE;
+  }
+
+  /* stack in adapter */
+  gst_adapter_push (qtwrapper->adapter, buf);
+
+  /* do we have enough to decode at least one frame ? */
+  while (gst_adapter_available (qtwrapper->adapter)) {
+    GstBuffer *outbuf;
+    OSStatus status;
+    guint32 outsamples = qtwrapper->bufferlist->mBuffers[0].mDataByteSize / 8;
+    guint32 savedbytes = qtwrapper->bufferlist->mBuffers[0].mDataByteSize;
+    guint32 realbytes;
+
+
+    GST_LOG_OBJECT (qtwrapper, "Calling FillBuffer(outsamples:%d , outdata:%p)",
+        outsamples, qtwrapper->bufferlist->mBuffers[0].mData);
+
+    /* Ask AudioConverter to give us data ! */
+    status = AudioConverterFillComplexBuffer (qtwrapper->aconv,
+        (AudioConverterComplexInputDataProc) process_buffer_cb,
+        qtwrapper, (UInt32 *) & outsamples, qtwrapper->bufferlist, NULL);
+
+    if ((status != noErr) && (status != 42)) {
+      if (status < 0)
+        GST_WARNING_OBJECT (qtwrapper,
+            "Error in AudioConverterFillComplexBuffer() : %d", (gint32) status);
+      else
+        GST_WARNING_OBJECT (qtwrapper,
+            "Error in AudioConverterFillComplexBuffer() : %" GST_FOURCC_FORMAT,
+            QT_FOURCC_ARGS (status));
+      ret = GST_FLOW_ERROR;
+      goto beach;
+    }
+
+    realbytes = qtwrapper->bufferlist->mBuffers[0].mDataByteSize;
+
+    GST_LOG_OBJECT (qtwrapper, "We now have %d samples [%d bytes]",
+        outsamples, realbytes);
+
+    qtwrapper->bufferlist->mBuffers[0].mDataByteSize = savedbytes;
+
+    if (!outsamples)
+      break;
+
+    /* 4. Create buffer and copy data in it */
+    ret = gst_pad_alloc_buffer (qtwrapper->srcpad, qtwrapper->cur_offset,
+        realbytes, GST_PAD_CAPS (qtwrapper->srcpad), &outbuf);
+    if (ret != GST_FLOW_OK)
+      goto beach;
+
+    /* copy data from bufferlist to output buffer */
+    g_memmove (GST_BUFFER_DATA (outbuf),
+        qtwrapper->bufferlist->mBuffers[0].mData, realbytes);
+
+    /* 5. calculate timestamp and duration */
+    GST_BUFFER_TIMESTAMP (outbuf) =
+        qtwrapper->initial_time + gst_util_uint64_scale_int (GST_SECOND,
+        qtwrapper->cur_offset, qtwrapper->samplerate);
+    GST_BUFFER_SIZE (outbuf) = realbytes;
+    GST_BUFFER_DURATION (outbuf) =
+        gst_util_uint64_scale_int (GST_SECOND,
+        realbytes / (qtwrapper->channels * 4), qtwrapper->samplerate);
+
+    GST_LOG_OBJECT (qtwrapper,
+        "timestamp:%" GST_TIME_FORMAT ", duration:%" GST_TIME_FORMAT
+        "offset:%lld, offset_end:%lld",
+        GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
+        GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
+        GST_BUFFER_OFFSET (outbuf), GST_BUFFER_OFFSET_END (outbuf));
+
+    qtwrapper->cur_offset += outsamples;
+
+    /* 6. push buffer downstream */
+
+    ret = gst_pad_push (qtwrapper->srcpad, outbuf);
+    if (ret != GST_FLOW_OK)
+      goto beach;
+  }
+
+beach:
+  gst_object_unref (qtwrapper);
+  return ret;
+}
+
+static gboolean
+qtwrapper_audio_decoder_sink_event (GstPad * pad, GstEvent * event)
+{
+  QTWrapperAudioDecoder *qtwrapper;
+  gboolean ret = FALSE;
+
+  qtwrapper = (QTWrapperAudioDecoder *) gst_pad_get_parent (pad);
+
+  GST_LOG_OBJECT (qtwrapper, "event:%s", GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_NEWSEGMENT:{
+      gint64 start, stop, position;
+      gboolean update;
+      gdouble rate;
+      GstFormat format;
+
+      GST_LOG ("We've got a newsegment");
+      gst_event_parse_new_segment (event, &update, &rate, &format, &start,
+          &stop, &position);
+
+      /* if the format isn't time, we need to create a new time newsegment */
+      /* FIXME : This is really bad, we should convert the values properly to time */
+      if (format != GST_FORMAT_TIME) {
+        GstEvent *newevent;
+
+        GST_WARNING_OBJECT (qtwrapper,
+            "Original event wasn't in GST_FORMAT_TIME, creating new fake one.");
+
+        start = 0;
+
+        newevent =
+            gst_event_new_new_segment (update, rate, GST_FORMAT_TIME, start,
+            GST_CLOCK_TIME_NONE, start);
+        gst_event_unref (event);
+        event = newevent;
+      }
+
+      qtwrapper->initial_time = start;
+      qtwrapper->cur_offset = 0;
+
+      gst_adapter_clear (qtwrapper->adapter);
+
+      GST_LOG ("initial_time is now %" GST_TIME_FORMAT, GST_TIME_ARGS (start));
+
+      if (qtwrapper->aconv)
+        qtwrapper->gotnewsegment = TRUE;
+
+      /* FIXME : reset adapter */
+      break;
+    }
+    default:
+      break;
+  }
+
+  ret = gst_pad_push_event (qtwrapper->srcpad, event);
+
+  gst_object_unref (qtwrapper);
+  return TRUE;
+}
+
+gboolean
+qtwrapper_audio_decoders_register (GstPlugin * plugin)
+{
+  gboolean res = TRUE;
+  OSErr result;
+  Component componentID = NULL;
+  ComponentDescription desc = {
+    'sdec', 0, 0, 0, 0
+  };
+  GTypeInfo typeinfo = {
+    sizeof (QTWrapperAudioDecoderClass),
+    (GBaseInitFunc) qtwrapper_audio_decoder_base_init,
+    NULL,
+    (GClassInitFunc) qtwrapper_audio_decoder_class_init,
+    NULL,
+    NULL,
+    sizeof (QTWrapperAudioDecoder),
+    0,
+    (GInstanceInitFunc) qtwrapper_audio_decoder_init,
+  };
+
+  /* Initialize quicktime environment */
+  result = EnterMovies ();
+  if (result != noErr) {
+    GST_ERROR ("Error initializing QuickTime environment");
+    res = FALSE;
+    goto beach;
+  }
+
+  /* Find all ImageDecoders ! */
+  GST_DEBUG ("There are %ld decompressors available", CountComponents (&desc));
+
+  /* loop over ImageDecoders */
+  do {
+    componentID = FindNextComponent (componentID, &desc);
+
+    GST_LOG ("componentID : %p", componentID);
+
+    if (componentID) {
+      ComponentDescription thisdesc;
+      gchar *name = NULL, *info = NULL;
+      GstCaps *caps = NULL;
+      gchar *type_name = NULL;
+      GType type;
+      QTWrapperAudioDecoderParams *params = NULL;
+
+      if (!(get_name_info_from_component (componentID, &thisdesc, &name,
+                  &info)))
+        goto next;
+
+      GST_LOG (" name:%s", name);
+      GST_LOG (" info:%s", info);
+
+      GST_LOG (" type:%" GST_FOURCC_FORMAT,
+          QT_FOURCC_ARGS (thisdesc.componentType));
+      GST_LOG (" subtype:%" GST_FOURCC_FORMAT,
+          QT_FOURCC_ARGS (thisdesc.componentSubType));
+      GST_LOG (" manufacturer:%" GST_FOURCC_FORMAT,
+          QT_FOURCC_ARGS (thisdesc.componentManufacturer));
+
+      if (!(caps =
+              fourcc_to_caps (QT_READ_UINT32 (&thisdesc.componentSubType))))
+        goto next;
+
+      type_name = g_strdup_printf ("qtwrapperaudiodec_%" GST_FOURCC_FORMAT,
+          QT_FOURCC_ARGS (thisdesc.componentSubType));
+      g_strdelimit (type_name, " .", '_');
+
+      if (g_type_from_name (type_name)) {
+        GST_WARNING ("We already have a registered plugin for %s", type_name);
+        goto next;
+      }
+
+      params = g_new0 (QTWrapperAudioDecoderParams, 1);
+      params->component = componentID;
+      params->sinkcaps = gst_caps_ref (caps);
+
+      type = g_type_register_static (GST_TYPE_ELEMENT, type_name, &typeinfo, 0);
+      /* Store params in type qdata */
+      g_type_set_qdata (type, QTWRAPPER_ADEC_PARAMS_QDATA, (gpointer) params);
+
+      /* register type */
+      if (!gst_element_register (plugin, type_name, GST_RANK_MARGINAL, type)) {
+        g_warning ("Failed to register %s", type_name);;
+        g_type_set_qdata (type, QTWRAPPER_ADEC_PARAMS_QDATA, NULL);
+        g_free (params);
+        res = FALSE;
+        goto next;
+      }
+
+    next:
+      if (name)
+        g_free (name);
+      if (info)
+        g_free (info);
+      if (type_name)
+        g_free (type_name);
+      if (caps)
+        gst_caps_unref (caps);
+    }
+
+  } while (componentID && res);
+
+beach:
+  return res;
+}
diff --git a/sys/qtwrapper/codecmapping.c b/sys/qtwrapper/codecmapping.c
new file mode 100644 (file)
index 0000000..6aec5f3
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * GStreamer QuickTime codec mapping
+ * Copyright <2006, 2007> Fluendo <gstreamer@fluendo.com>
+ * Copyright <2006, 2007> Pioneers of the Inevitable <songbird@songbirdnest.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "qtwrapper.h"
+#include "codecmapping.h"
+#include "qtutils.h"
+
+static GstCaps *
+audio_caps_from_string (gchar * str)
+{
+  GstCaps *res;
+
+  res = gst_caps_from_string (str);
+  gst_caps_set_simple (res,
+      "rate", GST_TYPE_INT_RANGE, 8000, 96000,
+      "channels", GST_TYPE_INT_RANGE, 1, 2, NULL);
+
+  return res;
+}
+
+GstCaps *
+fourcc_to_caps (guint32 fourcc)
+{
+  GstCaps *caps = NULL;
+
+  GST_DEBUG ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
+
+  switch (fourcc) {
+      /* VIDEO */
+    case QT_MAKE_FOURCC_LE ('S', 'V', 'Q', '1'):
+      caps = gst_caps_new_simple ("video/x-svq",
+          "svqversion", G_TYPE_INT, 1, NULL);
+      break;
+    case QT_MAKE_FOURCC_LE ('S', 'V', 'Q', '3'):
+      caps = gst_caps_new_simple ("video/x-svq",
+          "svqversion", G_TYPE_INT, 3, NULL);
+      break;
+    case QT_MAKE_FOURCC_LE ('a', 'v', 'c', '1'):
+      caps = gst_caps_from_string ("video/x-h264");
+      break;
+    case QT_MAKE_FOURCC_LE ('m', 'p', '4', 'v'):
+      caps =
+          gst_caps_from_string
+          ("video/mpeg,mpegversion=4,systemstream=(boolean)false");
+      break;
+    case QT_MAKE_FOURCC_LE ('m', 'p', 'e', 'g'):
+      caps = gst_caps_from_string ("video/mpeg, "
+          "systemstream = (boolean) false, " "mpegversion = (int) 1");
+      break;
+    case QT_MAKE_FOURCC_LE ('h', '2', '6', '3'):
+    case QT_MAKE_FOURCC_LE ('H', '2', '6', '3'):
+    case QT_MAKE_FOURCC_LE ('s', '2', '6', '3'):
+    case QT_MAKE_FOURCC_LE ('U', '2', '6', '3'):
+      caps = gst_caps_from_string ("video/x-h263");
+      break;
+    case QT_MAKE_FOURCC_LE ('c', 'v', 'i', 'd'):
+      caps = gst_caps_from_string ("video/x-cinepak");
+      break;
+    case QT_MAKE_FOURCC_LE ('d', 'v', 'c', 'p'):
+    case QT_MAKE_FOURCC_LE ('d', 'v', 'c', ' '):
+    case QT_MAKE_FOURCC_LE ('d', 'v', 's', 'd'):
+    case QT_MAKE_FOURCC_LE ('D', 'V', 'S', 'D'):
+    case QT_MAKE_FOURCC_LE ('d', 'v', 'c', 's'):
+    case QT_MAKE_FOURCC_LE ('D', 'V', 'C', 'S'):
+    case QT_MAKE_FOURCC_LE ('d', 'v', '2', '5'):
+    case QT_MAKE_FOURCC_LE ('d', 'v', 'p', 'p'):
+      caps = gst_caps_from_string ("video/x-dv, systemstream=(boolean)false");
+      break;
+
+      /* AUDIO */
+    case QT_MAKE_FOURCC_LE ('.', 'm', 'p', '3'):
+      caps =
+          audio_caps_from_string
+          ("audio/mpeg,mpegversion=1,layer=3,parsed=(boolean)true");
+      break;
+    case QT_MAKE_FOURCC_LE ('Q', 'D', 'M', '2'):
+      caps = audio_caps_from_string ("audio/x-qdm2");
+      break;
+    case QT_MAKE_FOURCC_LE ('a', 'g', 's', 'm'):
+      caps = audio_caps_from_string ("audio/x-gsm");
+      break;
+    case QT_MAKE_FOURCC_LE ('a', 'l', 'a', 'c'):
+      caps = audio_caps_from_string ("audio/x-alac");
+      break;
+    case QT_MAKE_FOURCC_LE ('a', 'l', 'a', 'w'):
+      caps = audio_caps_from_string ("audio/x-alaw");
+      break;
+    case QT_MAKE_FOURCC_LE ('m', 'p', '4', 'a'):
+    case QT_MAKE_FOURCC_LE ('a', 'a', 'c', ' '):
+      caps = audio_caps_from_string ("audio/mpeg,mpegversion=4");
+      break;
+    case QT_MAKE_FOURCC_LE ('s', 'a', 'm', 'r'):
+      caps = audio_caps_from_string ("audio/AMR");
+      break;
+    case QT_MAKE_FOURCC_LE ('u', 'l', 'a', 'w'):
+      caps = audio_caps_from_string ("audio/x-mulaw");
+      break;
+      /* TO FILL !! */
+    case QT_MAKE_FOURCC_LE ('M', 'A', 'C', '3'):
+    case QT_MAKE_FOURCC_LE ('M', 'A', 'C', '6'):
+    case QT_MAKE_FOURCC_LE ('Q', 'D', 'M', 'C'):
+    case QT_MAKE_FOURCC_LE ('Q', 'c', 'l', 'p'):
+    case QT_MAKE_FOURCC_LE ('Q', 'c', 'l', 'q'):
+    case QT_MAKE_FOURCC_LE ('d', 'v', 'c', 'a'):
+    default:
+      break;
+  }
+
+  return caps;
+}
diff --git a/sys/qtwrapper/codecmapping.h b/sys/qtwrapper/codecmapping.h
new file mode 100644 (file)
index 0000000..78600b6
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * GStreamer QuickTime codec mapping
+ * Copyright <2006, 2007> Fluendo <gstreamer@fluendo.com>
+ * Copyright <2006, 2007> Pioneers of the Inevitable <songbird@songbirdnest.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <QuickTime/Movies.h>
+#include <QuickTime/ImageCodec.h>
+#include <gst/gst.h>
+
+/*
+ * fourcc_to_caps:
+ *
+ * Return the caps for a given fourcc.
+ */
+
+GstCaps *fourcc_to_caps (guint32 fourcc);
diff --git a/sys/qtwrapper/imagedescription.c b/sys/qtwrapper/imagedescription.c
new file mode 100644 (file)
index 0000000..7cdf399
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * GStreamer QuickTime video decoder codecs wrapper
+ * Copyright <2006, 2007> Fluendo <gstreamer@fluendo.com>
+ * Copyright <2006, 2007> Pioneers of the Inevitable <songbird@songbirdnest.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "imagedescription.h"
+
+static ImageDescription *
+image_description_for_avc1 (GstBuffer * buf)
+{
+  ImageDescription *desc = NULL;
+  gpointer pos;
+
+  desc = g_malloc0 (sizeof (ImageDescription) + GST_BUFFER_SIZE (buf) + 8);
+  pos = (gpointer) ((gulong) desc + (gulong) sizeof (ImageDescription));
+
+  desc->idSize = sizeof (ImageDescription) + GST_BUFFER_SIZE (buf) + 8;
+  /* write size in Big-Endian */
+  GST_WRITE_UINT32_BE (pos, GST_BUFFER_SIZE (buf) + 8);
+  GST_WRITE_UINT32_LE (pos + 4, QT_MAKE_FOURCC_BE ('a', 'v', 'c', 'C'));
+  g_memmove (pos + 8, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
+
+  return desc;
+}
+
+/* image_description_for_mp4v
+ *
+ * mpeg4 video has an 'esds' atom as extension for the ImageDescription.
+ * It is meant to contain the ES Description.
+ * We here create a fake one.
+ */
+
+static ImageDescription *
+image_description_for_mp4v (GstBuffer * buf)
+{
+  ImageDescription *desc = NULL;
+  guint32 offset = sizeof (ImageDescription);
+  gpointer location;
+
+  GST_LOG ("buf %p , size:%d", buf, GST_BUFFER_SIZE (buf));
+
+  /* this image description contains:
+   *  ImageDescription  sizeof(ImageDescription)
+   *  esds atom         34 bytes
+   *  buffer            GST_BUFFER_SIZE (buf)
+   *  ending            3 bytes
+   */
+
+  desc = g_malloc0 (offset + 37 + GST_BUFFER_SIZE (buf));
+  desc->idSize = offset + 37 + GST_BUFFER_SIZE (buf);
+
+  location = (gpointer) ((gulong) desc + (gulong) offset);
+
+  /* Fill in ESDS */
+  /*  size */
+  GST_WRITE_UINT32_BE (location, 37 + GST_BUFFER_SIZE (buf));
+  /*  atom */
+  GST_WRITE_UINT32_LE (location + 4, GST_MAKE_FOURCC ('e', 's', 'd', 's'));
+  /*  version + flags */
+  QT_WRITE_UINT32 (location + 8, 0);
+  /*  tag */
+  QT_WRITE_UINT8 (location + 12, 0x3);
+  /*  size (buffsize + 23) */
+  QT_WRITE_UINT8 (location + 13, GST_BUFFER_SIZE (buf) + 23);
+  /*  ESID */
+  QT_WRITE_UINT16 (location + 14, 0);
+  /*  priority */
+  QT_WRITE_UINT8 (location + 16, 0);
+  /*  tag */
+  QT_WRITE_UINT8 (location + 17, 0x4);
+  /*  size (buffsize + 8) */
+  QT_WRITE_UINT8 (location + 18, GST_BUFFER_SIZE (buf) + 15);
+  /*  object type */
+  QT_WRITE_UINT8 (location + 19, 0x20);
+  /*  stream type */
+  QT_WRITE_UINT8 (location + 20, 0x11);
+  /*  buffersize db */
+  QT_WRITE_UINT24 (location + 21, 13640);
+  /*  max bitrate */
+  QT_WRITE_UINT32 (location + 24, 1849648);
+  /*  avg bitrate */
+  QT_WRITE_UINT32 (location + 28, 918191);
+  /*  tag */
+  QT_WRITE_UINT8 (location + 32, 0x05);
+  /*  size */
+  QT_WRITE_UINT8 (location + 33, GST_BUFFER_SIZE (buf));
+  /*  codec data */
+  g_memmove (location + 34, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
+  /*  end */
+  QT_WRITE_UINT8 (location + 34 + GST_BUFFER_SIZE (buf), 0x06);
+  QT_WRITE_UINT8 (location + 34 + GST_BUFFER_SIZE (buf) + 1, 0x01);
+  QT_WRITE_UINT8 (location + 34 + GST_BUFFER_SIZE (buf) + 2, 0x02);
+
+  return desc;
+}
+
+static ImageDescription *
+image_description_from_stsd_buffer (GstBuffer * buf)
+{
+  ImageDescription *desc = NULL;
+  gpointer content;
+  guint size, imds;
+
+  GST_LOG ("buffer %p, size:%u", buf, GST_BUFFER_SIZE (buf));
+
+  /* The buffer contains a full atom, we only need the contents */
+  /* This buffer has data in big-endian, we need to read it as such.
+   * except for the fourcc which are ALWAYS big-endian. */
+  content = GST_BUFFER_DATA (buf) + 16;
+  size = GST_BUFFER_SIZE (buf) - 16;
+
+#if DEBUG_DUMP
+  GST_LOG ("incoming data in big-endian");
+  gst_util_dump_mem (content, size);
+#endif
+
+  desc = g_malloc0 (size);
+  desc->idSize = size;
+  desc->cType = GST_READ_UINT32_BE (content + 4);
+  desc->version = QT_UINT16 (content + 16);
+  desc->revisionLevel = QT_UINT16 (content + 18);
+  desc->vendor = GST_READ_UINT32_BE (content + 20);
+  desc->temporalQuality = QT_UINT32 (content + 24);
+  desc->spatialQuality = QT_UINT32 (content + 24);
+  desc->dataSize = QT_UINT32 (content + 44);
+  desc->frameCount = QT_UINT16 (content + 48);
+  desc->depth = QT_UINT16 (content + 82);
+  desc->clutID = QT_UINT16 (content + 84);
+
+  imds = 86;                    /* sizeof (ImageDescription); */
+
+  if (desc->idSize > imds) {
+    GST_LOG ("Copying %d bytes from %p to %p",
+        size - imds, content + imds, desc + imds);
+    memcpy ((gpointer) ((gulong) desc + imds),
+        (gpointer) ((gulong) content + imds), size - imds);
+  }
+#if DEBUG_DUMP
+  GST_LOG ("outgoing data in machine-endian");
+  dump_image_description (desc);
+#endif
+
+  return desc;
+}
+
+ImageDescription *
+image_description_from_codec_data (GstBuffer * buf, guint32 codectype)
+{
+  ImageDescription *desc = NULL;
+
+  GST_LOG ("codectype:%" GST_FOURCC_FORMAT " buf:%p",
+      GST_FOURCC_ARGS (codectype), buf);
+
+  if ((GST_BUFFER_SIZE (buf) == GST_READ_UINT32_BE (GST_BUFFER_DATA (buf))) &&
+      (QT_MAKE_FOURCC_LE ('s', 't', 's',
+              'd') == GST_READ_UINT32_BE (GST_BUFFER_DATA (buf) + 4))) {
+    /* We have the full stsd (ImageDescription) in our codec_data */
+    desc = image_description_from_stsd_buffer (buf);
+  } else {
+    switch (codectype) {
+      case QT_MAKE_FOURCC_LE ('m', 'p', '4', 'v'):
+        desc = image_description_for_mp4v (buf);
+        break;
+      case QT_MAKE_FOURCC_LE ('a', 'v', 'c', '1'):
+        desc = image_description_for_avc1 (buf);
+        break;
+      default:
+        GST_WARNING ("Format not handled !");
+    }
+  }
+  return desc;
+}
diff --git a/sys/qtwrapper/imagedescription.h b/sys/qtwrapper/imagedescription.h
new file mode 100644 (file)
index 0000000..fe5ed9a
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * GStreamer QuickTime video decoder codecs wrapper
+ * Copyright <2006, 2007> Fluendo <gstreamer@fluendo.com>
+ * Copyright <2006, 2007> Pioneers of the Inevitable <songbird@songbirdnest.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <QuickTime/Movies.h>
+#include "qtwrapper.h"
+#include "qtutils.h"
+
+ImageDescription *image_description_from_codec_data (GstBuffer * buf,
+    guint32 codec);
diff --git a/sys/qtwrapper/qtutils.c b/sys/qtwrapper/qtutils.c
new file mode 100644 (file)
index 0000000..441a87d
--- /dev/null
@@ -0,0 +1,477 @@
+/*
+ * GStreamer QuickTime codec mapping
+ * Copyright <2006, 2007> Fluendo <gstreamer@fluendo.com>
+ * Copyright <2006, 2007> Pioneers of the Inevitable <songbird@songbirdnest.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "qtutils.h"
+
+gboolean
+get_name_info_from_component (Component componentID,
+    ComponentDescription * desc, gchar ** name, gchar ** info)
+{
+  gchar *tmp1 = NULL;
+  gchar *tmp2 = NULL;
+  gchar *tmpname;
+  gchar *tmpinfo;
+  OSErr result;
+
+  result = GetComponentInfo (componentID, desc, &tmp1, &tmp2, NULL);
+  if (result != noErr)
+    return FALSE;
+
+#if DEBUG_DUMP
+  GST_LOG ("ComponentDescription dump");
+  gst_util_dump_mem ((const guchar *) desc, sizeof (ComponentDescription));
+#endif
+
+  if (tmp1 && name) {
+    gsize read, written;
+
+    tmpname = g_strndup (tmp1 + 1, (guint8) * tmp1);
+    *name = g_convert_with_fallback (tmpname, -1, "ASCII", "MAC",
+        " ", &read, &written, NULL);
+    if (!*name)
+      GST_WARNING ("read:%" G_GSIZE_FORMAT ", written:%" G_GSIZE_FORMAT, read,
+          written);
+    g_free (tmpname);
+  }
+
+  if (tmp2 && info) {
+    tmpinfo = g_strndup (tmp2 + 1, (guint8) * tmp2);
+    *info = g_convert_with_fallback (tmpinfo, -1, "ASCII", "MAC",
+        " ", NULL, NULL, NULL);
+    g_free (tmpinfo);
+  }
+
+  return TRUE;
+}
+
+/*
+struct CodecDecompressParams {
+   ImageSequence              sequenceID;
+   ImageDescriptionHandle     imageDescription;
+   Ptr                        data;
+   long                       bufferSize;
+   long                       frameNumber;
+   long                       startLine;
+   long                       stopLine;
+   long                       conditionFlags;
+   CodecFlags                 callerFlags;
+   CodecCapabilities *        capabilities;
+   ICMProgressProcRecord      progressProcRecord;
+   ICMCompletionProcRecord    completionProcRecord;
+   ICMDataProcRecord          dataProcRecord;
+   CGrafPtr                   port;
+   PixMap                     dstPixMap;
+   BitMapPtr                  maskBits;
+   PixMapPtr                  mattePixMap;
+   Rect                       srcRect;
+   MatrixRecord *             matrix;
+   CodecQ                     accuracy;
+   short                      transferMode;
+   ICMFrameTimePtr            frameTime;
+   long                       reserved[1];
+   SInt8                      matrixFlags;
+   SInt8                      matrixType;
+   Rect                       dstRect;
+   UInt16                     majorSourceChangeSeed;
+   UInt16                     minorSourceChangeSeed;
+   CDSequenceDataSourcePtr    sourceData;
+   RgnHandle                  maskRegion;
+   OSType **                  wantedDestinationPixelTypes;
+   long                       screenFloodMethod;
+   long                       screenFloodValue;
+   short                      preferredOffscreenPixelSize;
+   ICMFrameTimeInfoPtr        syncFrameTime;
+   Boolean                    needUpdateOnTimeChange;
+   Boolean                    enableBlackLining;
+   Boolean                    needUpdateOnSourceChange;
+   Boolean                    pad;
+   long                       unused;
+   CGrafPtr                   finalDestinationPort;
+   long                       requestedBufferWidth;
+   long                       requestedBufferHeight;
+   Rect                       displayableAreaOfRequestedBuffer;
+   Boolean                    requestedSingleField;
+   Boolean                    needUpdateOnNextIdle;
+   Boolean                    pad2[2];
+   fixed                      bufferGammaLevel;
+   UInt32                     taskWeight;
+   OSType                     taskName;
+};
+ */
+
+/* struct ImageDescription {  */
+/*     long idSize;            /\* total size of this structure *\/  */
+/*  4  CodecType cType;        /\* compressor creator type *\/  */
+/*  8  long resvd1;            /\* reserved--must be set to 0 *\/  */
+/* 12  short resvd2;           /\* reserved--must be set to 0 *\/  */
+/* 14  short dataRefIndex;     /\* reserved--must be set to 0 *\/  */
+/* 16  short version;          /\* version of compressed data *\/  */
+/* 18  short revisionLevel;    /\* compressor that created data *\/  */
+/* 20  long vendor;            /\* compressor developer that created data *\/  */
+/* 24  CodecQ temporalQuality;       */
+/*                             /\* degree of temporal compression *\/  */
+/* 28  CodecQ spatialQuality;        */
+/*                             /\* degree of spatial compression *\/  */
+/* 32  short width;            /\* width of source image in pixels *\/  */
+/* 34  short height;           /\* height of source image in pixels *\/  */
+/* 36  Fixed hRes;             /\* horizontal resolution of source image *\/  */
+/* 40  Fixed vRes;             /\* vertical resolution of source image *\/  */
+/* 44  long dataSize;          /\* size in bytes of compressed data *\/  */
+/* 48  short frameCount;       /\* number of frames in image data *\/  */
+/* 50  Str31 name;             /\* name of compression algorithm *\/  */
+/* 82  short depth;            /\* pixel depth of source image *\/  */
+/* 84  short clutID;           /\* ID number of the color table for image *\/  */
+/* }; */
+
+
+gboolean
+get_output_info_from_component (Component componentID)
+{
+  gboolean ret = FALSE;
+  ComponentInstance instance;
+  ImageSubCodecDecompressCapabilities caps;
+  CodecInfo info;
+
+  GST_LOG ("Creating an instance");
+
+  /* 1. Create an instance */
+  if (!(instance = OpenComponent (componentID))) {
+    GST_WARNING ("Couldn't open component");
+    return FALSE;
+  }
+
+  /* 2. initialize */
+  memset (&caps, 0, sizeof (ImageSubCodecDecompressCapabilities));
+  if (ImageCodecInitialize (instance, &caps) != noErr) {
+    GST_WARNING ("ImageCodecInitialize() failed");
+    goto beach;
+  }
+#if DEBUG_DUMP
+  GST_LOG ("ImageSubCodecDecompressCapabilities");
+  gst_util_dump_mem ((const guchar *) &caps,
+      sizeof (ImageSubCodecDecompressCapabilities));
+#endif
+
+  GST_LOG ("recordSize:%ld", caps.recordSize);
+  GST_LOG ("decompressRecordSize:%ld", caps.decompressRecordSize);
+  GST_LOG ("canAsync:%d", caps.canAsync);
+
+  /* 3. Get codec info */
+  memset (&info, 0, sizeof (CodecInfo));
+  if (ImageCodecGetCodecInfo (instance, &info) != noErr) {
+    GST_WARNING ("ImageCodecInfo() failed");
+    goto beach;
+  };
+
+#if DEBUG_DUMP
+  GST_LOG ("CodecInfo");
+  gst_util_dump_mem ((const guchar *) &info, sizeof (CodecInfo));
+#endif
+
+  GST_LOG ("version:%d", info.version);
+  GST_LOG ("revisionLevel:%d", info.revisionLevel);
+  GST_LOG ("vendor:%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (info.vendor));
+
+  /* Compression flags */
+  /* Contains flags (see below) that specify the decompression capabilities of
+   * the component. Typically, these flags are of interest only to developers of
+   * image decompressors. */
+  GST_LOG ("decompressFlags:%lx", info.decompressFlags);
+  if (info.decompressFlags & codecInfoDoes1)
+    GST_LOG ("Depth 1 OK");
+  if (info.decompressFlags & codecInfoDoes2)
+    GST_LOG ("Depth 2 OK");
+  if (info.decompressFlags & codecInfoDoes4)
+    GST_LOG ("Depth 4 OK");
+  if (info.decompressFlags & codecInfoDoes8)
+    GST_LOG ("Depth 8 OK");
+  if (info.decompressFlags & codecInfoDoes16)
+    GST_LOG ("Depth 16 OK");
+  if (info.decompressFlags & codecInfoDoes32)
+    GST_LOG ("Depth 32 OK");
+  GST_LOG ("compressFlags:%lx", info.compressFlags);
+
+  /* Format FLAGS */
+  /* Contains flags (see below) that describe the possible format for compressed
+   * data produced by this component and the format of compressed files that the
+   * component can handle during decompression. Typically, these flags are of
+   * interest only to developers of compressor components.
+   */
+  GST_LOG ("formatFlags:%lx", info.formatFlags);
+  if (info.formatFlags & codecInfoDepth1)
+    GST_LOG ("Depth 1 OK");
+  if (info.formatFlags & codecInfoDepth2)
+    GST_LOG ("Depth 2 OK");
+  if (info.formatFlags & codecInfoDepth4)
+    GST_LOG ("Depth 4 OK");
+  if (info.formatFlags & codecInfoDepth8)
+    GST_LOG ("Depth 8 OK");
+  if (info.formatFlags & codecInfoDepth16)
+    GST_LOG ("Depth 16 OK");
+  if (info.formatFlags & codecInfoDepth24)
+    GST_LOG ("Depth 24 OK");
+  if (info.formatFlags & codecInfoDepth32)
+    GST_LOG ("Depth 32 OK");
+  if (info.formatFlags & codecInfoDepth33)
+    GST_LOG ("Depth 33 OK");
+  if (info.formatFlags & codecInfoDepth34)
+    GST_LOG ("Depth 34 OK");
+  if (info.formatFlags & codecInfoDepth36)
+    GST_LOG ("Depth 36 OK");
+  if (info.formatFlags & codecInfoDepth40)
+    GST_LOG ("Depth 40 OK");
+  if (info.formatFlags & codecInfoStoresClut)
+    GST_LOG ("StoresClut OK");
+  if (info.formatFlags & codecInfoDoesLossless)
+    GST_LOG ("Lossless OK");
+  if (info.formatFlags & codecInfoSequenceSensitive)
+    GST_LOG ("SequenceSentitive OK");
+
+
+  GST_LOG ("compressionAccuracy:%u", info.compressionAccuracy);
+  GST_LOG ("decompressionAccuracy:%u", info.decompressionAccuracy);
+  GST_LOG ("compressionSpeed:%d", info.compressionSpeed);
+  GST_LOG ("decompressionSpeed:%d", info.decompressionSpeed);
+  GST_LOG ("compressionLevel:%u", info.compressionLevel);
+  GST_LOG ("minimumHeight:%d", info.minimumHeight);
+  GST_LOG ("minimumWidth:%d", info.minimumWidth);
+
+/*   /\* . Call ImageCodecPreDecompress *\/ */
+/*   memset(&params, 0, sizeof(CodecDecompressParams)); */
+/*   GST_LOG ("calling imagecodecpredecompress"); */
+/*   if (ImageCodecPreDecompress (instance, &params) != noErr) { */
+/*     GST_WARNING ("Error in ImageCodecPreDecompress"); */
+/*     goto beach; */
+/*   } */
+
+/*   GST_INFO ("sequenceID : %d", params.sequenceID); */
+
+  ret = TRUE;
+
+beach:
+  /* Free instance */
+  CloseComponent (instance);
+  return TRUE;
+}
+
+void
+dump_avcc_atom (gpointer atom)
+{
+  /* first 8 bytes : length + atom */
+  GST_LOG ("version:0x%x", QT_UINT8 (atom + 8));
+  GST_LOG ("Profile:%d", QT_UINT8 (atom + 9));
+  GST_LOG ("Compatible profiles : 0x%x", QT_UINT8 (atom + 10));
+  GST_LOG ("Level:%d", QT_UINT8 (atom + 11));
+}
+
+void
+dump_image_description (ImageDescription * desc)
+{
+  GST_LOG ("Description %p , size:%" G_GSIZE_FORMAT, desc, desc->idSize);
+
+#if DEBUG_DUMP
+  gst_util_dump_mem ((const guchar *) desc, desc->idSize);
+#endif
+
+  GST_LOG ("cType : %" GST_FOURCC_FORMAT, QT_FOURCC_ARGS (desc->cType));
+  GST_LOG ("version:%d", desc->version);
+  GST_LOG ("revisionLevel:%d", desc->revisionLevel);
+  GST_LOG ("vendor:%" GST_FOURCC_FORMAT, QT_FOURCC_ARGS (desc->vendor));
+  GST_LOG ("temporalQuality:%lu", desc->temporalQuality);
+  GST_LOG ("spatialQuality:%lu", desc->spatialQuality);
+  GST_LOG ("width:%u", desc->width);
+  GST_LOG ("height:%u", desc->height);
+  GST_LOG ("hres:%f", desc->hRes / 65536.0);
+  GST_LOG ("vres:%f", desc->vRes / 65536.0);
+  GST_LOG ("dataSize:%" G_GSIZE_FORMAT, desc->dataSize);
+  GST_LOG ("frameCount:%d", desc->frameCount);
+  GST_LOG ("name:%.*s", desc->name[0], desc->name + 1);
+  GST_LOG ("depth:%d", desc->depth);
+  GST_LOG ("clutID:%d", desc->clutID);
+
+  if (desc->idSize > sizeof (ImageDescription)) {
+    gpointer extradata =
+        (gpointer) (gulong) desc + (gulong) sizeof (ImageDescription);
+    guint32 type = QT_READ_UINT32 (extradata + 4);
+
+    GST_LOG ("Extra Data size:%lu",
+        (gulong) desc->idSize - (gulong) sizeof (ImageDescription));
+#if DEBUG_DUMP
+    gst_util_dump_mem ((gulong) desc + (gulong) sizeof (ImageDescription),
+        (gulong) desc->idSize - (gulong) sizeof (ImageDescription));
+#endif
+    GST_LOG ("Extra Data Type : %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (type));
+    if (type == QT_MAKE_FOURCC ('a', 'v', 'c', 'C'))
+      dump_avcc_atom (extradata);
+  }
+}
+
+void
+dump_codec_decompress_params (CodecDecompressParams * params)
+{
+  GST_LOG ("params %p", params);
+
+#if DEBUG_DUMP
+  gst_util_dump_mem ((const guchar *) params, sizeof (CodecDecompressParams));
+#endif
+
+  GST_LOG ("SequenceID:%ld", params->sequenceID);
+  GST_LOG ("imageDescription:%p", params->imageDescription);
+  GST_LOG ("data:%p", params->data);
+  GST_LOG ("bufferSize:%ld", params->bufferSize);
+  GST_LOG ("frameNumber:%ld", params->frameNumber);
+  GST_LOG ("startLine:%ld  , StopLine:%ld", params->startLine,
+      params->stopLine);
+  GST_LOG ("conditionFlags:0x%lx", params->conditionFlags);
+  GST_LOG ("callerFlags:0x%x", params->callerFlags);
+  GST_LOG ("capabilities:%p", params->capabilities);
+  GST_LOG ("port:%p", params->port);
+  GST_LOG ("dstPixMap");
+  gst_util_dump_mem ((const guchar *) &params->dstPixMap, sizeof (PixMap));
+
+  GST_LOG ("maskBits:%p", params->maskBits);
+  GST_LOG ("mattePixMap:%p", params->mattePixMap);
+  GST_LOG ("srcRect %d/%d/%d/%d",
+      params->srcRect.top, params->srcRect.bottom,
+      params->srcRect.left, params->srcRect.right);
+
+  GST_LOG ("matrix:%p", params->matrix);
+  GST_LOG ("accuracy:%ld", params->accuracy);
+  GST_LOG ("transferMode:%d", params->transferMode);
+  GST_LOG ("frameTime:%p", params->frameTime);
+  GST_LOG ("matrixFlags:%x", params->matrixFlags);
+
+  GST_LOG ("dstRect %d/%d/%d/%d",
+      params->dstRect.top, params->dstRect.bottom,
+      params->dstRect.left, params->dstRect.right);
+
+  GST_LOG ("sourceData:%p", params->sourceData);
+
+  if (params->wantedDestinationPixelTypes) {
+    OSType *tmp;
+
+    for (tmp = *params->wantedDestinationPixelTypes; *tmp; tmp++)
+      GST_LOG ("Destination pixel %" GST_FOURCC_FORMAT, QT_FOURCC_ARGS (*tmp));
+  }
+}
+
+void
+addSInt32ToDictionary (CFMutableDictionaryRef dictionary, CFStringRef key,
+    SInt32 numberSInt32)
+{
+  CFNumberRef number =
+      CFNumberCreate (NULL, kCFNumberSInt32Type, &numberSInt32);
+  if (!number)
+    return;
+  CFDictionaryAddValue (dictionary, key, number);
+  CFRelease (number);
+}
+
+void
+dump_cvpixel_buffer (CVPixelBufferRef pixbuf)
+{
+  gsize left, right, top, bottom;
+
+  GST_LOG ("buffer %p", pixbuf);
+  if (CVPixelBufferLockBaseAddress (pixbuf, 0)) {
+    GST_WARNING ("Couldn't lock base adress on pixel buffer !");
+    return;
+  }
+  GST_LOG ("Width:%" G_GSIZE_FORMAT " , Height:%" G_GSIZE_FORMAT,
+      CVPixelBufferGetWidth (pixbuf), CVPixelBufferGetHeight (pixbuf));
+  GST_LOG ("Format:%" GST_FOURCC_FORMAT,
+      GST_FOURCC_ARGS (CVPixelBufferGetPixelFormatType (pixbuf)));
+  GST_LOG ("base address:%p", CVPixelBufferGetBaseAddress (pixbuf));
+  GST_LOG ("Bytes per row:%" G_GSIZE_FORMAT,
+      CVPixelBufferGetBytesPerRow (pixbuf));
+  GST_LOG ("Data Size:%" G_GSIZE_FORMAT, CVPixelBufferGetDataSize (pixbuf));
+  GST_LOG ("Plane count:%" G_GSIZE_FORMAT, CVPixelBufferGetPlaneCount (pixbuf));
+  CVPixelBufferGetExtendedPixels (pixbuf, &left, &right, &top, &bottom);
+  GST_LOG ("Extended pixels. left/right/top/bottom : %" G_GSIZE_FORMAT
+      "/%" G_GSIZE_FORMAT "/%" G_GSIZE_FORMAT "/%" G_GSIZE_FORMAT,
+      left, right, top, bottom);
+  CVPixelBufferUnlockBaseAddress (pixbuf, 0);
+}
+
+
+// Convenience function to dispose of our audio buffers
+void
+DestroyAudioBufferList (AudioBufferList * list)
+{
+  UInt32 i;
+
+  if (list) {
+    for (i = 0; i < list->mNumberBuffers; i++) {
+      if (list->mBuffers[i].mData)
+        free (list->mBuffers[i].mData);
+    }
+    free (list);
+  }
+}
+
+// Convenience function to allocate our audio buffers
+AudioBufferList *
+AllocateAudioBufferList (UInt32 numChannels, UInt32 size)
+{
+  AudioBufferList *list;
+  UInt32 i;
+
+  list =
+      (AudioBufferList *) calloc (1,
+      sizeof (AudioBufferList) + sizeof (AudioBuffer));
+  if (list == NULL)
+    return NULL;
+
+  list->mNumberBuffers = 1;
+  for (i = 0; i < 1; ++i) {
+    list->mBuffers[i].mNumberChannels = numChannels;
+    list->mBuffers[i].mDataByteSize = size;
+    list->mBuffers[i].mData = malloc (size);
+    if (list->mBuffers[i].mData == NULL) {
+      DestroyAudioBufferList (list);
+      return NULL;
+    }
+  }
+  return list;
+}
diff --git a/sys/qtwrapper/qtutils.h b/sys/qtwrapper/qtutils.h
new file mode 100644 (file)
index 0000000..cb550c8
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * GStreamer QuickTime codec mapping
+ * Copyright <2006, 2007> Fluendo <gstreamer@fluendo.com>
+ * Copyright <2006, 2007> Pioneers of the Inevitable <songbird@songbirdnest.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <QuickTime/Movies.h>
+#include <QuickTime/ImageCodec.h>
+#include <gst/gst.h>
+#include "qtwrapper.h"
+
+#ifndef __QTUTILS_H__
+#define __QTUTILS_H__
+
+#define QT_UINT32(a)  (GST_READ_UINT32_BE(a))
+#define QT_UINT24(a)  (GST_READ_UINT32_BE(a) >> 8)
+#define QT_UINT16(a)  (GST_READ_UINT16_BE(a))
+#define QT_UINT8(a)   (GST_READ_UINT8(a))
+#define QT_FP32(a)    ((GST_READ_UINT32_BE(a))/65536.0)
+#define QT_FP16(a)    ((GST_READ_UINT16_BE(a))/256.0)
+#define QT_FOURCC(a)  (GST_READ_UINT32_LE(a))
+#define QT_UINT64(a)  ((((guint64)QT_UINT32(a))<<32)|QT_UINT32(((guint8 *)a)+4))
+#define QT_FOURCC_ARGS(fourcc)                 \
+  ((gchar) (((fourcc)>>24)&0xff)),             \
+    ((gchar) (((fourcc)>>16)&0xff)),           \
+    ((gchar) (((fourcc)>>8 )&0xff)),           \
+    ((gchar) ((fourcc)     &0xff))
+
+#define QT_WRITE_UINT8(data, num)      GST_WRITE_UINT8(data, num)
+
+#define QT_MAKE_FOURCC_BE(a,b,c,d)      (guint32)((a)|(b)<<8|(c)<<16|(d)<<24)
+#define QT_MAKE_FOURCC_LE(a,b,c,d)     QT_MAKE_FOURCC_BE(d,c,b,a)
+
+#define _QT_PUT(__data, __idx, __size, __shift, __num) \
+    (((guint8 *) (__data))[__idx] = (((guint##__size) __num) >> __shift) & 0xff)
+
+/* endianness-dependent macros */
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#define QT_MAKE_FOURCC(a,b,c,d)                QT_MAKE_FOURCC_LE(a,b,c,d)
+#define QT_WRITE_UINT16(data, num)     GST_WRITE_UINT16_LE(data, num)
+#define QT_WRITE_UINT24(data, num)     do {                            \
+                                         _QT_PUT (data, 0, 32,  0, num); \
+                                         _QT_PUT (data, 1, 32,  8, num); \
+                                         _QT_PUT (data, 2, 32, 16, num); \
+                                       } while (0)
+#define QT_WRITE_UINT32(data, num)     GST_WRITE_UINT32_LE(data, num)
+#define QT_READ_UINT16(data)           GST_READ_UINT16_LE(data)
+#define QT_READ_UINT32(data)           GST_READ_UINT32_LE(data)
+#else
+#define QT_MAKE_FOURCC(a,b,c,d)         QT_MAKE_FOURCC_BE(a,b,c,d)
+#define QT_WRITE_UINT16(data, num)     GST_WRITE_UINT16_BE(data, num)
+#define QT_WRITE_UINT24(data, num)     do {                            \
+                                         _QT_PUT (data, 0, 32, 16, num); \
+                                         _QT_PUT (data, 1, 32,  8, num); \
+                                         _QT_PUT (data, 2, 32,  0, num); \
+                                       } while (0)
+#define QT_WRITE_UINT32(data, num)     GST_WRITE_UINT32_BE(data, num)
+#define QT_READ_UINT16(data)           GST_READ_UINT16_BE(data)
+#define QT_READ_UINT32(data)           GST_READ_UINT32_BE(data)
+#endif
+
+
+/*
+ * get_name_info_from_component:
+ *
+ * Fills name and info with the name and description from a Component
+ */
+
+gboolean
+get_name_info_from_component (Component component, ComponentDescription * desc,
+    gchar ** name, gchar ** info);
+
+
+
+gboolean get_output_info_from_component (Component component);
+
+
+
+void dump_image_description (ImageDescription * desc);
+void dump_codec_decompress_params (CodecDecompressParams * params);
+
+guint32 destination_pixel_types_to_fourcc (OSType ** types);
+void
+addSInt32ToDictionary (CFMutableDictionaryRef dictionary, CFStringRef key,
+    SInt32 numberSInt32);
+
+void dump_cvpixel_buffer (CVPixelBufferRef pixbuf);
+
+AudioBufferList *AllocateAudioBufferList(UInt32 numChannels, UInt32 size);
+
+void DestroyAudioBufferList(AudioBufferList* list);
+
+#endif /* __QTUTILS_H__ */
diff --git a/sys/qtwrapper/qtwrapper.c b/sys/qtwrapper/qtwrapper.c
new file mode 100644 (file)
index 0000000..ca4793e
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * GStreamer QuickTime codecs wrapper
+ * Copyright <2006, 2007> Fluendo <gstreamer@fluendo.com>
+ * Copyright <2006, 2007> Pioneers of the Inevitable <songbird@songbirdnest.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "qtwrapper.h"
+
+GST_DEBUG_CATEGORY (qtwrapper_debug);
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  gboolean res;
+
+  GST_DEBUG_CATEGORY_INIT (qtwrapper_debug, "qtwrapper",
+      0, "QuickTime codecs wrappers");
+
+  res = qtwrapper_video_decoders_register (plugin);
+  res &= qtwrapper_audio_decoders_register (plugin);
+
+  return res;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    "qtwrapper",
+    "QuickTime codecs wrapper",
+    plugin_init, VERSION, "LGPL", "GStreamer", "http://gstreamer.net/")
diff --git a/sys/qtwrapper/qtwrapper.h b/sys/qtwrapper/qtwrapper.h
new file mode 100644 (file)
index 0000000..bba744b
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * GStreamer QuickTime codecs wrapper
+ * Copyright <2006, 2007> Fluendo <gstreamer@fluendo.com>
+ * Copyright <2006, 2007> Pioneers of the Inevitable <songbird@songbirdnest.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_QTWRAPPER_H__
+#define __GST_QTWRAPPER_H__
+
+#include <gst/gst.h>
+
+/* Set following to 1 if you want to have extra debug in form of
+ * memory dumps */
+#define DEBUG_DUMP 0
+
+GST_DEBUG_CATEGORY_EXTERN (qtwrapper_debug);
+#define GST_CAT_DEFAULT qtwrapper_debug
+
+G_BEGIN_DECLS
+
+extern gboolean qtwrapper_video_decoders_register (GstPlugin *);
+extern gboolean qtwrapper_audio_decoders_register (GstPlugin *);
+
+G_END_DECLS
+#endif /* __GST_QTWRAPPER_H__ */
diff --git a/sys/qtwrapper/videodecoders.c b/sys/qtwrapper/videodecoders.c
new file mode 100644 (file)
index 0000000..d0b5445
--- /dev/null
@@ -0,0 +1,874 @@
+/*
+ * GStreamer QuickTime video decoder codecs wrapper
+ * Copyright <2006, 2007> Fluendo <gstreamer@fluendo.com>
+ * Copyright <2006, 2007> Pioneers of the Inevitable <songbird@songbirdnest.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <QuickTime/Movies.h>
+
+#include "qtwrapper.h"
+#include "codecmapping.h"
+#include "qtutils.h"
+#include "imagedescription.h"
+
+#define QTWRAPPER_VDEC_PARAMS_QDATA g_quark_from_static_string("qtwrapper-vdec-params")
+
+static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-raw-yuv"));
+
+typedef struct _QTWrapperVideoDecoder QTWrapperVideoDecoder;
+typedef struct _QTWrapperVideoDecoderClass QTWrapperVideoDecoderClass;
+
+#define MAC_LOCK(qtwrapper) g_mutex_lock (qtwrapper->lock)
+#define MAC_UNLOCK(qtwrapper) g_mutex_unlock (qtwrapper->lock)
+
+struct _QTWrapperVideoDecoder
+{
+  GstElement parent;
+
+  GstPad *sinkpad;
+  GstPad *srcpad;
+
+  GMutex *lock;
+  ComponentInstance instance;
+  CodecInfo codecinfo;
+  ImageDescriptionHandle idesc;
+  CodecDecompressParams *dparams;
+  CodecCapabilities codeccaps;
+  guint64 frameNumber;
+  ICMDecompressionSessionRef decsession;
+  GstFlowReturn lastret;
+  guint64 outsize;
+  guint width, height;
+  GstClockTime last_ts;
+  GstClockTime last_duration;
+  GstBuffer *prevbuf;
+  gboolean flushing;
+  gboolean framebuffering;
+
+  /* width/height of output buffer */
+  Rect rect;
+};
+
+struct _QTWrapperVideoDecoderClass
+{
+  GstElementClass parent_class;
+
+  Component component;
+  guint32 componentType;
+  guint32 componentSubType;
+
+  GstPadTemplate *sinktempl;
+};
+
+typedef struct _QTWrapperVideoDecoderParams QTWrapperVideoDecoderParams;
+
+struct _QTWrapperVideoDecoderParams
+{
+  Component component;
+  GstCaps *sinkcaps;
+};
+
+static GstElementClass *parent_class = NULL;
+
+static gboolean
+qtwrapper_video_decoder_sink_setcaps (GstPad * pad, GstCaps * caps);
+static GstFlowReturn qtwrapper_video_decoder_chain (GstPad * pad,
+    GstBuffer * buf);
+static gboolean qtwrapper_video_decoder_sink_event (GstPad * pad,
+    GstEvent * event);
+
+static void qtwrapper_video_decoder_finalize (GObject * object);
+static void decompressCb (void *decompressionTrackingRefCon,
+    OSStatus result,
+    ICMDecompressionTrackingFlags decompressionTrackingFlags,
+    CVPixelBufferRef pixelBuffer,
+    TimeValue64 displayTime,
+    TimeValue64 displayDuration,
+    ICMValidTimeFlags validTimeFlags, void *reserved, void *sourceFrameRefCon);
+
+/*
+ * Class setup
+ */
+
+static void
+qtwrapper_video_decoder_base_init (QTWrapperVideoDecoderClass * klass)
+{
+  GstElementDetails details;
+  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+  gchar *name = NULL;
+  gchar *info = NULL;
+  ComponentDescription desc;
+  QTWrapperVideoDecoderParams *params;
+
+  params = (QTWrapperVideoDecoderParams *)
+      g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass),
+      QTWRAPPER_VDEC_PARAMS_QDATA);
+  g_assert (params);
+
+  get_name_info_from_component (params->component, &desc, &name, &info);
+
+  /* Fill in details */
+  details.longname = g_strdup_printf ("QTWrapper Video Decoder : %s", name);
+  details.klass = "Codec/Decoder/Video";
+  details.description = info;
+  details.author = "Fluendo <gstreamer@fluendo.com>, "
+      "Pioneers of the Inevitable <songbird@songbirdnest.com>";
+  gst_element_class_set_details (element_class, &details);
+
+  g_free (details.longname);
+  g_free (name);
+  g_free (info);
+
+  klass->sinktempl = gst_pad_template_new ("sink", GST_PAD_SINK,
+      GST_PAD_ALWAYS, params->sinkcaps);
+
+  gst_element_class_add_pad_template (element_class, klass->sinktempl);
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&src_templ));
+
+  /* Store class-global values */
+  klass->component = params->component;
+  klass->componentType = desc.componentType;
+  klass->componentSubType = desc.componentSubType;
+}
+
+static void
+qtwrapper_video_decoder_class_init (QTWrapperVideoDecoderClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->finalize =
+      GST_DEBUG_FUNCPTR (qtwrapper_video_decoder_finalize);
+}
+
+static void
+qtwrapper_video_decoder_init (QTWrapperVideoDecoder * qtwrapper)
+{
+  QTWrapperVideoDecoderClass *oclass;
+  ImageSubCodecDecompressCapabilities capabs;
+
+  GST_LOG ("...");
+  oclass = (QTWrapperVideoDecoderClass *) (G_OBJECT_GET_CLASS (qtwrapper));
+
+  /* 1. Create a ocmponent instance */
+  if (!(qtwrapper->instance = OpenComponent (oclass->component))) {
+    GST_ERROR_OBJECT (qtwrapper, "Couldn't create a component instance !");
+    return;
+  }
+
+  /* 2. Initialize decoder */
+  memset (&capabs, 0, sizeof (ImageSubCodecDecompressCapabilities));
+  if (ImageCodecInitialize (qtwrapper->instance, &capabs) != noErr) {
+    GST_ERROR_OBJECT (qtwrapper, "Couldn't initialize the QT component !");
+    return;
+  }
+
+  /* 3. Get codec info */
+  memset (&qtwrapper->codecinfo, 0, sizeof (CodecInfo));
+  if (ImageCodecGetCodecInfo (qtwrapper->instance,
+          &qtwrapper->codecinfo) != noErr) {
+    GST_ERROR_OBJECT (qtwrapper, "Couldn't get Codec Information !");
+    return;
+  }
+
+  /* sink pad */
+  qtwrapper->sinkpad = gst_pad_new_from_template (oclass->sinktempl, "sink");
+  gst_pad_set_setcaps_function (qtwrapper->sinkpad,
+      GST_DEBUG_FUNCPTR (qtwrapper_video_decoder_sink_setcaps));
+  gst_pad_set_chain_function (qtwrapper->sinkpad,
+      GST_DEBUG_FUNCPTR (qtwrapper_video_decoder_chain));
+  gst_pad_set_event_function (qtwrapper->sinkpad,
+      GST_DEBUG_FUNCPTR (qtwrapper_video_decoder_sink_event));
+  gst_element_add_pad (GST_ELEMENT (qtwrapper), qtwrapper->sinkpad);
+
+  /* src pad */
+  qtwrapper->srcpad = gst_pad_new_from_static_template (&src_templ, "src");
+  gst_element_add_pad (GST_ELEMENT (qtwrapper), qtwrapper->srcpad);
+
+  qtwrapper->lock = g_mutex_new ();
+}
+
+static void
+qtwrapper_video_decoder_finalize (GObject * object)
+{
+  QTWrapperVideoDecoder *qtwrapper;
+
+  qtwrapper = (QTWrapperVideoDecoder *) object;
+
+  if (qtwrapper->lock)
+    g_mutex_free (qtwrapper->lock);
+
+  if (G_OBJECT_CLASS (parent_class)->finalize)
+    G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+/* fill_image_description
+ * Fills an ImageDescription with codec-specific values
+ *
+ * Doesn't fill in the idSize, width and height.
+ */
+
+static void
+fill_image_description (QTWrapperVideoDecoder * qtwrapper,
+    ImageDescription * desc)
+{
+  QTWrapperVideoDecoderClass *oclass;
+
+  oclass = (QTWrapperVideoDecoderClass *) (G_OBJECT_GET_CLASS (qtwrapper));
+
+  desc->cType = oclass->componentSubType;
+  desc->version = qtwrapper->codecinfo.version;
+  desc->revisionLevel = qtwrapper->codecinfo.revisionLevel;
+  desc->vendor = qtwrapper->codecinfo.vendor;
+  desc->temporalQuality = codecMaxQuality;
+  desc->spatialQuality = codecNormalQuality;
+  desc->hRes = Long2Fix (72);
+  desc->vRes = Long2Fix (72);
+  desc->frameCount = 1;
+  /* The following is a pure empiric calculation ... so there's are chances it
+   * might not work. To be fixed when we can figure out what the exact value should
+   * be. */
+  desc->depth = 24;
+  /* no color table */
+  desc->clutID = -1;
+}
+
+
+/* new_image_description
+ *
+ * Create an ImageDescription for the given 'codec_data' buffer.
+ */
+
+static ImageDescription *
+new_image_description (QTWrapperVideoDecoder * qtwrapper, GstBuffer * buf,
+    guint width, guint height)
+{
+  QTWrapperVideoDecoderClass *oclass;
+  ImageDescription *desc = NULL;
+
+  oclass = (QTWrapperVideoDecoderClass *) (G_OBJECT_GET_CLASS (qtwrapper));
+
+  if (buf) {
+    GST_LOG ("buf %p , size:%d", buf, GST_BUFFER_SIZE (buf));
+#if DEBUG_DUMP
+    gst_util_dump_mem (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
+#endif
+  }
+
+  if (!buf) {
+    /* standard case, no codec data */
+    desc = g_new0 (ImageDescription, 1);
+    desc->idSize = sizeof (ImageDescription);
+    fill_image_description (qtwrapper, desc);
+  } else {
+    if ((desc =
+            image_description_from_codec_data (buf, oclass->componentSubType)))
+      fill_image_description (qtwrapper, desc);
+    else
+      goto beach;
+  }
+
+  /* Fix up values */
+  desc->width = width;
+  desc->height = height;
+  desc->hRes = Long2Fix (72);
+  desc->vRes = Long2Fix (72);
+
+  /* if we have h264, we need frame buffering */
+  if ((oclass->componentSubType == QT_MAKE_FOURCC_LE ('a', 'v', 'c', '1')))
+    qtwrapper->framebuffering = TRUE;
+  else
+    qtwrapper->framebuffering = FALSE;
+
+beach:
+  return desc;
+}
+
+/* close_decoder
+ *
+ * Close and free decoder
+ */
+#if 0
+static void
+close_decoder (QTWrapperVideoDecoder * qtwrapper)
+{
+  if (qtwrapper->idesc) {
+    DisposeHandle ((Handle) qtwrapper->idesc);
+    qtwrapper->idesc = NULL;
+  }
+
+  if (qtwrapper->prevbuf) {
+    gst_buffer_unref (qtwrapper->prevbuf);
+    qtwrapper->prevbuf = NULL;
+  }
+
+  if (qtwrapper->dparams) {
+    g_free (qtwrapper->dparams);
+    qtwrapper->dparams = NULL;
+  }
+
+}
+#endif
+/* open_decoder
+ *
+ * Attempt to initialize the ImageDecompressorComponent with the given
+ * caps.
+ *
+ * Returns TRUE and fills *outcaps if the decoder was properly initialized
+ * Returns FALSE if something went wrong.
+ */
+
+static gboolean
+open_decoder (QTWrapperVideoDecoder * qtwrapper, GstCaps * caps,
+    GstCaps ** outcaps)
+{
+  ImageDescription *desc;
+  gint width, height;
+  GstStructure *s;
+  const GValue *par = NULL;
+  const GValue *rate = NULL;
+  const GValue *cdata = NULL;
+  OSErr oserr;
+  gboolean res = FALSE;
+  guint32 outformat;
+
+  ICMDecompressionSessionOptionsRef sessionoptions = NULL;
+  ICMDecompressionTrackingCallbackRecord cbrecord;
+  CFMutableDictionaryRef pixelBufferAttributes = NULL;
+
+
+  s = gst_caps_get_structure (caps, 0);
+
+  /* 1. Extract information from incoming caps */
+  if ((!gst_structure_get_int (s, "width", &width)) ||
+      (!gst_structure_get_int (s, "height", &height)) ||
+      (!(rate = gst_structure_get_value (s, "framerate"))))
+    goto beach;
+  par = gst_structure_get_value (s, "pixel-aspect-ratio");
+  cdata = gst_structure_get_value (s, "codec_data");
+
+  /* 2. Create ImageDescription */
+  if (cdata) {
+    GstBuffer *cdatabuf;
+
+    cdatabuf = gst_value_get_buffer (cdata);
+    desc = new_image_description (qtwrapper, cdatabuf, width, height);
+  } else {
+    desc = new_image_description (qtwrapper, NULL, width, height);
+  }
+
+#if DEBUG_DUMP
+  dump_image_description (desc);
+#endif
+
+  /* 3.a. Create a handle to receive the ImageDescription */
+  GST_LOG_OBJECT (qtwrapper,
+      "Creating a new ImageDescriptionHandle of %" G_GSIZE_FORMAT " bytes",
+      desc->idSize);
+  qtwrapper->idesc = (ImageDescriptionHandle) NewHandleClear (desc->idSize);
+  if (G_UNLIKELY (qtwrapper->idesc == NULL)) {
+    GST_WARNING_OBJECT (qtwrapper,
+        "Failed to create an ImageDescriptionHandle of size %" G_GSIZE_FORMAT,
+        desc->idSize);
+    g_free (desc);
+    goto beach;
+  }
+
+  /* 3.b. Copy the ImageDescription to the handle */
+  GST_LOG_OBJECT (qtwrapper,
+      "Copying %" G_GSIZE_FORMAT
+      " bytes from desc [%p] to *qtwrapper->video [%p]", desc->idSize, desc,
+      *qtwrapper->idesc);
+  memcpy (*qtwrapper->idesc, desc, desc->idSize);
+  g_free (desc);
+
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+  outformat = kYUVSPixelFormat;
+#else
+  outformat = k2vuyPixelFormat;
+#endif
+
+  /* 4. Put output pixel info in dictionnnary */
+  pixelBufferAttributes =
+      CFDictionaryCreateMutable (NULL, 0, &kCFTypeDictionaryKeyCallBacks,
+      &kCFTypeDictionaryValueCallBacks);
+
+  addSInt32ToDictionary (pixelBufferAttributes, kCVPixelBufferWidthKey, width);
+  addSInt32ToDictionary (pixelBufferAttributes, kCVPixelBufferHeightKey,
+      height);
+  addSInt32ToDictionary (pixelBufferAttributes,
+      kCVPixelBufferPixelFormatTypeKey, outformat);
+
+  /* 5. fill in callback structure */
+
+  cbrecord.decompressionTrackingCallback = decompressCb;
+  cbrecord.decompressionTrackingRefCon = qtwrapper;
+
+  /* 6. create decompressionsession */
+  oserr = ICMDecompressionSessionCreate (NULL,
+      qtwrapper->idesc,
+      sessionoptions, pixelBufferAttributes, &cbrecord, &qtwrapper->decsession);
+
+  qtwrapper->outsize = width * height * 2;
+  qtwrapper->width = width;
+  qtwrapper->height = height;
+
+  if (oserr != noErr) {
+    GST_DEBUG_OBJECT (qtwrapper,
+        "Error when Calling ICMDecompressionSessionCreate : %d", oserr);
+    goto beach;
+  }
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+  outformat = GST_MAKE_FOURCC ('Y', 'U', 'Y', '2');
+#else
+  outformat = GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y');
+#endif
+
+  /* 9. Create output caps */
+  *outcaps = gst_caps_new_simple ("video/x-raw-yuv",
+      "format", GST_TYPE_FOURCC, outformat,
+      "width", G_TYPE_INT, width,
+      "height", G_TYPE_INT, height,
+      "framerate", GST_TYPE_FRACTION,
+      gst_value_get_fraction_numerator (rate),
+      gst_value_get_fraction_denominator (rate), NULL);
+  if (par)
+    gst_structure_set_value (gst_caps_get_structure (*outcaps, 0),
+        "pixel-aspect-ratio", par);
+  res = TRUE;
+
+beach:
+  return res;
+}
+
+static gboolean
+qtwrapper_video_decoder_sink_setcaps (GstPad * pad, GstCaps * caps)
+{
+  QTWrapperVideoDecoder *qtwrapper;
+  gboolean ret = FALSE;
+  GstCaps *othercaps = NULL;
+
+  qtwrapper = (QTWrapperVideoDecoder *) gst_pad_get_parent (pad);
+
+  GST_LOG_OBJECT (qtwrapper, "caps:%" GST_PTR_FORMAT, caps);
+
+  /* Setup the decoder with the given input caps */
+  if (!(open_decoder (qtwrapper, caps, &othercaps))) {
+    goto beach;
+  }
+
+  ret = gst_pad_set_caps (qtwrapper->srcpad, othercaps);
+  if (!ret)
+    goto beach;
+
+beach:
+  if (othercaps)
+    gst_caps_unref (othercaps);
+  gst_object_unref (qtwrapper);
+  return ret;
+}
+
+static void
+decompressCb (void *decompressionTrackingRefCon,
+    OSStatus result,
+    ICMDecompressionTrackingFlags decompressionTrackingFlags,
+    CVPixelBufferRef pixelBuffer,
+    TimeValue64 displayTime,
+    TimeValue64 displayDuration,
+    ICMValidTimeFlags validTimeFlags, void *reserved, void *sourceFrameRefCon)
+{
+  QTWrapperVideoDecoder *qtwrapper;
+  GstBuffer *origbuf = (GstBuffer *) sourceFrameRefCon;
+
+  qtwrapper = (QTWrapperVideoDecoder *) decompressionTrackingRefCon;
+
+  GST_LOG_OBJECT (qtwrapper,
+      "result:%d, flags:0x%x, pixelBuffer:%p, displayTime:%lld, displayDuration:%lld",
+      (guint32) result, (guint32) decompressionTrackingFlags, pixelBuffer,
+      displayTime, displayDuration);
+
+  GST_LOG_OBJECT (qtwrapper,
+      "validTimeFlags:0x%x, reserved:%p, sourceFrameRefCon:%p",
+      (guint32) validTimeFlags, reserved, sourceFrameRefCon);
+
+  if (decompressionTrackingFlags & kICMDecompressionTracking_ReleaseSourceData) {
+    GST_LOG ("removing previous buffer : %p", origbuf);
+    gst_buffer_unref (origbuf);
+  }
+
+  if (decompressionTrackingFlags & kICMDecompressionTracking_EmittingFrame)
+    GST_LOG ("EMITTING FRAME");
+  if (decompressionTrackingFlags & kICMDecompressionTracking_FrameDecoded)
+    GST_LOG ("FRAME DECODED");
+  if (decompressionTrackingFlags & kICMDecompressionTracking_FrameDropped)
+    GST_LOG ("FRAME DROPPED");
+  if (decompressionTrackingFlags &
+      kICMDecompressionTracking_FrameNeedsRequeueing)
+    GST_LOG ("FRAME NEEDS REQUEUING");
+
+  if ((decompressionTrackingFlags & kICMDecompressionTracking_EmittingFrame)
+      && pixelBuffer) {
+    gpointer addr;
+    GstBuffer *outbuf;
+    gsize size;
+
+    size = CVPixelBufferGetDataSize (pixelBuffer);
+    GstClockTime outtime = gst_util_uint64_scale (displayTime, GST_SECOND, 600);
+
+    GST_LOG ("Got a buffer ready outtime : %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (outtime));
+
+    if (qtwrapper->flushing) {
+      CVPixelBufferRelease (pixelBuffer);
+      goto beach;
+    }
+
+    dump_cvpixel_buffer (pixelBuffer);
+
+    CVPixelBufferRetain (pixelBuffer);
+    if (CVPixelBufferLockBaseAddress (pixelBuffer, 0))
+      GST_WARNING ("Couldn't lock base adress on pixel buffer !");
+    addr = CVPixelBufferGetBaseAddress (pixelBuffer);
+
+    /* allocate buffer */
+    qtwrapper->lastret =
+        gst_pad_alloc_buffer (qtwrapper->srcpad, GST_BUFFER_OFFSET_NONE,
+        qtwrapper->outsize, GST_PAD_CAPS (qtwrapper->srcpad), &outbuf);
+    if (G_UNLIKELY (qtwrapper->lastret != GST_FLOW_OK)) {
+      GST_LOG ("gst_pad_alloc_buffer() returned %s",
+          gst_flow_get_name (qtwrapper->lastret));
+      goto beach;
+    }
+
+    /* copy data */
+    GST_LOG ("copying data in buffer from %p to %p",
+        addr, GST_BUFFER_DATA (outbuf));
+    if (G_UNLIKELY ((qtwrapper->width * 2) !=
+            CVPixelBufferGetBytesPerRow (pixelBuffer))) {
+      guint i;
+      gulong stride, realpixels;
+
+      stride = CVPixelBufferGetBytesPerRow (pixelBuffer);
+      realpixels = qtwrapper->width * 2;
+
+      /* special copy for stride handling */
+      for (i = 0; i < qtwrapper->height; i++)
+        g_memmove (GST_BUFFER_DATA (outbuf) + realpixels * i,
+            addr + stride * i, realpixels);
+
+    } else
+      g_memmove (GST_BUFFER_DATA (outbuf), addr, qtwrapper->outsize);
+
+    /* Release CVPixelBuffer */
+    CVPixelBufferUnlockBaseAddress (pixelBuffer, 0);
+    CVPixelBufferRelease (pixelBuffer);
+
+    /* Set proper timestamp ! */
+    gst_buffer_set_caps (outbuf, GST_PAD_CAPS (qtwrapper->srcpad));
+    GST_BUFFER_TIMESTAMP (outbuf) = qtwrapper->last_ts;
+    GST_BUFFER_DURATION (outbuf) = qtwrapper->last_duration;
+    GST_BUFFER_SIZE (outbuf) = qtwrapper->outsize;
+
+    /* See if we push buffer downstream */
+    if (G_LIKELY (!qtwrapper->framebuffering)) {
+      GST_LOG ("No buffering needed, pushing buffer downstream");
+      MAC_UNLOCK (qtwrapper);
+      qtwrapper->lastret = gst_pad_push (qtwrapper->srcpad, outbuf);
+      MAC_LOCK (qtwrapper);
+    } else {
+      /* Check if we push the current buffer or the stored buffer */
+      if (!qtwrapper->prevbuf) {
+        GST_LOG ("Storing buffer");
+        qtwrapper->prevbuf = outbuf;
+        qtwrapper->lastret = GST_FLOW_OK;
+      } else if (GST_BUFFER_TIMESTAMP (qtwrapper->prevbuf) >
+          GST_BUFFER_TIMESTAMP (outbuf)) {
+        GST_LOG ("Newly decoded buffer is earliest, pushing that one !");
+        MAC_UNLOCK (qtwrapper);
+        qtwrapper->lastret = gst_pad_push (qtwrapper->srcpad, outbuf);
+        MAC_LOCK (qtwrapper);
+      } else {
+        GstBuffer *tmp;
+
+        tmp = qtwrapper->prevbuf;
+        qtwrapper->prevbuf = outbuf;
+        GST_LOG ("Stored buffer is earliest, pushing that one !");
+        MAC_UNLOCK (qtwrapper);
+        qtwrapper->lastret = gst_pad_push (qtwrapper->srcpad, tmp);
+        MAC_LOCK (qtwrapper);
+      }
+    }
+  } else {
+    qtwrapper->lastret = GST_FLOW_OK;
+  }
+
+beach:
+  return;
+}
+
+/* _chain
+ *
+ * Here we feed the data to the decoder and ask to decode frames.
+ *
+ * Known issues/questions are:
+ *  * How can we be guaranteed that one frame in automatically gives one output
+ *    frame ?
+ *  * PTS/DTS timestamp issues. With mpeg-derivate formats, the incoming order is
+ *    different from the output order.
+ */
+
+static GstFlowReturn
+qtwrapper_video_decoder_chain (GstPad * pad, GstBuffer * buf)
+{
+  QTWrapperVideoDecoder *qtwrapper;
+  GstFlowReturn ret = GST_FLOW_OK;
+  ICMFrameTimeRecord frameTime = { {0} };
+  OSErr oserr;
+  guint64 intime;
+
+  qtwrapper = (QTWrapperVideoDecoder *) gst_pad_get_parent (pad);
+
+  intime = gst_util_uint64_scale (GST_BUFFER_TIMESTAMP (buf), 600, GST_SECOND);
+
+  GST_DEBUG_OBJECT (qtwrapper,
+      "buffer:%p timestamp:%" GST_TIME_FORMAT " intime:%llu Size:%d", buf,
+      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), intime,
+      GST_BUFFER_SIZE (buf));
+
+  frameTime.recordSize = sizeof (ICMFrameTimeRecord);
+/*   *(TimeValue64 *)&frameTime.value = intime; */
+  frameTime.value.lo = intime;
+  frameTime.value.hi = 0;
+  frameTime.base = 0;
+  frameTime.scale = 600;
+  frameTime.rate = fixed1;
+  frameTime.duration = 1;
+  frameTime.flags = icmFrameTimeDecodeImmediately;
+/*   frameTime.flags = icmFrameTimeIsNonScheduledDisplayTime; */
+  frameTime.frameNumber = ++qtwrapper->frameNumber;
+
+  MAC_LOCK (qtwrapper);
+
+  qtwrapper->last_ts = GST_BUFFER_TIMESTAMP (buf);
+  qtwrapper->last_duration = GST_BUFFER_DURATION (buf);
+
+  oserr = ICMDecompressionSessionDecodeFrame (qtwrapper->decsession,
+      GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf), NULL, &frameTime, buf);
+  MAC_UNLOCK (qtwrapper);
+
+  if (oserr != noErr) {
+    GST_WARNING_OBJECT (qtwrapper, "Error when Calling DecodeFrame() : %d",
+        oserr);
+    ret = GST_FLOW_ERROR;
+    goto beach;
+  }
+
+beach:
+  gst_object_unref (qtwrapper);
+  return qtwrapper->lastret;
+}
+
+static gboolean
+qtwrapper_video_decoder_sink_event (GstPad * pad, GstEvent * event)
+{
+  gboolean res;
+  QTWrapperVideoDecoder *qtwrapper;
+
+  qtwrapper = (QTWrapperVideoDecoder *) gst_pad_get_parent (pad);
+
+  GST_LOG_OBJECT (pad, "event : %s", GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH_START:
+      MAC_LOCK (qtwrapper);
+      qtwrapper->flushing = TRUE;
+      if (qtwrapper->prevbuf) {
+        GST_LOG ("About to unref buffer %p", qtwrapper->prevbuf);
+        gst_buffer_unref (qtwrapper->prevbuf);
+        qtwrapper->prevbuf = NULL;
+      }
+      ICMDecompressionSessionFlush (qtwrapper->decsession);
+      MAC_UNLOCK (qtwrapper);
+      break;
+    case GST_EVENT_FLUSH_STOP:
+      MAC_LOCK (qtwrapper);
+      qtwrapper->flushing = FALSE;
+      qtwrapper->prevbuf = NULL;
+      MAC_UNLOCK (qtwrapper);
+      break;
+    default:
+      break;
+  }
+
+  res = gst_pad_push_event (qtwrapper->srcpad, event);
+
+  gst_object_unref (qtwrapper);
+  return res;
+}
+
+/* _register
+ *
+ * Scan through all available Image Decompressor components to find the ones we
+ * can handle and wrap in this plugin.
+ */
+
+gboolean
+qtwrapper_video_decoders_register (GstPlugin * plugin)
+{
+  gboolean res = TRUE;
+  OSErr result;
+  Component componentID = NULL;
+  ComponentDescription desc = {
+    'imdc', 0, 0, 0, 0
+  };
+  GTypeInfo typeinfo = {
+    sizeof (QTWrapperVideoDecoderClass),
+    (GBaseInitFunc) qtwrapper_video_decoder_base_init,
+    NULL,
+    (GClassInitFunc) qtwrapper_video_decoder_class_init,
+    NULL,
+    NULL,
+    sizeof (QTWrapperVideoDecoder),
+    0,
+    (GInstanceInitFunc) qtwrapper_video_decoder_init,
+  };
+
+  /* Initialize quicktime environment */
+  result = EnterMovies ();
+  if (result != noErr) {
+    GST_ERROR ("Error initializing QuickTime environment");
+    res = FALSE;
+    goto beach;
+  }
+
+  /* Find all ImageDecoders ! */
+  GST_DEBUG ("There are %ld decompressors available", CountComponents (&desc));
+
+  /* loop over ImageDecoders */
+  do {
+    componentID = FindNextComponent (componentID, &desc);
+
+    GST_LOG ("componentID : %p", componentID);
+
+    if (componentID) {
+      ComponentDescription thisdesc;
+      gchar *name = NULL, *info = NULL;
+      GstCaps *caps = NULL;
+      gchar *type_name = NULL;
+      GType type;
+      QTWrapperVideoDecoderParams *params = NULL;
+
+      if (!(get_name_info_from_component (componentID, &thisdesc, &name,
+                  &info)))
+        goto next;
+
+      if (!get_output_info_from_component (componentID)) {
+        GST_WARNING ("Couldn't get output info from component");
+        goto next;
+      }
+
+      GST_LOG (" name:%s", name);
+      GST_LOG (" info:%s", info);
+
+      GST_LOG (" type:%" GST_FOURCC_FORMAT,
+          QT_FOURCC_ARGS (thisdesc.componentType));
+      GST_LOG (" subtype:%" GST_FOURCC_FORMAT,
+          QT_FOURCC_ARGS (thisdesc.componentSubType));
+      GST_LOG (" manufacturer:%" GST_FOURCC_FORMAT,
+          QT_FOURCC_ARGS (thisdesc.componentManufacturer));
+
+      if (!(caps = fourcc_to_caps (thisdesc.componentSubType))) {
+        GST_LOG
+            ("We can't find caps for this component, switching to the next one !");
+        goto next;
+      }
+
+      type_name = g_strdup_printf ("qtwrappervideodec_%" GST_FOURCC_FORMAT,
+          QT_FOURCC_ARGS (thisdesc.componentSubType));
+      g_strdelimit (type_name, " ", '_');
+
+      if (g_type_from_name (type_name)) {
+        GST_WARNING ("We already have a registered plugin for %s", type_name);
+        goto next;
+      }
+
+      params = g_new0 (QTWrapperVideoDecoderParams, 1);
+      params->component = componentID;
+      params->sinkcaps = gst_caps_ref (caps);
+
+      type = g_type_register_static (GST_TYPE_ELEMENT, type_name, &typeinfo, 0);
+      /* Store params in type qdata */
+      g_type_set_qdata (type, QTWRAPPER_VDEC_PARAMS_QDATA, (gpointer) params);
+
+      /* register type */
+      if (!gst_element_register (plugin, type_name, GST_RANK_MARGINAL, type)) {
+        g_warning ("Failed to register %s", type_name);;
+        g_type_set_qdata (type, QTWRAPPER_VDEC_PARAMS_QDATA, NULL);
+        g_free (params);
+        res = FALSE;
+        goto next;
+      }
+
+    next:
+      if (name)
+        g_free (name);
+      if (info)
+        g_free (info);
+      if (type_name)
+        g_free (type_name);
+      if (caps)
+        gst_caps_unref (caps);
+    }
+
+  } while (componentID && res);
+
+beach:
+  return res;
+}