mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-22 08:17:01 +00:00
configure.ac: Add QuickTime Wrapper plug-in.
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.
This commit is contained in:
parent
5153aa15d4
commit
307925e307
15 changed files with 2978 additions and 6 deletions
46
ChangeLog
46
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>
|
2007-11-26 Stefan Kost <ensonic@users.sf.net>
|
||||||
|
|
||||||
* gst/spectrum/gstspectrum.c:
|
* gst/spectrum/gstspectrum.c:
|
||||||
|
|
|
@ -298,6 +298,12 @@ AG_GST_CHECK_FEATURE(OPENGL, [Open GL], glsink, [
|
||||||
CPPFLAGS="$save_CPPFLAGS"
|
CPPFLAGS="$save_CPPFLAGS"
|
||||||
LIBS="$save_LIBS"
|
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
|
dnl check for Video CD
|
||||||
translit(dnm, m, l) AM_CONDITIONAL(USE_VCD, true)
|
translit(dnm, m, l) AM_CONDITIONAL(USE_VCD, true)
|
||||||
AG_GST_CHECK_FEATURE(VCD, [Video CD], vcdsrc, [
|
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
|
dnl but we still need to set the conditionals
|
||||||
|
|
||||||
AM_CONDITIONAL(USE_OPENGL, false)
|
AM_CONDITIONAL(USE_OPENGL, false)
|
||||||
|
AM_CONDITIONAL(USE_QUICKTIME, false)
|
||||||
AM_CONDITIONAL(USE_VCD, false)
|
AM_CONDITIONAL(USE_VCD, false)
|
||||||
AM_CONDITIONAL(USE_X, false)
|
AM_CONDITIONAL(USE_X, false)
|
||||||
AM_CONDITIONAL(USE_ALSA, false)
|
AM_CONDITIONAL(USE_ALSA, false)
|
||||||
|
@ -1086,6 +1093,7 @@ gst-libs/gst/app/Makefile
|
||||||
sys/Makefile
|
sys/Makefile
|
||||||
sys/glsink/Makefile
|
sys/glsink/Makefile
|
||||||
sys/dvb/Makefile
|
sys/dvb/Makefile
|
||||||
|
sys/qtwrapper/Makefile
|
||||||
sys/vcd/Makefile
|
sys/vcd/Makefile
|
||||||
examples/Makefile
|
examples/Makefile
|
||||||
examples/app/Makefile
|
examples/app/Makefile
|
||||||
|
|
|
@ -594,8 +594,9 @@ gst_speex_resample_push_drain (GstSpeexResample * resample)
|
||||||
GST_FRAMES_TO_CLOCK_TIME (out_processed, resample->outrate);
|
GST_FRAMES_TO_CLOCK_TIME (out_processed, resample->outrate);
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_LOG ("Pushing drain buffer of %ld bytes with timestamp %" GST_TIME_FORMAT
|
GST_LOG ("Pushing drain buffer of %u bytes with timestamp %" GST_TIME_FORMAT
|
||||||
" duration %" GST_TIME_FORMAT " offset %lld offset_end %lld",
|
" duration %" GST_TIME_FORMAT " offset %" G_GUINT64_FORMAT
|
||||||
|
" offset_end %" G_GUINT64_FORMAT,
|
||||||
GST_BUFFER_SIZE (buf),
|
GST_BUFFER_SIZE (buf),
|
||||||
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
|
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
|
||||||
GST_TIME_ARGS (GST_BUFFER_DURATION (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));
|
GST_ERROR ("Failed to convert data: %s", resample_resampler_strerror (err));
|
||||||
return GST_FLOW_ERROR;
|
return GST_FLOW_ERROR;
|
||||||
} else {
|
} else {
|
||||||
GST_LOG ("Converted to buffer of %ld bytes with timestamp %" GST_TIME_FORMAT
|
GST_LOG ("Converted to buffer of %u bytes with timestamp %" GST_TIME_FORMAT
|
||||||
", duration %" GST_TIME_FORMAT ", offset %lld, offset_end %lld",
|
", duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT
|
||||||
|
", offset_end %" G_GUINT64_FORMAT,
|
||||||
GST_BUFFER_SIZE (outbuf),
|
GST_BUFFER_SIZE (outbuf),
|
||||||
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
|
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
|
||||||
GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
|
GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
|
||||||
|
|
|
@ -34,6 +34,12 @@ else
|
||||||
DVB_DIR=
|
DVB_DIR=
|
||||||
endif
|
endif
|
||||||
|
|
||||||
SUBDIRS = $(GL_DIR) $(DVB_DIR) $(VCD_DIR)
|
if USE_QUICKTIME
|
||||||
|
QT_DIR=qtwrapper
|
||||||
|
else
|
||||||
|
QT_DIR=
|
||||||
|
endif
|
||||||
|
|
||||||
DIST_SUBDIRS = glsink dvb vcd
|
SUBDIRS = $(GL_DIR) $(DVB_DIR) $(VCD_DIR) $(QT_DIR)
|
||||||
|
|
||||||
|
DIST_SUBDIRS = glsink dvb vcd qtwrapper
|
||||||
|
|
24
sys/qtwrapper/Makefile.am
Normal file
24
sys/qtwrapper/Makefile.am
Normal file
|
@ -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
|
799
sys/qtwrapper/audiodecoders.c
Normal file
799
sys/qtwrapper/audiodecoders.c
Normal file
|
@ -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;
|
||||||
|
}
|
151
sys/qtwrapper/codecmapping.c
Normal file
151
sys/qtwrapper/codecmapping.c
Normal file
|
@ -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;
|
||||||
|
}
|
55
sys/qtwrapper/codecmapping.h
Normal file
55
sys/qtwrapper/codecmapping.h
Normal file
|
@ -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);
|
211
sys/qtwrapper/imagedescription.c
Normal file
211
sys/qtwrapper/imagedescription.c
Normal file
|
@ -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;
|
||||||
|
}
|
54
sys/qtwrapper/imagedescription.h
Normal file
54
sys/qtwrapper/imagedescription.h
Normal file
|
@ -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);
|
477
sys/qtwrapper/qtutils.c
Normal file
477
sys/qtwrapper/qtutils.c
Normal file
|
@ -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(¶ms, 0, sizeof(CodecDecompressParams)); */
|
||||||
|
/* GST_LOG ("calling imagecodecpredecompress"); */
|
||||||
|
/* if (ImageCodecPreDecompress (instance, ¶ms) != 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 *) ¶ms->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;
|
||||||
|
}
|
131
sys/qtwrapper/qtutils.h
Normal file
131
sys/qtwrapper/qtutils.h
Normal file
|
@ -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__ */
|
71
sys/qtwrapper/qtwrapper.c
Normal file
71
sys/qtwrapper/qtwrapper.c
Normal file
|
@ -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/")
|
63
sys/qtwrapper/qtwrapper.h
Normal file
63
sys/qtwrapper/qtwrapper.h
Normal file
|
@ -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__ */
|
874
sys/qtwrapper/videodecoders.c
Normal file
874
sys/qtwrapper/videodecoders.c
Normal file
|
@ -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;
|
||||||
|
}
|
Loading…
Reference in a new issue