diff options
-rw-r--r-- | ChangeLog | 19 | ||||
-rw-r--r-- | gst/flv/gstflvdemux.c | 20 | ||||
-rw-r--r-- | gst/flv/gstflvdemux.h | 2 | ||||
-rw-r--r-- | gst/flv/gstflvparse.c | 425 | ||||
-rw-r--r-- | sys/dshowdecwrapper/gstdshowaudiodec.c | 28 | ||||
-rw-r--r-- | sys/dshowdecwrapper/gstdshowaudiodec.h | 2 | ||||
-rw-r--r-- | sys/dshowdecwrapper/gstdshowvideodec.c | 36 | ||||
-rw-r--r-- | sys/dshowdecwrapper/gstdshowvideodec.h | 2 |
8 files changed, 318 insertions, 216 deletions
@@ -1,3 +1,22 @@ +2008-06-14 Julien Moutte <julien@fluendo.com> + + * gst/flv/gstflvdemux.c: (gst_flv_demux_cleanup), + (gst_flv_demux_dispose): + * gst/flv/gstflvdemux.h: + * gst/flv/gstflvparse.c: (gst_flv_parse_audio_negotiate), + (gst_flv_parse_tag_audio), (gst_flv_parse_video_negotiate), + (gst_flv_parse_tag_video): Introduce demuxing support for AAC and + H.264/AVC inside FLV. + * sys/dshowdecwrapper/gstdshowaudiodec.c: (gst_dshowaudiodec_init), + (gst_dshowaudiodec_chain), (gst_dshowaudiodec_push_buffer), + (gst_dshowaudiodec_sink_event), (gst_dshowaudiodec_setup_graph): + * sys/dshowdecwrapper/gstdshowaudiodec.h: + * sys/dshowdecwrapper/gstdshowvideodec.c: (gst_dshowvideodec_init), + (gst_dshowvideodec_sink_event), (gst_dshowvideodec_chain), + (gst_dshowvideodec_push_buffer), (gst_dshowvideodec_src_getcaps): + * sys/dshowdecwrapper/gstdshowvideodec.h: Lot of random fixes + to improve stability (ref counting, safety checks...) + 2008-06-13 Wim Taymans <wim.taymans@collabora.co.uk> * gst/real/gstrealaudiodec.c: (gst_real_audio_dec_probe_modules): diff --git a/gst/flv/gstflvdemux.c b/gst/flv/gstflvdemux.c index 045b3450f..0f5e3f797 100644 --- a/gst/flv/gstflvdemux.c +++ b/gst/flv/gstflvdemux.c @@ -118,6 +118,16 @@ gst_flv_demux_cleanup (GstFLVDemux * demux) gst_adapter_clear (demux->adapter); + if (demux->audio_codec_data) { + gst_buffer_unref (demux->audio_codec_data); + demux->audio_codec_data = NULL; + } + + if (demux->video_codec_data) { + gst_buffer_unref (demux->video_codec_data); + demux->video_codec_data = NULL; + } + if (demux->audio_pad) { gst_element_remove_pad (GST_ELEMENT (demux), demux->audio_pad); gst_object_unref (demux->audio_pad); @@ -1098,6 +1108,16 @@ gst_flv_demux_dispose (GObject * object) demux->new_seg_event = NULL; } + if (demux->audio_codec_data) { + gst_buffer_unref (demux->audio_codec_data); + demux->audio_codec_data = NULL; + } + + if (demux->video_codec_data) { + gst_buffer_unref (demux->video_codec_data); + demux->video_codec_data = NULL; + } + if (demux->audio_pad) { gst_object_unref (demux->audio_pad); demux->audio_pad = NULL; diff --git a/gst/flv/gstflvdemux.h b/gst/flv/gstflvdemux.h index bd0832b0d..989584c41 100644 --- a/gst/flv/gstflvdemux.h +++ b/gst/flv/gstflvdemux.h @@ -88,6 +88,7 @@ struct _GstFLVDemux gboolean audio_need_discont; gboolean audio_need_segment; gboolean audio_linked; + GstBuffer * audio_codec_data; /* Video infos */ guint32 w; @@ -100,6 +101,7 @@ struct _GstFLVDemux gboolean video_need_segment; gboolean video_linked; gboolean got_par; + GstBuffer * video_codec_data; gboolean random_access; gboolean need_header; diff --git a/gst/flv/gstflvparse.c b/gst/flv/gstflvparse.c index 3a0e97b7f..55a3ac67a 100644 --- a/gst/flv/gstflvparse.c +++ b/gst/flv/gstflvparse.c @@ -391,6 +391,90 @@ gst_flv_parse_tag_script (GstFLVDemux * demux, const guint8 * data, return ret; } +static gboolean +gst_flv_parse_audio_negotiate (GstFLVDemux * demux, guint32 codec_tag, + guint32 rate, guint32 channels, guint32 width) +{ + GstCaps *caps = NULL; + gchar *codec_name = NULL; + gboolean ret = FALSE; + + switch (codec_tag) { + case 1: + caps = gst_caps_new_simple ("audio/x-adpcm", "layout", G_TYPE_STRING, + "swf", NULL); + codec_name = "Shockwave ADPCM"; + break; + case 2: + caps = gst_caps_new_simple ("audio/mpeg", + "mpegversion", G_TYPE_INT, 1, "layer", G_TYPE_INT, 3, NULL); + codec_name = "MPEG 1 Audio, Layer 3 (MP3)"; + break; + case 0: + case 3: + caps = gst_caps_new_simple ("audio/x-raw-int", + "endianness", G_TYPE_INT, G_BYTE_ORDER, + "signed", G_TYPE_BOOLEAN, TRUE, + "width", G_TYPE_INT, width, "depth", G_TYPE_INT, width, NULL); + codec_name = "Raw Audio"; + break; + case 4: + case 5: + case 6: + caps = gst_caps_new_simple ("audio/x-nellymoser", NULL); + codec_name = "Nellymoser ASAO"; + break; + case 10: + caps = gst_caps_new_simple ("audio/mpeg", + "mpegversion", G_TYPE_INT, 4, NULL); + codec_name = "AAC"; + break; + default: + GST_WARNING_OBJECT (demux, "unsupported audio codec tag %u", codec_tag); + } + + if (G_UNLIKELY (!caps)) { + GST_WARNING_OBJECT (demux, "failed creating caps for audio pad"); + goto beach; + } + + gst_caps_set_simple (caps, + "rate", G_TYPE_INT, rate, "channels", G_TYPE_INT, channels, NULL); + + if (demux->audio_codec_data) { + gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, + demux->audio_codec_data, NULL); + } + + ret = gst_pad_set_caps (demux->audio_pad, caps); + + if (G_LIKELY (ret)) { + /* Store the caps we have set */ + demux->audio_codec_tag = codec_tag; + demux->rate = rate; + demux->channels = channels; + demux->width = width; + + if (codec_name) { + if (demux->taglist == NULL) + demux->taglist = gst_tag_list_new (); + gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE, + GST_TAG_AUDIO_CODEC, codec_name, NULL); + } + + GST_DEBUG_OBJECT (demux->audio_pad, "successfully negotiated caps %" + GST_PTR_FORMAT, caps); + } else { + GST_WARNING_OBJECT (demux->audio_pad, "failed negotiating caps %" + GST_PTR_FORMAT, caps); + } + + gst_caps_unref (caps); + +beach: + return ret; +} + GstFlowReturn gst_flv_parse_tag_audio (GstFLVDemux * demux, const guint8 * data, size_t data_size) @@ -433,7 +517,11 @@ gst_flv_parse_tag_audio (GstFLVDemux * demux, const guint8 * data, } /* Codec tag */ codec_tag = flags >> 4; - codec_data = 1; + if (codec_tag == 10) { /* AAC has an extra byte for packet type */ + codec_data = 2; + } else { + codec_data = 1; + } GST_LOG_OBJECT (demux, "audio tag with %d channels, %dHz sampling rate, " "%d bits width, codec tag %u (flags %02X)", channels, rate, width, @@ -441,8 +529,6 @@ gst_flv_parse_tag_audio (GstFLVDemux * demux, const guint8 * data, /* If we don't have our audio pad created, then create it. */ if (G_UNLIKELY (!demux->audio_pad)) { - GstCaps *caps = NULL; - gchar *codec_name = NULL; demux->audio_pad = gst_pad_new ("audio", GST_PAD_SRC); if (G_UNLIKELY (!demux->audio_pad)) { @@ -454,64 +540,17 @@ gst_flv_parse_tag_audio (GstFLVDemux * demux, const guint8 * data, /* Make it active */ gst_pad_set_active (demux->audio_pad, TRUE); - switch (codec_tag) { - case 1: - caps = - gst_caps_new_simple ("audio/x-adpcm", "layout", G_TYPE_STRING, - "swf", NULL); - codec_name = "Shockwave ADPCM"; - break; - case 2: - caps = gst_caps_new_simple ("audio/mpeg", - "mpegversion", G_TYPE_INT, 1, "layer", G_TYPE_INT, 3, NULL); - codec_name = "MPEG 1 Audio, Layer 3 (MP3)"; - break; - case 0: - case 3: - caps = gst_caps_new_simple ("audio/x-raw-int", - "endianness", G_TYPE_INT, G_BYTE_ORDER, - "signed", G_TYPE_BOOLEAN, TRUE, - "width", G_TYPE_INT, width, "depth", G_TYPE_INT, width, NULL); - codec_name = "Raw Audio"; - break; - case 5: - case 6: - caps = gst_caps_new_simple ("audio/x-nellymoser", NULL); - codec_name = "Nellymoser ASAO"; - break; - default: - GST_WARNING_OBJECT (demux, "unsupported audio codec tag %u", codec_tag); - } - - if (G_UNLIKELY (!caps)) { - GST_WARNING_OBJECT (demux, "failed creating caps for audio pad"); - ret = GST_FLOW_ERROR; + /* Negotiate caps */ + if (!gst_flv_parse_audio_negotiate (demux, codec_tag, rate, channels, + width)) { gst_object_unref (demux->audio_pad); demux->audio_pad = NULL; + ret = GST_FLOW_ERROR; goto beach; } - gst_caps_set_simple (caps, - "rate", G_TYPE_INT, rate, "channels", G_TYPE_INT, channels, NULL); - - gst_pad_set_caps (demux->audio_pad, caps); - if (codec_name) { - if (demux->taglist == NULL) - demux->taglist = gst_tag_list_new (); - gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE, - GST_TAG_AUDIO_CODEC, codec_name, NULL); - } - GST_DEBUG_OBJECT (demux, "created audio pad with caps %" GST_PTR_FORMAT, - caps); - - gst_caps_unref (caps); - - /* Store the caps we have set */ - demux->audio_codec_tag = codec_tag; - demux->rate = rate; - demux->channels = channels; - demux->width = width; + GST_PAD_CAPS (demux->audio_pad)); /* Set functions on the pad */ gst_pad_set_query_type_function (demux->audio_pad, @@ -537,61 +576,10 @@ gst_flv_parse_tag_audio (GstFLVDemux * demux, const guint8 * data, /* Check if caps have changed */ if (G_UNLIKELY (rate != demux->rate || channels != demux->channels || codec_tag != demux->audio_codec_tag || width != demux->width)) { - GstCaps *caps = NULL; - gchar *codec_name = NULL; - GST_DEBUG_OBJECT (demux, "audio settings have changed, changing caps"); - switch (codec_tag) { - case 1: - caps = - gst_caps_new_simple ("audio/x-adpcm", "layout", G_TYPE_STRING, - "swf", NULL); - codec_name = "Shockwave ADPCM"; - break; - case 2: - caps = gst_caps_new_simple ("audio/mpeg", - "mpegversion", G_TYPE_INT, 1, "layer", G_TYPE_INT, 3, NULL); - codec_name = "MPEG 1 Audio, Layer 3 (MP3)"; - break; - case 0: - case 3: - caps = gst_caps_new_simple ("audio/x-raw-int", NULL); - codec_name = "Raw Audio"; - break; - case 6: - caps = gst_caps_new_simple ("audio/x-nellymoser", NULL); - codec_name = "Nellymoser ASAO"; - break; - default: - GST_WARNING_OBJECT (demux, "unsupported audio codec tag %u", codec_tag); - } - - if (G_UNLIKELY (!caps)) { - GST_WARNING_OBJECT (demux, "failed creating caps for audio pad"); - ret = GST_FLOW_ERROR; - goto beach; - } - - gst_caps_set_simple (caps, - "rate", G_TYPE_INT, rate, - "channels", G_TYPE_INT, channels, "width", G_TYPE_INT, width, NULL); - - gst_pad_set_caps (demux->audio_pad, caps); - if (codec_name) { - if (demux->taglist == NULL) - demux->taglist = gst_tag_list_new (); - gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE, - GST_TAG_AUDIO_CODEC, codec_name, NULL); - } - - gst_caps_unref (caps); - - /* Store the caps we have set */ - demux->audio_codec_tag = codec_tag; - demux->rate = rate; - demux->channels = channels; - demux->width = width; + /* Negotiate caps */ + gst_flv_parse_audio_negotiate (demux, codec_tag, rate, channels, width); } /* Push taglist if present */ @@ -627,8 +615,38 @@ gst_flv_parse_tag_audio (GstFLVDemux * demux, const guint8 * data, goto beach; } + memcpy (GST_BUFFER_DATA (buffer), data + 7 + codec_data, + MIN (demux->tag_data_size - codec_data, GST_BUFFER_SIZE (buffer))); + demux->audio_linked = TRUE; + if (demux->audio_codec_tag == 10) { + guint8 aac_packet_type = GST_READ_UINT8 (data + 8); + + switch (aac_packet_type) { + case 0: + { + /* AudioSpecificConfic data */ + GST_LOG_OBJECT (demux, "got an AAC codec data packet"); + if (demux->audio_codec_data) { + gst_buffer_unref (demux->audio_codec_data); + } + demux->audio_codec_data = buffer; + /* Use that buffer data in the caps */ + gst_flv_parse_audio_negotiate (demux, codec_tag, rate, channels, width); + goto beach; + break; + } + case 1: + /* AAC raw packet */ + GST_LOG_OBJECT (demux, "got a raw AAC audio packet"); + break; + default: + GST_WARNING_OBJECT (demux, "invalid AAC packet type %u", + aac_packet_type); + } + } + /* Fill buffer with data */ GST_BUFFER_TIMESTAMP (buffer) = pts * GST_MSECOND; GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE; @@ -663,9 +681,6 @@ gst_flv_parse_tag_audio (GstFLVDemux * demux, const guint8 * data, demux->audio_need_segment = FALSE; } - memcpy (GST_BUFFER_DATA (buffer), data + 7 + codec_data, - demux->tag_data_size - codec_data); - GST_LOG_OBJECT (demux, "pushing %d bytes buffer at pts %" GST_TIME_FORMAT " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)), @@ -678,6 +693,74 @@ beach: return ret; } +static gboolean +gst_flv_parse_video_negotiate (GstFLVDemux * demux, guint32 codec_tag) +{ + gboolean ret = FALSE; + GstCaps *caps = NULL; + gchar *codec_name = NULL; + + /* Generate caps for that pad */ + switch (codec_tag) { + case 2: + caps = gst_caps_new_simple ("video/x-flash-video", NULL); + codec_name = "Sorenson Video"; + break; + case 3: + caps = gst_caps_new_simple ("video/x-flash-screen", NULL); + codec_name = "Flash Screen Video"; + case 4: + case 5: + caps = gst_caps_new_simple ("video/x-vp6-flash", NULL); + codec_name = "On2 VP6 Video"; + break; + case 7: + caps = gst_caps_new_simple ("video/x-h264", NULL); + codec_name = "H.264/AVC Video"; + break; + default: + GST_WARNING_OBJECT (demux, "unsupported video codec tag %u", codec_tag); + } + + if (G_UNLIKELY (!caps)) { + GST_WARNING_OBJECT (demux, "failed creating caps for video pad"); + goto beach; + } + + gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION, + demux->par_x, demux->par_y, NULL); + + if (demux->video_codec_data) { + gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, + demux->video_codec_data, NULL); + } + + ret = gst_pad_set_caps (demux->video_pad, caps); + + if (G_LIKELY (ret)) { + /* Store the caps we have set */ + demux->video_codec_tag = codec_tag; + + if (codec_name) { + if (demux->taglist == NULL) + demux->taglist = gst_tag_list_new (); + gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE, + GST_TAG_VIDEO_CODEC, codec_name, NULL); + } + + GST_DEBUG_OBJECT (demux->video_pad, "successfully negotiated caps %" + GST_PTR_FORMAT, caps); + } else { + GST_WARNING_OBJECT (demux->video_pad, "failed negotiating caps %" + GST_PTR_FORMAT, caps); + } + + gst_caps_unref (caps); + +beach: + return ret; +} + GstFlowReturn gst_flv_parse_tag_video (GstFLVDemux * demux, const guint8 * data, size_t data_size) @@ -710,6 +793,8 @@ gst_flv_parse_tag_video (GstFLVDemux * demux, const guint8 * data, codec_tag = flags & 0x0F; if (codec_tag == 4 || codec_tag == 5) { codec_data = 2; + } else if (codec_tag == 7) { + codec_data = 5; } GST_LOG_OBJECT (demux, "video tag with codec tag %u, keyframe (%d) " @@ -717,9 +802,6 @@ gst_flv_parse_tag_video (GstFLVDemux * demux, const guint8 * data, /* If we don't have our video pad created, then create it. */ if (G_UNLIKELY (!demux->video_pad)) { - GstCaps *caps = NULL; - gchar *codec_name = NULL; - demux->video_pad = gst_pad_new ("video", GST_PAD_SRC); if (G_UNLIKELY (!demux->video_pad)) { GST_WARNING_OBJECT (demux, "failed creating video pad"); @@ -729,54 +811,19 @@ gst_flv_parse_tag_video (GstFLVDemux * demux, const guint8 * data, /* Make it active */ gst_pad_set_active (demux->video_pad, TRUE); - /* Generate caps for that pad */ - switch (codec_tag) { - case 2: - caps = gst_caps_new_simple ("video/x-flash-video", NULL); - codec_name = "Sorenson Video"; - break; - case 3: - caps = gst_caps_new_simple ("video/x-flash-screen", NULL); - codec_name = "Flash Screen Video"; - case 4: - case 5: - caps = gst_caps_new_simple ("video/x-vp6-flash", NULL); - codec_name = "On2 VP6 Video"; - break; - default: - GST_WARNING_OBJECT (demux, "unsupported video codec tag %d", codec_tag); - } - - if (G_UNLIKELY (!caps)) { - GST_WARNING_OBJECT (demux, "failed creating caps for video pad"); + if (!gst_flv_parse_video_negotiate (demux, codec_tag)) { gst_object_unref (demux->video_pad); demux->video_pad = NULL; ret = GST_FLOW_ERROR; goto beach; } - gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION, - demux->par_x, demux->par_y, NULL); - /* When we ve set pixel-aspect-ratio we use that boolean to detect a * metadata tag that would come later and trigger a caps change */ demux->got_par = FALSE; - gst_pad_set_caps (demux->video_pad, caps); - GST_DEBUG_OBJECT (demux, "created video pad with caps %" GST_PTR_FORMAT, - caps); - - gst_caps_unref (caps); - if (codec_name) { - if (demux->taglist == NULL) - demux->taglist = gst_tag_list_new (); - gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE, - GST_TAG_VIDEO_CODEC, codec_name, NULL); - } - - /* Store the caps we have set */ - demux->video_codec_tag = codec_tag; + GST_PAD_CAPS (demux->video_pad)); /* Set functions on the pad */ gst_pad_set_query_type_function (demux->video_pad, @@ -801,54 +848,14 @@ gst_flv_parse_tag_video (GstFLVDemux * demux, const guint8 * data, /* Check if caps have changed */ if (G_UNLIKELY (codec_tag != demux->video_codec_tag || demux->got_par)) { - GstCaps *caps = NULL; - gchar *codec_name = NULL; GST_DEBUG_OBJECT (demux, "video settings have changed, changing caps"); - /* Generate caps for that pad */ - switch (codec_tag) { - case 2: - caps = gst_caps_new_simple ("video/x-flash-video", NULL); - codec_name = "Sorenson Video"; - break; - case 3: - caps = gst_caps_new_simple ("video/x-flash-screen", NULL); - codec_name = "Flash Screen Video"; - case 4: - case 5: - caps = gst_caps_new_simple ("video/x-vp6", NULL); - codec_name = "On2 VP6 Video"; - break; - default: - GST_WARNING_OBJECT (demux, "unsupported video codec tag %d", codec_tag); - } - - if (G_UNLIKELY (!caps)) { - GST_WARNING_OBJECT (demux, "failed creating caps for video pad"); - ret = GST_FLOW_ERROR; - goto beach; - } - - gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION, - demux->par_x, demux->par_y, NULL); + gst_flv_parse_video_negotiate (demux, codec_tag); /* When we ve set pixel-aspect-ratio we use that boolean to detect a * metadata tag that would come later and trigger a caps change */ demux->got_par = FALSE; - - gst_pad_set_caps (demux->video_pad, caps); - - gst_caps_unref (caps); - if (codec_name) { - if (demux->taglist == NULL) - demux->taglist = gst_tag_list_new (); - gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE, - GST_TAG_VIDEO_CODEC, codec_name, NULL); - } - - /* Store the caps we have set */ - demux->video_codec_tag = codec_tag; } /* Push taglist if present */ @@ -886,6 +893,36 @@ gst_flv_parse_tag_video (GstFLVDemux * demux, const guint8 * data, demux->video_linked = TRUE; + memcpy (GST_BUFFER_DATA (buffer), data + 7 + codec_data, + MIN (demux->tag_data_size - codec_data, GST_BUFFER_SIZE (buffer))); + + if (demux->video_codec_tag == 7) { + guint8 avc_packet_type = GST_READ_UINT8 (data + 8); + + switch (avc_packet_type) { + case 0: + { + /* AVCDecoderConfigurationRecord data */ + GST_LOG_OBJECT (demux, "got an H.264 codec data packet"); + if (demux->video_codec_data) { + gst_buffer_unref (demux->video_codec_data); + } + demux->video_codec_data = buffer; + /* Use that buffer data in the caps */ + gst_flv_parse_video_negotiate (demux, codec_tag); + goto beach; + break; + } + case 1: + /* H.264 NALU packet */ + GST_LOG_OBJECT (demux, "got a H.264 NALU audio packet"); + break; + default: + GST_WARNING_OBJECT (demux, "invalid AAC packet type %u", + avc_packet_type); + } + } + /* Fill buffer with data */ GST_BUFFER_TIMESTAMP (buffer) = pts * GST_MSECOND; GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE; @@ -934,10 +971,6 @@ gst_flv_parse_tag_video (GstFLVDemux * demux, const guint8 * data, demux->video_need_segment = FALSE; } - /* FIXME: safety checks */ - memcpy (GST_BUFFER_DATA (buffer), data + 7 + codec_data, - demux->tag_data_size - codec_data); - GST_LOG_OBJECT (demux, "pushing %d bytes buffer at pts %" GST_TIME_FORMAT " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT ", keyframe (%d)", GST_BUFFER_SIZE (buffer), diff --git a/sys/dshowdecwrapper/gstdshowaudiodec.c b/sys/dshowdecwrapper/gstdshowaudiodec.c index 6bb298ce7..b7be7ac6f 100644 --- a/sys/dshowdecwrapper/gstdshowaudiodec.c +++ b/sys/dshowdecwrapper/gstdshowaudiodec.c @@ -308,6 +308,8 @@ gst_dshowaudiodec_init (GstDshowAudioDec * adec, adec->layer = 0; adec->codec_data = NULL; + adec->last_ret = GST_FLOW_OK; + CoInitializeEx (NULL, COINIT_MULTITHREADED); } @@ -420,7 +422,6 @@ end: static GstFlowReturn gst_dshowaudiodec_chain (GstPad * pad, GstBuffer * buffer) { - GstFlowReturn ret = GST_FLOW_OK; GstDshowAudioDec *adec = (GstDshowAudioDec *) gst_pad_get_parent (pad); gboolean discount = FALSE; @@ -436,13 +437,20 @@ gst_dshowaudiodec_chain (GstPad * pad, GstBuffer * buffer) /* setup dshow graph */ if (!gst_dshowaudiodec_setup_graph (adec)) { - return GST_FLOW_ERROR; + adec->last_ret = GST_FLOW_ERROR; + goto beach; } } if (!adec->gstdshowsrcfilter) { /* we are not setup */ - ret = GST_FLOW_WRONG_STATE; + 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; } @@ -470,7 +478,7 @@ gst_dshowaudiodec_chain (GstPad * pad, GstBuffer * buffer) beach: gst_buffer_unref (buffer); gst_object_unref (adec); - return ret; + return adec->last_ret; } static gboolean @@ -509,7 +517,7 @@ gst_dshowaudiodec_push_buffer (byte * buffer, long size, byte * src_object, /* buffer is in our segment allocate a new out buffer and clip it if needed */ /* allocate a new buffer for raw audio */ - gst_pad_alloc_buffer (adec->srcpad, GST_BUFFER_OFFSET_NONE, + adec->last_ret = gst_pad_alloc_buffer (adec->srcpad, GST_BUFFER_OFFSET_NONE, size, GST_PAD_CAPS (adec->srcpad), &out_buf); if (!out_buf) { GST_CAT_ERROR_OBJECT (dshowaudiodec_debug, adec, @@ -518,10 +526,10 @@ gst_dshowaudiodec_push_buffer (byte * buffer, long size, byte * src_object, } /* set buffer properties */ - GST_BUFFER_SIZE (out_buf) = size; GST_BUFFER_TIMESTAMP (out_buf) = buf_start; GST_BUFFER_DURATION (out_buf) = buf_stop - buf_start; - memcpy (GST_BUFFER_DATA (out_buf), buffer, size); + memcpy (GST_BUFFER_DATA (out_buf), buffer, + MIN (size, GST_BUFFER_SIZE (out_buf))); /* we have to remove some heading samples */ if (clip_start > buf_start) { @@ -560,7 +568,7 @@ gst_dshowaudiodec_push_buffer (byte * buffer, long size, byte * src_object, GST_BUFFER_DURATION (out_buf)), GST_TIME_ARGS (GST_BUFFER_DURATION (out_buf))); - gst_pad_push (adec->srcpad, out_buf); + adec->last_ret = gst_pad_push (adec->srcpad, out_buf); return TRUE; } @@ -608,6 +616,9 @@ gst_dshowaudiodec_sink_event (GstPad * pad, GstEvent * event) ret = gst_pad_event_default (pad, event); break; } + + gst_object_unref (adec); + return ret; } @@ -899,7 +910,6 @@ gst_dshowaudiodec_setup_graph (GstDshowAudioDec * adec) ret = TRUE; adec->setup = TRUE; end: - gst_object_unref (adec); if (input_format) g_free (input_format); if (gstdshowinterface) diff --git a/sys/dshowdecwrapper/gstdshowaudiodec.h b/sys/dshowdecwrapper/gstdshowaudiodec.h index d29ad7c17..d667aa469 100644 --- a/sys/dshowdecwrapper/gstdshowaudiodec.h +++ b/sys/dshowdecwrapper/gstdshowaudiodec.h @@ -68,6 +68,8 @@ struct _GstDshowAudioDec /* element pads */ GstPad *sinkpad; GstPad *srcpad; + + GstFlowReturn last_ret; /* filters interfaces*/ IBaseFilter *srcfilter; diff --git a/sys/dshowdecwrapper/gstdshowvideodec.c b/sys/dshowdecwrapper/gstdshowvideodec.c index 01cf6813b..c31bb9454 100644 --- a/sys/dshowdecwrapper/gstdshowvideodec.c +++ b/sys/dshowdecwrapper/gstdshowvideodec.c @@ -329,6 +329,8 @@ gst_dshowvideodec_init (GstDshowVideoDec * vdec, vdec->decfilter = NULL; vdec->sinkfilter = NULL; + vdec->last_ret = GST_FLOW_OK; + vdec->filtergraph = NULL; vdec->mediafilter = NULL; vdec->gstdshowsrcfilter = NULL; @@ -659,20 +661,28 @@ gst_dshowvideodec_sink_event (GstPad * pad, GstEvent * event) ret = gst_pad_event_default (pad, event); break; } + + gst_object_unref (vdec); + return ret; } static GstFlowReturn gst_dshowvideodec_chain (GstPad * pad, GstBuffer * buffer) { - GstFlowReturn ret = GST_FLOW_OK; GstDshowVideoDec *vdec = (GstDshowVideoDec *) gst_pad_get_parent (pad); gboolean discount = FALSE; GstClockTime stop; if (!vdec->gstdshowsrcfilter) { /* we are not setup */ - ret = GST_FLOW_WRONG_STATE; + 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; } @@ -707,7 +717,7 @@ beach: gst_buffer_unref (buffer); gst_object_unref (vdec); - return ret; + return vdec->last_ret; } static gboolean @@ -733,8 +743,9 @@ gst_dshowvideodec_push_buffer (byte * buffer, long size, byte * src_object, return FALSE; } - /* buffer is in our segment allocate a new out buffer and clip its timestamps */ - gst_pad_alloc_buffer (vdec->srcpad, GST_BUFFER_OFFSET_NONE, + /* buffer is in our segment allocate a new out buffer and clip its + * timestamps */ + vdec->last_ret = gst_pad_alloc_buffer (vdec->srcpad, GST_BUFFER_OFFSET_NONE, size, GST_PAD_CAPS (vdec->srcpad), &buf); if (!buf) { GST_CAT_WARNING_OBJECT (dshowvideodec_debug, vdec, @@ -743,7 +754,6 @@ gst_dshowvideodec_push_buffer (byte * buffer, long size, byte * src_object, } /* set buffer properties */ - GST_BUFFER_SIZE (buf) = size; GST_BUFFER_TIMESTAMP (buf) = clip_start; GST_BUFFER_DURATION (buf) = clip_stop - clip_start; @@ -760,7 +770,7 @@ gst_dshowvideodec_push_buffer (byte * buffer, long size, byte * src_object, buffer + (size - ((line + 1) * (stride))), stride); } } else { - memcpy (GST_BUFFER_DATA (buf), buffer, size); + memcpy (GST_BUFFER_DATA (buf), buffer, MIN (size, GST_BUFFER_SIZE (buf))); } GST_CAT_LOG_OBJECT (dshowvideodec_debug, vdec, @@ -771,7 +781,7 @@ gst_dshowvideodec_push_buffer (byte * buffer, long size, byte * src_object, GST_TIME_ARGS (GST_BUFFER_DURATION (buf))); /* push the buffer downstream */ - gst_pad_push (vdec->srcpad, buf); + vdec->last_ret = gst_pad_push (vdec->srcpad, buf); return TRUE; } @@ -781,6 +791,7 @@ 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 (); @@ -795,7 +806,7 @@ gst_dshowvideodec_src_getcaps (GstPad * pad) &output_pin)) { GST_ELEMENT_ERROR (vdec, STREAM, FAILED, ("failed getting ouput pin from the decoder"), (NULL)); - return NULL; + goto beach; } hres = IPin_EnumMediaTypes (output_pin, &enum_mediatypes); @@ -848,9 +859,12 @@ gst_dshowvideodec_src_getcaps (GstPad * pad) } if (vdec->srccaps) - return gst_caps_ref (vdec->srccaps); + caps = gst_caps_ref (vdec->srccaps); + +beach: + gst_object_unref (vdec); - return NULL; + return caps; } static gboolean diff --git a/sys/dshowdecwrapper/gstdshowvideodec.h b/sys/dshowdecwrapper/gstdshowvideodec.h index 12f3a28e1..0989dabc4 100644 --- a/sys/dshowdecwrapper/gstdshowvideodec.h +++ b/sys/dshowdecwrapper/gstdshowvideodec.h @@ -70,6 +70,8 @@ struct _GstDshowVideoDec /* caps of our src pad */ GstCaps *srccaps; + + GstFlowReturn last_ret; /* list of dshow mediatypes coresponding to the caps list */ GList *mediatypes; |