diff options
author | Dave Robillard <dave@drobilla.net> | 2009-08-09 00:14:42 -0400 |
---|---|---|
committer | Dave Robillard <dave@drobilla.net> | 2009-08-09 00:14:42 -0400 |
commit | af3f7e7f20eaf961f4384940ec6ad987bb0afbb6 (patch) | |
tree | c42a7ad4f2dea47dd645a729a6ee0399bd80cfb1 /gst/mpegdemux | |
parent | adadf06b0a9e26005ba9363aa0049dc0b740c94d (diff) | |
parent | dd5afbf0c6557ad89994cbfd91e4117e8503b81a (diff) | |
download | gst-plugins-bad-af3f7e7f20eaf961f4384940ec6ad987bb0afbb6.tar.gz gst-plugins-bad-af3f7e7f20eaf961f4384940ec6ad987bb0afbb6.tar.bz2 gst-plugins-bad-af3f7e7f20eaf961f4384940ec6ad987bb0afbb6.zip |
Merge branch 'fdo' into lv2
Diffstat (limited to 'gst/mpegdemux')
-rw-r--r-- | gst/mpegdemux/gstmpegdefs.h | 65 | ||||
-rw-r--r-- | gst/mpegdemux/gstmpegdemux.c | 295 | ||||
-rw-r--r-- | gst/mpegdemux/gstmpegdemux.h | 3 | ||||
-rw-r--r-- | gst/mpegdemux/gstmpegtsdemux.c | 102 |
4 files changed, 252 insertions, 213 deletions
diff --git a/gst/mpegdemux/gstmpegdefs.h b/gst/mpegdemux/gstmpegdefs.h index 375f1dc0..40551137 100644 --- a/gst/mpegdemux/gstmpegdefs.h +++ b/gst/mpegdemux/gstmpegdefs.h @@ -147,39 +147,52 @@ * 0x0F-0x7F ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Reserved * 0x80-0xFF User Private */ -#define ST_RESERVED 0x00 -#define ST_VIDEO_MPEG1 0x01 -#define ST_VIDEO_MPEG2 0x02 -#define ST_AUDIO_MPEG1 0x03 -#define ST_AUDIO_MPEG2 0x04 -#define ST_PRIVATE_SECTIONS 0x05 -#define ST_PRIVATE_DATA 0x06 -#define ST_MHEG 0x07 -#define ST_DSMCC 0x08 -#define ST_H222_1 0x09 +#define ST_RESERVED 0x00 +#define ST_VIDEO_MPEG1 0x01 +#define ST_VIDEO_MPEG2 0x02 +#define ST_AUDIO_MPEG1 0x03 +#define ST_AUDIO_MPEG2 0x04 +#define ST_PRIVATE_SECTIONS 0x05 +#define ST_PRIVATE_DATA 0x06 +#define ST_MHEG 0x07 +#define ST_DSMCC 0x08 +#define ST_H222_1 0x09 /* later extensions */ -#define ST_AUDIO_AAC 0x0f -#define ST_VIDEO_MPEG4 0x10 -#define ST_VIDEO_H264 0x1b +#define ST_AUDIO_AAC 0x0f +#define ST_VIDEO_MPEG4 0x10 +#define ST_VIDEO_H264 0x1b /* Un-official Dirac extension */ -#define ST_VIDEO_DIRAC 0xd1 +#define ST_VIDEO_DIRAC 0xd1 /* private stream types */ -#define ST_PS_AUDIO_AC3 0x81 -#define ST_PS_AUDIO_DTS 0x8a -#define ST_PS_AUDIO_LPCM 0x8b +#define ST_PS_AUDIO_AC3 0x81 +#define ST_PS_AUDIO_DTS 0x8a +#define ST_PS_AUDIO_LPCM 0x8b #define ST_PS_DVD_SUBPICTURE 0xff -/* Blu-ray PGS subpictures */ +/* Blu-ray related */ +#define ST_BD_AUDIO_LPCM 0x80 +#define ST_BD_AUDIO_AC3 0x81 +#define ST_BD_AUDIO_DTS 0x82 +#define ST_BD_AUDIO_AC3_TRUE_HD 0x83 +#define ST_BD_AUDIO_AC3_PLUS 0x84 +#define ST_BD_AUDIO_DTS_HD 0x85 #define ST_BD_PGS_SUBPICTURE 0x90 +#define ST_BD_IGS 0x91 +#define ST_BD_SUBTITLE 0x92 +#define ST_BD_SECONDARY_AC3_PLUS 0xa1 +#define ST_BD_SECONDARY_DTS_HD 0xa2 + +/* VC1 extension */ +#define ST_VIDEO_VC1 0xea /* HDV AUX stream mapping * 0xA0 ISO/IEC 61834-11 * 0xA1 ISO/IEC 61834-11 */ -#define ST_HDV_AUX_A 0xa0 -#define ST_HDV_AUX_V 0xa1 +#define ST_HDV_AUX_A 0xa0 +#define ST_HDV_AUX_V 0xa1 /* Un-official time-code stream */ #define ST_PS_TIMECODE 0xd2 @@ -202,16 +215,16 @@ /* sync:4 == 00xx ! pts:3 ! 1 ! pts:15 ! 1 | pts:15 ! 1 */ #define READ_TS(data, target, lost_sync_label) \ if ((*data & 0x01) != 0x01) goto lost_sync_label; \ - target = ((guint64) (*data++ & 0x0E)) << 29; \ - target |= ((guint64) (*data++ )) << 22; \ + target = ((guint64) (*data++ & 0x0E)) << 29; \ + target |= ((guint64) (*data++ )) << 22; \ if ((*data & 0x01) != 0x01) goto lost_sync_label; \ - target |= ((guint64) (*data++ & 0xFE)) << 14; \ - target |= ((guint64) (*data++ )) << 7; \ + target |= ((guint64) (*data++ & 0xFE)) << 14; \ + target |= ((guint64) (*data++ )) << 7; \ if ((*data & 0x01) != 0x01) goto lost_sync_label; \ target |= ((guint64) (*data++ & 0xFE)) >> 1; /* some extra GstFlowReturn values used internally */ -#define GST_FLOW_NEED_MORE_DATA -100 -#define GST_FLOW_LOST_SYNC -101 +#define GST_FLOW_NEED_MORE_DATA -100 +#define GST_FLOW_LOST_SYNC -101 #endif /* __GST_MPEG_DEFS_H__ */ diff --git a/gst/mpegdemux/gstmpegdemux.c b/gst/mpegdemux/gstmpegdemux.c index 75d5960f..5fe27711 100644 --- a/gst/mpegdemux/gstmpegdemux.c +++ b/gst/mpegdemux/gstmpegdemux.c @@ -53,7 +53,7 @@ #define MAX_DVD_AUDIO_STREAMS 8 #define MAX_DVD_SUBPICTURE_STREAMS 32 -#define BLOCK_SZ 4096 +#define BLOCK_SZ 32768 #define SCAN_SCR_SZ 12 #define SCAN_PTS_SZ 80 @@ -77,42 +77,6 @@ typedef enum GST_DEBUG_CATEGORY_STATIC (gstflupsdemux_debug); #define GST_CAT_DEFAULT (gstflupsdemux_debug) -#ifndef GST_CHECK_VERSION -#define GST_CHECK_VERSION(major,minor,micro) \ - (GST_VERSION_MAJOR > (major) || \ - (GST_VERSION_MAJOR == (major) && GST_VERSION_MINOR > (minor)) || \ - (GST_VERSION_MAJOR == (major) && GST_VERSION_MINOR == (minor) && \ - GST_VERSION_MICRO >= (micro))) -#endif - -#if !GST_CHECK_VERSION(0,10,9) -#define GST_BUFFER_IS_DISCONT(buffer) \ - (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) -#endif - -#if GST_CHECK_VERSION(0,10,6) -#define HAVE_NEWSEG_FULL -#else -static GstBuffer * -gst_adapter_take_buffer (GstAdapter * adapter, guint nbytes) -{ - GstBuffer *buf = NULL; - - if (G_UNLIKELY (nbytes > adapter->size)) - return NULL; - - buf = gst_buffer_new_and_alloc (nbytes); - - if (G_UNLIKELY (!buf)) - return NULL; - - /* Slow... */ - memcpy (GST_BUFFER_DATA (buf), gst_adapter_peek (adapter, nbytes), nbytes); - - return buf; -} -#endif - /* elementfactory information */ static GstElementDetails flups_demux_details = { "The Fluendo MPEG Program Stream Demuxer", @@ -176,7 +140,7 @@ static GstStaticPadTemplate audio_template = GST_PAD_SRC, GST_PAD_SOMETIMES, GST_STATIC_CAPS ("audio/mpeg, " - "mpegversion = (int) 1;" + "mpegversion = (int) { 1, 4 };" "audio/x-private1-lpcm; " "audio/x-private1-ac3;" "audio/x-private1-dts;" "audio/ac3") ); @@ -211,6 +175,7 @@ static void gst_flups_demux_loop (GstPad * pad); static gboolean gst_flups_demux_src_event (GstPad * pad, GstEvent * event); static gboolean gst_flups_demux_src_query (GstPad * pad, GstQuery * query); +static const GstQueryType *gst_flups_demux_src_query_type (GstPad * pad); static GstStateChangeReturn gst_flups_demux_change_state (GstElement * element, GstStateChange transition); @@ -220,9 +185,9 @@ static inline gboolean gst_flups_demux_scan_forward_ts (GstFluPSDemux * demux, static inline gboolean gst_flups_demux_scan_backward_ts (GstFluPSDemux * demux, guint64 * pos, SCAN_MODE mode, guint64 * rts); -static void gst_flups_demux_send_segment_updates (GstFluPSDemux * demux, +static inline void gst_flups_demux_send_segment_updates (GstFluPSDemux * demux, GstClockTime new_time); -static void gst_flups_demux_clear_times (GstFluPSDemux * demux); +static inline void gst_flups_demux_clear_times (GstFluPSDemux * demux); static GstElementClass *parent_class = NULL; @@ -316,6 +281,9 @@ gst_flups_demux_init (GstFluPSDemux * demux) demux->streams = g_malloc0 (sizeof (GstFluPSStream *) * (GST_FLUPS_DEMUX_MAX_STREAMS)); + demux->streams_found = + g_malloc0 (sizeof (GstFluPSStream *) * (GST_FLUPS_DEMUX_MAX_STREAMS)); + demux->found_count = 0; } @@ -324,6 +292,7 @@ gst_flups_demux_finalize (GstFluPSDemux * demux) { gst_flups_demux_reset (demux); g_free (demux->streams); + g_free (demux->streams_found); G_OBJECT_CLASS (parent_class)->finalize (G_OBJECT (demux)); } @@ -346,6 +315,9 @@ gst_flups_demux_reset (GstFluPSDemux * demux) demux->streams[i] = NULL; } } + memset (demux->streams_found, 0, + sizeof (GstFluPSStream *) * (GST_FLUPS_DEMUX_MAX_STREAMS)); + demux->found_count = 0; p_ev = &demux->lang_codes; gst_event_replace (p_ev, NULL); @@ -402,7 +374,12 @@ gst_flups_demux_create_stream (GstFluPSDemux * demux, gint id, gint stream_type) case ST_PRIVATE_DATA: case ST_MHEG: case ST_DSMCC: + break; case ST_AUDIO_AAC: + template = klass->audio_template; + name = g_strdup_printf ("audio_%02x", id); + caps = gst_caps_new_simple ("audio/mpeg", + "mpegversion", G_TYPE_INT, 4, NULL); break; case ST_VIDEO_H264: template = klass->video_template; @@ -454,6 +431,8 @@ gst_flups_demux_create_stream (GstFluPSDemux * demux, gint id, gint stream_type) GST_DEBUG_FUNCPTR (gst_flups_demux_src_event)); gst_pad_set_query_function (stream->pad, GST_DEBUG_FUNCPTR (gst_flups_demux_src_query)); + gst_pad_set_query_type_function (stream->pad, + GST_DEBUG_FUNCPTR (gst_flups_demux_src_query_type)); gst_pad_use_fixed_caps (stream->pad); gst_pad_set_caps (stream->pad, caps); gst_caps_unref (caps); @@ -480,6 +459,7 @@ gst_flups_demux_get_stream (GstFluPSDemux * demux, gint id, gint type) gst_element_add_pad (GST_ELEMENT (demux), stream->pad); demux->streams[id] = stream; + demux->streams_found[demux->found_count++] = stream; } return stream; @@ -503,13 +483,13 @@ gst_flups_demux_send_data (GstFluPSDemux * demux, GstFluPSStream * stream, goto no_stream; /* timestamps */ - if (demux->next_pts != G_MAXUINT64) + if (G_UNLIKELY (demux->next_pts != G_MAXUINT64)) timestamp = MPEGTIME_TO_GSTTIME (demux->next_pts); else timestamp = GST_CLOCK_TIME_NONE; /* discont */ - if (stream->need_segment) { + if (G_UNLIKELY (stream->need_segment)) { gint64 time, start, stop; GstEvent *newsegment; @@ -545,7 +525,6 @@ gst_flups_demux_send_data (GstFluPSDemux * demux, GstFluPSStream * stream, else time = 0; -#ifdef HAVE_NEWSEG_FULL GST_INFO_OBJECT (demux, "sending new segment: rate %g applied_rate %g " "start: %" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT ", time: %" GST_TIME_FORMAT " to pad %" GST_PTR_FORMAT, @@ -556,16 +535,6 @@ gst_flups_demux_send_data (GstFluPSDemux * demux, GstFluPSStream * stream, newsegment = gst_event_new_new_segment_full (FALSE, demux->sink_segment.rate, demux->sink_segment.applied_rate, GST_FORMAT_TIME, start, stop, time); -#else - GST_INFO_OBJECT (demux, "sending new segment: rate %g " - "start: %" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT - ", time: %" GST_TIME_FORMAT " to pad %" GST_PTR_FORMAT, - demux->sink_segment.rate, GST_TIME_ARGS (start), - GST_TIME_ARGS (stop), GST_TIME_ARGS (time), stream->pad); - - newsegment = gst_event_new_new_segment (FALSE, - demux->sink_segment.rate, GST_FORMAT_TIME, start, stop, time); -#endif gst_pad_push_event (stream->pad, newsegment); @@ -628,17 +597,17 @@ no_stream: } } -static void +static inline void gst_flups_demux_mark_discont (GstFluPSDemux * demux, gboolean discont, gboolean need_segment) { - gint id; + gint i, count = demux->found_count; /* mark discont on all streams */ - for (id = 0; id < GST_FLUPS_DEMUX_MAX_STREAMS; id++) { - GstFluPSStream *stream = demux->streams[id]; + for (i = 0; i < count; i++) { + GstFluPSStream *stream = demux->streams_found[i]; - if (stream) { + if (G_LIKELY (stream)) { stream->discont |= discont; stream->need_segment |= need_segment; GST_DEBUG_OBJECT (demux, "marked stream as discont %d, need_segment %d", @@ -647,14 +616,14 @@ gst_flups_demux_mark_discont (GstFluPSDemux * demux, gboolean discont, } } -static gboolean +static inline gboolean gst_flups_demux_send_event (GstFluPSDemux * demux, GstEvent * event) { - gint id; + gint i, count = demux->found_count; gboolean ret = FALSE; - for (id = 0; id < GST_FLUPS_DEMUX_MAX_STREAMS; id++) { - GstFluPSStream *stream = demux->streams[id]; + for (i = 0; i < count; i++) { + GstFluPSStream *stream = demux->streams_found[i]; if (stream && !stream->notlinked) { (void) gst_event_ref (event); @@ -715,7 +684,7 @@ gst_flups_demux_handle_dvd_event (GstFluPSDemux * demux, GstEvent * event) break; case 0x2: case 0x3: - /* MPEG audio without and with extension stream are + /* MPEG audio without and with extension stream are * treated the same */ stream_id = 0xC0 + i; temp = gst_flups_demux_get_stream (demux, stream_id, ST_AUDIO_MPEG1); @@ -777,27 +746,27 @@ gst_flups_demux_flush (GstFluPSDemux * demux) demux->bytes_since_scr = 0; } -static void +static inline void gst_flups_demux_clear_times (GstFluPSDemux * demux) { - gint id; + gint i, count = demux->found_count; /* Clear the last ts for all streams */ - for (id = 0; id < GST_FLUPS_DEMUX_MAX_STREAMS; id++) { - GstFluPSStream *stream = demux->streams[id]; + for (i = 0; i < count; i++) { + GstFluPSStream *stream = demux->streams_found[i]; - if (stream) { + if (G_LIKELY (stream)) { stream->last_seg_start = stream->last_ts = GST_CLOCK_TIME_NONE; } } } -static void +static inline void gst_flups_demux_send_segment_updates (GstFluPSDemux * demux, GstClockTime new_time) { /* Advance all lagging streams by sending a segment update */ - gint id; + gint i, count = demux->found_count; GstEvent *event = NULL; /* FIXME: Handle reverse playback */ @@ -805,8 +774,8 @@ gst_flups_demux_send_segment_updates (GstFluPSDemux * demux, if (new_time > demux->src_segment.stop) return; - for (id = 0; id < GST_FLUPS_DEMUX_MAX_STREAMS; id++) { - GstFluPSStream *stream = demux->streams[id]; + for (i = 0; i < count; i++) { + GstFluPSStream *stream = demux->streams_found[i]; if (stream) { if (stream->last_ts == GST_CLOCK_TIME_NONE || @@ -840,17 +809,15 @@ gst_flups_demux_send_segment_updates (GstFluPSDemux * demux, gst_event_unref (event); } -static void +static inline void gst_flups_demux_close_segment (GstFluPSDemux * demux) { - gint id; + gint i, count = demux->found_count; GstEvent *event = NULL; guint64 base_time; -#if POST_10_10 GST_INFO_OBJECT (demux, "closing running segment %" GST_SEGMENT_FORMAT, &demux->src_segment); -#endif /* FIXME: Need to send a different segment-close to each pad where the * last_seg_start != clock_time_none, as that indicates a sparse-stream @@ -859,7 +826,6 @@ gst_flups_demux_close_segment (GstFluPSDemux * demux) if ((base_time = demux->base_time) == (guint64) - 1) base_time = 0; - /* Close the current segment for a linear playback */ if (demux->src_segment.rate >= 0) { /* for forward playback, we played from start to last_stop */ @@ -881,8 +847,8 @@ gst_flups_demux_close_segment (GstFluPSDemux * demux) } if (event) { - for (id = 0; id < GST_FLUPS_DEMUX_MAX_STREAMS; id++) { - GstFluPSStream *stream = demux->streams[id]; + for (i = 0; i < count; i++) { + GstFluPSStream *stream = demux->streams_found[i]; if (stream && !stream->notlinked && !stream->need_segment) { (void) gst_event_ref (event); @@ -905,14 +871,7 @@ gst_flups_demux_close_segment (GstFluPSDemux * demux) static inline gboolean have_open_streams (GstFluPSDemux * demux) { - gint id; - - for (id = 0; id < GST_FLUPS_DEMUX_MAX_STREAMS; id++) { - if (demux->streams[id]) - return TRUE; - } - - return FALSE; + return (demux->streams_found[0] != NULL); } static gboolean @@ -942,7 +901,6 @@ gst_flups_demux_sink_event (GstPad * pad, GstEvent * event) /* Close current segment */ gst_flups_demux_close_segment (demux); -#ifdef HAVE_NEWSEG_FULL { gdouble arate; @@ -960,19 +918,6 @@ gst_flups_demux_sink_event (GstPad * pad, GstEvent * event) } } -#else - gst_event_parse_new_segment (event, &update, &rate, &format, - &start, &stop, &time); - gst_segment_set_newsegment (&demux->sink_segment, update, rate, - format, start, stop, time); - if (format == GST_FORMAT_BYTES && demux->scr_rate_n != G_MAXUINT64 - && demux->scr_rate_d != G_MAXUINT64) { - - gst_segment_set_newsegment (&demux->src_segment, update, rate, - GST_FORMAT_TIME, BYTES_TO_GSTTIME (start), BYTES_TO_GSTTIME (stop), - BYTES_TO_GSTTIME (time)); - } -#endif GST_INFO_OBJECT (demux, "received new segment: rate %g " "format %d, start: %" G_GINT64_FORMAT ", stop: %" G_GINT64_FORMAT @@ -1096,10 +1041,8 @@ gst_flups_demux_do_seek (GstFluPSDemux * demux, GstSegment * seeksegment) scr = MAX (demux->first_scr, scr); fscr = scr; -#if POST_10_10 GST_INFO_OBJECT (demux, "sink segment configured %" GST_SEGMENT_FORMAT ", trying to go at SCR: %" G_GUINT64_FORMAT, &demux->sink_segment, scr); -#endif offset = MIN (gst_util_uint64_scale (scr, scr_rate_n, scr_rate_d), demux->sink_segment.stop); @@ -1156,6 +1099,7 @@ gst_flups_demux_handle_seek_pull (GstFluPSDemux * demux, GstEvent * event) if (flush) { /* Flush start up and downstream to make sure data flow and loops are idle */ + demux->flushing = TRUE; gst_flups_demux_send_event (demux, gst_event_new_flush_start ()); gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ()); } else { @@ -1168,25 +1112,22 @@ gst_flups_demux_handle_seek_pull (GstFluPSDemux * demux, GstEvent * event) if (flush) { /* Stop flushing upstream we need to pull */ + demux->flushing = FALSE; gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop ()); } /* Work on a copy until we are sure the seek succeeded. */ memcpy (&seeksegment, &demux->src_segment, sizeof (GstSegment)); -#if POST_10_10 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT, &demux->src_segment); -#endif /* Apply the seek to our segment */ gst_segment_set_seek (&seeksegment, rate, format, flags, start_type, start, stop_type, stop, &update); -#if POST_10_10 GST_DEBUG_OBJECT (demux, "seek segment configured %" GST_SEGMENT_FORMAT, &seeksegment); -#endif if (flush || seeksegment.last_stop != demux->src_segment.last_stop) { /* Do the actual seeking */ @@ -1204,10 +1145,8 @@ gst_flups_demux_handle_seek_pull (GstFluPSDemux * demux, GstEvent * event) /* update the rate in our src segment */ demux->sink_segment.rate = rate; -#if POST_10_10 GST_DEBUG_OBJECT (demux, "seek segment adjusted %" GST_SEGMENT_FORMAT, &seeksegment); -#endif if (flush) { /* Stop flushing, the sinks are at time 0 now */ @@ -1283,6 +1222,19 @@ gst_flups_demux_src_event (GstPad * pad, GstEvent * event) return res; } +static const GstQueryType * +gst_flups_demux_src_query_type (GstPad * pad) +{ + static const GstQueryType types[] = { + GST_QUERY_POSITION, + GST_QUERY_DURATION, + GST_QUERY_SEEKING, + 0 + }; + + return types; +} + static gboolean gst_flups_demux_src_query (GstPad * pad, GstQuery * query) { @@ -1349,7 +1301,7 @@ gst_flups_demux_src_query (GstPad * pad, GstQuery * query) break; } - /* Upstream didn't know, so we can only answer TIME queries from + /* Upstream didn't know, so we can only answer TIME queries from * here on */ if (format != GST_FORMAT_TIME) { GST_DEBUG_OBJECT (demux, "duration not supported for format %d", @@ -1423,7 +1375,7 @@ gst_flups_demux_src_query (GstPad * pad, GstQuery * query) * have the SCR */ peerquery = gst_query_new_seeking (GST_FORMAT_BYTES); - res = gst_pad_peer_query (demux->sinkpad, query); + res = gst_pad_peer_query (demux->sinkpad, peerquery); if (!res || demux->scr_rate_n == G_MAXUINT64 || demux->scr_rate_d == G_MAXUINT64) { gst_query_set_seeking (query, fmt, FALSE, -1, -1); @@ -1482,6 +1434,33 @@ gst_flups_demux_reset_psm (GstFluPSDemux * demux) #undef FILL_TYPE } +/* ISO/IEC 13818-1: + * pack_header() { + * pack_start_code 32 bslbf -+ + * '01' 2 bslbf | + * system_clock_reference_base [32..30] 3 bslbf | + * marker_bit 1 bslbf | + * system_clock_reference_base [29..15] 15 bslbf | + * marker_bit 1 bslbf | + * system_clock_reference_base [14..0] 15 bslbf | + * marker_bit 1 bslbf | 112 bits + * system_clock_reference_extension 9 ubslbf | + * marker_bit 1 bslbf | + * program_mux_rate 22 ubslbf | + * marker_bit 1 bslbf | + * marker_bit 1 bslbf | + * reserved 5 bslbf | + * pack_stuffing_length 3 ubslbf -+ + * + * for (i = 0; i < pack_stuffing_length; i++) { + * stuffing_byte '1111 1111' 8 bslbf + * } + * + * 112 bits = 14 bytes, as max value for pack_stuffing_length is 7, then + * in total it's needed 14 + 7 = 21 bytes. + */ +#define PACK_START_SIZE 21 + static GstFlowReturn gst_flups_demux_parse_pack_start (GstFluPSDemux * demux) { @@ -1491,21 +1470,24 @@ gst_flups_demux_parse_pack_start (GstFluPSDemux * demux) guint64 scr, scr_adjusted, new_rate; guint64 scr_rate_n; guint64 scr_rate_d; + guint avail = gst_adapter_available (demux->adapter); GST_DEBUG ("parsing pack start"); - /* fixed length to begin with, start code and two scr values */ - length = 8 + 4; - - if (!(data = gst_adapter_peek (demux->adapter, length))) + if (G_UNLIKELY (avail < PACK_START_SIZE)) goto need_more_data; + data = gst_adapter_peek (demux->adapter, PACK_START_SIZE); + /* skip start code */ data += 4; scr1 = GUINT32_FROM_BE (*(guint32 *) data); scr2 = GUINT32_FROM_BE (*(guint32 *) (data + 4)); + /* fixed length to begin with, start code and two scr values */ + length = 8 + 4; + /* start parsing the stream */ if ((*data & 0xc0) == 0x40) { guint32 scr_ext; @@ -1517,13 +1499,11 @@ gst_flups_demux_parse_pack_start (GstFluPSDemux * demux) /* mpeg2 has more data */ length += 2; - if (gst_adapter_available (demux->adapter) < length) - goto need_more_data; /* :2=01 ! scr:3 ! marker:1==1 ! scr:15 ! marker:1==1 ! scr:15 */ /* check markers */ - if ((scr1 & 0xc4000400) != 0x44000400) + if (G_UNLIKELY ((scr1 & 0xc4000400) != 0x44000400)) goto lost_sync; scr = ((guint64) scr1 & 0x38000000) << 3; @@ -1532,7 +1512,7 @@ gst_flups_demux_parse_pack_start (GstFluPSDemux * demux) scr |= ((guint64) scr2 & 0xf8000000) >> 27; /* marker:1==1 ! scr_ext:9 ! marker:1==1 */ - if ((scr2 & 0x04010000) != 0x04010000) + if (G_UNLIKELY ((scr2 & 0x04010000) != 0x04010000)) goto lost_sync; scr_ext = (scr2 & 0x03fe0000) >> 17; @@ -1549,7 +1529,7 @@ gst_flups_demux_parse_pack_start (GstFluPSDemux * demux) data += 6; /* PMR:22 ! :2==11 ! reserved:5 ! stuffing_len:3 */ next32 = (GUINT32_FROM_BE ((*(guint32 *) data))); - if ((next32 & 0x00000300) != 0x00000300) + if (G_UNLIKELY ((next32 & 0x00000300) != 0x00000300)) goto lost_sync; new_rate = (next32 & 0xfffffc00) >> 10; @@ -1558,6 +1538,7 @@ gst_flups_demux_parse_pack_start (GstFluPSDemux * demux) GST_DEBUG_OBJECT (demux, "stuffing bytes: %d", stuffing_bytes); data += 4; + length += stuffing_bytes; while (stuffing_bytes--) { if (*data++ != 0xff) goto lost_sync; @@ -1567,10 +1548,10 @@ gst_flups_demux_parse_pack_start (GstFluPSDemux * demux) demux->is_mpeg2_pack = FALSE; /* check markers */ - if ((scr1 & 0xf1000100) != 0x21000100) + if (G_UNLIKELY ((scr1 & 0xf1000100) != 0x21000100)) goto lost_sync; - if ((scr2 & 0x01800001) != 0x01800001) + if (G_UNLIKELY ((scr2 & 0x01800001) != 0x01800001)) goto lost_sync; /* :4=0010 ! scr:3 ! marker:1==1 ! scr:15 ! marker:1==1 ! scr:15 ! marker:1==1 */ @@ -1599,14 +1580,14 @@ gst_flups_demux_parse_pack_start (GstFluPSDemux * demux) GST_TIME_ARGS (MPEGTIME_TO_GSTTIME ((guint64) scr))); /* keep the first src in order to calculate delta time */ - if (demux->first_scr == G_MAXUINT64) { + if (G_UNLIKELY (demux->first_scr == G_MAXUINT64)) { demux->first_scr = scr; demux->first_scr_offset = demux->cur_scr_offset; demux->base_time = MPEGTIME_TO_GSTTIME (demux->first_scr); /* at begin consider the new_rate as the scr rate, bytes/clock ticks */ scr_rate_n = new_rate; scr_rate_d = CLOCK_FREQ; - } else if (demux->first_scr_offset != demux->cur_scr_offset) { + } else if (G_LIKELY (demux->first_scr_offset != demux->cur_scr_offset)) { /* estimate byte rate related to the SCR */ scr_rate_n = demux->cur_scr_offset - demux->first_scr_offset; scr_rate_d = scr_adjusted - demux->first_scr; @@ -1625,7 +1606,7 @@ gst_flups_demux_parse_pack_start (GstFluPSDemux * demux) scr_rate_n, scr_rate_d, (float) scr_rate_n / scr_rate_d); /* adjustment of the SCR */ - if (demux->current_scr != G_MAXUINT64) { + if (G_LIKELY (demux->current_scr != G_MAXUINT64)) { gint64 diff; guint64 old_scr, old_mux_rate, bss, adjust = 0; @@ -1636,8 +1617,7 @@ gst_flups_demux_parse_pack_start (GstFluPSDemux * demux) /* Bytes since SCR is the amount we placed in the adapter since then * (demux->bytes_since_scr) minus the amount remaining in the adapter, * clamped to >= 0 */ - bss = MAX (0, (gint) (demux->bytes_since_scr - - gst_adapter_available (demux->adapter))); + bss = MAX (0, (gint) (demux->bytes_since_scr - avail)); /* estimate the new SCR using the previous one according the notes on point 2.5.2.2 of the ISO/IEC 13818-1 document */ @@ -1656,14 +1636,14 @@ gst_flups_demux_parse_pack_start (GstFluPSDemux * demux) /* calculate the absolute deference between the last scr and the new one */ - if (old_scr > scr_adjusted) + if (G_UNLIKELY (old_scr > scr_adjusted)) diff = old_scr - scr_adjusted; else diff = scr_adjusted - old_scr; /* if the difference is more than 1 second we need to reconfigure adjustment */ - if (diff > CLOCK_FREQ) { + if (G_UNLIKELY (diff > CLOCK_FREQ)) { demux->scr_adjust = demux->next_scr - scr; GST_DEBUG_OBJECT (demux, "discont found, diff: %" G_GINT64_FORMAT ", adjust %" G_GINT64_FORMAT, diff, demux->scr_adjust); @@ -1684,7 +1664,7 @@ gst_flups_demux_parse_pack_start (GstFluPSDemux * demux) /* Reset the bytes_since_scr value to count the data remaining in the * adapter */ - demux->bytes_since_scr = gst_adapter_available (demux->adapter); + demux->bytes_since_scr = avail; gst_adapter_flush (demux->adapter, length); ADAPTER_OFFSET_FLUSH (length); @@ -1702,6 +1682,32 @@ need_more_data: } } +/* ISO/IEC 13818-1: + * system_header () { + * system_header_start_code 32 bslbf -+ + * header_length 16 uimsbf | + * marker_bit 1 bslbf | + * rate_bound 22 uimsbf | + * marker_bit 1 bslbf | + * audio_bound 6 uimsbf | + * fixed_flag 1 bslbf | + * CSPS_flag 1 bslbf | 96 bits + * system_audio_lock_flag 1 bslbf | + * system_video_lock_flag 1 bslbf | + * marker_bit 1 bslbf | + * video_bound 5 uimsbf | + * packet_rate_restriction_flag 1 bslbf | + * reserved_bits 7 bslbf -+ + * while (nextbits () = = '1') { + * stream_id 8 uimsbf -+ + * '11' 2 bslbf | 24 bits + * P-STD_buffer_bound_scale 1 bslbf | + * P-STD_buffer_size_bound 13 uimsbf -+ + * } + * } + * 96 bits = 12 bytes, 24 bits = 3 bytes. + */ + static GstFlowReturn gst_flups_demux_parse_sys_head (GstFluPSDemux * demux) { @@ -1941,7 +1947,15 @@ gst_flups_demux_parse_psm (GstFluPSDemux * demux) GST_DEBUG_OBJECT (demux, "Stream type %02X with id %02X and %u bytes info", stream_type, stream_id, stream_info_length); - demux->psm[stream_id] = stream_type; + if (G_LIKELY (stream_id != 0xbd)) + demux->psm[stream_id] = stream_type; + else { + /* Ignore stream type for private_stream_1 and discover it looking at + * the stream data. + * Fixes demuxing some clips with lpcm that was wrongly declared as + * mpeg audio */ + GST_DEBUG_OBJECT (demux, "stream type for private_stream_1 ignored"); + } es_map_base += stream_info_length; } @@ -1993,7 +2007,7 @@ gst_flups_demux_data_cb (GstPESFilter * filter, gboolean first, if (start_code == ID_PRIVATE_STREAM_1 && datalen >= 2) { guint8 nframes; - /* VDR writes A52 streams without any header bytes + /* VDR writes A52 streams without any header bytes * (see ftp://ftp.mplayerhq.hu/MPlayer/samples/MPEG-VOB/vdr-AC3) */ if (datalen >= 4) { guint hdr = GST_READ_UINT32_BE (data); @@ -2049,7 +2063,7 @@ gst_flups_demux_data_cb (GstPESFilter * filter, gboolean first, demux->current_stream = gst_flups_demux_get_stream (demux, id, stream_type); } - if (demux->current_stream == NULL) { + if (G_UNLIKELY (demux->current_stream == NULL)) { GST_DEBUG_OBJECT (demux, "Dropping buffer for unknown stream id 0x%02x", id); goto done; @@ -2105,7 +2119,7 @@ gst_flups_demux_resync (GstFluPSDemux * demux, gboolean save) gboolean found; avail = gst_adapter_available (demux->adapter); - if (avail < 4) + if (G_UNLIKELY (avail < 4)) goto need_data; /* Common case, read 4 bytes an check it */ @@ -2121,7 +2135,7 @@ gst_flups_demux_resync (GstFluPSDemux * demux, gboolean save) return TRUE; } - /* Otherwise, we are starting at byte 4 and we need to search + /* Otherwise, we are starting at byte 4 and we need to search the sync code in all available data in the adapter */ offset = 4; if (offset >= avail) @@ -2556,12 +2570,10 @@ gst_flups_sink_get_duration (GstFluPSDemux * demux) gst_segment_set_last_stop (&demux->src_segment, GST_FORMAT_TIME, demux->src_segment.start); } -#if POST_10_10 GST_INFO_OBJECT (demux, "sink segment configured %" GST_SEGMENT_FORMAT, &demux->sink_segment); GST_INFO_OBJECT (demux, "src segment configured %" GST_SEGMENT_FORMAT, &demux->src_segment); -#endif res = TRUE; @@ -2603,6 +2615,11 @@ gst_flups_demux_loop (GstPad * pad) demux = GST_FLUPS_DEMUX (gst_pad_get_parent (pad)); + if (G_UNLIKELY (demux->flushing)) { + ret = GST_FLOW_WRONG_STATE; + goto pause; + } + if (G_UNLIKELY (demux->sink_segment.format == GST_FORMAT_UNDEFINED)) gst_flups_sink_get_duration (demux); @@ -2851,6 +2868,10 @@ gst_flups_demux_chain (GstPad * pad, GstBuffer * buffer) save = TRUE; while (gst_flups_demux_resync (demux, save)) { gboolean ps_sync = TRUE; + if (G_UNLIKELY (demux->flushing)) { + ret = GST_FLOW_WRONG_STATE; + goto done; + } /* now switch on last synced byte */ switch (demux->last_sync_code) { diff --git a/gst/mpegdemux/gstmpegdemux.h b/gst/mpegdemux/gstmpegdemux.h index 29b3d5e5..a8822350 100644 --- a/gst/mpegdemux/gstmpegdemux.h +++ b/gst/mpegdemux/gstmpegdemux.h @@ -101,6 +101,7 @@ struct _GstFluPSDemux GstPad *sinkpad; gboolean random_access; /* If we operate in pull mode */ + gboolean flushing; GstAdapter *adapter; GstAdapter *rev_adapter; @@ -136,6 +137,8 @@ struct _GstFluPSDemux guint64 next_pts; guint64 next_dts; GstFluPSStream **streams; + GstFluPSStream **streams_found; + gint found_count; gboolean need_no_more_pads; /* Indicates an MPEG-2 stream */ diff --git a/gst/mpegdemux/gstmpegtsdemux.c b/gst/mpegdemux/gstmpegtsdemux.c index 8de7cc75..0a6f28a5 100644 --- a/gst/mpegdemux/gstmpegtsdemux.c +++ b/gst/mpegdemux/gstmpegtsdemux.c @@ -48,37 +48,17 @@ #include <string.h> #include <stdlib.h> -#ifdef USE_LIBOIL #include <liboil/liboil.h> -#endif #include "gstmpegdefs.h" #include "gstmpegtsdemux.h" #include "flutspatinfo.h" #include "flutspmtinfo.h" -#ifndef GST_CHECK_VERSION -#define GST_CHECK_VERSION(major,minor,micro) \ - (GST_VERSION_MAJOR > (major) || \ - (GST_VERSION_MAJOR == (major) && GST_VERSION_MINOR > (minor)) || \ - (GST_VERSION_MAJOR == (major) && GST_VERSION_MINOR == (minor) && \ - GST_VERSION_MICRO >= (micro))) -#endif - -#ifndef GST_BUFFER_IS_DISCONT -#define GST_BUFFER_IS_DISCONT(buffer) \ - (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) -#endif - GST_DEBUG_CATEGORY_STATIC (gstmpegtsdemux_debug); #define GST_CAT_DEFAULT (gstmpegtsdemux_debug) /* elementfactory information */ -#ifdef USE_LIBOIL -#define LONGNAME "The Fluendo MPEG Transport stream demuxer (liboil build)" -#else -#define LONGNAME "The Fluendo MPEG Transport stream demuxer" -#endif #ifndef __always_inline #if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) @@ -95,7 +75,7 @@ GST_DEBUG_CATEGORY_STATIC (gstmpegtsdemux_debug); #endif static GstElementDetails mpegts_demux_details = { - LONGNAME, + "The Fluendo MPEG Transport stream demuxer", "Codec/Demuxer", "Demultiplexes MPEG2 Transport Streams", "Wim Taymans <wim@fluendo.com>" @@ -139,7 +119,10 @@ enum "mpegversion = (int) { 1, 2, 4 }, " \ "systemstream = (boolean) FALSE; " \ "video/x-h264;" \ - "video/x-dirac" \ + "video/x-dirac;" \ + "video/x-wmv," \ + "wmvversion = (int) 3, " \ + "format = (fourcc) WVC1" \ ) #define AUDIO_CAPS \ @@ -153,8 +136,9 @@ enum "dynamic_range = (int) [ 0, 255 ], " \ "emphasis = (boolean) { FALSE, TRUE }, " \ "mute = (boolean) { FALSE, TRUE }; " \ - "audio/x-ac3;" \ - "audio/x-dts" \ + "audio/x-ac3; audio/x-eac3;" \ + "audio/x-dts;" \ + "audio/x-private1-lpcm" \ ) /* Can also use the subpicture pads for text subtitles? */ @@ -212,6 +196,7 @@ static gboolean gst_mpegts_demux_sink_setcaps (GstPad * pad, GstCaps * caps); static GstClock *gst_mpegts_demux_provide_clock (GstElement * element); static gboolean gst_mpegts_demux_src_pad_query (GstPad * pad, GstQuery * query); +static const GstQueryType *gst_mpegts_demux_src_pad_query_type (GstPad * pad); static GstStateChangeReturn gst_mpegts_demux_change_state (GstElement * element, GstStateChange transition); @@ -355,9 +340,7 @@ gst_mpegts_demux_init (GstMpegTSDemux * demux) demux->pcr[1] = -1; demux->cache_duration = GST_CLOCK_TIME_NONE; demux->base_pts = GST_CLOCK_TIME_NONE; -#ifdef USE_LIBOIL oil_init (); -#endif } static void @@ -402,7 +385,10 @@ gst_mpegts_demux_reset (GstMpegTSDemux * demux) gst_section_filter_uninit (&stream->section_filter); break; } - + if (stream->pes_buffer) { + gst_buffer_unref (stream->pes_buffer); + stream->pes_buffer = NULL; + } g_free (stream); demux->streams[i] = NULL; } @@ -577,6 +563,7 @@ gst_mpegts_stream_is_video (GstMpegTSStream * stream) case ST_VIDEO_MPEG2: case ST_VIDEO_MPEG4: case ST_VIDEO_H264: + case ST_VIDEO_VC1: return TRUE; case ST_VIDEO_DIRAC: return gst_mpegts_is_dirac_stream (stream); @@ -673,10 +660,18 @@ gst_mpegts_demux_fill_stream (GstMpegTSStream * stream, guint8 id, caps = gst_caps_new_simple ("video/x-dirac", NULL); } break; - case ST_PS_AUDIO_AC3: + case ST_VIDEO_VC1: + template = klass->video_template; + name = g_strdup_printf ("video_%04x", stream->PID); + caps = gst_caps_new_simple ("video/x-wmv", + "wmvversion", G_TYPE_INT, 3, + "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('W', 'V', 'C', '1'), + NULL); + break; + case ST_BD_AUDIO_AC3: template = klass->audio_template; name = g_strdup_printf ("audio_%04x", stream->PID); - caps = gst_caps_new_simple ("audio/x-ac3", NULL); + caps = gst_caps_new_simple ("audio/x-eac3", NULL); break; case ST_PS_AUDIO_DTS: template = klass->audio_template; @@ -688,6 +683,11 @@ gst_mpegts_demux_fill_stream (GstMpegTSStream * stream, guint8 id, name = g_strdup_printf ("audio_%04x", stream->PID); caps = gst_caps_new_simple ("audio/x-lpcm", NULL); break; + case ST_BD_AUDIO_LPCM: + template = klass->audio_template; + name = g_strdup_printf ("audio_%04x", stream->PID); + caps = gst_caps_new_simple ("audio/x-private1-lpcm", NULL); + break; case ST_PS_DVD_SUBPICTURE: template = klass->subpicture_template; name = g_strdup_printf ("subpicture_%04x", stream->PID); @@ -713,6 +713,8 @@ gst_mpegts_demux_fill_stream (GstMpegTSStream * stream, guint8 id, gst_caps_unref (caps); gst_pad_set_query_function (stream->pad, GST_DEBUG_FUNCPTR (gst_mpegts_demux_src_pad_query)); + gst_pad_set_query_type_function (stream->pad, + GST_DEBUG_FUNCPTR (gst_mpegts_demux_src_pad_query_type)); gst_pad_set_event_function (stream->pad, GST_DEBUG_FUNCPTR (gst_mpegts_demux_src_event)); g_free (name); @@ -855,10 +857,6 @@ gst_mpegts_demux_send_tags_for_stream (GstMpegTSDemux * demux, } } -#ifndef GST_FLOW_IS_SUCCESS -#define GST_FLOW_IS_SUCCESS(ret) ((ret) >= GST_FLOW_OK) -#endif - static GstFlowReturn gst_mpegts_demux_combine_flows (GstMpegTSDemux * demux, GstMpegTSStream * stream, GstFlowReturn ret) @@ -1537,11 +1535,7 @@ gst_mpegts_stream_parse_private_section (GstMpegTSStream * stream, /* just dump this down the pad */ if (gst_pad_alloc_buffer (stream->pad, 0, datalen, NULL, &buffer) == GST_FLOW_OK) { -#ifdef USE_LIBOIL oil_memcpy (buffer->data, data, datalen); -#else - memcpy (buffer->data, data, datalen); -#endif gst_pad_push (stream->pad, buffer); } @@ -2104,11 +2098,7 @@ gst_mpegts_stream_pes_buffer_push (GstMpegTSStream * stream, stream->pes_buffer_used = 0; } out_data = GST_BUFFER_DATA (stream->pes_buffer) + stream->pes_buffer_used; -#ifdef USE_LIBOIL oil_memcpy (out_data, in_data, in_size); -#else - memcpy (out_data, in_data, in_size); -#endif stream->pes_buffer_used += in_size; done: return ret; @@ -2136,11 +2126,7 @@ gst_mpegts_demux_push_fragment (GstMpegTSStream * stream, { GstFlowReturn ret; GstBuffer *es_buf = gst_buffer_new_and_alloc (in_size); -#ifdef USE_LIBOIL oil_memcpy (GST_BUFFER_DATA (es_buf), in_data, in_size); -#else - memcpy (GST_BUFFER_DATA (es_buf), in_data, in_size); -#endif ret = gst_pes_filter_push (&stream->filter, es_buf); /* If PES filter return ok then PES fragment buffering @@ -2280,11 +2266,7 @@ gst_mpegts_demux_parse_stream (GstMpegTSDemux * demux, GstMpegTSStream * stream, /* FIXME: try to use data directly instead of creating a buffer and pushing in into adapter at section filter */ sec_buf = gst_buffer_new_and_alloc (datalen); -#ifdef USE_LIBOIL oil_memcpy (GST_BUFFER_DATA (sec_buf), data, datalen); -#else - memcpy (GST_BUFFER_DATA (sec_buf), data, datalen); -#endif if (gst_section_filter_push (&stream->section_filter, payload_unit_start_indicator, continuity_counter, sec_buf)) { GST_DEBUG_OBJECT (demux, "section finished"); @@ -2701,6 +2683,19 @@ gst_mpegts_demux_provide_clock (GstElement * element) return NULL; } +static const GstQueryType * +gst_mpegts_demux_src_pad_query_type (GstPad * pad) +{ + static const GstQueryType types[] = { + GST_QUERY_LATENCY, + GST_QUERY_DURATION, + GST_QUERY_SEEKING, + 0 + }; + + return types; +} + static gboolean gst_mpegts_demux_src_pad_query (GstPad * pad, GstQuery * query) { @@ -2800,11 +2795,18 @@ gst_mpegts_demux_src_pad_query (GstPad * pad, GstQuery * query) goto beach; } + /* We can't say anything about seekability if we didn't + * have a second PCR yet because the bitrate is calculated + * from this + */ + if (demux->bitrate == -1 && demux->pcr[1] == -1) + goto beach; + /* We can seek if upstream supports BYTES seeks and we * have a bitrate */ peerquery = gst_query_new_seeking (GST_FORMAT_BYTES); - res = gst_pad_peer_query (demux->sinkpad, query); + res = gst_pad_peer_query (demux->sinkpad, peerquery); if (!res || demux->bitrate == -1) { gst_query_set_seeking (query, fmt, FALSE, -1, -1); } else { |