summaryrefslogtreecommitdiff
path: root/sys/dshowdecwrapper
diff options
context:
space:
mode:
authorMichael Smith <msmith@xiph.org>2008-09-10 23:15:11 +0000
committerMichael Smith <msmith@xiph.org>2008-09-10 23:15:11 +0000
commit007478f09c8c10a24b473d6ac8eef1929ce25ca0 (patch)
tree7cd3ed7569f937c69df398d48e72eefe7a7753a2 /sys/dshowdecwrapper
parent61dee512910cd2c9e407cc0679a492cc57333194 (diff)
downloadgstreamer-plugins-bad-007478f09c8c10a24b473d6ac8eef1929ce25ca0.tar.gz
sys/dshowdecwrapper/: Major rewrite of dshowdecwrapper. Converts code to
Original commit message from CVS: * sys/dshowdecwrapper/Makefile.am: * sys/dshowdecwrapper/gstdshowaudiodec.c: * sys/dshowdecwrapper/gstdshowaudiodec.cpp: * sys/dshowdecwrapper/gstdshowaudiodec.h: * sys/dshowdecwrapper/gstdshowdecwrapper.c: * sys/dshowdecwrapper/gstdshowdecwrapper.cpp: * sys/dshowdecwrapper/gstdshowdecwrapper.h: * sys/dshowdecwrapper/gstdshowfakesrc.cpp: * sys/dshowdecwrapper/gstdshowfakesrc.h: * sys/dshowdecwrapper/gstdshowutil.cpp: * sys/dshowdecwrapper/gstdshowutil.h: * sys/dshowdecwrapper/gstdshowvideodec.c: * sys/dshowdecwrapper/gstdshowvideodec.cpp: * sys/dshowdecwrapper/gstdshowvideodec.h: Major rewrite of dshowdecwrapper. Converts code to C++, moves to direct use of DirectShow base classes, make a lot of code clearer, simplify, etc. Fix decode of MP3 on Vista by working around an apparent bug in the decoder.
Diffstat (limited to 'sys/dshowdecwrapper')
-rw-r--r--sys/dshowdecwrapper/Makefile.am11
-rw-r--r--sys/dshowdecwrapper/gstdshowaudiodec.cpp1074
-rw-r--r--sys/dshowdecwrapper/gstdshowaudiodec.h56
-rw-r--r--sys/dshowdecwrapper/gstdshowdecwrapper.cpp73
-rw-r--r--sys/dshowdecwrapper/gstdshowfakesrc.cpp153
-rw-r--r--sys/dshowdecwrapper/gstdshowfakesrc.h65
-rw-r--r--sys/dshowdecwrapper/gstdshowutil.cpp156
-rw-r--r--sys/dshowdecwrapper/gstdshowutil.h42
-rw-r--r--sys/dshowdecwrapper/gstdshowvideodec.cpp1170
-rw-r--r--sys/dshowdecwrapper/gstdshowvideodec.h56
10 files changed, 2840 insertions, 16 deletions
diff --git a/sys/dshowdecwrapper/Makefile.am b/sys/dshowdecwrapper/Makefile.am
index 7e9782bf7..8b48452a4 100644
--- a/sys/dshowdecwrapper/Makefile.am
+++ b/sys/dshowdecwrapper/Makefile.am
@@ -1,9 +1,14 @@
plugin_LTLIBRARIES = libgstdshowdecwrapper.la
-libgstdshowdecwrapper_la_SOURCES = gstdshowaudiodec.c gstdshowdecwrapper.c gstdshowvideodec.c
+libgstdshowdecwrapper_la_SOURCES = gstdshowaudiodec.cpp gstdshowdecwrapper.cpp \
+ gstdshowvideodec.cpp gstdshowutil.cpp \
+ gstdshowfakesrc.cpp
libgstdshowdecwrapper_la_CFLAGS = $(GST_CFLAGS) -I$(top_srcdir)/gst-libs/gst -DLIBGSTDSHOWDECWRAPPER_EXPORTS
-libgstdshowdecwrapper_la_LIBADD = $(GST_LIBS) $(top_builddir)/gst-libs/gst/dshow/libgstdshow-@GST_MAJORMINOR@.la
+libgstdshowdecwrapper_la_LIBADD = $(top_builddir)/gst-libs/gst/dshow/libgstdshow-@GST_MAJORMINOR@.la \
+ $(GST_BASE_LIBS) $(GST_LIBS)
libgstdshowdecwrapper_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
-noinst_HEADERS = gstdshowaudiodec.h gstdshowdecwrapper.h gstdshowvideodec.h
+noinst_HEADERS = gstdshowaudiodec.h gstdshowvideodec.h gstdshowfakesrc.h \
+ gstdshowutil.h
+
diff --git a/sys/dshowdecwrapper/gstdshowaudiodec.cpp b/sys/dshowdecwrapper/gstdshowaudiodec.cpp
new file mode 100644
index 000000000..dd2d98d7d
--- /dev/null
+++ b/sys/dshowdecwrapper/gstdshowaudiodec.cpp
@@ -0,0 +1,1074 @@
+/*
+ * GStreamer DirectShow codecs wrapper
+ * Copyright <2006, 2007, 2008> Fluendo <gstreamer@fluendo.com>
+ * Copyright <2006, 2007, 2008> Pioneers of the Inevitable <songbird@songbirdnest.com>
+ * Copyright <2007,2008> Sebastien Moutte <sebastien@moutte.net>
+ *
+ * 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 "gstdshowaudiodec.h"
+#include <mmreg.h>
+
+GST_DEBUG_CATEGORY_STATIC (dshowaudiodec_debug);
+#define GST_CAT_DEFAULT dshowaudiodec_debug
+
+GST_BOILERPLATE (GstDshowAudioDec, gst_dshowaudiodec, GstElement,
+ GST_TYPE_ELEMENT);
+
+static const AudioCodecEntry *tmp;
+
+static void gst_dshowaudiodec_dispose (GObject * object);
+static GstStateChangeReturn gst_dshowaudiodec_change_state
+ (GstElement * element, GstStateChange transition);
+
+/* sink pad overwrites */
+static gboolean gst_dshowaudiodec_sink_setcaps (GstPad * pad, GstCaps * caps);
+static GstFlowReturn gst_dshowaudiodec_chain (GstPad * pad, GstBuffer * buffer);
+static gboolean gst_dshowaudiodec_sink_event (GstPad * pad, GstEvent * event);
+
+/* utils */
+static gboolean gst_dshowaudiodec_create_graph_and_filters (GstDshowAudioDec *
+ adec);
+static gboolean gst_dshowaudiodec_destroy_graph_and_filters (GstDshowAudioDec *
+ adec);
+static gboolean gst_dshowaudiodec_flush (GstDshowAudioDec * adec);
+static gboolean gst_dshowaudiodec_get_filter_settings (GstDshowAudioDec * adec);
+static gboolean gst_dshowaudiodec_setup_graph (GstDshowAudioDec * adec, GstCaps *caps);
+
+/* All the GUIDs we want are generated from the FOURCC like this */
+#define GUID_MEDIASUBTYPE_FROM_FOURCC(fourcc) \
+ { fourcc , 0x0000, 0x0010, \
+ { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }}
+
+static const AudioCodecEntry audio_dec_codecs[] = {
+ {"dshowadec_wma1",
+ "Windows Media Audio 7",
+ WAVE_FORMAT_MSAUDIO1,
+ "audio/x-wma, wmaversion = (int) 1"},
+ {"dshowadec_wma2",
+ "Windows Media Audio 8",
+ WAVE_FORMAT_WMAUDIO2,
+ "audio/x-wma, wmaversion = (int) 2"},
+ {"dshowadec_wma3",
+ "Windows Media Audio 9 Professional",
+ WAVE_FORMAT_WMAUDIO3,
+ "audio/x-wma, wmaversion = (int) 3"},
+ {"dshowadec_wma4",
+ "Windows Media Audio 9 Lossless",
+ WAVE_FORMAT_WMAUDIO_LOSSLESS,
+ "audio/x-wma, wmaversion = (int) 4"},
+ {"dshowadec_wms",
+ "Windows Media Audio Voice v9",
+ WAVE_FORMAT_WMAVOICE9,
+ "audio/x-wms"},
+ {"dshowadec_mp3",
+ "MPEG Layer 3 Audio",
+ WAVE_FORMAT_MPEGLAYER3,
+ "audio/mpeg, "
+ "mpegversion = (int) 1, "
+ "layer = (int)3, "
+ "rate = (int) [ 8000, 48000 ], "
+ "channels = (int) [ 1, 2 ], "
+ "parsed= (boolean) true"},
+ {"dshowadec_mpeg_1_2",
+ "MPEG Layer 1,2 Audio",
+ WAVE_FORMAT_MPEG,
+ "audio/mpeg, "
+ "mpegversion = (int) 1, "
+ "layer = (int) [ 1, 2 ], "
+ "rate = (int) [ 8000, 48000 ], "
+ "channels = (int) [ 1, 2 ], "
+ "parsed= (boolean) true"},
+};
+
+HRESULT AudioFakeSink::DoRenderSample(IMediaSample *pMediaSample)
+{
+ GstBuffer *out_buf = NULL;
+ gboolean in_seg = FALSE;
+ GstClockTime buf_start, buf_stop;
+ gint64 clip_start = 0, clip_stop = 0;
+ guint start_offset = 0, stop_offset;
+ GstClockTime duration;
+
+ if(pMediaSample)
+ {
+ BYTE *pBuffer = NULL;
+ LONGLONG lStart = 0, lStop = 0;
+ long size = pMediaSample->GetActualDataLength();
+
+ pMediaSample->GetPointer(&pBuffer);
+ pMediaSample->GetTime(&lStart, &lStop);
+
+ if (!GST_CLOCK_TIME_IS_VALID (mDec->timestamp)) {
+ // Convert REFERENCE_TIME to GST_CLOCK_TIME
+ mDec->timestamp = (GstClockTime)lStart * 100;
+ }
+ duration = (lStop - lStart) * 100;
+
+ buf_start = mDec->timestamp;
+ buf_stop = mDec->timestamp + duration;
+
+ /* save stop position to start next buffer with it */
+ mDec->timestamp = buf_stop;
+
+ /* check if this buffer is in our current segment */
+ in_seg = gst_segment_clip (mDec->segment, GST_FORMAT_TIME,
+ buf_start, buf_stop, &clip_start, &clip_stop);
+
+ /* if the buffer is out of segment do not push it downstream */
+ if (!in_seg) {
+ GST_DEBUG_OBJECT (mDec,
+ "buffer is out of segment, start %" GST_TIME_FORMAT " stop %"
+ GST_TIME_FORMAT, GST_TIME_ARGS (buf_start), GST_TIME_ARGS (buf_stop));
+ goto done;
+ }
+
+ /* buffer is entirely or partially in-segment, so allocate a
+ * GstBuffer for output, and clip if required */
+
+ /* allocate a new buffer for raw audio */
+ mDec->last_ret = gst_pad_alloc_buffer (mDec->srcpad,
+ GST_BUFFER_OFFSET_NONE,
+ size,
+ GST_PAD_CAPS (mDec->srcpad), &out_buf);
+ if (!out_buf) {
+ GST_WARNING_OBJECT (mDec, "cannot allocate a new GstBuffer");
+ goto done;
+ }
+
+ /* set buffer properties */
+ GST_BUFFER_TIMESTAMP (out_buf) = buf_start;
+ GST_BUFFER_DURATION (out_buf) = duration;
+ memcpy (GST_BUFFER_DATA (out_buf), pBuffer,
+ MIN ((unsigned int)size, GST_BUFFER_SIZE (out_buf)));
+
+ /* we have to remove some heading samples */
+ if (clip_start > buf_start) {
+ start_offset = (guint)gst_util_uint64_scale_int (clip_start - buf_start,
+ mDec->rate, GST_SECOND) * mDec->depth / 8 * mDec->channels;
+ }
+ else
+ start_offset = 0;
+ /* we have to remove some trailing samples */
+ if (clip_stop < buf_stop) {
+ stop_offset = (guint)gst_util_uint64_scale_int (buf_stop - clip_stop,
+ mDec->rate, GST_SECOND) * mDec->depth / 8 * mDec->channels;
+ }
+ else
+ stop_offset = size;
+
+ /* truncating */
+ if ((start_offset != 0) || (stop_offset != (size_t) size)) {
+ GstBuffer *subbuf = gst_buffer_create_sub (out_buf, start_offset,
+ stop_offset - start_offset);
+
+ if (subbuf) {
+ gst_buffer_set_caps (subbuf, GST_PAD_CAPS (mDec->srcpad));
+ gst_buffer_unref (out_buf);
+ out_buf = subbuf;
+ }
+ }
+
+ GST_BUFFER_TIMESTAMP (out_buf) = clip_start;
+ GST_BUFFER_DURATION (out_buf) = clip_stop - clip_start;
+
+ /* replace the saved stop position by the clipped one */
+ mDec->timestamp = clip_stop;
+
+ GST_DEBUG_OBJECT (mDec,
+ "push_buffer (size %d)=> pts %" GST_TIME_FORMAT " stop %" GST_TIME_FORMAT
+ " duration %" GST_TIME_FORMAT, size,
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (out_buf)),
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (out_buf) +
+ GST_BUFFER_DURATION (out_buf)),
+ GST_TIME_ARGS (GST_BUFFER_DURATION (out_buf)));
+
+ mDec->last_ret = gst_pad_push (mDec->srcpad, out_buf);
+ }
+
+done:
+ return S_OK;
+}
+
+HRESULT AudioFakeSink::CheckMediaType(const CMediaType *pmt)
+{
+ if(pmt != NULL)
+ {
+ /* The Vista MP3 decoder (and possibly others?) outputs an
+ * AM_MEDIA_TYPE with the wrong cbFormat. So, rather than using
+ * CMediaType.operator==, we implement a sufficient check ourselves.
+ * I think this is a bug in the MP3 decoder.
+ */
+ if (IsEqualGUID (pmt->majortype, m_MediaType.majortype) &&
+ IsEqualGUID (pmt->subtype, m_MediaType.subtype) &&
+ IsEqualGUID (pmt->formattype, m_MediaType.formattype))
+ {
+ /* Types are the same at the top-level. Now, we need to compare
+ * the format blocks.
+ * We special case WAVEFORMATEX to not check that
+ * pmt->cbFormat == m_MediaType.cbFormat, though the actual format
+ * blocks must still be the same.
+ */
+ if (pmt->formattype == FORMAT_WaveFormatEx) {
+ if (pmt->cbFormat >= sizeof (WAVEFORMATEX) &&
+ m_MediaType.cbFormat >= sizeof (WAVEFORMATEX))
+ {
+ WAVEFORMATEX *wf1 = (WAVEFORMATEX *)pmt->pbFormat;
+ WAVEFORMATEX *wf2 = (WAVEFORMATEX *)m_MediaType.pbFormat;
+ if (wf1->cbSize == wf2->cbSize &&
+ memcmp (wf1, wf2, sizeof(WAVEFORMATEX) + wf1->cbSize) == 0)
+ return S_OK;
+ }
+ }
+ else {
+ if (pmt->cbFormat == m_MediaType.cbFormat &&
+ pmt->cbFormat == 0 ||
+ (pmt->pbFormat != NULL && m_MediaType.pbFormat != NULL &&
+ memcmp (pmt->pbFormat, m_MediaType.pbFormat, pmt->cbFormat) == 0))
+ return S_OK;
+ }
+ }
+ }
+
+ return S_FALSE;
+}
+
+static void
+gst_dshowaudiodec_base_init (gpointer klass)
+{
+ GstDshowAudioDecClass *audiodec_class = (GstDshowAudioDecClass *)klass;
+ GstPadTemplate *src, *sink;
+ GstCaps *srccaps, *sinkcaps;
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+ GstElementDetails details;
+
+ audiodec_class->entry = tmp;
+ details.longname = g_strdup_printf ("DirectShow %s Decoder Wrapper",
+ tmp->element_longname);
+ details.klass = g_strdup ("Codec/Decoder/Audio");
+ details.description = g_strdup_printf ("DirectShow %s Decoder Wrapper",
+ tmp->element_longname);
+ details.author = "Sebastien Moutte <sebastien@moutte.net>";
+ gst_element_class_set_details (element_class, &details);
+ g_free (details.longname);
+ g_free (details.klass);
+ g_free (details.description);
+
+ sinkcaps = gst_caps_from_string (tmp->sinkcaps);
+
+ srccaps = gst_caps_from_string (
+ "audio/x-raw-int,"
+ "width = (int)[1, 32],"
+ "depth = (int)[1, 32],"
+ "rate = (int)[1, MAX],"
+ "channels = (int)[1, MAX],"
+ "signed = (boolean)true,"
+ "endianness = (int)" G_STRINGIFY(G_LITTLE_ENDIAN));
+
+ sink = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, sinkcaps);
+ src = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, srccaps);
+
+ /* register */
+ gst_element_class_add_pad_template (element_class, src);
+ gst_element_class_add_pad_template (element_class, sink);
+}
+
+static void
+gst_dshowaudiodec_class_init (GstDshowAudioDecClass * klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+
+ gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_dshowaudiodec_dispose);
+
+ gstelement_class->change_state =
+ GST_DEBUG_FUNCPTR (gst_dshowaudiodec_change_state);
+
+ if (!parent_class)
+ parent_class = (GstElementClass *)g_type_class_ref (GST_TYPE_ELEMENT);
+
+ if (!dshowaudiodec_debug) {
+ GST_DEBUG_CATEGORY_INIT (dshowaudiodec_debug, "dshowaudiodec", 0,
+ "Directshow filter audio decoder");
+ }
+}
+
+static void
+gst_dshowaudiodec_init (GstDshowAudioDec * adec,
+ GstDshowAudioDecClass * adec_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_GET_CLASS (adec);
+ HRESULT hr;
+
+ /* setup pads */
+ adec->sinkpad =
+ gst_pad_new_from_template (gst_element_class_get_pad_template
+ (element_class, "sink"), "sink");
+
+ gst_pad_set_setcaps_function (adec->sinkpad, gst_dshowaudiodec_sink_setcaps);
+ gst_pad_set_event_function (adec->sinkpad, gst_dshowaudiodec_sink_event);
+ gst_pad_set_chain_function (adec->sinkpad, gst_dshowaudiodec_chain);
+ gst_element_add_pad (GST_ELEMENT (adec), adec->sinkpad);
+
+ adec->srcpad =
+ gst_pad_new_from_template (gst_element_class_get_pad_template
+ (element_class, "src"), "src");
+ gst_element_add_pad (GST_ELEMENT (adec), adec->srcpad);
+
+ adec->fakesrc = NULL;
+ adec->fakesink = NULL;
+
+ adec->decfilter = 0;
+ adec->filtergraph = 0;
+ adec->mediafilter = 0;
+
+ adec->timestamp = GST_CLOCK_TIME_NONE;
+ adec->segment = gst_segment_new ();
+ adec->setup = FALSE;
+ adec->depth = 0;
+ adec->bitrate = 0;
+ adec->block_align = 0;
+ adec->channels = 0;
+ adec->rate = 0;
+ adec->layer = 0;
+ adec->codec_data = NULL;
+
+ adec->last_ret = GST_FLOW_OK;
+
+ hr = CoInitialize (0);
+ if (SUCCEEDED(hr)) {
+ adec->comInitialized = TRUE;
+ }
+}
+
+static void
+gst_dshowaudiodec_dispose (GObject * object)
+{
+ GstDshowAudioDec *adec = (GstDshowAudioDec *) (object);
+
+ if (adec->segment) {
+ gst_segment_free (adec->segment);
+ adec->segment = NULL;
+ }
+
+ if (adec->codec_data) {
+ gst_buffer_unref (adec->codec_data);
+ adec->codec_data = NULL;
+ }
+
+ if (adec->comInitialized) {
+ CoUninitialize ();
+ adec->comInitialized = FALSE;
+ }
+
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+
+static GstStateChangeReturn
+gst_dshowaudiodec_change_state (GstElement * element, GstStateChange transition)
+{
+ GstDshowAudioDec *adec = (GstDshowAudioDec *) (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ if (!gst_dshowaudiodec_create_graph_and_filters (adec))
+ return GST_STATE_CHANGE_FAILURE;
+ break;
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+ break;
+ case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ adec->depth = 0;
+ adec->bitrate = 0;
+ adec->block_align = 0;
+ adec->channels = 0;
+ adec->rate = 0;
+ adec->layer = 0;
+ if (adec->codec_data) {
+ gst_buffer_unref (adec->codec_data);
+ adec->codec_data = NULL;
+ }
+ break;
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ if (!gst_dshowaudiodec_destroy_graph_and_filters (adec))
+ return GST_STATE_CHANGE_FAILURE;
+ break;
+ default:
+ break;
+ }
+
+ return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+}
+
+static gboolean
+gst_dshowaudiodec_sink_setcaps (GstPad * pad, GstCaps * caps)
+{
+ gboolean ret = FALSE;
+ GstDshowAudioDec *adec = (GstDshowAudioDec *) gst_pad_get_parent (pad);
+ GstStructure *s = gst_caps_get_structure (caps, 0);
+ const GValue *v = NULL;
+
+ adec->timestamp = GST_CLOCK_TIME_NONE;
+
+ /* read data, only rate and channels are needed */
+ if (!gst_structure_get_int (s, "rate", &adec->rate) ||
+ !gst_structure_get_int (s, "channels", &adec->channels)) {
+ GST_ELEMENT_ERROR (adec, CORE, NEGOTIATION,
+ ("error getting audio specs from caps"), (NULL));
+ goto end;
+ }
+
+ gst_structure_get_int (s, "depth", &adec->depth);
+ gst_structure_get_int (s, "bitrate", &adec->bitrate);
+ gst_structure_get_int (s, "block_align", &adec->block_align);
+ gst_structure_get_int (s, "layer", &adec->layer);
+
+ if (adec->codec_data) {
+ gst_buffer_unref (adec->codec_data);
+ adec->codec_data = NULL;
+ }
+
+ if ((v = gst_structure_get_value (s, "codec_data")))
+ adec->codec_data = gst_buffer_ref (gst_value_get_buffer (v));
+
+ ret = gst_dshowaudiodec_setup_graph (adec, caps);
+end:
+ gst_object_unref (adec);
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_dshowaudiodec_chain (GstPad * pad, GstBuffer * buffer)
+{
+ GstDshowAudioDec *adec = (GstDshowAudioDec *) gst_pad_get_parent (pad);
+ bool discont = FALSE;
+
+ if (!adec->setup) {
+ /* we are not set up */
+ GST_WARNING_OBJECT (adec, "Decoder not set up, failing");
+ adec->last_ret = GST_FLOW_WRONG_STATE;
+ goto beach;
+ }
+
+ if (GST_FLOW_IS_FATAL (adec->last_ret)) {
+ GST_DEBUG_OBJECT (adec, "last decoding iteration generated a fatal error "
+ "%s", gst_flow_get_name (adec->last_ret));
+ goto beach;
+ }
+
+ GST_CAT_DEBUG_OBJECT (dshowaudiodec_debug, adec, "chain (size %d)=> pts %"
+ GST_TIME_FORMAT " stop %" GST_TIME_FORMAT,
+ GST_BUFFER_SIZE (buffer), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer) +
+ GST_BUFFER_DURATION (buffer)));
+
+ /* if the incoming buffer has discont flag set => flush decoder data */
+ if (buffer && GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
+ GST_CAT_DEBUG_OBJECT (dshowaudiodec_debug, adec,
+ "this buffer has a DISCONT flag (%" GST_TIME_FORMAT "), flushing",
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
+ gst_dshowaudiodec_flush (adec);
+ discont = TRUE;
+ }
+
+ /* push the buffer to the directshow decoder */
+ adec->fakesrc->GetOutputPin()->PushBuffer (
+ GST_BUFFER_DATA (buffer), GST_BUFFER_TIMESTAMP (buffer),
+ GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer),
+ GST_BUFFER_SIZE (buffer), (bool)discont);
+
+beach:
+ gst_buffer_unref (buffer);
+ gst_object_unref (adec);
+ return adec->last_ret;
+}
+
+static gboolean
+gst_dshowaudiodec_sink_event (GstPad * pad, GstEvent * event)
+{
+ gboolean ret = TRUE;
+ GstDshowAudioDec *adec = (GstDshowAudioDec *) gst_pad_get_parent (pad);
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_FLUSH_STOP:{
+ gst_dshowaudiodec_flush (adec);
+ ret = gst_pad_event_default (pad, event);
+ break;
+ }
+ case GST_EVENT_NEWSEGMENT:
+ {
+ GstFormat format;
+ gdouble rate;
+ gint64 start, stop, time;
+ gboolean update;
+
+ gst_event_parse_new_segment (event, &update, &rate, &format, &start,
+ &stop, &time);
+
+ GST_CAT_DEBUG_OBJECT (dshowaudiodec_debug, adec,
+ "received new segment from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
+
+ if (update) {
+ GST_CAT_DEBUG_OBJECT (dshowaudiodec_debug, adec,
+ "closing current segment flushing..");
+ gst_dshowaudiodec_flush (adec);
+ }
+
+ /* save the new segment in our local current segment */
+ gst_segment_set_newsegment (adec->segment, update, rate, format, start,
+ stop, time);
+
+ ret = gst_pad_event_default (pad, event);
+ break;
+ }
+ default:
+ ret = gst_pad_event_default (pad, event);
+ break;
+ }
+
+ gst_object_unref (adec);
+
+ return ret;
+}
+
+static gboolean
+gst_dshowaudiodec_flush (GstDshowAudioDec * adec)
+{
+ if (!adec->fakesrc)
+ return FALSE;
+
+ /* flush dshow decoder and reset timestamp */
+ adec->fakesrc->GetOutputPin()->Flush();
+ adec->timestamp = GST_CLOCK_TIME_NONE;
+
+ return TRUE;
+}
+
+static AM_MEDIA_TYPE *
+dshowaudiodec_set_input_format (GstDshowAudioDec *adec, GstCaps *caps)
+{
+ AM_MEDIA_TYPE *mediatype;
+ WAVEFORMATEX *format;
+ GstDshowAudioDecClass *klass =
+ (GstDshowAudioDecClass *) G_OBJECT_GET_CLASS (adec);
+ const AudioCodecEntry *codec_entry = klass->entry;
+ int size;
+
+ mediatype = (AM_MEDIA_TYPE *)g_malloc0 (sizeof(AM_MEDIA_TYPE));
+ mediatype->majortype = MEDIATYPE_Audio;
+ GUID subtype = GUID_MEDIASUBTYPE_FROM_FOURCC (0x00000000);
+ subtype.Data1 = codec_entry->format;
+ mediatype->subtype = subtype;
+ mediatype->bFixedSizeSamples = TRUE;
+ mediatype->bTemporalCompression = FALSE;
+ if (adec->block_align)
+ mediatype->lSampleSize = adec->block_align;
+ else
+ mediatype->lSampleSize = 8192; /* need to evaluate it dynamically */
+ mediatype->formattype = FORMAT_WaveFormatEx;
+
+ /* We need this special behaviour for layers 1 and 2 (layer 3 uses a different
+ * decoder which doesn't need this */
+ if (adec->layer == 1 || adec->layer == 2) {
+ MPEG1WAVEFORMAT *mpeg1_format;
+ int version, samples;
+ GstStructure *structure = gst_caps_get_structure (caps, 0);
+
+ size = sizeof (MPEG1WAVEFORMAT);
+ format = (WAVEFORMATEX *)g_malloc0 (size);
+ format->cbSize = sizeof (MPEG1WAVEFORMAT) - sizeof (WAVEFORMATEX);
+ format->wFormatTag = WAVE_FORMAT_MPEG;
+
+ mpeg1_format = (MPEG1WAVEFORMAT *) format;
+
+ mpeg1_format->wfx.nChannels = adec->channels;
+ if (adec->channels == 2)
+ mpeg1_format->fwHeadMode = ACM_MPEG_STEREO;
+ else
+ mpeg1_format->fwHeadMode = ACM_MPEG_SINGLECHANNEL;
+
+ mpeg1_format->fwHeadModeExt = 0;
+ mpeg1_format->wHeadEmphasis = 0;
+ mpeg1_format->fwHeadFlags = 0;
+
+ switch (adec->layer) {
+ case 1:
+ mpeg1_format->fwHeadLayer = ACM_MPEG_LAYER3;
+ break;
+ case 2:
+ mpeg1_format->fwHeadLayer = ACM_MPEG_LAYER2;
+ break;
+ case 3:
+ mpeg1_format->fwHeadLayer = ACM_MPEG_LAYER1;
+ break;
+ };
+
+ gst_structure_get_int (structure, "mpegaudioversion", &version);
+ if (adec->layer == 1) {
+ samples = 384;
+ } else {
+ if (version == 1) {
+ samples = 576;
+ } else {
+ samples = 1152;
+ }
+ }
+ mpeg1_format->wfx.nBlockAlign = (WORD) samples;
+ mpeg1_format->wfx.nSamplesPerSec = adec->rate;
+ mpeg1_format->dwHeadBitrate = 128000; /* This doesn't seem to matter */
+ mpeg1_format->wfx.nAvgBytesPerSec = mpeg1_format->dwHeadBitrate / 8;
+ }
+ else
+ {
+ size = sizeof (WAVEFORMATEX) +
+ (adec->codec_data ? GST_BUFFER_SIZE (adec->codec_data) : 0);
+ format = (WAVEFORMATEX *)g_malloc0 (size);
+ if (adec->codec_data) { /* Codec data is appended after our header */
+ memcpy (((guchar *) format) + sizeof (WAVEFORMATEX),
+ GST_BUFFER_DATA (adec->codec_data),
+ GST_BUFFER_SIZE (adec->codec_data));
+ format->cbSize = GST_BUFFER_SIZE (adec->codec_data);
+ }
+
+ format->wFormatTag = codec_entry->format;
+ format->nChannels = adec->channels;
+ format->nSamplesPerSec = adec->rate;
+ format->nAvgBytesPerSec = adec->bitrate / 8;
+ format->nBlockAlign = adec->block_align;
+ format->wBitsPerSample = adec->depth;
+ }
+
+ mediatype->cbFormat = size;
+ mediatype->pbFormat = (BYTE *) format;
+
+ return mediatype;
+}
+
+static AM_MEDIA_TYPE *
+dshowaudiodec_set_output_format (GstDshowAudioDec *adec)
+{
+ AM_MEDIA_TYPE *mediatype;
+ WAVEFORMATEX *format;
+ GstDshowAudioDecClass *klass =
+ (GstDshowAudioDecClass *) G_OBJECT_GET_CLASS (adec);
+ const AudioCodecEntry *codec_entry = klass->entry;
+
+ if (!gst_dshowaudiodec_get_filter_settings (adec)) {
+ return NULL;
+ }
+
+ format = (WAVEFORMATEX *)g_malloc0(sizeof (WAVEFORMATEX));
+ format->wFormatTag = WAVE_FORMAT_PCM;
+ format->wBitsPerSample = adec->depth;
+ format->nChannels = adec->channels;
+ format->nBlockAlign = adec->channels * (adec->depth / 8);
+ format->nSamplesPerSec = adec->rate;
+ format->nAvgBytesPerSec = format->nBlockAlign * adec->rate;
+
+ mediatype = (AM_MEDIA_TYPE *)g_malloc0(sizeof (AM_MEDIA_TYPE));
+ mediatype->majortype = MEDIATYPE_Audio;
+ GUID subtype = GUID_MEDIASUBTYPE_FROM_FOURCC (WAVE_FORMAT_PCM);
+ mediatype->subtype = subtype;
+ mediatype->bFixedSizeSamples = TRUE;
+ mediatype->bTemporalCompression = FALSE;
+ mediatype->lSampleSize = format->nBlockAlign;
+ mediatype->formattype = FORMAT_WaveFormatEx;
+ mediatype->cbFormat = sizeof (WAVEFORMATEX);
+ mediatype->pbFormat = (BYTE *)format;
+
+ return mediatype;
+}
+
+static void
+dshowadec_free_mediatype (AM_MEDIA_TYPE *mediatype)
+{
+ if (mediatype->pbFormat)
+ g_free (mediatype->pbFormat);
+ g_free (mediatype);
+}
+
+static gboolean
+gst_dshowaudiodec_setup_graph (GstDshowAudioDec * adec, GstCaps *caps)
+{
+ gboolean ret = FALSE;
+ GstDshowAudioDecClass *klass =
+ (GstDshowAudioDecClass *) G_OBJECT_GET_CLASS (adec);
+ HRESULT hres;
+ GstCaps *outcaps;
+ AM_MEDIA_TYPE *output_mediatype = NULL;
+ AM_MEDIA_TYPE *input_mediatype = NULL;
+ CComPtr<IPin> output_pin;
+ CComPtr<IPin> input_pin;
+ const AudioCodecEntry *codec_entry = klass->entry;
+ CComQIPtr<IBaseFilter> srcfilter;
+ CComQIPtr<IBaseFilter> sinkfilter;
+
+ input_mediatype = dshowaudiodec_set_input_format (adec, caps);
+
+ adec->fakesrc->GetOutputPin()->SetMediaType (input_mediatype);
+
+ srcfilter = adec->fakesrc;
+
+ /* connect our fake source to decoder */
+ output_pin = gst_dshow_get_pin_from_filter (srcfilter, PINDIR_OUTPUT);
+ if (!output_pin) {
+ GST_ELEMENT_ERROR (adec, CORE, NEGOTIATION,
+ ("Can't get output pin from our directshow fakesrc filter"), (NULL));
+ goto end;
+ }
+ input_pin = gst_dshow_get_pin_from_filter (adec->decfilter, PINDIR_INPUT);
+ if (!input_pin) {
+ GST_ELEMENT_ERROR (adec, CORE, NEGOTIATION,
+ ("Can't get input pin from decoder filter"), (NULL));
+ goto end;
+ }
+
+ hres = adec->filtergraph->ConnectDirect (output_pin, input_pin,
+ NULL);
+ if (hres != S_OK) {
+ GST_ELEMENT_ERROR (adec, CORE, NEGOTIATION,
+ ("Can't connect fakesrc with decoder (error=%x)", hres), (NULL));
+ goto end;
+ }
+
+ output_mediatype = dshowaudiodec_set_output_format (adec);
+ if (!output_mediatype) {
+ GST_ELEMENT_ERROR (adec, CORE, NEGOTIATION,
+ ("Can't get audio output format from decoder"), (NULL));
+ goto end;
+ }
+
+ adec->fakesink->SetMediaType(output_mediatype);
+
+ outcaps = gst_caps_new_simple ("audio/x-raw-int",
+ "width", G_TYPE_INT, adec->depth,
+ "depth", G_TYPE_INT, adec->depth,
+ "rate", G_TYPE_INT, adec->rate,
+ "channels", G_TYPE_INT, adec->channels,
+ "signed", G_TYPE_BOOLEAN, TRUE,
+ "endianness", G_TYPE_INT, G_LITTLE_ENDIAN,
+ NULL);
+
+ if (!gst_pad_set_caps (adec->srcpad, outcaps)) {
+ gst_caps_unref (outcaps);
+ GST_ELEMENT_ERROR (adec, CORE, NEGOTIATION,
+ ("Failed to negotiate output"), (NULL));
+ goto end;
+ }
+ gst_caps_unref (outcaps);
+
+ /* connect the decoder to our fake sink */
+ output_pin = gst_dshow_get_pin_from_filter (adec->decfilter, PINDIR_OUTPUT);
+ if (!output_pin) {
+ GST_ELEMENT_ERROR (adec, CORE, NEGOTIATION,
+ ("Can't get output pin from our decoder filter"), (NULL));
+ goto end;
+ }
+
+ sinkfilter = adec->fakesink;
+ input_pin = gst_dshow_get_pin_from_filter (sinkfilter, PINDIR_INPUT);
+ if (!input_pin) {
+ GST_ELEMENT_ERROR (adec, CORE, NEGOTIATION,
+ ("Can't get input pin from our directshow fakesink filter"), (NULL));
+ goto end;
+ }
+
+ hres = adec->filtergraph->ConnectDirect(output_pin, input_pin, NULL);
+ if (hres != S_OK) {
+ GST_ELEMENT_ERROR (adec, CORE, NEGOTIATION,
+ ("Can't connect decoder with fakesink (error=%x)", hres), (NULL));
+ goto end;
+ }
+
+ hres = adec->mediafilter->Run (-1);
+ if (hres != S_OK) {
+ GST_ELEMENT_ERROR (adec, CORE, NEGOTIATION,
+ ("Can't run the directshow graph (error=%x)", hres), (NULL));
+ goto end;
+ }
+
+ ret = TRUE;
+ adec->setup = TRUE;
+end:
+ if (input_mediatype)
+ dshowadec_free_mediatype (input_mediatype);
+ if (output_mediatype)
+ dshowadec_free_mediatype (output_mediatype);
+
+ return ret;
+}
+
+static gboolean
+gst_dshowaudiodec_get_filter_settings (GstDshowAudioDec * adec)
+{
+ CComPtr<IPin> output_pin;
+ CComPtr<IEnumMediaTypes> enum_mediatypes;
+ HRESULT hres;
+ ULONG fetched;
+ BOOL ret = FALSE;
+
+ if (adec->decfilter == 0)
+ return FALSE;
+
+ output_pin = gst_dshow_get_pin_from_filter (adec->decfilter, PINDIR_OUTPUT);
+ if (!output_pin) {
+ GST_ELEMENT_ERROR (adec, CORE, NEGOTIATION,
+ ("failed getting ouput pin from the decoder"), (NULL));
+ return FALSE;
+ }
+
+ hres = output_pin->EnumMediaTypes (&enum_mediatypes);
+ if (hres == S_OK && enum_mediatypes) {
+ AM_MEDIA_TYPE *mediatype = NULL;
+
+ enum_mediatypes->Reset();
+ while (!ret && enum_mediatypes->Next(1, &mediatype, &fetched) == S_OK)
+ {
+ if (IsEqualGUID (mediatype->subtype, MEDIASUBTYPE_PCM) &&
+ IsEqualGUID (mediatype->formattype, FORMAT_WaveFormatEx))
+ {
+ WAVEFORMATEX *audio_info = (WAVEFORMATEX *) mediatype->pbFormat;
+
+ adec->channels = audio_info->nChannels;
+ adec->depth = audio_info->wBitsPerSample;
+ adec->rate = audio_info->nSamplesPerSec;
+ ret = TRUE;
+ }
+ DeleteMediaType (mediatype);
+ }
+ }
+
+ return ret;
+}
+
+static gboolean
+gst_dshowaudiodec_create_graph_and_filters (GstDshowAudioDec * adec)
+{
+ HRESULT hres;
+ GstDshowAudioDecClass *klass =
+ (GstDshowAudioDecClass *) G_OBJECT_GET_CLASS (adec);
+ CComQIPtr<IBaseFilter> srcfilter;
+ CComQIPtr<IBaseFilter> sinkfilter;
+ GUID insubtype = GUID_MEDIASUBTYPE_FROM_FOURCC (klass->entry->format);
+ GUID outsubtype = GUID_MEDIASUBTYPE_FROM_FOURCC (WAVE_FORMAT_PCM);
+
+ /* create the filter graph manager object */
+ hres = adec->filtergraph.CoCreateInstance (
+ CLSID_FilterGraph, NULL, CLSCTX_INPROC);
+ if (FAILED (hres)) {
+ GST_ELEMENT_ERROR (adec, STREAM, FAILED,
+ ("Can't create an instance of the directshow graph manager (error=%d)",
+ hres), (NULL));
+ goto error;
+ }
+
+ hres = adec->filtergraph->QueryInterface (&adec->mediafilter);
+ if (FAILED (hres)) {
+ GST_WARNING_OBJECT (adec, "Can't QI filtergraph to mediafilter");
+ goto error;
+ }
+
+ /* create fake src filter */
+ adec->fakesrc = new FakeSrc();
+ /* Created with a refcount of zero, so increment that */
+ adec->fakesrc->AddRef();
+
+ /* create decoder filter */
+ if (!gst_dshow_find_filter (MEDIATYPE_Audio,
+ insubtype,
+ MEDIATYPE_Audio,
+ outsubtype,
+ NULL, &adec->decfilter)) {
+ GST_ELEMENT_ERROR (adec, STREAM, FAILED,
+ ("Can't create an instance of the decoder filter"), (NULL));
+ goto error;
+ }
+
+ /* create fake sink filter */
+ adec->fakesink = new AudioFakeSink(adec);
+ /* Created with a refcount of zero, so increment that */
+ adec->fakesink->AddRef();
+
+ /* add filters to the graph */
+ srcfilter = adec->fakesrc;
+ hres = adec->filtergraph->AddFilter (srcfilter, L"src");
+ if (hres != S_OK) {
+ GST_ELEMENT_ERROR (adec, STREAM, FAILED,
+ ("Can't add fakesrc filter to the graph (error=%d)", hres), (NULL));
+ goto error;
+ }
+
+ hres = adec->filtergraph->AddFilter(adec->decfilter, L"decoder");
+ if (hres != S_OK) {
+ GST_ELEMENT_ERROR (adec, STREAM, FAILED,
+ ("Can't add decoder filter to the graph (error=%d)", hres), (NULL));
+ goto error;
+ }
+
+ sinkfilter = adec->fakesink;
+ hres = adec->filtergraph->AddFilter(sinkfilter, L"sink");
+ if (hres != S_OK) {
+ GST_ELEMENT_ERROR (adec, STREAM, FAILED,
+ ("Can't add fakesink filter to the graph (error=%d)", hres), (NULL));
+ goto error;
+ }
+
+ return TRUE;
+
+error:
+ if (adec->fakesrc) {
+ adec->fakesrc->Release();
+ adec->fakesrc = NULL;
+ }
+ if (adec->fakesink) {
+ adec->fakesink->Release();
+ adec->fakesink = NULL;
+ }
+ adec->decfilter = 0;
+ adec->mediafilter = 0;
+ adec->filtergraph = 0;
+
+ return FALSE;
+}
+
+static gboolean
+gst_dshowaudiodec_destroy_graph_and_filters (GstDshowAudioDec * adec)
+{
+ if (adec->mediafilter) {
+ adec->mediafilter->Stop();
+ }
+
+ if (adec->fakesrc) {
+ if (adec->filtergraph) {
+ CComQIPtr<IBaseFilter> filter = adec->fakesrc;
+ adec->filtergraph->RemoveFilter(filter);
+ }
+ adec->fakesrc->Release();
+ adec->fakesrc = NULL;
+ }
+ if (adec->decfilter) {
+ if (adec->filtergraph)
+ adec->filtergraph->RemoveFilter(adec->decfilter);
+ adec->decfilter = 0;
+ }
+ if (adec->fakesink) {
+ if (adec->filtergraph) {
+ CComQIPtr<IBaseFilter> filter = adec->fakesink;
+ adec->filtergraph->RemoveFilter(filter);
+ }
+
+ adec->fakesink->Release();
+ adec->fakesink = NULL;
+ }
+ adec->mediafilter = 0;
+ adec->filtergraph = 0;
+
+ adec->setup = FALSE;
+
+ return TRUE;
+}
+
+gboolean
+dshow_adec_register (GstPlugin * plugin)
+{
+ GTypeInfo info = {
+ sizeof (GstDshowAudioDecClass),
+ (GBaseInitFunc) gst_dshowaudiodec_base_init,
+ NULL,
+ (GClassInitFunc) gst_dshowaudiodec_class_init,
+ NULL,
+ NULL,
+ sizeof (GstDshowAudioDec),
+ 0,
+ (GInstanceInitFunc) gst_dshowaudiodec_init,
+ };
+ gint i;
+ HRESULT hr;
+
+ GST_DEBUG_CATEGORY_INIT (dshowaudiodec_debug, "dshowaudiodec", 0,
+ "Directshow filter audio decoder");
+
+ hr = CoInitialize(0);
+ for (i = 0; i < sizeof (audio_dec_codecs) / sizeof (AudioCodecEntry); i++) {
+ GType type;
+
+ GUID insubtype = GUID_MEDIASUBTYPE_FROM_FOURCC (audio_dec_codecs[i].format);
+ GUID outsubtype = GUID_MEDIASUBTYPE_FROM_FOURCC (WAVE_FORMAT_PCM);
+ if (gst_dshow_find_filter (MEDIATYPE_Audio,
+ insubtype,
+ MEDIATYPE_Audio,
+ outsubtype,
+ NULL, NULL)) {
+
+ GST_CAT_DEBUG (dshowaudiodec_debug, "Registering %s",
+ audio_dec_codecs[i].element_name);
+
+ tmp = &audio_dec_codecs[i];
+ type =
+ g_type_register_static (GST_TYPE_ELEMENT,
+ audio_dec_codecs[i].element_name, &info, (GTypeFlags)0);
+ if (!gst_element_register (plugin, audio_dec_codecs[i].element_name,
+ GST_RANK_PRIMARY, type)) {
+ return FALSE;
+ }
+ GST_CAT_DEBUG (dshowaudiodec_debug, "Registered %s",
+ audio_dec_codecs[i].element_name);
+ } else {
+ GST_CAT_DEBUG (dshowaudiodec_debug,
+ "Element %s not registered (the format is not supported by the system)",
+ audio_dec_codecs[i].element_name);
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ CoUninitialize ();
+
+ return TRUE;
+}
diff --git a/sys/dshowdecwrapper/gstdshowaudiodec.h b/sys/dshowdecwrapper/gstdshowaudiodec.h
index 732e636d4..6301b31f5 100644
--- a/sys/dshowdecwrapper/gstdshowaudiodec.h
+++ b/sys/dshowdecwrapper/gstdshowaudiodec.h
@@ -47,11 +47,21 @@
#ifndef __GST_DSHOWAUDIODEC_H__
#define __GST_DSHOWAUDIODEC_H__
+#include <atlbase.h>
+
#include <gst/gst.h>
-#include "gstdshowdecwrapper.h"
+#include "gstdshowutil.h"
+#include "gstdshowfakesrc.h"
G_BEGIN_DECLS
+typedef struct {
+ gchar *element_name; /* The gst element factory name */
+ gchar *element_longname; /* Description string for element */
+ gint32 format; /* WAVEFORMATEX format */
+ gchar *sinkcaps; /* GStreamer caps of input format */
+} AudioCodecEntry;
+
#define GST_TYPE_DSHOWAUDIODEC (gst_dshowaudiodec_get_type())
#define GST_DSHOWAUDIODEC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DSHOWAUDIODEC,GstDshowAudioDec))
#define GST_DSHOWAUDIODEC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DSHOWAUDIODEC,GstDshowAudioDecClass))
@@ -61,6 +71,8 @@ G_BEGIN_DECLS
typedef struct _GstDshowAudioDec GstDshowAudioDec;
typedef struct _GstDshowAudioDecClass GstDshowAudioDecClass;
+class AudioFakeSink;
+
struct _GstDshowAudioDec
{
GstElement element;
@@ -72,14 +84,14 @@ struct _GstDshowAudioDec
GstFlowReturn last_ret;
/* filters interfaces*/
- IBaseFilter *srcfilter;
- IGstDshowInterface *gstdshowsrcfilter;
- IBaseFilter *decfilter;
- IBaseFilter *sinkfilter;
+ FakeSrc *fakesrc;
+ AudioFakeSink *fakesink;
+
+ CComPtr<IBaseFilter> decfilter;
/* graph manager interfaces */
- IMediaFilter *mediafilter;
- IFilterGraph *filtergraph;
+ CComPtr<IMediaFilter> mediafilter;
+ CComPtr<IFilterGraph> filtergraph;
/* true when dshow graph is setup */
gboolean setup;
@@ -105,11 +117,39 @@ struct _GstDshowAudioDec
struct _GstDshowAudioDecClass
{
GstElementClass parent_class;
- const CodecEntry *entry;
+ const AudioCodecEntry *entry;
};
gboolean dshow_adec_register (GstPlugin * plugin);
+const GUID CLSID_AudioFakeSink =
+{ 0x3867f537, 0x3e3d, 0x44da,
+ { 0xbb, 0xf2, 0x02, 0x48, 0x7b, 0xb0, 0xbc, 0xc4} };
+
+class AudioFakeSink : public CBaseRenderer
+{
+public:
+ AudioFakeSink(GstDshowAudioDec *dec) :
+ m_hres(S_OK),
+ CBaseRenderer(CLSID_AudioFakeSink, L"AudioFakeSink", NULL, &m_hres),
+ mDec(dec)
+ {};
+ virtual ~AudioFakeSink() {};
+
+ HRESULT DoRenderSample(IMediaSample *pMediaSample);
+ HRESULT CheckMediaType(const CMediaType *pmt);
+ HRESULT SetMediaType (AM_MEDIA_TYPE *pmt)
+ {
+ m_MediaType.Set (*pmt);
+ return S_OK;
+ }
+
+protected:
+ HRESULT m_hres;
+ CMediaType m_MediaType;
+ GstDshowAudioDec *mDec;
+};
+
G_END_DECLS
#endif /* __GST_DSHOWAUDIODEC_H__ */
diff --git a/sys/dshowdecwrapper/gstdshowdecwrapper.cpp b/sys/dshowdecwrapper/gstdshowdecwrapper.cpp
new file mode 100644
index 000000000..c64257c8e
--- /dev/null
+++ b/sys/dshowdecwrapper/gstdshowdecwrapper.cpp
@@ -0,0 +1,73 @@
+/*
+ * GStreamer DirectShow codecs wrapper
+ * Copyright <2006, 2007, 2008> Fluendo <gstreamer@fluendo.com>
+ * Copyright <2006, 2007, 2008> Pioneers of the Inevitable <songbird@songbirdnest.com>
+ * Copyright <2007,2008> Sebastien Moutte <sebastien@moutte.net>
+ *
+ * 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 "gstdshowaudiodec.h"
+#include "gstdshowvideodec.h"
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ if (!dshow_adec_register (plugin))
+ return FALSE;
+
+ if (!dshow_vdec_register (plugin))
+ return FALSE;
+
+ return TRUE;
+}
+
+extern "C" {
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "dshowdecwrapper",
+ "DirectShow decoder wrapper plugin",
+ plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
+
+}
diff --git a/sys/dshowdecwrapper/gstdshowfakesrc.cpp b/sys/dshowdecwrapper/gstdshowfakesrc.cpp
new file mode 100644
index 000000000..8095c36e1
--- /dev/null
+++ b/sys/dshowdecwrapper/gstdshowfakesrc.cpp
@@ -0,0 +1,153 @@
+/* GStreamer
+ * Copyright (C) 2007 Sebastien Moutte <sebastien@moutte.net>
+ *
+ * gstdshowfakesrc.cpp:
+ *
+ * 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 "gstdshowfakesrc.h"
+
+const GUID CLSID_DecodeFakeSrc =
+{ 0x039527db, 0x6b48, 0x45a7, { 0xab, 0xcf, 0x21, 0xab, 0xc5, 0x44, 0xbb, 0xb6} };
+
+static CCritSec g_pCriticSec;
+
+/* output pin*/
+FakeOutputPin::FakeOutputPin (CBaseFilter *pFilter, CCritSec *sec):
+ CBaseOutputPin("FakeOutputPin", pFilter, sec, &m_hres, L"output")
+{
+}
+
+FakeOutputPin::~FakeOutputPin()
+{
+}
+
+HRESULT FakeOutputPin::GetMediaType(int iPosition,
+ CMediaType *pMediaType)
+{
+ if(iPosition == 0) {
+ *pMediaType = m_MediaType;
+ return S_OK;
+ }
+
+ return VFW_S_NO_MORE_ITEMS;
+}
+
+HRESULT FakeOutputPin::CheckMediaType(const CMediaType *pmt)
+{
+ if (m_MediaType == *pmt) {
+ return S_OK;
+ }
+
+ return S_FALSE;
+}
+
+HRESULT FakeOutputPin::DecideBufferSize (IMemAllocator *pAlloc,
+ ALLOCATOR_PROPERTIES *ppropInputRequest)
+{
+ ALLOCATOR_PROPERTIES properties;
+ ppropInputRequest->cbBuffer = m_SampleSize;
+ ppropInputRequest->cBuffers = 1;
+ HRESULT hres = pAlloc->SetProperties(ppropInputRequest, &properties);
+ pAlloc->Commit();
+
+ return S_OK;
+}
+
+STDMETHODIMP FakeOutputPin::SetMediaType (AM_MEDIA_TYPE *pmt)
+{
+ m_MediaType.Set (*pmt);
+ m_SampleSize = m_MediaType.GetSampleSize();
+ return S_OK;
+}
+
+STDMETHODIMP FakeOutputPin::PushBuffer(byte *buffer,
+ __int64 start, __int64 stop,
+ unsigned int size, bool discont)
+{
+ IMediaSample *pSample = NULL;
+
+ if (start != -1) {
+ start /= 100;
+ stop /= 100;
+ }
+
+ HRESULT hres = GetDeliveryBuffer(&pSample, NULL, NULL, 0);
+ if (hres == S_OK && pSample)
+ {
+ BYTE *sample_buffer;
+ pSample->GetPointer(&sample_buffer);
+ if(sample_buffer)
+ {
+ memcpy (sample_buffer, buffer, size);
+ pSample->SetActualDataLength(size);
+ }
+ pSample->SetDiscontinuity(discont);
+
+ pSample->SetSyncPoint(TRUE);
+ pSample->SetPreroll(FALSE);
+
+ if (start != -1)
+ pSample->SetTime(&start, &stop);
+
+ hres = Deliver(pSample);
+ pSample->Release();
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP FakeOutputPin::Flush ()
+{
+ DeliverBeginFlush();
+ DeliverEndFlush();
+ return S_OK;
+}
+
+STDMETHODIMP FakeOutputPin::SetSampleSize (unsigned int size)
+{
+ m_SampleSize = size;
+ return S_OK;
+}
+
+/* filter */
+FakeSrc::FakeSrc() :
+ CBaseFilter("DshowFakeSink", NULL, &g_pCriticSec, CLSID_DecodeFakeSrc)
+{
+ m_pOutputPin = new FakeOutputPin((CSource *)this, m_pLock);
+}
+
+FakeSrc::~FakeSrc()
+{
+ if (m_pOutputPin)
+ delete m_pOutputPin;
+}
+
+int FakeSrc::GetPinCount()
+{
+ return 1;
+}
+
+CBasePin *FakeSrc::GetPin(int n)
+{
+ return (CBasePin *)m_pOutputPin;
+}
+
+FakeOutputPin *FakeSrc::GetOutputPin()
+{
+ return m_pOutputPin;
+} \ No newline at end of file
diff --git a/sys/dshowdecwrapper/gstdshowfakesrc.h b/sys/dshowdecwrapper/gstdshowfakesrc.h
new file mode 100644
index 000000000..03e013464
--- /dev/null
+++ b/sys/dshowdecwrapper/gstdshowfakesrc.h
@@ -0,0 +1,65 @@
+/* GStreamer
+ * Copyright (C) 2007 Sebastien Moutte <sebastien@moutte.net>
+ *
+ * gstdshowfakesrc.h:
+ *
+ * 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 _DSHOWDECWRAPPER_FAKESRC_H_
+#define _DSHOWDECWRAPPER_FAKESRC_H_
+
+#include <gst/gst.h>
+#include "gstdshowutil.h"
+
+class FakeOutputPin : public CBaseOutputPin
+{
+protected:
+/* members */
+ HRESULT m_hres;
+ CMediaType m_MediaType;
+ unsigned int m_SampleSize;
+
+public:
+/* methods */
+ FakeOutputPin (CBaseFilter *pFilter, CCritSec *sec);
+ ~FakeOutputPin ();
+
+ virtual HRESULT CheckMediaType(const CMediaType *pmt);
+ HRESULT GetMediaType(int iPosition, CMediaType *pMediaType);
+ virtual HRESULT DecideBufferSize (IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest);
+ STDMETHOD (SetMediaType) (AM_MEDIA_TYPE *pmt);
+ STDMETHOD (PushBuffer) (byte *buffer, __int64 start, __int64 stop, unsigned int size, bool discont);
+ STDMETHOD (Flush) ();
+ STDMETHOD (SetSampleSize) (unsigned int size);
+};
+
+class FakeSrc : public CBaseFilter
+{
+public:
+/* members */
+ FakeOutputPin *m_pOutputPin;
+
+/* methods */
+ FakeSrc ();
+ virtual ~FakeSrc ();
+
+ virtual int GetPinCount();
+ virtual CBasePin *GetPin(int n);
+
+ FakeOutputPin *GetOutputPin();
+};
+
+#endif // _DSHOWDECWRAPPER_FAKESRC_H_ \ No newline at end of file
diff --git a/sys/dshowdecwrapper/gstdshowutil.cpp b/sys/dshowdecwrapper/gstdshowutil.cpp
new file mode 100644
index 000000000..df2f65d11
--- /dev/null
+++ b/sys/dshowdecwrapper/gstdshowutil.cpp
@@ -0,0 +1,156 @@
+/* GStreamer
+ * Copyright (C) 2007 Sebastien Moutte <sebastien@moutte.net>
+ *
+ * gstdshow.cpp:
+ *
+ * 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 <atlbase.h>
+
+#include "gstdshowutil.h"
+#include "gstdshowfakesrc.h"
+
+IPin *
+gst_dshow_get_pin_from_filter (IBaseFilter *filter, PIN_DIRECTION pindir)
+{
+ CComPtr<IEnumPins> enumpins;
+ CComPtr<IPin> pin;
+ HRESULT hres;
+
+ hres = filter->EnumPins (&enumpins);
+ if (FAILED(hres)) {
+ return NULL;
+ }
+
+ while (enumpins->Next (1, &pin, NULL) == S_OK)
+ {
+ PIN_DIRECTION pindirtmp;
+ hres = pin->QueryDirection (&pindirtmp);
+ if (hres == S_OK && pindir == pindirtmp) {
+ return pin;
+ }
+ pin.Release();
+ }
+
+ return NULL;
+}
+
+gboolean gst_dshow_find_filter(CLSID input_majortype, CLSID input_subtype,
+ CLSID output_majortype, CLSID output_subtype,
+ gchar * prefered_filter_name, IBaseFilter **filter)
+{
+ gboolean ret = FALSE;
+ HRESULT hres;
+ GUID arrayInTypes[2];
+ GUID arrayOutTypes[2];
+ IFilterMapper2 *mapper = NULL;
+ IEnumMoniker *enum_moniker = NULL;
+ IMoniker *moniker = NULL;
+ ULONG fetched;
+ gchar *prefered_filter_upper = NULL;
+ gboolean exit = FALSE;
+
+ /* initialize output parameter */
+ if (filter)
+ *filter = NULL;
+
+ /* create a private copy of prefered filter substring in upper case */
+ if (prefered_filter_name) {
+ prefered_filter_upper = g_strdup (prefered_filter_name);
+ strupr (prefered_filter_upper);
+ }
+
+ hres = CoCreateInstance(CLSID_FilterMapper2, NULL, CLSCTX_INPROC,
+ IID_IFilterMapper2, (void **) &mapper);
+ if (FAILED(hres))
+ goto clean;
+
+ memcpy(&arrayInTypes[0], &input_majortype, sizeof (CLSID));
+ memcpy(&arrayInTypes[1], &input_subtype, sizeof (CLSID));
+ memcpy(&arrayOutTypes[0], &output_majortype, sizeof (CLSID));
+ memcpy(&arrayOutTypes[1], &output_subtype, sizeof (CLSID));
+
+ hres = mapper->EnumMatchingFilters (&enum_moniker, 0, FALSE, MERIT_DO_NOT_USE+1,
+ TRUE, 1, arrayInTypes, NULL, NULL, FALSE,
+ TRUE, 1, arrayOutTypes, NULL, NULL);
+ if (FAILED(hres))
+ goto clean;
+
+ enum_moniker->Reset ();
+
+ while(hres = enum_moniker->Next (1, &moniker, &fetched),hres == S_OK
+ && !exit) {
+ IBaseFilter *filter_temp = NULL;
+ IPropertyBag *property_bag = NULL;
+ gchar * friendly_name = NULL;
+
+ hres = moniker->BindToStorage (NULL, NULL, IID_IPropertyBag, (void **)&property_bag);
+ if(SUCCEEDED(hres) && property_bag) {
+ VARIANT varFriendlyName;
+ VariantInit (&varFriendlyName);
+
+ hres = property_bag->Read (L"FriendlyName", &varFriendlyName, NULL);
+ if(hres == S_OK && varFriendlyName.bstrVal) {
+ friendly_name = g_utf16_to_utf8((const gunichar2*)varFriendlyName.bstrVal,
+ wcslen(varFriendlyName.bstrVal), NULL, NULL, NULL);
+ if (friendly_name)
+ strupr (friendly_name);
+ SysFreeString (varFriendlyName.bstrVal);
+ }
+ property_bag->Release ();
+ }
+
+ hres = moniker->BindToObject(NULL, NULL, IID_IBaseFilter, (void**)&filter_temp);
+ if(SUCCEEDED(hres) && filter_temp) {
+ ret = TRUE;
+ if (filter) {
+ if (*filter)
+ (*filter)->Release ();
+
+ *filter = filter_temp;
+ (*filter)->AddRef ();
+
+ if (prefered_filter_upper && friendly_name &&
+ strstr(friendly_name, prefered_filter_upper))
+ exit = TRUE;
+ }
+
+ /* if we just want to know if the formats are supported OR
+ if we don't care about what will be the filter used
+ => we can stop enumeration */
+ if (!filter || !prefered_filter_upper)
+ exit = TRUE;
+
+ filter_temp->Release ();
+ }
+
+ if (friendly_name)
+ g_free (friendly_name);
+ moniker->Release ();
+ }
+
+clean:
+ if (prefered_filter_upper)
+ g_free (prefered_filter_upper);
+ if (enum_moniker)
+ enum_moniker->Release ();
+ if (mapper)
+ mapper->Release ();
+
+ return ret;
+}
+
diff --git a/sys/dshowdecwrapper/gstdshowutil.h b/sys/dshowdecwrapper/gstdshowutil.h
new file mode 100644
index 000000000..0b5ca90e2
--- /dev/null
+++ b/sys/dshowdecwrapper/gstdshowutil.h
@@ -0,0 +1,42 @@
+/* GStreamer
+ * Copyright (C) 2007 Sebastien Moutte <sebastien@moutte.net>
+ *
+ * gstdshow.h:
+ *
+ * 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_DSHOW_UTIL_H_
+#define _GST_DSHOW_UTIL_H_
+
+#include <windows.h>
+#include <objbase.h>
+#include <dshow.h>
+#include <Rpc.h>
+#include <streams.h>
+#include <strmif.h>
+
+#include <glib.h>
+
+/* get a pin from directshow filter */
+IPin *gst_dshow_get_pin_from_filter (IBaseFilter *filter, PIN_DIRECTION pindir);
+
+/* find and return a filter according to the input and output types */
+gboolean gst_dshow_find_filter(CLSID input_majortype, CLSID input_subtype,
+ CLSID output_majortype, CLSID output_subtype,
+ gchar * prefered_filter_name, IBaseFilter **filter);
+
+#endif /* _GST_DSHOW_UTIL_H_ */
diff --git a/sys/dshowdecwrapper/gstdshowvideodec.cpp b/sys/dshowdecwrapper/gstdshowvideodec.cpp
new file mode 100644
index 000000000..80a1a1931
--- /dev/null
+++ b/sys/dshowdecwrapper/gstdshowvideodec.cpp
@@ -0,0 +1,1170 @@
+/*
+ * GStreamer DirectShow codecs wrapper
+ * Copyright <2006, 2007, 2008> Fluendo <gstreamer@fluendo.com>
+ * Copyright <2006, 2007, 2008> Pioneers of the Inevitable <songbird@songbirdnest.com>
+ * Copyright <2007,2008> Sebastien Moutte <sebastien@moutte.net>
+ *
+ * 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 <atlbase.h>
+
+#include "gstdshowvideodec.h"
+
+GST_DEBUG_CATEGORY_STATIC (dshowvideodec_debug);
+#define GST_CAT_DEFAULT dshowvideodec_debug
+
+GST_BOILERPLATE (GstDshowVideoDec, gst_dshowvideodec, GstElement,
+ GST_TYPE_ELEMENT);
+static const VideoCodecEntry *tmp;
+
+static void gst_dshowvideodec_dispose (GObject * object);
+static GstStateChangeReturn gst_dshowvideodec_change_state
+ (GstElement * element, GstStateChange transition);
+
+/* sink pad overwrites */
+static gboolean gst_dshowvideodec_sink_setcaps (GstPad * pad, GstCaps * caps);
+static gboolean gst_dshowvideodec_sink_event (GstPad * pad, GstEvent * event);
+static GstFlowReturn gst_dshowvideodec_chain (GstPad * pad, GstBuffer * buffer);
+
+/* src pad overwrites */
+static GstCaps *gst_dshowvideodec_src_getcaps (GstPad * pad);
+static gboolean gst_dshowvideodec_src_setcaps (GstPad * pad, GstCaps * caps);
+
+/* utils */
+static gboolean gst_dshowvideodec_create_graph_and_filters (GstDshowVideoDec *
+ vdec);
+static gboolean gst_dshowvideodec_destroy_graph_and_filters (GstDshowVideoDec *
+ vdec);
+static gboolean gst_dshowvideodec_flush (GstDshowVideoDec * adec);
+static gboolean gst_dshowvideodec_get_filter_output_format (GstDshowVideoDec *
+ vdec, const GUID subtype, VIDEOINFOHEADER ** format, guint * size);
+
+
+#define GUID_MEDIATYPE_VIDEO {0x73646976, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }}
+#define GUID_MEDIASUBTYPE_WMVV1 {0x31564d57, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }}
+#define GUID_MEDIASUBTYPE_WMVV2 {0x32564d57, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }}
+#define GUID_MEDIASUBTYPE_WMVV3 {0x33564d57, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }}
+#define GUID_MEDIASUBTYPE_WMVP {0x50564d57, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }}
+#define GUID_MEDIASUBTYPE_WMVA {0x41564d57, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }}
+#define GUID_MEDIASUBTYPE_CVID {0x64697663, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }}
+#define GUID_MEDIASUBTYPE_MP4S {0x5334504d, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }}
+#define GUID_MEDIASUBTYPE_MP42 {0x3234504d, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }}
+#define GUID_MEDIASUBTYPE_MP43 {0x3334504d, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }}
+#define GUID_MEDIASUBTYPE_M4S2 {0x3253344d, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }}
+#define GUID_MEDIASUBTYPE_XVID {0x44495658, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }}
+#define GUID_MEDIASUBTYPE_DX50 {0x30355844, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }}
+#define GUID_MEDIASUBTYPE_DIVX {0x58564944, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }}
+#define GUID_MEDIASUBTYPE_DIV3 {0x33564944, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }}
+
+#define GUID_MEDIASUBTYPE_MPG4 {0x3447504d, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }}
+#define GUID_MEDIASUBTYPE_MPEG1Payload {0xe436eb81, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}}
+
+
+/* output types */
+#define GUID_MEDIASUBTYPE_YUY2 {0x32595559, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }}
+#define GUID_MEDIASUBTYPE_YV12 {0x32315659, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }}
+#define GUID_MEDIASUBTYPE_RGB32 {0xe436eb7e, 0x524f, 0x11ce, { 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 }}
+#define GUID_MEDIASUBTYPE_RGB565 {0xe436eb7b, 0x524f, 0x11ce, { 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 }}
+
+/* video codecs array */
+static const VideoCodecEntry video_dec_codecs[] = {
+ {"dshowvdec_wmv1",
+ "Windows Media Video 7",
+ "DMO",
+ GST_MAKE_FOURCC ('W', 'M', 'V', '1'),
+ GUID_MEDIATYPE_VIDEO, GUID_MEDIASUBTYPE_WMVV1,
+ "video/x-wmv, wmvversion = (int) 1",
+ GUID_MEDIATYPE_VIDEO, GUID_MEDIASUBTYPE_YUY2,
+ "video/x-raw-yuv, format=(fourcc)YUY2"},
+ {"dshowvdec_wmv2",
+ "Windows Media Video 8",
+ "DMO",
+ GST_MAKE_FOURCC ('W', 'M', 'V', '2'),
+ GUID_MEDIATYPE_VIDEO, GUID_MEDIASUBTYPE_WMVV2,
+ "video/x-wmv, wmvversion = (int) 2",
+ GUID_MEDIATYPE_VIDEO, GUID_MEDIASUBTYPE_YUY2,
+ "video/x-raw-yuv, format=(fourcc)YUY2"},
+ {"dshowvdec_wmv3",
+ "Windows Media Video 9",
+ "DMO",
+ GST_MAKE_FOURCC ('W', 'M', 'V', '3'),
+ GUID_MEDIATYPE_VIDEO, GUID_MEDIASUBTYPE_WMVV3,
+ "video/x-wmv, wmvversion = (int) 3, " "format = (fourcc) WMV3",
+ GUID_MEDIATYPE_VIDEO, GUID_MEDIASUBTYPE_YUY2,
+ "video/x-raw-yuv, format=(fourcc)YUY2"},
+ {"dshowvdec_wmvp",
+ "Windows Media Video 9 Image",
+ "DMO",
+ GST_MAKE_FOURCC ('W', 'M', 'V', 'P'),
+ GUID_MEDIATYPE_VIDEO, GUID_MEDIASUBTYPE_WMVP,
+ "video/x-wmv, wmvversion = (int) 3, " "format = (fourcc) WMVP",
+ GUID_MEDIATYPE_VIDEO, GUID_MEDIASUBTYPE_YUY2,
+ "video/x-raw-yuv, format=(fourcc)YUY2"},
+ {"dshowvdec_wmva",
+ "Windows Media Video 9 Advanced",
+ "DMO",
+ GST_MAKE_FOURCC ('W', 'M', 'V', 'A'),
+ GUID_MEDIATYPE_VIDEO, GUID_MEDIASUBTYPE_WMVA,
+ "video/x-wmv, wmvversion = (int) 3, " "format = (fourcc) WMVA",
+ GUID_MEDIATYPE_VIDEO, GUID_MEDIASUBTYPE_YUY2,
+ "video/x-raw-yuv, format=(fourcc)YUY2"},
+ {"dshowvdec_cinepak",
+ "Cinepack",
+ "AVI Decompressor",
+ 0x64697663,
+ GUID_MEDIATYPE_VIDEO, GUID_MEDIASUBTYPE_CVID,
+ "video/x-cinepak",
+ GUID_MEDIATYPE_VIDEO, GUID_MEDIASUBTYPE_RGB32,
+ "video/x-raw-rgb, bpp=(int)32, depth=(int)24, "
+ "endianness=(int)4321, red_mask=(int)65280, "
+ "green_mask=(int)16711680, blue_mask=(int)-16777216"},
+ {"dshowvdec_msmpeg41",
+ "Microsoft ISO MPEG-4 version 1",
+ "DMO",
+ GST_MAKE_FOURCC ('M', 'P', '4', 'S'),
+ GUID_MEDIATYPE_VIDEO, GUID_MEDIASUBTYPE_MP4S,
+ "video/x-msmpeg, msmpegversion=(int)41",
+ GUID_MEDIATYPE_VIDEO, GUID_MEDIASUBTYPE_YUY2,
+ "video/x-raw-yuv, format=(fourcc)YUY2"},
+ {"dshowvdec_msmpeg42",
+ "Microsoft ISO MPEG-4 version 2",
+ "DMO",
+ GST_MAKE_FOURCC ('M', 'P', '4', '2'),
+ GUID_MEDIATYPE_VIDEO, GUID_MEDIASUBTYPE_MP42,
+ "video/x-msmpeg, msmpegversion=(int)42",
+ GUID_MEDIATYPE_VIDEO, GUID_MEDIASUBTYPE_YUY2,
+ "video/x-raw-yuv, format=(fourcc)YUY2"},
+ {"dshowvdec_msmpeg43",
+ "Microsoft ISO MPEG-4 version 3",
+ "DMO",
+ GST_MAKE_FOURCC ('M', 'P', '4', '3'),
+ GUID_MEDIATYPE_VIDEO, GUID_MEDIASUBTYPE_MP43,
+ "video/x-msmpeg, msmpegversion=(int)43",
+ GUID_MEDIATYPE_VIDEO, GUID_MEDIASUBTYPE_YUY2,
+ "video/x-raw-yuv, format=(fourcc)YUY2"},
+ {"dshowvdec_msmpeg4",
+ "Microsoft ISO MPEG-4 version 1.1",
+ "DMO",
+ GST_MAKE_FOURCC ('M', '4', 'S', '2'),
+ GUID_MEDIATYPE_VIDEO, GUID_MEDIASUBTYPE_M4S2,
+ "video/x-msmpeg, msmpegversion=(int)4",
+ GUID_MEDIATYPE_VIDEO, GUID_MEDIASUBTYPE_YUY2,
+ "video/x-raw-yuv, format=(fourcc)YUY2"},
+ {"dshowvdec_mpeg1",
+ "MPEG-1 Video",
+ "MPEG Video Decoder",
+ GST_MAKE_FOURCC ('M', 'P', 'E', 'G'),
+ GUID_MEDIATYPE_VIDEO, GUID_MEDIASUBTYPE_MPEG1Payload,
+ "video/mpeg, mpegversion= (int) 1, "
+ "parsed= (boolean) true, " "systemstream= (boolean) false",
+ GUID_MEDIATYPE_VIDEO, GUID_MEDIASUBTYPE_YUY2,
+ "video/x-raw-yuv, format=(fourcc)YUY2"},
+ {"dshowvdec_xvid",
+ "XVID Video",
+ "ffdshow",
+ GST_MAKE_FOURCC ('X', 'V', 'I', 'D'),
+ GUID_MEDIATYPE_VIDEO, GUID_MEDIASUBTYPE_XVID,
+ "video/x-xvid",
+ GUID_MEDIATYPE_VIDEO, GUID_MEDIASUBTYPE_YUY2,
+ "video/x-raw-yuv, format=(fourcc)YUY2"},
+ {"dshowvdec_divx5",
+ "DIVX 5.0 Video",
+ "ffdshow",
+ GST_MAKE_FOURCC ('D', 'X', '5', '0'),
+ GUID_MEDIATYPE_VIDEO, GUID_MEDIASUBTYPE_DX50,
+ "video/x-divx, divxversion=(int)5",
+ GUID_MEDIATYPE_VIDEO, GUID_MEDIASUBTYPE_YUY2,
+ "video/x-raw-yuv, format=(fourcc)YUY2"},
+ {"dshowvdec_divx4",
+ "DIVX 4.0 Video",
+ "ffdshow",
+ GST_MAKE_FOURCC ('D', 'I', 'V', 'X'),
+ GUID_MEDIATYPE_VIDEO, GUID_MEDIASUBTYPE_DIVX,
+ "video/x-divx, divxversion=(int)4",
+ GUID_MEDIATYPE_VIDEO, GUID_MEDIASUBTYPE_YUY2,
+ "video/x-raw-yuv, format=(fourcc)YUY2"},
+ {"dshowvdec_divx3",
+ "DIVX 3.0 Video",
+ "ffdshow",
+ GST_MAKE_FOURCC ('D', 'I', 'V', '3'),
+ GUID_MEDIATYPE_VIDEO, GUID_MEDIASUBTYPE_DIV3,
+ "video/x-divx, divxversion=(int)3",
+ GUID_MEDIATYPE_VIDEO, GUID_MEDIASUBTYPE_YUY2,
+ "video/x-raw-yuv, format=(fourcc)YUY2"}
+ /*,
+ { "dshowvdec_mpeg4",
+ "DMO",
+ GST_MAKE_FOURCC ('M', 'P', 'G', '4'),
+ GUID_MEDIATYPE_VIDEO, GUID_MEDIASUBTYPE_MPG4,
+ "video/mpeg, msmpegversion=(int)4",
+ GUID_MEDIATYPE_VIDEO, GUID_MEDIASUBTYPE_YUY2,
+ "video/x-raw-yuv, format=(fourcc)YUY2"
+ } */
+};
+
+HRESULT VideoFakeSink::DoRenderSample(IMediaSample *pMediaSample)
+{
+ gboolean in_seg = FALSE;
+ gint64 clip_start = 0, clip_stop = 0;
+ GstDshowVideoDecClass *klass =
+ (GstDshowVideoDecClass *) G_OBJECT_GET_CLASS (mDec);
+ GstBuffer *buf = NULL;
+ GstClockTime start, stop;
+
+ if(pMediaSample)
+ {
+ BYTE *pBuffer = NULL;
+ LONGLONG lStart = 0, lStop = 0;
+ long size = pMediaSample->GetActualDataLength();
+
+ pMediaSample->GetPointer(&pBuffer);
+ pMediaSample->GetTime(&lStart, &lStop);
+
+ start = lStart * 100;
+ stop = lStop * 100;
+ /* check if this buffer is in our current segment */
+ in_seg = gst_segment_clip (mDec->segment, GST_FORMAT_TIME,
+ start, stop, &clip_start, &clip_stop);
+
+ /* if the buffer is out of segment do not push it downstream */
+ if (!in_seg) {
+ GST_DEBUG_OBJECT (mDec,
+ "buffer is out of segment, start %" GST_TIME_FORMAT " stop %"
+ GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
+ goto done;
+ }
+
+ /* buffer is in our segment, allocate a new out buffer and clip its
+ * timestamps */
+ mDec->last_ret = gst_pad_alloc_buffer (mDec->srcpad,
+ GST_BUFFER_OFFSET_NONE,
+ size,
+ GST_PAD_CAPS (mDec->srcpad), &buf);
+ if (!buf) {
+ GST_WARNING_OBJECT (mDec,
+ "cannot allocate a new GstBuffer");
+ goto done;
+ }
+
+ /* set buffer properties */
+ GST_BUFFER_TIMESTAMP (buf) = clip_start;
+ GST_BUFFER_DURATION (buf) = clip_stop - clip_start;
+
+ if (strstr (klass->entry->srccaps, "rgb")) {
+ /* FOR RGB directshow decoder will return bottom-up BITMAP
+ * There is probably a way to get top-bottom video frames from
+ * the decoder...
+ */
+ gint line = 0;
+ guint stride = mDec->width * 4;
+
+ for (; line < mDec->height; line++) {
+ memcpy (GST_BUFFER_DATA (buf) + (line * stride),
+ pBuffer + (size - ((line + 1) * (stride))), stride);
+ }
+ } else {
+ memcpy (GST_BUFFER_DATA (buf), pBuffer, MIN ((unsigned int)size, GST_BUFFER_SIZE (buf)));
+ }
+
+ GST_LOG_OBJECT (mDec,
+ "push_buffer (size %d)=> pts %" GST_TIME_FORMAT " stop %" GST_TIME_FORMAT
+ " duration %" GST_TIME_FORMAT, size,
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf)),
+ GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
+
+ /* push the buffer downstream */
+ mDec->last_ret = gst_pad_push (mDec->srcpad, buf);
+ }
+done:
+
+ return S_OK;
+}
+
+HRESULT VideoFakeSink::CheckMediaType(const CMediaType *pmt)
+{
+ if (pmt != NULL) {
+ if (*pmt == m_MediaType)
+ return S_OK;
+ }
+
+ return S_FALSE;
+}
+
+static void
+gst_dshowvideodec_base_init (gpointer klass)
+{
+ GstDshowVideoDecClass *videodec_class = (GstDshowVideoDecClass *)klass;
+ GstPadTemplate *src, *sink;
+ GstCaps *srccaps, *sinkcaps;
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+ GstElementDetails details;
+
+ videodec_class->entry = tmp;
+
+ details.longname = g_strdup_printf ("DirectShow %s Decoder Wrapper",
+ tmp->element_longname);
+ details.klass = g_strdup ("Codec/Decoder/Video");
+ details.description = g_strdup_printf ("DirectShow %s Decoder Wrapper",
+ tmp->element_longname);
+ details.author = "Sebastien Moutte <sebastien@moutte.net>";
+ gst_element_class_set_details (element_class, &details);
+ g_free (details.longname);
+ g_free (details.klass);
+ g_free (details.description);
+
+ sinkcaps = gst_caps_from_string (tmp->sinkcaps);
+ gst_caps_set_simple (sinkcaps,
+ "width", GST_TYPE_INT_RANGE, 16, 4096,
+ "height", GST_TYPE_INT_RANGE, 16, 4096,
+ "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
+
+ srccaps = gst_caps_from_string (tmp->srccaps);
+
+ sink = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, sinkcaps);
+ src = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, srccaps);
+
+ gst_element_class_add_pad_template (element_class, src);
+ gst_element_class_add_pad_template (element_class, sink);
+}
+
+static void
+gst_dshowvideodec_class_init (GstDshowVideoDecClass * klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+
+ gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_dshowvideodec_dispose);
+
+ gstelement_class->change_state =
+ GST_DEBUG_FUNCPTR (gst_dshowvideodec_change_state);
+
+ if (!parent_class)
+ parent_class = (GstElementClass *)g_type_class_ref (GST_TYPE_ELEMENT);
+
+ if (!dshowvideodec_debug) {
+ GST_DEBUG_CATEGORY_INIT (dshowvideodec_debug, "dshowvideodec", 0,
+ "Directshow filter video decoder");
+ }
+}
+
+static void
+gst_dshowvideodec_init (GstDshowVideoDec * vdec,
+ GstDshowVideoDecClass * vdec_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_GET_CLASS (vdec);
+ HRESULT hr;
+
+ /* setup pads */
+ vdec->sinkpad =
+ gst_pad_new_from_template (gst_element_class_get_pad_template
+ (element_class, "sink"), "sink");
+
+ gst_pad_set_setcaps_function (vdec->sinkpad, gst_dshowvideodec_sink_setcaps);
+ gst_pad_set_event_function (vdec->sinkpad, gst_dshowvideodec_sink_event);
+ gst_pad_set_chain_function (vdec->sinkpad, gst_dshowvideodec_chain);
+ gst_element_add_pad (GST_ELEMENT (vdec), vdec->sinkpad);
+
+ vdec->srcpad =
+ gst_pad_new_from_template (gst_element_class_get_pad_template
+ (element_class, "src"), "src");
+/* needed to implement caps negociation on our src pad */
+/* gst_pad_set_getcaps_function (vdec->srcpad, gst_dshowvideodec_src_getcaps);
+ gst_pad_set_setcaps_function (vdec->srcpad, gst_dshowvideodec_src_setcaps);*/
+ gst_element_add_pad (GST_ELEMENT (vdec), vdec->srcpad);
+
+ vdec->fakesrc = NULL;
+ vdec->fakesink = NULL;
+ vdec->decfilter = NULL;
+
+ vdec->last_ret = GST_FLOW_OK;
+
+ vdec->filtergraph = NULL;
+ vdec->mediafilter = NULL;
+ vdec->srccaps = NULL;
+ vdec->segment = gst_segment_new ();
+
+ vdec->setup = FALSE;
+
+ hr = CoInitialize (0);
+ if (SUCCEEDED(hr)) {
+ vdec->comInitialized = TRUE;
+ }
+}
+
+static void
+gst_dshowvideodec_dispose (GObject * object)
+{
+ GstDshowVideoDec *vdec = (GstDshowVideoDec *) (object);
+
+ if (vdec->segment) {
+ gst_segment_free (vdec->segment);
+ vdec->segment = NULL;
+ }
+
+ if (vdec->comInitialized) {
+ CoUninitialize ();
+ vdec->comInitialized = FALSE;
+ }
+
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static GstStateChangeReturn
+gst_dshowvideodec_change_state (GstElement * element, GstStateChange transition)
+{
+ GstDshowVideoDec *vdec = (GstDshowVideoDec *) (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ if (!gst_dshowvideodec_create_graph_and_filters (vdec))
+ return GST_STATE_CHANGE_FAILURE;
+ break;
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+ break;
+ case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ break;
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ if (!gst_dshowvideodec_destroy_graph_and_filters (vdec))
+ return GST_STATE_CHANGE_FAILURE;
+ break;
+ default:
+ break;
+ }
+
+ return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+}
+
+static gboolean
+gst_dshowvideodec_sink_setcaps (GstPad * pad, GstCaps * caps)
+{
+ gboolean ret = FALSE;
+ HRESULT hres;
+ GstStructure *s = gst_caps_get_structure (caps, 0);
+ GstDshowVideoDec *vdec = (GstDshowVideoDec *) gst_pad_get_parent (pad);
+ GstDshowVideoDecClass *klass =
+ (GstDshowVideoDecClass *) G_OBJECT_GET_CLASS (vdec);
+ GstBuffer *extradata = NULL;
+ const GValue *v = NULL;
+ guint size = 0;
+ GstCaps *caps_out;
+ AM_MEDIA_TYPE output_mediatype, input_mediatype;
+ VIDEOINFOHEADER *input_vheader = NULL, *output_vheader = NULL;
+ CComPtr<IPin> output_pin;
+ CComPtr<IPin> input_pin;
+ IBaseFilter *srcfilter = NULL;
+ IBaseFilter *sinkfilter = NULL;
+ const GValue *fps;
+
+ /* read data */
+ if (!gst_structure_get_int (s, "width", &vdec->width) ||
+ !gst_structure_get_int (s, "height", &vdec->height)) {
+ GST_ELEMENT_ERROR (vdec, CORE, NEGOTIATION,
+ ("error getting video width or height from caps"), (NULL));
+ goto end;
+ }
+ fps = gst_structure_get_value (s, "framerate");
+ if (!fps) {
+ GST_ELEMENT_ERROR (vdec, CORE, NEGOTIATION,
+ ("error getting video framerate from caps"), (NULL));
+ goto end;
+ }
+ vdec->fps_n = gst_value_get_fraction_numerator (fps);
+ vdec->fps_d = gst_value_get_fraction_denominator (fps);
+
+ if ((v = gst_structure_get_value (s, "codec_data")))
+ extradata = gst_value_get_buffer (v);
+
+ /* define the input type format */
+ memset (&input_mediatype, 0, sizeof (AM_MEDIA_TYPE));
+ input_mediatype.majortype = klass->entry->input_majortype;
+ input_mediatype.subtype = klass->entry->input_subtype;
+ input_mediatype.bFixedSizeSamples = FALSE;
+ input_mediatype.bTemporalCompression = TRUE;
+
+ if (strstr (klass->entry->sinkcaps, "video/mpeg, mpegversion= (int) 1")) {
+ size =
+ sizeof (MPEG1VIDEOINFO) + (extradata ? GST_BUFFER_SIZE (extradata) -
+ 1 : 0);
+ input_vheader = (VIDEOINFOHEADER *)g_malloc0 (size);
+
+ input_vheader->bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
+ if (extradata) {
+ MPEG1VIDEOINFO *mpeg_info = (MPEG1VIDEOINFO *) input_vheader;
+
+ memcpy (mpeg_info->bSequenceHeader,
+ GST_BUFFER_DATA (extradata), GST_BUFFER_SIZE (extradata));
+ mpeg_info->cbSequenceHeader = GST_BUFFER_SIZE (extradata);
+ }
+ input_mediatype.formattype = FORMAT_MPEGVideo;
+ } else {
+ size =
+ sizeof (VIDEOINFOHEADER) +
+ (extradata ? GST_BUFFER_SIZE (extradata) : 0);
+ input_vheader = (VIDEOINFOHEADER *)g_malloc0 (size);
+
+ input_vheader->bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
+ if (extradata) { /* Codec data is appended after our header */
+ memcpy (((guchar *) input_vheader) + sizeof (VIDEOINFOHEADER),
+ GST_BUFFER_DATA (extradata), GST_BUFFER_SIZE (extradata));
+ input_vheader->bmiHeader.biSize += GST_BUFFER_SIZE (extradata);
+ }
+ input_mediatype.formattype = FORMAT_VideoInfo;
+ }
+ input_vheader->rcSource.top = input_vheader->rcSource.left = 0;
+ input_vheader->rcSource.right = vdec->width;
+ input_vheader->rcSource.bottom = vdec->height;
+ input_vheader->rcTarget = input_vheader->rcSource;
+ input_vheader->bmiHeader.biWidth = vdec->width;
+ input_vheader->bmiHeader.biHeight = vdec->height;
+ input_vheader->bmiHeader.biPlanes = 1;
+ input_vheader->bmiHeader.biBitCount = 16;
+ input_vheader->bmiHeader.biCompression = klass->entry->format;
+ input_vheader->bmiHeader.biSizeImage =
+ (vdec->width * vdec->height) * (input_vheader->bmiHeader.biBitCount / 8);
+
+ input_mediatype.cbFormat = size;
+ input_mediatype.pbFormat = (BYTE *) input_vheader;
+ input_mediatype.lSampleSize = input_vheader->bmiHeader.biSizeImage;
+
+ vdec->fakesrc->GetOutputPin()->SetMediaType(&input_mediatype);
+
+ /* set the sample size for fakesrc filter to the output buffer size */
+ vdec->fakesrc->GetOutputPin()->SetSampleSize(input_mediatype.lSampleSize);
+
+ /* connect our fake src to decoder */
+ hres = vdec->fakesrc->QueryInterface(IID_IBaseFilter,
+ (void **) &srcfilter);
+ if (FAILED (hres)) {
+ GST_ELEMENT_ERROR (vdec, CORE, NEGOTIATION,
+ ("Can't QT fakesrc to IBaseFilter: %x", hres), (NULL));
+ goto end;
+ }
+
+ output_pin = gst_dshow_get_pin_from_filter (srcfilter, PINDIR_OUTPUT);
+ if (!output_pin) {
+ GST_ELEMENT_ERROR (vdec, CORE, NEGOTIATION,
+ ("Can't get output pin from our directshow fakesrc filter"), (NULL));
+ goto end;
+ }
+ input_pin = gst_dshow_get_pin_from_filter (vdec->decfilter, PINDIR_INPUT);
+ if (!input_pin) {
+ GST_ELEMENT_ERROR (vdec, CORE, NEGOTIATION,
+ ("Can't get input pin from decoder filter"), (NULL));
+ goto end;
+ }
+
+ hres = vdec->filtergraph->ConnectDirect (output_pin, input_pin, NULL);
+ if (hres != S_OK) {
+ GST_ELEMENT_ERROR (vdec, CORE, NEGOTIATION,
+ ("Can't connect fakesrc with decoder (error=%x)", hres), (NULL));
+ goto end;
+ }
+
+ /* get decoder output video format */
+ if (!gst_dshowvideodec_get_filter_output_format (vdec,
+ klass->entry->output_subtype, &output_vheader, &size)) {
+ GST_ELEMENT_ERROR (vdec, CORE, NEGOTIATION,
+ ("Can't get decoder output video format"), (NULL));
+ goto end;
+ }
+
+ memset (&output_mediatype, 0, sizeof (AM_MEDIA_TYPE));
+ output_mediatype.majortype = klass->entry->output_majortype;
+ output_mediatype.subtype = klass->entry->output_subtype;
+ output_mediatype.bFixedSizeSamples = TRUE;
+ output_mediatype.bTemporalCompression = FALSE;
+ output_mediatype.lSampleSize = output_vheader->bmiHeader.biSizeImage;
+ output_mediatype.formattype = FORMAT_VideoInfo;
+ output_mediatype.cbFormat = size;
+ output_mediatype.pbFormat = (BYTE *) output_vheader;
+
+ vdec->fakesink->SetMediaType (&output_mediatype);
+
+ /* connect decoder to our fake sink */
+ output_pin = gst_dshow_get_pin_from_filter (vdec->decfilter, PINDIR_OUTPUT);
+ if (!output_pin) {
+ GST_ELEMENT_ERROR (vdec, CORE, NEGOTIATION,
+ ("Can't get output pin from our decoder filter"), (NULL));
+ goto end;
+ }
+
+ hres = vdec->fakesink->QueryInterface(IID_IBaseFilter,
+ (void **) &sinkfilter);
+ if (FAILED (hres)) {
+ GST_ELEMENT_ERROR (vdec, CORE, NEGOTIATION,
+ ("Can't QT fakesink to IBaseFilter: %x", hres), (NULL));
+ goto end;
+ }
+
+ input_pin = gst_dshow_get_pin_from_filter (sinkfilter, PINDIR_INPUT);
+ if (!input_pin) {
+ GST_ELEMENT_ERROR (vdec, CORE, NEGOTIATION,
+ ("Can't get input pin from our directshow fakesink filter"), (NULL));
+ goto end;
+ }
+
+ hres = vdec->filtergraph->ConnectDirect(output_pin, input_pin,
+ &output_mediatype);
+ if (hres != S_OK) {
+ GST_ELEMENT_ERROR (vdec, CORE, NEGOTIATION,
+ ("Can't connect decoder with fakesink (error=%x)", hres), (NULL));
+ goto end;
+ }
+
+ /* negotiate output */
+ caps_out = gst_caps_from_string (klass->entry->srccaps);
+ gst_caps_set_simple (caps_out,
+ "width", G_TYPE_INT, vdec->width,
+ "height", G_TYPE_INT, vdec->height,
+ "framerate", GST_TYPE_FRACTION, vdec->fps_n, vdec->fps_d, NULL);
+ if (!gst_pad_set_caps (vdec->srcpad, caps_out)) {
+ gst_caps_unref (caps_out);
+ GST_ELEMENT_ERROR (vdec, CORE, NEGOTIATION,
+ ("Failed to negotiate output"), (NULL));
+ goto end;
+ }
+ gst_caps_unref (caps_out);
+
+ hres = vdec->mediafilter->Run (-1);
+ if (hres != S_OK) {
+ GST_ELEMENT_ERROR (vdec, CORE, NEGOTIATION,
+ ("Can't run the directshow graph (error=%d)", hres), (NULL));
+ goto end;
+ }
+
+ ret = TRUE;
+end:
+ gst_object_unref (vdec);
+ if (input_vheader)
+ g_free (input_vheader);
+ if (srcfilter)
+ srcfilter->Release();
+ if (sinkfilter)
+ sinkfilter->Release();
+ return ret;
+}
+
+static gboolean
+gst_dshowvideodec_sink_event (GstPad * pad, GstEvent * event)
+{
+ gboolean ret = TRUE;
+ GstDshowVideoDec *vdec = (GstDshowVideoDec *) gst_pad_get_parent (pad);
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_FLUSH_STOP:
+ gst_dshowvideodec_flush (vdec);
+ ret = gst_pad_event_default (pad, event);
+ break;
+ case GST_EVENT_NEWSEGMENT:
+ {
+ GstFormat format;
+ gdouble rate;
+ gint64 start, stop, time;
+ gboolean update;
+
+ gst_event_parse_new_segment (event, &update, &rate, &format, &start,
+ &stop, &time);
+
+ /* save the new segment in our local current segment */
+ gst_segment_set_newsegment (vdec->segment, update, rate, format, start,
+ stop, time);
+
+ GST_CAT_DEBUG_OBJECT (dshowvideodec_debug, vdec,
+ "new segment received => start=%" GST_TIME_FORMAT " stop=%"
+ GST_TIME_FORMAT, GST_TIME_ARGS (vdec->segment->start),
+ GST_TIME_ARGS (vdec->segment->stop));
+
+ if (update) {
+ GST_CAT_DEBUG_OBJECT (dshowvideodec_debug, vdec,
+ "closing current segment flushing..");
+ gst_dshowvideodec_flush (vdec);
+ }
+
+ ret = gst_pad_event_default (pad, event);
+ break;
+ }
+ default:
+ ret = gst_pad_event_default (pad, event);
+ break;
+ }
+
+ gst_object_unref (vdec);
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_dshowvideodec_chain (GstPad * pad, GstBuffer * buffer)
+{
+ GstDshowVideoDec *vdec = (GstDshowVideoDec *) gst_pad_get_parent (pad);
+ bool discont = FALSE;
+ GstClockTime stop;
+
+ if (!vdec->setup) {
+ /* we are not setup */
+ GST_WARNING_OBJECT (vdec, "Decoder not set up, failing");
+ vdec->last_ret = GST_FLOW_WRONG_STATE;
+ goto beach;
+ }
+
+ if (GST_FLOW_IS_FATAL (vdec->last_ret)) {
+ GST_DEBUG_OBJECT (vdec, "last decoding iteration generated a fatal error "
+ "%s", gst_flow_get_name (vdec->last_ret));
+ goto beach;
+ }
+
+ /* check if duration is valid and use duration only when it's valid
+ /* because dshow is not decoding frames having stop smaller than start */
+ if (GST_BUFFER_DURATION_IS_VALID (buffer)) {
+ stop = GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer);
+ } else {
+ stop = GST_BUFFER_TIMESTAMP (buffer);
+ }
+
+ GST_CAT_LOG_OBJECT (dshowvideodec_debug, vdec,
+ "chain (size %d)=> pts %" GST_TIME_FORMAT " stop %" GST_TIME_FORMAT,
+ GST_BUFFER_SIZE (buffer), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
+ GST_TIME_ARGS (stop));
+
+ /* if the incoming buffer has discont flag set => flush decoder data */
+ if (buffer && GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
+ GST_CAT_DEBUG_OBJECT (dshowvideodec_debug, vdec,
+ "this buffer has a DISCONT flag (%" GST_TIME_FORMAT "), flushing",
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
+ gst_dshowvideodec_flush (vdec);
+ discont = TRUE;
+ }
+
+ /* push the buffer to the directshow decoder */
+ vdec->fakesrc->GetOutputPin()->PushBuffer(
+ GST_BUFFER_DATA (buffer), GST_BUFFER_TIMESTAMP (buffer), stop,
+ GST_BUFFER_SIZE (buffer), discont);
+
+beach:
+ gst_buffer_unref (buffer);
+ gst_object_unref (vdec);
+
+ return vdec->last_ret;
+}
+
+static GstCaps *
+gst_dshowvideodec_src_getcaps (GstPad * pad)
+{
+ GstDshowVideoDec *vdec = (GstDshowVideoDec *) gst_pad_get_parent (pad);
+ GstCaps *caps = NULL;
+
+ if (!vdec->srccaps)
+ vdec->srccaps = gst_caps_new_empty ();
+
+ if (vdec->decfilter) {
+ CComPtr<IPin> output_pin;
+ CComPtr<IEnumMediaTypes> enum_mediatypes;
+ HRESULT hres;
+ ULONG fetched;
+
+ output_pin = gst_dshow_get_pin_from_filter (vdec->decfilter, PINDIR_OUTPUT);
+ if (!output_pin) {
+ GST_ELEMENT_ERROR (vdec, STREAM, FAILED,
+ ("failed getting ouput pin from the decoder"), (NULL));
+ goto beach;
+ }
+
+ hres = output_pin->EnumMediaTypes (&enum_mediatypes);
+ if (hres == S_OK && enum_mediatypes) {
+ AM_MEDIA_TYPE *mediatype = NULL;
+
+ enum_mediatypes->Reset();
+ while (hres =
+ enum_mediatypes->Next(1, &mediatype, &fetched),
+ hres == S_OK)
+ {
+ VIDEOINFOHEADER *video_info;
+ GstCaps *mediacaps = NULL;
+
+ /* RGB24 */
+ if (IsEqualGUID (mediatype->subtype, MEDIASUBTYPE_RGB24) &&
+ IsEqualGUID (mediatype->formattype, FORMAT_VideoInfo))
+ {
+ video_info = (VIDEOINFOHEADER *) mediatype->pbFormat;
+
+ /* ffmpegcolorspace handles RGB24 in BIG_ENDIAN */
+ mediacaps = gst_caps_new_simple ("video/x-raw-rgb",
+ "bpp", G_TYPE_INT, 24,
+ "depth", G_TYPE_INT, 24,
+ "width", G_TYPE_INT, video_info->bmiHeader.biWidth,
+ "height", G_TYPE_INT, video_info->bmiHeader.biHeight,
+ "framerate", GST_TYPE_FRACTION,
+ (int) (10000000 / video_info->AvgTimePerFrame), 1, "endianness",
+ G_TYPE_INT, G_BIG_ENDIAN, "red_mask", G_TYPE_INT, 255,
+ "green_mask", G_TYPE_INT, 65280, "blue_mask", G_TYPE_INT,
+ 16711680, NULL);
+
+ if (mediacaps) {
+ vdec->mediatypes = g_list_append (vdec->mediatypes, mediatype);
+ gst_caps_append (vdec->srccaps, mediacaps);
+ } else {
+ DeleteMediaType (mediatype);
+ }
+ } else {
+ DeleteMediaType (mediatype);
+ }
+
+ }
+ }
+ }
+
+ if (vdec->srccaps)
+ caps = gst_caps_ref (vdec->srccaps);
+
+beach:
+ gst_object_unref (vdec);
+
+ return caps;
+}
+
+static gboolean
+gst_dshowvideodec_src_setcaps (GstPad * pad, GstCaps * caps)
+{
+ gboolean ret = FALSE;
+
+ return ret;
+}
+
+static gboolean
+gst_dshowvideodec_flush (GstDshowVideoDec * vdec)
+{
+ if (!vdec->fakesrc)
+ return FALSE;
+
+ /* flush dshow decoder and reset timestamp */
+ vdec->fakesrc->GetOutputPin()->Flush();
+
+ return TRUE;
+}
+
+static gboolean
+gst_dshowvideodec_get_filter_output_format (GstDshowVideoDec * vdec,
+ const GUID subtype, VIDEOINFOHEADER ** format, guint * size)
+{
+ CComPtr<IPin> output_pin;
+ CComPtr<IEnumMediaTypes> enum_mediatypes;
+ HRESULT hres;
+ ULONG fetched;
+ BOOL ret = FALSE;
+
+ if (!vdec->decfilter)
+ return FALSE;
+
+ output_pin = gst_dshow_get_pin_from_filter (vdec->decfilter, PINDIR_OUTPUT);
+ if (!output_pin) {
+ GST_ELEMENT_ERROR (vdec, CORE, NEGOTIATION,
+ ("failed getting ouput pin from the decoder"), (NULL));
+ return FALSE;
+ }
+
+ hres = output_pin->EnumMediaTypes (&enum_mediatypes);
+ if (hres == S_OK && enum_mediatypes) {
+ AM_MEDIA_TYPE *mediatype = NULL;
+
+ enum_mediatypes->Reset();
+ while (hres =
+ enum_mediatypes->Next(1, &mediatype, &fetched),
+ hres == S_OK)
+ {
+ if (IsEqualGUID (mediatype->subtype, subtype) &&
+ IsEqualGUID (mediatype->formattype, FORMAT_VideoInfo))
+ {
+ *size = mediatype->cbFormat;
+ *format = (VIDEOINFOHEADER *)g_malloc0 (*size);
+ memcpy (*format, mediatype->pbFormat, *size);
+ ret = TRUE;
+ }
+ DeleteMediaType (mediatype);
+ if (ret)
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static gboolean
+gst_dshowvideodec_create_graph_and_filters (GstDshowVideoDec * vdec)
+{
+ HRESULT hres = S_FALSE;
+ GstDshowVideoDecClass *klass =
+ (GstDshowVideoDecClass *) G_OBJECT_GET_CLASS (vdec);
+ IBaseFilter *srcfilter = NULL;
+ IBaseFilter *sinkfilter = NULL;
+ gboolean ret = FALSE;
+
+ /* create the filter graph manager object */
+ hres = CoCreateInstance (CLSID_FilterGraph, NULL, CLSCTX_INPROC,
+ IID_IFilterGraph, (LPVOID *) & vdec->filtergraph);
+ if (hres != S_OK || !vdec->filtergraph) {
+ GST_ELEMENT_ERROR (vdec, STREAM, FAILED, ("Can't create an instance "
+ "of the directshow graph manager (error=%d)", hres), (NULL));
+ goto error;
+ }
+
+ hres = vdec->filtergraph->QueryInterface(IID_IMediaFilter,
+ (void **) &vdec->mediafilter);
+ if (hres != S_OK || !vdec->mediafilter) {
+ GST_ELEMENT_ERROR (vdec, STREAM, FAILED,
+ ("Can't get IMediacontrol interface "
+ "from the graph manager (error=%d)", hres), (NULL));
+ goto error;
+ }
+
+ /* create fake src filter */
+ vdec->fakesrc = new FakeSrc();
+ /* Created with a refcount of zero, so increment that */
+ vdec->fakesrc->AddRef();
+
+ hres = vdec->fakesrc->QueryInterface(IID_IBaseFilter,
+ (void **) &srcfilter);
+ if (FAILED (hres)) {
+ GST_WARNING_OBJECT (vdec, "Failed to QI fakesrc to IBaseFilter");
+ goto error;
+ }
+
+ /* search a decoder filter and create it */
+ if (!gst_dshow_find_filter (klass->entry->input_majortype,
+ klass->entry->input_subtype,
+ klass->entry->output_majortype,
+ klass->entry->output_subtype,
+ klass->entry->preferred_filter_substring, &vdec->decfilter)) {
+ GST_ELEMENT_ERROR (vdec, STREAM, FAILED, ("Can't create an instance "
+ "of the decoder filter"), (NULL));
+ goto error;
+ }
+
+ /* create fake sink filter */
+ vdec->fakesink = new VideoFakeSink(vdec);
+ /* Created with a refcount of zero, so increment that */
+ vdec->fakesink->AddRef();
+
+ hres = vdec->fakesink->QueryInterface(IID_IBaseFilter,
+ (void **) &sinkfilter);
+ if (FAILED (hres)) {
+ GST_WARNING_OBJECT (vdec, "Failed to QI fakesink to IBaseFilter");
+ goto error;
+ }
+
+ /* add filters to the graph */
+ hres = vdec->filtergraph->AddFilter (srcfilter, L"src");
+ if (hres != S_OK) {
+ GST_ELEMENT_ERROR (vdec, STREAM, FAILED, ("Can't add fakesrc filter "
+ "to the graph (error=%d)", hres), (NULL));
+ goto error;
+ }
+
+ hres = vdec->filtergraph->AddFilter(vdec->decfilter, L"decoder");
+ if (hres != S_OK) {
+ GST_ELEMENT_ERROR (vdec, STREAM, FAILED, ("Can't add decoder filter "
+ "to the graph (error=%d)", hres), (NULL));
+ goto error;
+ }
+
+ hres = vdec->filtergraph->AddFilter(sinkfilter, L"sink");
+ if (hres != S_OK) {
+ GST_ELEMENT_ERROR (vdec, STREAM, FAILED, ("Can't add fakesink filter "
+ "to the graph (error=%d)", hres), (NULL));
+ goto error;
+ }
+
+ vdec->setup = TRUE;
+
+ ret = TRUE;
+
+done:
+ if (srcfilter)
+ srcfilter->Release();
+ if (sinkfilter)
+ sinkfilter->Release();
+ return ret;
+
+error:
+ if (vdec->fakesrc) {
+ vdec->fakesrc->Release();
+ vdec->fakesrc = NULL;
+ }
+ if (vdec->decfilter) {
+ vdec->decfilter->Release();
+ vdec->decfilter = NULL;
+ }
+ if (vdec->fakesink) {
+ vdec->fakesink->Release();
+ vdec->fakesink = NULL;
+ }
+ if (vdec->mediafilter) {
+ vdec->mediafilter->Release();
+ vdec->mediafilter = NULL;
+ }
+ if (vdec->filtergraph) {
+ vdec->filtergraph->Release();
+ vdec->filtergraph = NULL;
+ }
+
+ goto done;
+}
+
+static gboolean
+gst_dshowvideodec_destroy_graph_and_filters (GstDshowVideoDec * vdec)
+{
+ HRESULT hres;
+
+ if (vdec->mediafilter) {
+ vdec->mediafilter->Stop();
+ }
+
+ if (vdec->fakesrc) {
+ if (vdec->filtergraph) {
+ IBaseFilter *filter;
+ hres = vdec->fakesrc->QueryInterface(IID_IBaseFilter,
+ (void **) &filter);
+ if (SUCCEEDED (hres)) {
+ vdec->filtergraph->RemoveFilter(filter);
+ filter->Release();
+ }
+ }
+
+ vdec->fakesrc->Release();
+ vdec->fakesrc = NULL;
+ }
+ if (vdec->decfilter) {
+ if (vdec->filtergraph)
+ vdec->filtergraph->RemoveFilter(vdec->decfilter);
+ vdec->decfilter->Release();
+ vdec->decfilter = NULL;
+ }
+ if (vdec->fakesink) {
+ if (vdec->filtergraph) {
+ IBaseFilter *filter;
+ hres = vdec->fakesink->QueryInterface(IID_IBaseFilter,
+ (void **) &filter);
+ if (SUCCEEDED (hres)) {
+ vdec->filtergraph->RemoveFilter(filter);
+ filter->Release();
+ }
+ }
+
+ vdec->fakesink->Release();
+ vdec->fakesink = NULL;
+ }
+ if (vdec->mediafilter) {
+ vdec->mediafilter->Release();
+ vdec->mediafilter = NULL;
+ }
+ if (vdec->filtergraph) {
+ vdec->filtergraph->Release();
+ vdec->filtergraph = NULL;
+ }
+
+ vdec->setup = FALSE;
+
+ return TRUE;
+}
+
+gboolean
+dshow_vdec_register (GstPlugin * plugin)
+{
+ GTypeInfo info = {
+ sizeof (GstDshowVideoDecClass),
+ (GBaseInitFunc) gst_dshowvideodec_base_init,
+ NULL,
+ (GClassInitFunc) gst_dshowvideodec_class_init,
+ NULL,
+ NULL,
+ sizeof (GstDshowVideoDec),
+ 0,
+ (GInstanceInitFunc) gst_dshowvideodec_init,
+ };
+ gint i;
+ HRESULT hr;
+
+ GST_DEBUG_CATEGORY_INIT (dshowvideodec_debug, "dshowvideodec", 0,
+ "Directshow filter video decoder");
+
+ hr = CoInitialize (0);
+
+ for (i = 0; i < sizeof (video_dec_codecs) / sizeof (VideoCodecEntry); i++) {
+ GType type;
+
+ if (gst_dshow_find_filter (video_dec_codecs[i].input_majortype,
+ video_dec_codecs[i].input_subtype,
+ video_dec_codecs[i].output_majortype,
+ video_dec_codecs[i].output_subtype,
+ video_dec_codecs[i].preferred_filter_substring, NULL)) {
+
+ GST_CAT_DEBUG (dshowvideodec_debug, "Registering %s",
+ video_dec_codecs[i].element_name);
+
+ tmp = &video_dec_codecs[i];
+ type =
+ g_type_register_static (GST_TYPE_ELEMENT,
+ video_dec_codecs[i].element_name, &info, (GTypeFlags)0);
+ if (!gst_element_register (plugin, video_dec_codecs[i].element_name,
+ GST_RANK_PRIMARY, type)) {
+ return FALSE;
+ }
+ GST_CAT_DEBUG (dshowvideodec_debug, "Registered %s",
+ video_dec_codecs[i].element_name);
+ } else {
+ GST_CAT_DEBUG (dshowvideodec_debug,
+ "Element %s not registered (the format is not supported by the system)",
+ video_dec_codecs[i].element_name);
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ CoUninitialize ();
+
+ return TRUE;
+}
diff --git a/sys/dshowdecwrapper/gstdshowvideodec.h b/sys/dshowdecwrapper/gstdshowvideodec.h
index 0ab7a5d71..29953d82d 100644
--- a/sys/dshowdecwrapper/gstdshowvideodec.h
+++ b/sys/dshowdecwrapper/gstdshowvideodec.h
@@ -47,10 +47,24 @@
#define __GST_DSHOWVIDEODEC_H__
#include <gst/gst.h>
-#include "gstdshowdecwrapper.h"
+#include "gstdshowutil.h"
+#include "gstdshowfakesrc.h"
G_BEGIN_DECLS
+typedef struct {
+ gchar *element_name; /* The gst element factory name */
+ gchar *element_longname; /* Description string for element */
+ gchar *preferred_filter_substring; /* TODO: Remove this? */
+ gint32 format; /* ??? */
+ GUID input_majortype;
+ GUID input_subtype;
+ gchar *sinkcaps; /* GStreamer caps of input format */
+ GUID output_majortype;
+ GUID output_subtype;
+ gchar *srccaps;
+} VideoCodecEntry;
+
#define GST_TYPE_DSHOWVIDEODEC (gst_dshowvideodec_get_type())
#define GST_DSHOWVIDEODEC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DSHOWVIDEODEC,GstDshowVideoDec))
#define GST_DSHOWVIDEODEC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DSHOWVIDEODEC,GstDshowVideoDecClass))
@@ -60,6 +74,8 @@ G_BEGIN_DECLS
typedef struct _GstDshowVideoDec GstDshowVideoDec;
typedef struct _GstDshowVideoDecClass GstDshowVideoDecClass;
+class VideoFakeSink;
+
struct _GstDshowVideoDec
{
GstElement element;
@@ -77,10 +93,10 @@ struct _GstDshowVideoDec
GList *mediatypes;
/* filters interfaces */
- IBaseFilter *srcfilter;
- IGstDshowInterface *gstdshowsrcfilter;
+ FakeSrc *fakesrc;
+ VideoFakeSink *fakesink;
+
IBaseFilter *decfilter;
- IBaseFilter *sinkfilter;
/* graph manager interfaces */
IMediaFilter *mediafilter;
@@ -93,17 +109,47 @@ struct _GstDshowVideoDec
/* current segment */
GstSegment *segment;
+ gboolean setup;
+
gboolean comInitialized;
};
struct _GstDshowVideoDecClass
{
GstElementClass parent_class;
- const CodecEntry *entry;
+ const VideoCodecEntry *entry;
};
gboolean dshow_vdec_register (GstPlugin * plugin);
+const GUID CLSID_VideoFakeSink =
+{ 0xff8f0c8e, 0x64f9, 0x4471,
+ { 0x96, 0x0e, 0xd2, 0xd3, 0x18, 0x87, 0x78, 0x9a} };
+
+class VideoFakeSink : public CBaseRenderer
+{
+public:
+ VideoFakeSink(GstDshowVideoDec *dec) :
+ m_hres(S_OK),
+ CBaseRenderer(CLSID_VideoFakeSink, L"VideoFakeSink", NULL, &m_hres),
+ mDec(dec)
+ {};
+ virtual ~VideoFakeSink() {};
+
+ HRESULT DoRenderSample(IMediaSample *pMediaSample);
+ HRESULT CheckMediaType(const CMediaType *pmt);
+ HRESULT SetMediaType (AM_MEDIA_TYPE *pmt)
+ {
+ m_MediaType.Set (*pmt);
+ return S_OK;
+ }
+
+protected:
+ HRESULT m_hres;
+ CMediaType m_MediaType;
+ GstDshowVideoDec *mDec;
+};
+
G_END_DECLS
#endif /* __GST_DSHOWVIDEODEC_H__ */