1 /*
2 * GStreamer DirectShow codecs wrapper
3 * Copyright <2006, 2007, 2008, 2009, 2010> Fluendo <support@fluendo.com>
4 * Copyright <2006, 2007, 2008> Pioneers of the Inevitable <songbird@songbirdnest.com>
5 * Copyright <2007,2008> Sebastien Moutte <sebastien@moutte.net>
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 *
25 * Alternatively, the contents of this file may be used under the
26 * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
27 * which case the following provisions apply instead of the ones
28 * mentioned above:
29 *
30 * This library is free software; you can redistribute it and/or
31 * modify it under the terms of the GNU Library General Public
32 * License as published by the Free Software Foundation; either
33 * version 2 of the License, or (at your option) any later version.
34 *
35 * This library is distributed in the hope that it will be useful,
36 * but WITHOUT ANY WARRANTY; without even the implied warranty of
37 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
38 * Library General Public License for more details.
39 *
40 * You should have received a copy of the GNU Library General Public
41 * License along with this library; if not, write to the
42 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
43 * Boston, MA 02110-1301, USA.
44 */
45
46 #ifdef HAVE_CONFIG_H
47 #include "config.h"
48 #endif
49
50 #include "gstdshowaudiodec.h"
51 #include <mmreg.h>
52 #include <dmoreg.h>
53 #include <wmcodecdsp.h>
54 #include <gst/audio/audio.h>
55
56 GST_DEBUG_CATEGORY_STATIC (dshowaudiodec_debug);
57 #define GST_CAT_DEFAULT dshowaudiodec_debug
58
59 #define gst_dshowaudiodec_parent_class parent_class
60 G_DEFINE_TYPE(GstDshowAudioDec, gst_dshowaudiodec, GST_TYPE_ELEMENT)
61
62 static void gst_dshowaudiodec_finalize (GObject * object);
63 static GstStateChangeReturn gst_dshowaudiodec_change_state
64 (GstElement * element, GstStateChange transition);
65
66 /* sink pad overwrites */
67 static gboolean gst_dshowaudiodec_sink_setcaps (GstPad * pad, GstCaps * caps);
68 static GstFlowReturn gst_dshowaudiodec_chain (GstPad * pad, GstObject *parent, GstBuffer * buffer);
69 static gboolean gst_dshowaudiodec_sink_event (GstPad * pad, GstObject *parent, GstEvent * event);
70
71 /* utils */
72 static gboolean gst_dshowaudiodec_create_graph_and_filters (GstDshowAudioDec *
73 adec);
74 static gboolean gst_dshowaudiodec_destroy_graph_and_filters (GstDshowAudioDec *
75 adec);
76 static gboolean gst_dshowaudiodec_flush (GstDshowAudioDec * adec);
77 static gboolean gst_dshowaudiodec_get_filter_settings (GstDshowAudioDec * adec);
78 static gboolean gst_dshowaudiodec_setup_graph (GstDshowAudioDec * adec, GstCaps *caps);
79
80 /* All the GUIDs we want are generated from the FOURCC like this */
81 #define GUID_MEDIASUBTYPE_FROM_FOURCC(fourcc) \
82 { fourcc , 0x0000, 0x0010, \
83 { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }}
84
85 /* WMA we should always use the DMO */
86 static PreferredFilter preferred_wma_filters[] = {
87 {&CLSID_CWMADecMediaObject, &DMOCATEGORY_AUDIO_DECODER},
88 {0}
89 };
90
91 /* Prefer the Vista (DMO) decoder if present, otherwise the XP
92 * decoder (not a DMO), otherwise fallback to highest-merit */
93 static const GUID CLSID_XP_MP3_DECODER = {0x38BE3000, 0xDBF4, 0x11D0,
94 {0x86,0x0E,0x00,0xA0,0x24,0xCF,0xEF,0x6D}};
95 static PreferredFilter preferred_mp3_filters[] = {
96 {&CLSID_CMP3DecMediaObject, &DMOCATEGORY_AUDIO_DECODER},
97 {&CLSID_XP_MP3_DECODER},
98 {0}
99 };
100
101 /* MPEG 1/2: use the MPEG Audio Decoder filter */
102 static const GUID CLSID_WINDOWS_MPEG_AUDIO_DECODER =
103 {0x4A2286E0, 0x7BEF, 0x11CE,
104 {0x9B, 0xD9, 0x00, 0x00, 0xE2, 0x02, 0x59, 0x9C}};
105 static PreferredFilter preferred_mpegaudio_filters[] = {
106 {&CLSID_WINDOWS_MPEG_AUDIO_DECODER},
107 {0}
108 };
109
110 static const AudioCodecEntry audio_dec_codecs[] = {
111 {"dshowadec_wma1", "Windows Media Audio 7",
112 WAVE_FORMAT_MSAUDIO1,
113 "audio/x-wma, wmaversion = (int) 1",
114 preferred_wma_filters},
115
116 {"dshowadec_wma2", "Windows Media Audio 8",
117 WAVE_FORMAT_WMAUDIO2,
118 "audio/x-wma, wmaversion = (int) 2",
119 preferred_wma_filters},
120
121 {"dshowadec_wma3", "Windows Media Audio 9 Professional",
122 WAVE_FORMAT_WMAUDIO3,
123 "audio/x-wma, wmaversion = (int) 3",
124 preferred_wma_filters},
125
126 {"dshowadec_wma4", "Windows Media Audio 9 Lossless",
127 WAVE_FORMAT_WMAUDIO_LOSSLESS,
128 "audio/x-wma, wmaversion = (int) 4",
129 preferred_wma_filters},
130
131 {"dshowadec_wms", "Windows Media Audio Voice v9",
132 WAVE_FORMAT_WMAVOICE9,
133 "audio/x-wms",
134 preferred_wma_filters},
135
136 {"dshowadec_mp3", "MPEG Layer 3 Audio",
137 WAVE_FORMAT_MPEGLAYER3,
138 "audio/mpeg, "
139 "mpegversion = (int) 1, "
140 "layer = (int)3, "
141 "rate = (int) [ 8000, 48000 ], "
142 "channels = (int) [ 1, 2 ], "
143 "parsed= (boolean) true",
144 preferred_mp3_filters},
145
146 {"dshowadec_mpeg_1_2", "MPEG Layer 1,2 Audio",
147 WAVE_FORMAT_MPEG,
148 "audio/mpeg, "
149 "mpegversion = (int) 1, "
150 "layer = (int) [ 1, 2 ], "
151 "rate = (int) [ 8000, 48000 ], "
152 "channels = (int) [ 1, 2 ], "
153 "parsed= (boolean) true",
154 preferred_mpegaudio_filters},
155 };
156
DoRenderSample(IMediaSample * pMediaSample)157 HRESULT AudioFakeSink::DoRenderSample(IMediaSample *pMediaSample)
158 {
159 GstBuffer *out_buf = NULL;
160 gboolean in_seg = FALSE;
161 GstClockTime buf_start, buf_stop;
162 guint64 clip_start = 0, clip_stop = 0;
163 guint start_offset = 0, stop_offset;
164 GstClockTime duration;
165
166 if(pMediaSample)
167 {
168 BYTE *pBuffer = NULL;
169 LONGLONG lStart = 0, lStop = 0;
170 long size = pMediaSample->GetActualDataLength();
171
172 pMediaSample->GetPointer(&pBuffer);
173 pMediaSample->GetTime(&lStart, &lStop);
174
175 if (!GST_CLOCK_TIME_IS_VALID (mDec->timestamp)) {
176 // Convert REFERENCE_TIME to GST_CLOCK_TIME
177 mDec->timestamp = (GstClockTime)lStart * 100;
178 }
179 duration = (lStop - lStart) * 100;
180
181 buf_start = mDec->timestamp;
182 buf_stop = mDec->timestamp + duration;
183
184 /* save stop position to start next buffer with it */
185 mDec->timestamp = buf_stop;
186
187 /* check if this buffer is in our current segment */
188 in_seg = gst_segment_clip (mDec->segment, GST_FORMAT_TIME,
189 buf_start, buf_stop, &clip_start, &clip_stop);
190
191 /* if the buffer is out of segment do not push it downstream */
192 if (!in_seg) {
193 GST_DEBUG_OBJECT (mDec,
194 "buffer is out of segment, start %" GST_TIME_FORMAT " stop %"
195 GST_TIME_FORMAT, GST_TIME_ARGS (buf_start), GST_TIME_ARGS (buf_stop));
196 goto done;
197 }
198
199 /* buffer is entirely or partially in-segment, so allocate a
200 * GstBuffer for output, and clip if required */
201
202 /* allocate a new buffer for raw audio */
203 out_buf = gst_buffer_new_and_alloc(size);
204 if (!out_buf) {
205 GST_WARNING_OBJECT (mDec, "cannot allocate a new GstBuffer");
206 goto done;
207 }
208
209 /* set buffer properties */
210 GST_BUFFER_TIMESTAMP (out_buf) = buf_start;
211 GST_BUFFER_DURATION (out_buf) = duration;
212
213 if (gst_buffer_fill(out_buf, 0, pBuffer, size) != size) {
214 gst_buffer_unref (out_buf);
215 GST_WARNING_OBJECT (mDec, "unable to fill output buffer");
216 goto done;
217 }
218
219 /* we have to remove some heading samples */
220 if ((GstClockTime) clip_start > buf_start) {
221 start_offset = (guint)gst_util_uint64_scale_int (clip_start - buf_start,
222 mDec->rate, GST_SECOND) * mDec->depth / 8 * mDec->channels;
223 }
224 else
225 start_offset = 0;
226 /* we have to remove some trailing samples */
227 if ((GstClockTime) clip_stop < buf_stop) {
228 stop_offset = (guint)gst_util_uint64_scale_int (buf_stop - clip_stop,
229 mDec->rate, GST_SECOND) * mDec->depth / 8 * mDec->channels;
230 }
231 else
232 stop_offset = size;
233
234 /* truncating */
235 if ((start_offset != 0) || (stop_offset != (size_t) size)) {
236
237 GstBuffer *subbuf = gst_buffer_copy_region (out_buf, GST_BUFFER_COPY_ALL,
238 start_offset, stop_offset - start_offset);
239
240 if (subbuf) {
241 gst_buffer_unref (out_buf);
242 out_buf = subbuf;
243 }
244 }
245
246 GST_BUFFER_TIMESTAMP (out_buf) = clip_start;
247 GST_BUFFER_DURATION (out_buf) = clip_stop - clip_start;
248
249 /* replace the saved stop position by the clipped one */
250 mDec->timestamp = clip_stop;
251
252 GST_DEBUG_OBJECT (mDec,
253 "push_buffer (size %d)=> pts %" GST_TIME_FORMAT " stop %" GST_TIME_FORMAT
254 " duration %" GST_TIME_FORMAT, size,
255 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (out_buf)),
256 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (out_buf) +
257 GST_BUFFER_DURATION (out_buf)),
258 GST_TIME_ARGS (GST_BUFFER_DURATION (out_buf)));
259
260 mDec->last_ret = gst_pad_push (mDec->srcpad, out_buf);
261 }
262
263 done:
264 return S_OK;
265 }
266
CheckMediaType(const CMediaType * pmt)267 HRESULT AudioFakeSink::CheckMediaType(const CMediaType *pmt)
268 {
269 if(pmt != NULL)
270 {
271 /* The Vista MP3 decoder (and possibly others?) outputs an
272 * AM_MEDIA_TYPE with the wrong cbFormat. So, rather than using
273 * CMediaType.operator==, we implement a sufficient check ourselves.
274 * I think this is a bug in the MP3 decoder.
275 */
276 if (IsEqualGUID (pmt->majortype, m_MediaType.majortype) &&
277 IsEqualGUID (pmt->subtype, m_MediaType.subtype) &&
278 IsEqualGUID (pmt->formattype, m_MediaType.formattype))
279 {
280 /* Types are the same at the top-level. Now, we need to compare
281 * the format blocks.
282 * We special case WAVEFORMATEX to not check that
283 * pmt->cbFormat == m_MediaType.cbFormat, though the actual format
284 * blocks must still be the same.
285 */
286 if (pmt->formattype == FORMAT_WaveFormatEx) {
287 if (pmt->cbFormat >= sizeof (WAVEFORMATEX) &&
288 m_MediaType.cbFormat >= sizeof (WAVEFORMATEX))
289 {
290 WAVEFORMATEX *wf1 = (WAVEFORMATEX *)pmt->pbFormat;
291 WAVEFORMATEX *wf2 = (WAVEFORMATEX *)m_MediaType.pbFormat;
292 if (wf1->cbSize == wf2->cbSize &&
293 memcmp (wf1, wf2, sizeof(WAVEFORMATEX) + wf1->cbSize) == 0)
294 return S_OK;
295 }
296 }
297 else {
298 if (pmt->cbFormat == m_MediaType.cbFormat &&
299 pmt->cbFormat == 0 ||
300 (pmt->pbFormat != NULL && m_MediaType.pbFormat != NULL &&
301 memcmp (pmt->pbFormat, m_MediaType.pbFormat, pmt->cbFormat) == 0))
302 return S_OK;
303 }
304 }
305 }
306
307 return S_FALSE;
308 }
309
GetBufferSize()310 int AudioFakeSink::GetBufferSize()
311 {
312 IMemAllocator *allocator = NULL;
313 if (m_pInputPin) {
314 allocator = m_pInputPin->Allocator();
315 if(allocator) {
316 ALLOCATOR_PROPERTIES props;
317 allocator->GetProperties(&props);
318 return props.cbBuffer;
319 }
320 }
321
322 return 0;
323 }
324
325 static void
gst_dshowaudiodec_base_init(gpointer klass)326 gst_dshowaudiodec_base_init (gpointer klass)
327 {
328 GstDshowAudioDecClass *audiodec_class = (GstDshowAudioDecClass *) klass;
329 GstPadTemplate *src, *sink;
330 GstCaps *srccaps, *sinkcaps;
331 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
332 const AudioCodecEntry *tmp;
333 gpointer qdata;
334 gchar *longname, *description;
335
336 qdata = g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass), DSHOW_CODEC_QDATA);
337
338 /* element details */
339 tmp = audiodec_class->entry = (AudioCodecEntry *) qdata;
340
341 longname = g_strdup_printf ("DirectShow %s Decoder Wrapper",
342 tmp->element_longname);
343 description = g_strdup_printf ("DirectShow %s Decoder Wrapper",
344 tmp->element_longname);
345
346 gst_element_class_set_metadata(element_class, longname, "Codec/Decoder/Audio", description,
347 "Sebastien Moutte <sebastien@moutte.net>");
348
349 g_free (longname);
350 g_free (description);
351
352 sinkcaps = gst_caps_from_string (tmp->sinkcaps);
353
354 srccaps = gst_caps_from_string (
355 "audio/x-raw,"
356 "format = (string)" GST_AUDIO_FORMATS_ALL ","
357 "rate = (int)[1, MAX],"
358 "channels = (int)[1, MAX],"
359 "layout = (string)interleaved");
360
361 sink = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, sinkcaps);
362 src = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, srccaps);
363
364 /* register */
365 gst_element_class_add_pad_template (element_class, src);
366 gst_element_class_add_pad_template (element_class, sink);
367
368 if (sinkcaps)
369 gst_caps_unref(sinkcaps);
370
371 if (srccaps)
372 gst_caps_unref(srccaps);
373 }
374
375 static void
gst_dshowaudiodec_class_init(GstDshowAudioDecClass * klass)376 gst_dshowaudiodec_class_init (GstDshowAudioDecClass * klass)
377 {
378 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
379 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
380
381 gobject_class->finalize = gst_dshowaudiodec_finalize;
382
383 gstelement_class->change_state =
384 GST_DEBUG_FUNCPTR (gst_dshowaudiodec_change_state);
385
386 parent_class = (GstElementClass *) g_type_class_peek_parent (klass);
387 }
388
389 static void
gst_dshowaudiodec_com_thread(GstDshowAudioDec * adec)390 gst_dshowaudiodec_com_thread (GstDshowAudioDec * adec)
391 {
392 HRESULT res;
393
394 g_mutex_lock (&adec->com_init_lock);
395
396 /* Initialize COM with a MTA for this process. This thread will
397 * be the first one to enter the apartement and the last one to leave
398 * it, unitializing COM properly */
399
400 res = CoInitializeEx (0, COINIT_MULTITHREADED);
401 if (res == S_FALSE)
402 GST_WARNING_OBJECT (adec, "COM has been already initialized in the same process");
403 else if (res == RPC_E_CHANGED_MODE)
404 GST_WARNING_OBJECT (adec, "The concurrency model of COM has changed.");
405 else
406 GST_INFO_OBJECT (adec, "COM initialized successfully");
407
408 adec->comInitialized = TRUE;
409
410 /* Signal other threads waiting on this condition that COM was initialized */
411 g_cond_signal (&adec->com_initialized);
412
413 g_mutex_unlock (&adec->com_init_lock);
414
415 /* Wait until the uninitialize condition is met to leave the COM apartement */
416 g_mutex_lock (&adec->com_deinit_lock);
417 g_cond_wait (&adec->com_uninitialize, &adec->com_deinit_lock);
418
419 CoUninitialize ();
420 GST_INFO_OBJECT (adec, "COM uninitialized successfully");
421 adec->comInitialized = FALSE;
422 g_cond_signal (&adec->com_uninitialized);
423 g_mutex_unlock (&adec->com_deinit_lock);
424 }
425
426 static void
gst_dshowaudiodec_init(GstDshowAudioDec * adec)427 gst_dshowaudiodec_init (GstDshowAudioDec * adec)
428 {
429 GstElementClass *element_class = GST_ELEMENT_GET_CLASS (adec);
430
431 /* setup pads */
432 adec->sinkpad =
433 gst_pad_new_from_template (gst_element_class_get_pad_template
434 (element_class, "sink"), "sink");
435
436 gst_pad_set_event_function (adec->sinkpad, gst_dshowaudiodec_sink_event);
437 gst_pad_set_chain_function (adec->sinkpad, gst_dshowaudiodec_chain);
438 gst_element_add_pad (GST_ELEMENT (adec), adec->sinkpad);
439
440 adec->srcpad =
441 gst_pad_new_from_template (gst_element_class_get_pad_template
442 (element_class, "src"), "src");
443 gst_element_add_pad (GST_ELEMENT (adec), adec->srcpad);
444
445 adec->fakesrc = NULL;
446 adec->fakesink = NULL;
447
448 adec->decfilter = 0;
449 adec->filtergraph = 0;
450 adec->mediafilter = 0;
451
452 adec->timestamp = GST_CLOCK_TIME_NONE;
453 adec->segment = gst_segment_new ();
454 adec->setup = FALSE;
455 adec->depth = 0;
456 adec->bitrate = 0;
457 adec->block_align = 0;
458 adec->channels = 0;
459 adec->rate = 0;
460 adec->layer = 0;
461 adec->codec_data = NULL;
462
463 adec->last_ret = GST_FLOW_OK;
464
465 g_mutex_init(&adec->com_init_lock);
466 g_mutex_init(&adec->com_deinit_lock);
467 g_cond_init(&adec->com_initialized);
468 g_cond_init(&adec->com_uninitialize);
469 g_cond_init(&adec->com_uninitialized);
470
471 g_mutex_lock (&adec->com_init_lock);
472
473 /* create the COM initialization thread */
474 g_thread_new ("COM init thread", (GThreadFunc)gst_dshowaudiodec_com_thread,
475 adec);
476
477 /* wait until the COM thread signals that COM has been initialized */
478 g_cond_wait (&adec->com_initialized, &adec->com_init_lock);
479 g_mutex_unlock (&adec->com_init_lock);
480 }
481
482 static void
gst_dshowaudiodec_finalize(GObject * object)483 gst_dshowaudiodec_finalize (GObject * object)
484 {
485 GstDshowAudioDec *adec = (GstDshowAudioDec *) (object);
486
487 if (adec->segment) {
488 gst_segment_free (adec->segment);
489 adec->segment = NULL;
490 }
491
492 if (adec->codec_data) {
493 gst_buffer_unref (adec->codec_data);
494 adec->codec_data = NULL;
495 }
496
497 /* signal the COM thread that it sould uninitialize COM */
498 if (adec->comInitialized) {
499 g_mutex_lock (&adec->com_deinit_lock);
500 g_cond_signal (&adec->com_uninitialize);
501 g_cond_wait (&adec->com_uninitialized, &adec->com_deinit_lock);
502 g_mutex_unlock (&adec->com_deinit_lock);
503 }
504
505 g_mutex_clear (&adec->com_init_lock);
506 g_mutex_clear (&adec->com_deinit_lock);
507 g_cond_clear (&adec->com_initialized);
508 g_cond_clear (&adec->com_uninitialize);
509 g_cond_clear (&adec->com_uninitialized);
510
511 G_OBJECT_CLASS (parent_class)->finalize (object);
512 }
513
514
515 static GstStateChangeReturn
gst_dshowaudiodec_change_state(GstElement * element,GstStateChange transition)516 gst_dshowaudiodec_change_state (GstElement * element, GstStateChange transition)
517 {
518 GstDshowAudioDec *adec = (GstDshowAudioDec *) (element);
519
520 switch (transition) {
521 case GST_STATE_CHANGE_NULL_TO_READY:
522 if (!gst_dshowaudiodec_create_graph_and_filters (adec))
523 return GST_STATE_CHANGE_FAILURE;
524 break;
525 case GST_STATE_CHANGE_READY_TO_PAUSED:
526 break;
527 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
528 break;
529 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
530 break;
531 case GST_STATE_CHANGE_PAUSED_TO_READY:
532 adec->depth = 0;
533 adec->bitrate = 0;
534 adec->block_align = 0;
535 adec->channels = 0;
536 adec->rate = 0;
537 adec->layer = 0;
538 if (adec->codec_data) {
539 gst_buffer_unref (adec->codec_data);
540 adec->codec_data = NULL;
541 }
542 break;
543 case GST_STATE_CHANGE_READY_TO_NULL:
544 if (!gst_dshowaudiodec_destroy_graph_and_filters (adec))
545 return GST_STATE_CHANGE_FAILURE;
546 break;
547 default:
548 break;
549 }
550
551 return GST_ELEMENT_CLASS(parent_class)->change_state (element, transition);
552 }
553
554 static gboolean
gst_dshowaudiodec_sink_setcaps(GstPad * pad,GstCaps * caps)555 gst_dshowaudiodec_sink_setcaps (GstPad * pad, GstCaps * caps)
556 {
557 gboolean ret = FALSE;
558 GstDshowAudioDec *adec = (GstDshowAudioDec *) gst_pad_get_parent (pad);
559 GstStructure *s = gst_caps_get_structure (caps, 0);
560 const GValue *v = NULL;
561
562 adec->timestamp = GST_CLOCK_TIME_NONE;
563
564 /* read data, only rate and channels are needed */
565 if (!gst_structure_get_int (s, "rate", &adec->rate) ||
566 !gst_structure_get_int (s, "channels", &adec->channels)) {
567 GST_ELEMENT_ERROR (adec, CORE, NEGOTIATION,
568 ("error getting audio specs from caps"), (NULL));
569 goto end;
570 }
571
572 gst_structure_get_int (s, "depth", &adec->depth);
573 gst_structure_get_int (s, "bitrate", &adec->bitrate);
574 gst_structure_get_int (s, "block_align", &adec->block_align);
575 gst_structure_get_int (s, "layer", &adec->layer);
576
577 if (adec->codec_data) {
578 gst_buffer_unref (adec->codec_data);
579 adec->codec_data = NULL;
580 }
581
582 if ((v = gst_structure_get_value (s, "codec_data")))
583 adec->codec_data = gst_buffer_ref (gst_value_get_buffer (v));
584
585 ret = gst_dshowaudiodec_setup_graph (adec, caps);
586 end:
587 gst_object_unref (adec);
588
589 return ret;
590 }
591
592 static GstFlowReturn
gst_dshowaudiodec_chain(GstPad * pad,GstObject * parent,GstBuffer * buffer)593 gst_dshowaudiodec_chain (GstPad *pad, GstObject *parent, GstBuffer *buffer)
594 {
595 GstDshowAudioDec *adec = (GstDshowAudioDec *) gst_pad_get_parent (pad);
596 GstMapInfo map;
597 bool discont = FALSE;
598
599 if (!adec->setup) {
600 /* we are not set up */
601 GST_WARNING_OBJECT (adec, "Decoder not set up, failing");
602 adec->last_ret = GST_FLOW_FLUSHING;
603 goto beach;
604 }
605
606 if (adec->last_ret != GST_FLOW_OK) {
607 GST_DEBUG_OBJECT (adec, "last decoding iteration generated a fatal error "
608 "%s", gst_flow_get_name (adec->last_ret));
609 goto beach;
610 }
611
612 GST_CAT_DEBUG_OBJECT (dshowaudiodec_debug, adec, "chain (size %d)=> pts %"
613 GST_TIME_FORMAT " stop %" GST_TIME_FORMAT,
614 gst_buffer_get_size(buffer), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
615 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer) +
616 GST_BUFFER_DURATION (buffer)));
617
618 /* if the incoming buffer has discont flag set => flush decoder data */
619 if (buffer && GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
620 GST_CAT_DEBUG_OBJECT (dshowaudiodec_debug, adec,
621 "this buffer has a DISCONT flag (%" GST_TIME_FORMAT "), flushing",
622 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
623 gst_dshowaudiodec_flush (adec);
624 discont = TRUE;
625 }
626
627 /* push the buffer to the directshow decoder */
628 gst_buffer_map(buffer, &map, GST_MAP_READ);
629 adec->fakesrc->GetOutputPin()->PushBuffer (
630 map.data, GST_BUFFER_TIMESTAMP (buffer),
631 GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer),
632 map.size, (bool)discont);
633 gst_buffer_unmap(buffer, &map);
634
635 beach:
636 gst_buffer_unref (buffer);
637 gst_object_unref (adec);
638 return adec->last_ret;
639 }
640
641 static gboolean
gst_dshowaudiodec_sink_event(GstPad * pad,GstObject * parent,GstEvent * event)642 gst_dshowaudiodec_sink_event (GstPad * pad, GstObject *parent, GstEvent * event)
643 {
644 gboolean ret = TRUE;
645 GstDshowAudioDec *adec = (GstDshowAudioDec *) parent;
646
647 switch (GST_EVENT_TYPE (event)) {
648 case GST_EVENT_CAPS:{
649 GstCaps *caps;
650 gst_event_parse_caps(event, &caps);
651 ret = gst_dshowaudiodec_sink_setcaps(pad, caps);
652 break;
653 }
654
655 case GST_EVENT_FLUSH_STOP:{
656 gst_dshowaudiodec_flush (adec);
657 ret = gst_pad_event_default (pad, parent, event);
658 break;
659 }
660
661 case GST_EVENT_SEGMENT:{
662 const GstSegment *segment;
663 gst_event_parse_segment (event, &segment);
664
665 GST_CAT_DEBUG_OBJECT (dshowaudiodec_debug, adec,
666 "received new segment from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
667 GST_TIME_ARGS (segment->start), GST_TIME_ARGS (segment->stop));
668
669 /* save the new segment in our local current segment */
670 gst_segment_copy_into(segment, adec->segment);
671
672 ret = gst_pad_event_default (pad, parent, event);
673 break;
674 }
675
676 default:
677 ret = gst_pad_event_default (pad, parent, event);
678 break;
679 }
680
681 return ret;
682 }
683
684 static gboolean
gst_dshowaudiodec_flush(GstDshowAudioDec * adec)685 gst_dshowaudiodec_flush (GstDshowAudioDec * adec)
686 {
687 if (!adec->fakesrc)
688 return FALSE;
689
690 /* flush dshow decoder and reset timestamp */
691 adec->fakesrc->GetOutputPin()->Flush();
692
693 adec->timestamp = GST_CLOCK_TIME_NONE;
694 adec->last_ret = GST_FLOW_OK;
695
696 return TRUE;
697 }
698
699 static AM_MEDIA_TYPE *
dshowaudiodec_set_input_format(GstDshowAudioDec * adec,GstCaps * caps)700 dshowaudiodec_set_input_format (GstDshowAudioDec *adec, GstCaps *caps)
701 {
702 AM_MEDIA_TYPE *mediatype;
703 WAVEFORMATEX *format;
704 GstDshowAudioDecClass *klass =
705 (GstDshowAudioDecClass *) G_OBJECT_GET_CLASS (adec);
706 const AudioCodecEntry *codec_entry = klass->entry;
707 int size;
708
709 mediatype = (AM_MEDIA_TYPE *)g_malloc0 (sizeof(AM_MEDIA_TYPE));
710 mediatype->majortype = MEDIATYPE_Audio;
711 GUID subtype = GUID_MEDIASUBTYPE_FROM_FOURCC (0x00000000);
712 subtype.Data1 = codec_entry->format;
713 mediatype->subtype = subtype;
714 mediatype->bFixedSizeSamples = TRUE;
715 mediatype->bTemporalCompression = FALSE;
716 if (adec->block_align)
717 mediatype->lSampleSize = adec->block_align;
718 else
719 mediatype->lSampleSize = 8192; /* need to evaluate it dynamically */
720 mediatype->formattype = FORMAT_WaveFormatEx;
721
722 /* We need this special behaviour for layers 1 and 2 (layer 3 uses a different
723 * decoder which doesn't need this */
724 if (adec->layer == 1 || adec->layer == 2) {
725 MPEG1WAVEFORMAT *mpeg1_format;
726 int samples, version;
727 GstStructure *structure = gst_caps_get_structure (caps, 0);
728
729 size = sizeof (MPEG1WAVEFORMAT);
730 format = (WAVEFORMATEX *)g_malloc0 (size);
731 format->cbSize = sizeof (MPEG1WAVEFORMAT) - sizeof (WAVEFORMATEX);
732 format->wFormatTag = WAVE_FORMAT_MPEG;
733
734 mpeg1_format = (MPEG1WAVEFORMAT *) format;
735
736 mpeg1_format->wfx.nChannels = adec->channels;
737 if (adec->channels == 2)
738 mpeg1_format->fwHeadMode = ACM_MPEG_STEREO;
739 else
740 mpeg1_format->fwHeadMode = ACM_MPEG_SINGLECHANNEL;
741
742 mpeg1_format->fwHeadModeExt = 0;
743 mpeg1_format->wHeadEmphasis = 0;
744 mpeg1_format->fwHeadFlags = 0;
745
746 switch (adec->layer) {
747 case 1:
748 mpeg1_format->fwHeadLayer = ACM_MPEG_LAYER3;
749 break;
750 case 2:
751 mpeg1_format->fwHeadLayer = ACM_MPEG_LAYER2;
752 break;
753 case 3:
754 mpeg1_format->fwHeadLayer = ACM_MPEG_LAYER1;
755 break;
756 };
757
758 gst_structure_get_int (structure, "mpegaudioversion", &version);
759 if (adec->layer == 1) {
760 samples = 384;
761 } else {
762 if (version == 1) {
763 samples = 576;
764 } else {
765 samples = 1152;
766 }
767 }
768 mpeg1_format->wfx.nBlockAlign = (WORD) samples;
769 mpeg1_format->wfx.nSamplesPerSec = adec->rate;
770 mpeg1_format->dwHeadBitrate = 128000; /* This doesn't seem to matter */
771 mpeg1_format->wfx.nAvgBytesPerSec = mpeg1_format->dwHeadBitrate / 8;
772 }
773 else
774 {
775 size = sizeof (WAVEFORMATEX) +
776 (adec->codec_data ? gst_buffer_get_size(adec->codec_data) : 0);
777
778 if (adec->layer == 3) {
779 MPEGLAYER3WAVEFORMAT *mp3format;
780
781 /* The WinXP mp3 decoder doesn't actually check the size of this structure,
782 * but requires that this be allocated and filled out (or we get obscure
783 * random crashes)
784 */
785 size = sizeof (MPEGLAYER3WAVEFORMAT);
786 mp3format = (MPEGLAYER3WAVEFORMAT *)g_malloc0 (size);
787 format = (WAVEFORMATEX *)mp3format;
788 format->cbSize = MPEGLAYER3_WFX_EXTRA_BYTES;
789
790 mp3format->wID = MPEGLAYER3_ID_MPEG;
791 mp3format->fdwFlags = MPEGLAYER3_FLAG_PADDING_ISO; /* No idea what this means for a decoder */
792
793 /* The XP decoder divides by nBlockSize, so we must set this to a
794 non-zero value, but it doesn't matter what - this is meaningless
795 for VBR mp3 anyway */
796 mp3format->nBlockSize = 1;
797 mp3format->nFramesPerBlock = 1;
798 mp3format->nCodecDelay = 0;
799 }
800 else {
801 format = (WAVEFORMATEX *)g_malloc0 (size);
802
803 if (adec->codec_data) { /* Codec data is appended after our header */
804 gsize codec_size = gst_buffer_get_size(adec->codec_data);
805 gst_buffer_extract(adec->codec_data, 0, ((guchar *) format) + sizeof (WAVEFORMATEX),
806 codec_size);
807 format->cbSize = codec_size;
808 }
809 }
810
811 format->wFormatTag = codec_entry->format;
812 format->nChannels = adec->channels;
813 format->nSamplesPerSec = adec->rate;
814 format->nAvgBytesPerSec = adec->bitrate / 8;
815 format->nBlockAlign = adec->block_align;
816 format->wBitsPerSample = adec->depth;
817 }
818
819 mediatype->cbFormat = size;
820 mediatype->pbFormat = (BYTE *) format;
821
822 return mediatype;
823 }
824
825 static AM_MEDIA_TYPE *
dshowaudiodec_set_output_format(GstDshowAudioDec * adec)826 dshowaudiodec_set_output_format (GstDshowAudioDec *adec)
827 {
828 AM_MEDIA_TYPE *mediatype;
829 WAVEFORMATEX *format;
830 GstDshowAudioDecClass *klass =
831 (GstDshowAudioDecClass *) G_OBJECT_GET_CLASS (adec);
832 const AudioCodecEntry *codec_entry = klass->entry;
833
834 if (!gst_dshowaudiodec_get_filter_settings (adec)) {
835 return NULL;
836 }
837
838 format = (WAVEFORMATEX *)g_malloc0(sizeof (WAVEFORMATEX));
839 format->wFormatTag = WAVE_FORMAT_PCM;
840 format->wBitsPerSample = adec->depth;
841 format->nChannels = adec->channels;
842 format->nBlockAlign = adec->channels * (adec->depth / 8);
843 format->nSamplesPerSec = adec->rate;
844 format->nAvgBytesPerSec = format->nBlockAlign * adec->rate;
845
846 mediatype = (AM_MEDIA_TYPE *)g_malloc0(sizeof (AM_MEDIA_TYPE));
847 mediatype->majortype = MEDIATYPE_Audio;
848 GUID subtype = GUID_MEDIASUBTYPE_FROM_FOURCC (WAVE_FORMAT_PCM);
849 mediatype->subtype = subtype;
850 mediatype->bFixedSizeSamples = TRUE;
851 mediatype->bTemporalCompression = FALSE;
852 mediatype->lSampleSize = format->nBlockAlign;
853 mediatype->formattype = FORMAT_WaveFormatEx;
854 mediatype->cbFormat = sizeof (WAVEFORMATEX);
855 mediatype->pbFormat = (BYTE *)format;
856
857 return mediatype;
858 }
859
860 static void
dshowadec_free_mediatype(AM_MEDIA_TYPE * mediatype)861 dshowadec_free_mediatype (AM_MEDIA_TYPE *mediatype)
862 {
863 g_free (mediatype->pbFormat);
864 g_free (mediatype);
865 }
866
867 static gboolean
gst_dshowaudiodec_setup_graph(GstDshowAudioDec * adec,GstCaps * caps)868 gst_dshowaudiodec_setup_graph (GstDshowAudioDec * adec, GstCaps *caps)
869 {
870 gboolean ret = FALSE;
871 GstDshowAudioDecClass *klass =
872 (GstDshowAudioDecClass *) G_OBJECT_GET_CLASS (adec);
873 HRESULT hres;
874 GstCaps *outcaps = NULL;
875 AM_MEDIA_TYPE *output_mediatype = NULL;
876 AM_MEDIA_TYPE *input_mediatype = NULL;
877 IPinPtr output_pin = NULL;
878 IPinPtr input_pin = NULL;
879 const AudioCodecEntry *codec_entry = klass->entry;
880 IBaseFilterPtr srcfilter;
881 IBaseFilterPtr sinkfilter;
882 GstAudioInfo audio_info;
883
884 input_mediatype = dshowaudiodec_set_input_format (adec, caps);
885
886 adec->fakesrc->GetOutputPin()->SetMediaType (input_mediatype);
887
888 srcfilter = adec->fakesrc;
889
890 /* connect our fake source to decoder */
891 output_pin = gst_dshow_get_pin_from_filter (srcfilter, PINDIR_OUTPUT);
892 if (!output_pin) {
893 GST_ELEMENT_ERROR (adec, CORE, NEGOTIATION,
894 ("Can't get output pin from our directshow fakesrc filter"), (NULL));
895 goto end;
896 }
897 input_pin = gst_dshow_get_pin_from_filter (adec->decfilter, PINDIR_INPUT);
898 if (!input_pin) {
899 GST_ELEMENT_ERROR (adec, CORE, NEGOTIATION,
900 ("Can't get input pin from decoder filter"), (NULL));
901 goto end;
902 }
903
904 hres = adec->filtergraph->ConnectDirect (output_pin, input_pin,
905 NULL);
906 if (hres != S_OK) {
907 GST_ELEMENT_ERROR (adec, CORE, NEGOTIATION,
908 ("Can't connect fakesrc with decoder (error=%x)", hres), (NULL));
909 goto end;
910 }
911
912 output_mediatype = dshowaudiodec_set_output_format (adec);
913 if (!output_mediatype) {
914 GST_ELEMENT_ERROR (adec, CORE, NEGOTIATION,
915 ("Can't get audio output format from decoder"), (NULL));
916 goto end;
917 }
918
919 adec->fakesink->SetMediaType(output_mediatype);
920
921 gst_audio_info_init(&audio_info);
922 gst_audio_info_set_format(&audio_info,
923 gst_audio_format_build_integer(TRUE, G_BYTE_ORDER, adec->depth, adec->depth),
924 adec->rate, adec->channels, NULL);
925
926 outcaps = gst_audio_info_to_caps(&audio_info);
927
928 if (!gst_pad_set_caps (adec->srcpad, outcaps)) {
929 GST_ELEMENT_ERROR (adec, CORE, NEGOTIATION,
930 ("Failed to negotiate output"), (NULL));
931 goto end;
932 }
933
934 /* connect the decoder to our fake sink */
935 output_pin = gst_dshow_get_pin_from_filter (adec->decfilter, PINDIR_OUTPUT);
936 if (!output_pin) {
937 GST_ELEMENT_ERROR (adec, CORE, NEGOTIATION,
938 ("Can't get output pin from our decoder filter"), (NULL));
939 goto end;
940 }
941
942 sinkfilter = adec->fakesink;
943 input_pin = gst_dshow_get_pin_from_filter (sinkfilter, PINDIR_INPUT);
944 if (!input_pin) {
945 GST_ELEMENT_ERROR (adec, CORE, NEGOTIATION,
946 ("Can't get input pin from our directshow fakesink filter"), (NULL));
947 goto end;
948 }
949
950 hres = adec->filtergraph->ConnectDirect(output_pin, input_pin, NULL);
951 if (hres != S_OK) {
952 GST_ELEMENT_ERROR (adec, CORE, NEGOTIATION,
953 ("Can't connect decoder with fakesink (error=%x)", hres), (NULL));
954 goto end;
955 }
956
957 hres = adec->mediafilter->Run (-1);
958 if (hres != S_OK) {
959 GST_ELEMENT_ERROR (adec, CORE, NEGOTIATION,
960 ("Can't run the directshow graph (error=%x)", hres), (NULL));
961 goto end;
962 }
963
964 ret = TRUE;
965 adec->setup = TRUE;
966 end:
967 if (outcaps)
968 gst_caps_unref(outcaps);
969 if (input_mediatype)
970 dshowadec_free_mediatype (input_mediatype);
971 if (output_mediatype)
972 dshowadec_free_mediatype (output_mediatype);
973
974 return ret;
975 }
976
977 static gboolean
gst_dshowaudiodec_get_filter_settings(GstDshowAudioDec * adec)978 gst_dshowaudiodec_get_filter_settings (GstDshowAudioDec * adec)
979 {
980 IPinPtr output_pin;
981 IEnumMediaTypesPtr enum_mediatypes;
982 HRESULT hres;
983 ULONG fetched;
984 BOOL ret = FALSE;
985
986 if (adec->decfilter == 0)
987 return FALSE;
988
989 output_pin = gst_dshow_get_pin_from_filter (adec->decfilter, PINDIR_OUTPUT);
990 if (!output_pin) {
991 GST_ELEMENT_ERROR (adec, CORE, NEGOTIATION,
992 ("failed getting output pin from the decoder"), (NULL));
993 return FALSE;
994 }
995
996 hres = output_pin->EnumMediaTypes (&enum_mediatypes);
997 if (hres == S_OK && enum_mediatypes) {
998 AM_MEDIA_TYPE *mediatype = NULL;
999
1000 enum_mediatypes->Reset();
1001 while (!ret && enum_mediatypes->Next(1, &mediatype, &fetched) == S_OK)
1002 {
1003 if (IsEqualGUID (mediatype->subtype, MEDIASUBTYPE_PCM) &&
1004 IsEqualGUID (mediatype->formattype, FORMAT_WaveFormatEx))
1005 {
1006 WAVEFORMATEX *audio_info = (WAVEFORMATEX *) mediatype->pbFormat;
1007
1008 adec->channels = audio_info->nChannels;
1009 adec->depth = audio_info->wBitsPerSample;
1010 adec->rate = audio_info->nSamplesPerSec;
1011 ret = TRUE;
1012 }
1013 DeleteMediaType (mediatype);
1014 }
1015 }
1016
1017 return ret;
1018 }
1019
1020 static gboolean
gst_dshowaudiodec_create_graph_and_filters(GstDshowAudioDec * adec)1021 gst_dshowaudiodec_create_graph_and_filters (GstDshowAudioDec * adec)
1022 {
1023 HRESULT hres;
1024 GstDshowAudioDecClass *klass =
1025 (GstDshowAudioDecClass *) G_OBJECT_GET_CLASS (adec);
1026 IBaseFilterPtr srcfilter;
1027 IBaseFilterPtr sinkfilter;
1028 GUID insubtype = GUID_MEDIASUBTYPE_FROM_FOURCC (klass->entry->format);
1029 GUID outsubtype = GUID_MEDIASUBTYPE_FROM_FOURCC (WAVE_FORMAT_PCM);
1030
1031 /* create the filter graph manager object */
1032 hres = adec->filtergraph.CreateInstance (
1033 CLSID_FilterGraph, NULL, CLSCTX_INPROC);
1034 if (FAILED (hres)) {
1035 GST_ELEMENT_ERROR (adec, STREAM, FAILED,
1036 ("Can't create an instance of the directshow graph manager (error=%d)",
1037 hres), (NULL));
1038 goto error;
1039 }
1040
1041 hres = adec->filtergraph->QueryInterface (&adec->mediafilter);
1042 if (FAILED (hres)) {
1043 GST_WARNING_OBJECT (adec, "Can't QI filtergraph to mediafilter");
1044 goto error;
1045 }
1046
1047 /* create fake src filter */
1048 adec->fakesrc = new FakeSrc();
1049 /* Created with a refcount of zero, so increment that */
1050 adec->fakesrc->AddRef();
1051
1052 /* create decoder filter */
1053 adec->decfilter = gst_dshow_find_filter (MEDIATYPE_Audio,
1054 insubtype,
1055 MEDIATYPE_Audio,
1056 outsubtype,
1057 klass->entry->preferred_filters);
1058 if (adec->decfilter == NULL) {
1059 GST_ELEMENT_ERROR (adec, STREAM, FAILED,
1060 ("Can't create an instance of the decoder filter"), (NULL));
1061 goto error;
1062 }
1063
1064 /* create fake sink filter */
1065 adec->fakesink = new AudioFakeSink(adec);
1066 /* Created with a refcount of zero, so increment that */
1067 adec->fakesink->AddRef();
1068
1069 /* add filters to the graph */
1070 srcfilter = adec->fakesrc;
1071 hres = adec->filtergraph->AddFilter (srcfilter, L"src");
1072 if (hres != S_OK) {
1073 GST_ELEMENT_ERROR (adec, STREAM, FAILED,
1074 ("Can't add fakesrc filter to the graph (error=%d)", hres), (NULL));
1075 goto error;
1076 }
1077
1078 hres = adec->filtergraph->AddFilter(adec->decfilter, L"decoder");
1079 if (hres != S_OK) {
1080 GST_ELEMENT_ERROR (adec, STREAM, FAILED,
1081 ("Can't add decoder filter to the graph (error=%d)", hres), (NULL));
1082 goto error;
1083 }
1084
1085 sinkfilter = adec->fakesink;
1086 hres = adec->filtergraph->AddFilter(sinkfilter, L"sink");
1087 if (hres != S_OK) {
1088 GST_ELEMENT_ERROR (adec, STREAM, FAILED,
1089 ("Can't add fakesink filter to the graph (error=%d)", hres), (NULL));
1090 goto error;
1091 }
1092
1093 return TRUE;
1094
1095 error:
1096 if (adec->fakesrc) {
1097 adec->fakesrc->Release();
1098 adec->fakesrc = NULL;
1099 }
1100 if (adec->fakesink) {
1101 adec->fakesink->Release();
1102 adec->fakesink = NULL;
1103 }
1104 adec->decfilter = 0;
1105 adec->mediafilter = 0;
1106 adec->filtergraph = 0;
1107
1108 return FALSE;
1109 }
1110
1111 static gboolean
gst_dshowaudiodec_destroy_graph_and_filters(GstDshowAudioDec * adec)1112 gst_dshowaudiodec_destroy_graph_and_filters (GstDshowAudioDec * adec)
1113 {
1114 if (adec->mediafilter) {
1115 adec->mediafilter->Stop();
1116 }
1117
1118 if (adec->fakesrc) {
1119 if (adec->filtergraph) {
1120 IBaseFilterPtr filter = adec->fakesrc;
1121 adec->filtergraph->RemoveFilter(filter);
1122 }
1123 adec->fakesrc->Release();
1124 adec->fakesrc = NULL;
1125 }
1126 if (adec->decfilter) {
1127 if (adec->filtergraph)
1128 adec->filtergraph->RemoveFilter(adec->decfilter);
1129 adec->decfilter = 0;
1130 }
1131 if (adec->fakesink) {
1132 if (adec->filtergraph) {
1133 IBaseFilterPtr filter = adec->fakesink;
1134 adec->filtergraph->RemoveFilter(filter);
1135 }
1136
1137 adec->fakesink->Release();
1138 adec->fakesink = NULL;
1139 }
1140 adec->mediafilter = 0;
1141 adec->filtergraph = 0;
1142
1143 adec->setup = FALSE;
1144
1145 return TRUE;
1146 }
1147
1148 gboolean
dshow_adec_register(GstPlugin * plugin)1149 dshow_adec_register (GstPlugin * plugin)
1150 {
1151 GTypeInfo info = {
1152 sizeof (GstDshowAudioDecClass),
1153 (GBaseInitFunc) gst_dshowaudiodec_base_init,
1154 NULL,
1155 (GClassInitFunc) gst_dshowaudiodec_class_init,
1156 NULL,
1157 NULL,
1158 sizeof (GstDshowAudioDec),
1159 0,
1160 (GInstanceInitFunc) gst_dshowaudiodec_init,
1161 };
1162 gint i;
1163 HRESULT hr;
1164
1165 GST_DEBUG_CATEGORY_INIT (dshowaudiodec_debug, "dshowaudiodec", 0,
1166 "Directshow filter audio decoder");
1167
1168 hr = CoInitialize(0);
1169 for (i = 0; i < sizeof (audio_dec_codecs) / sizeof (AudioCodecEntry); i++) {
1170 GType type;
1171 IBaseFilterPtr filter;
1172 GUID insubtype = GUID_MEDIASUBTYPE_FROM_FOURCC (audio_dec_codecs[i].format);
1173 GUID outsubtype = GUID_MEDIASUBTYPE_FROM_FOURCC (WAVE_FORMAT_PCM);
1174
1175 filter = gst_dshow_find_filter (MEDIATYPE_Audio,
1176 insubtype,
1177 MEDIATYPE_Audio,
1178 outsubtype,
1179 audio_dec_codecs[i].preferred_filters);
1180
1181 if (filter)
1182 {
1183 GST_DEBUG ("Registering %s", audio_dec_codecs[i].element_name);
1184
1185 type = g_type_register_static (GST_TYPE_ELEMENT,
1186 audio_dec_codecs[i].element_name, &info, (GTypeFlags)0);
1187 g_type_set_qdata (type, DSHOW_CODEC_QDATA, (gpointer) (audio_dec_codecs + i));
1188 if (!gst_element_register (plugin, audio_dec_codecs[i].element_name,
1189 GST_RANK_MARGINAL, type)) {
1190 return FALSE;
1191 }
1192 GST_CAT_DEBUG (dshowaudiodec_debug, "Registered %s",
1193 audio_dec_codecs[i].element_name);
1194 }
1195 else {
1196 GST_DEBUG ("Element %s not registered "
1197 "(the format is not supported by the system)",
1198 audio_dec_codecs[i].element_name);
1199 }
1200 }
1201
1202 if (SUCCEEDED(hr))
1203 CoUninitialize ();
1204
1205 return TRUE;
1206 }
1207