X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gst%2Favi%2Fgstavidemux.c;h=6bcdffd73c5159058bfab0d2f2f1899f2001ad42;hb=86933b40e928d1697a1eb72ded294e8714f00b9b;hp=4474f3cac1203b4d716fe3388b432d4a71f717fe;hpb=abd9c0c657ea0f8f0cf90a37adca160cc99f62df;p=platform%2Fupstream%2Fgst-plugins-good.git diff --git a/gst/avi/gstavidemux.c b/gst/avi/gstavidemux.c index 4474f3c..6bcdffd 100644 --- a/gst/avi/gstavidemux.c +++ b/gst/avi/gstavidemux.c @@ -57,6 +57,12 @@ #define DIV_ROUND_UP(s,v) (((s) + ((v)-1)) / (v)) +#define GST_AVI_KEYFRAME 1 +#define ENTRY_IS_KEYFRAME(e) ((e)->flags == GST_AVI_KEYFRAME) +#define ENTRY_SET_KEYFRAME(e) ((e)->flags = GST_AVI_KEYFRAME) +#define ENTRY_UNSET_KEYFRAME(e) ((e)->flags = 0) + + GST_DEBUG_CATEGORY_STATIC (avidemux_debug); #define GST_CAT_DEFAULT avidemux_debug @@ -145,13 +151,6 @@ gst_avi_demux_get_type (void) static void gst_avi_demux_base_init (GstAviDemuxClass * klass) { - static const GstElementDetails gst_avi_demux_details = - GST_ELEMENT_DETAILS ("Avi demuxer", - "Codec/Demuxer", - "Demultiplex an avi file into audio and video", - "Erik Walthinsen \n" - "Wim Taymans \n" - "Thijs Vermeir "); GstElementClass *element_class = GST_ELEMENT_CLASS (klass); GstPadTemplate *videosrctempl, *audiosrctempl, *subsrctempl; GstCaps *audcaps, *vidcaps, *subcaps; @@ -175,7 +174,12 @@ gst_avi_demux_base_init (GstAviDemuxClass * klass) gst_element_class_add_pad_template (element_class, subsrctempl); gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&sink_templ)); - gst_element_class_set_details (element_class, &gst_avi_demux_details); + gst_element_class_set_details_simple (element_class, "Avi demuxer", + "Codec/Demuxer", + "Demultiplex an avi file into audio and video", + "Erik Walthinsen , " + "Wim Taymans , " + "Thijs Vermeir "); } static void @@ -285,6 +289,10 @@ gst_avi_demux_reset (GstAviDemux * avi) gst_object_unref (avi->element_index); avi->element_index = NULL; + if (avi->close_seg_event) { + gst_event_unref (avi->close_seg_event); + avi->close_seg_event = NULL; + } if (avi->seg_event) { gst_event_unref (avi->seg_event); avi->seg_event = NULL; @@ -640,9 +648,9 @@ gst_avi_demux_seek_streams (GstAviDemux * avi, guint64 offset, gboolean before) if (before) { if (entry) { + gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &val); GST_DEBUG_OBJECT (avi, "stream %d, previous entry at %" G_GUINT64_FORMAT, i, val); - gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &val); if (val < min) min = val; } @@ -707,9 +715,9 @@ gst_avi_demux_seek_streams_index (GstAviDemux * avi, guint64 offset, if (before) { if (entry) { + val = stream->index[index].offset; GST_DEBUG_OBJECT (avi, "stream %d, previous entry at %" G_GUINT64_FORMAT, i, val); - val = stream->index[index].offset; if (val < min) min = val; } @@ -1984,22 +1992,36 @@ gst_avi_demux_parse_stream (GstAviDemux * avi, GstBuffer * buf) GST_DEBUG_OBJECT (element, "marking video as VBR, res %d", res); break; case GST_RIFF_FCC_auds: - stream->is_vbr = (stream->strh->samplesize == 0) - && stream->strh->scale > 1; res = gst_riff_parse_strf_auds (element, sub, &stream->strf.auds, &stream->extradata); + stream->is_vbr = (stream->strh->samplesize == 0) + && stream->strh->scale > 1 + && stream->strf.auds->blockalign != 1; sub = NULL; GST_DEBUG_OBJECT (element, "marking audio as VBR:%d, res %d", stream->is_vbr, res); /* we need these or we have no way to come up with timestamps */ - if ((stream->is_vbr && !stream->strf.auds->av_bps) || - (!stream->is_vbr && (!stream->strh->scale || + if ((!stream->is_vbr && !stream->strf.auds->av_bps) || + (stream->is_vbr && (!stream->strh->scale || !stream->strh->rate))) { GST_WARNING_OBJECT (element, "invalid audio header, ignoring stream"); goto fail; } + /* some more sanity checks */ + if (stream->is_vbr) { + if (stream->strf.auds->blockalign <= 4) { + /* that would mean (too) many frames per chunk, + * so not likely set as expected */ + GST_DEBUG_OBJECT (element, + "suspicious blockalign %d for VBR audio; " + "overriding to 1 frame per chunk", + stream->strf.auds->blockalign); + /* this should top any likely value */ + stream->strf.auds->blockalign = (1 << 12); + } + } break; case GST_RIFF_FCC_iavs: stream->is_vbr = TRUE; @@ -2073,6 +2095,9 @@ gst_avi_demux_parse_stream (GstAviDemux * avi, GstBuffer * buf) } GST_DEBUG_OBJECT (avi, "stream name: %s", stream->name); break; + case GST_RIFF_IDIT: + gst_avi_demux_parse_idit (avi, sub); + break; default: if (tag == GST_MAKE_FOURCC ('i', 'n', 'd', 'x') || tag == GST_MAKE_FOURCC ('i', 'x', '0' + avi->num_streams / 10, @@ -2348,7 +2373,7 @@ gst_avi_demux_parse_odml (GstAviDemux * avi, GstBuffer * buf) static guint gst_avi_demux_index_last (GstAviDemux * avi, GstAviStream * stream) { - return stream->idx_n - 1; + return stream->idx_n; } /* find a previous entry in the index with the given flags */ @@ -2751,7 +2776,7 @@ gst_avi_demux_stream_index_push (GstAviDemux * avi) GST_DEBUG ("will parse index chunk size %u for tag %" GST_FOURCC_FORMAT, GST_BUFFER_SIZE (buf), GST_FOURCC_ARGS (tag)); - avi->offset = avi->first_movi_offset - 8; + avi->offset = avi->first_movi_offset; gst_avi_demux_parse_index (avi, buf); #ifndef GST_DISABLE_GST_DEBUG @@ -3358,9 +3383,12 @@ header_wrong_avih: } static void -gst_avi_demux_add_date_tag (GstAviDemux * avi, gint y, gint m, gint d) +gst_avi_demux_add_date_tag (GstAviDemux * avi, gint y, gint m, gint d, + gint h, gint min, gint s) { GDate *date; + GstDateTime *dt; + date = g_date_new_dmy (d, m, y); if (!g_date_valid (date)) { /* bogus date */ @@ -3369,12 +3397,19 @@ gst_avi_demux_add_date_tag (GstAviDemux * avi, gint y, gint m, gint d) return; } + dt = gst_date_time_new_local_time (y, m, d, h, min, s); + if (avi->globaltags == NULL) avi->globaltags = gst_tag_list_new (); gst_tag_list_add (avi->globaltags, GST_TAG_MERGE_REPLACE, GST_TAG_DATE, date, NULL); g_date_free (date); + if (dt) { + gst_tag_list_add (avi->globaltags, GST_TAG_MERGE_REPLACE, GST_TAG_DATE_TIME, + dt, NULL); + gst_date_time_unref (dt); + } } static void @@ -3388,7 +3423,7 @@ gst_avi_demux_parse_idit_nums_only (GstAviDemux * avi, gchar * data) GST_WARNING_OBJECT (avi, "Failed to parse IDIT tag"); return; } - gst_avi_demux_add_date_tag (avi, y, m, d); + gst_avi_demux_add_date_tag (avi, y, m, d, 0, 0, 0); } static gint @@ -3439,7 +3474,7 @@ gst_avi_demux_parse_idit_text (GstAviDemux * avi, gchar * data) return; } month = get_month_num (monthstr, strlen (monthstr)); - gst_avi_demux_add_date_tag (avi, year, month, day); + gst_avi_demux_add_date_tag (avi, year, month, day, hour, min, sec); } static void @@ -3914,7 +3949,7 @@ gst_avi_demux_do_seek (GstAviDemux * avi, GstSegment * segment) GstAviStream *stream; seek_time = segment->last_stop; - keyframe = !!(segment->flags & GST_SEEK_FLAG_KEY_UNIT); + keyframe = ! !(segment->flags & GST_SEEK_FLAG_KEY_UNIT); GST_DEBUG_OBJECT (avi, "seek to: %" GST_TIME_FORMAT " keyframe seeking:%d", GST_TIME_ARGS (seek_time), keyframe); @@ -4059,6 +4094,7 @@ gst_avi_demux_handle_seek (GstAviDemux * avi, GstPad * pad, GstEvent * event) * actually never fails. */ gst_avi_demux_do_seek (avi, &seeksegment); + gst_event_replace (&avi->close_seg_event, NULL); if (flush) { GstEvent *fevent = gst_event_new_flush_stop (); @@ -4066,16 +4102,13 @@ gst_avi_demux_handle_seek (GstAviDemux * avi, GstPad * pad, GstEvent * event) gst_avi_demux_push_event (avi, gst_event_ref (fevent)); gst_pad_push_event (avi->sinkpad, fevent); } else if (avi->segment_running) { - GstEvent *seg; - /* we are running the current segment and doing a non-flushing seek, * close the segment first based on the last_stop. */ GST_DEBUG_OBJECT (avi, "closing running segment %" G_GINT64_FORMAT " to %" G_GINT64_FORMAT, avi->segment.start, avi->segment.last_stop); - seg = gst_event_new_new_segment_full (TRUE, + avi->close_seg_event = gst_event_new_new_segment_full (TRUE, avi->segment.rate, avi->segment.applied_rate, avi->segment.format, avi->segment.start, avi->segment.last_stop, avi->segment.time); - gst_avi_demux_push_event (avi, seg); } /* now update the real segment info */ @@ -4182,7 +4215,7 @@ avi_demux_handle_seek_push (GstAviDemux * avi, GstPad * pad, GstEvent * event) gst_segment_set_seek (&seeksegment, rate, format, flags, cur_type, cur, stop_type, stop, &update); - keyframe = !!(flags & GST_SEEK_FLAG_KEY_UNIT); + keyframe = ! !(flags & GST_SEEK_FLAG_KEY_UNIT); cur = seeksegment.last_stop; GST_DEBUG_OBJECT (avi, @@ -4483,7 +4516,7 @@ gst_avi_demux_advance (GstAviDemux * avi, GstAviStream * stream, new_entry = old_entry + 1; /* see if we reached the end */ - if (new_entry > stream->stop_entry) { + if (new_entry >= stream->stop_entry) { if (avi->segment.rate < 0.0) { if (stream->step_entry == stream->start_entry) { /* we stepped all the way to the start, eos */ @@ -4855,9 +4888,13 @@ gst_avi_demux_stream_data (GstAviDemux * avi) * through the whole file */ if (avi->abort_buffering) { avi->abort_buffering = FALSE; - gst_adapter_flush (avi->adapter, 8); + if (size) { + gst_adapter_flush (avi->adapter, 8); + return GST_FLOW_OK; + } + } else { + return GST_FLOW_OK; } - return GST_FLOW_OK; } GST_DEBUG ("chunk ID %" GST_FOURCC_FORMAT ", size %u", GST_FOURCC_ARGS (tag), size); @@ -4886,9 +4923,13 @@ gst_avi_demux_stream_data (GstAviDemux * avi) if (saw_desired_kf) { gst_adapter_flush (avi->adapter, 8); /* get buffer */ - buf = gst_adapter_take_buffer (avi->adapter, GST_ROUND_UP_2 (size)); - /* patch the size */ - GST_BUFFER_SIZE (buf) = size; + if (size) { + buf = gst_adapter_take_buffer (avi->adapter, GST_ROUND_UP_2 (size)); + /* patch the size */ + GST_BUFFER_SIZE (buf) = size; + } else { + buf = NULL; + } } else { GST_DEBUG_OBJECT (avi, "Desired keyframe not yet reached, flushing chunk"); @@ -4962,6 +5003,7 @@ gst_avi_demux_stream_data (GstAviDemux * avi) stream->discont = FALSE; } res = gst_pad_push (stream->pad, buf); + buf = NULL; /* combine flows */ res = gst_avi_demux_combine_flows (avi, stream, res); @@ -5051,6 +5093,10 @@ gst_avi_demux_loop (GstPad * pad) avi->state = GST_AVI_DEMUX_MOVI; break; case GST_AVI_DEMUX_MOVI: + if (G_UNLIKELY (avi->close_seg_event)) { + gst_avi_demux_push_event (avi, avi->close_seg_event); + avi->close_seg_event = NULL; + } if (G_UNLIKELY (avi->seg_event)) { gst_avi_demux_push_event (avi, avi->seg_event); avi->seg_event = NULL; @@ -5076,13 +5122,13 @@ gst_avi_demux_loop (GstPad * pad) return; /* ERRORS */ -pause: - GST_LOG_OBJECT (avi, "pausing task, reason %s", gst_flow_get_name (res)); - avi->segment_running = FALSE; - gst_pad_pause_task (avi->sinkpad); +pause:{ + + gboolean push_eos = FALSE; + GST_LOG_OBJECT (avi, "pausing task, reason %s", gst_flow_get_name (res)); + avi->segment_running = FALSE; + gst_pad_pause_task (avi->sinkpad); - if (GST_FLOW_IS_FATAL (res) || (res == GST_FLOW_NOT_LINKED)) { - gboolean push_eos = TRUE; if (res == GST_FLOW_UNEXPECTED) { /* handle end-of-stream/segment */ @@ -5098,13 +5144,17 @@ pause: (GST_ELEMENT_CAST (avi), gst_message_new_segment_done (GST_OBJECT_CAST (avi), GST_FORMAT_TIME, stop)); - push_eos = FALSE; + } else { + push_eos = TRUE; } - } else { - /* for fatal errors we post an error message */ + } else if (res == GST_FLOW_NOT_LINKED || res < GST_FLOW_UNEXPECTED) { + /* for fatal errors we post an error message, wrong-state is + * not fatal because it happens due to flushes and only means + * that we should stop now. */ GST_ELEMENT_ERROR (avi, STREAM, FAILED, (_("Internal data stream error.")), ("streaming stopped, reason %s", gst_flow_get_name (res))); + push_eos = TRUE; } if (push_eos) { GST_INFO_OBJECT (avi, "sending eos"); @@ -5150,6 +5200,10 @@ gst_avi_demux_chain (GstPad * pad, GstBuffer * buf) } break; case GST_AVI_DEMUX_MOVI: + if (G_UNLIKELY (avi->close_seg_event)) { + gst_avi_demux_push_event (avi, avi->close_seg_event); + avi->close_seg_event = NULL; + } if (G_UNLIKELY (avi->seg_event)) { gst_avi_demux_push_event (avi, avi->seg_event); avi->seg_event = NULL; @@ -5341,6 +5395,7 @@ gst_avi_demux_change_state (GstElement * element, GstStateChange transition) switch (transition) { case GST_STATE_CHANGE_PAUSED_TO_READY: + avi->have_index = FALSE; gst_avi_demux_reset (avi); break; default: