diff --git a/gst/mpegstream/gstmpegdemux.c b/gst/mpegstream/gstmpegdemux.c index 31bd64d4fd..195c29d148 100644 --- a/gst/mpegstream/gstmpegdemux.c +++ b/gst/mpegstream/gstmpegdemux.c @@ -202,21 +202,16 @@ gst_mpeg_demux_init (GstMPEGDemux *mpeg_demux) /* i think everything is already zero'd, but oh well*/ for (i=0;iprivate_1_pad[i] = NULL; - mpeg_demux->private_1_PTS[i] = 0; } for (i=0;isubtitle_pad[i] = NULL; - mpeg_demux->subtitle_offset[i] = 0; } mpeg_demux->private_2_pad = NULL; - mpeg_demux->private_2_offset = 0; for (i=0;ivideo_pad[i] = NULL; - mpeg_demux->video_PTS[i] = 0; } for (i=0;iaudio_pad[i] = NULL; - mpeg_demux->audio_PTS[i] = 0; } GST_FLAG_SET (mpeg_demux, GST_ELEMENT_EVENT_AWARE); @@ -225,7 +220,7 @@ gst_mpeg_demux_init (GstMPEGDemux *mpeg_demux) static void gst_mpeg_demux_send_data (GstMPEGParse *mpeg_parse, GstData *data, GstClockTime time) { - //GstMPEGDemux *mpeg_demux = GST_MPEG_DEMUX (mpeg_parse); + /* GstMPEGDemux *mpeg_demux = GST_MPEG_DEMUX (mpeg_parse); */ if (GST_IS_BUFFER (data)) { gst_buffer_unref (GST_BUFFER (data)); @@ -245,32 +240,30 @@ static void gst_mpeg_demux_handle_discont (GstMPEGParse *mpeg_parse) { GstMPEGDemux *mpeg_demux = GST_MPEG_DEMUX (mpeg_parse); - gint i; gint64 current_time = MPEGTIME_TO_GSTTIME (mpeg_parse->current_scr); + gint i; - GST_DEBUG (GST_CAT_EVENT, "mpegdemux: discont %llu\n", current_time); + GST_DEBUG (GST_CAT_EVENT, "discont %llu\n", current_time); for (i=0;ivideo_pad[i] && - GST_PAD_IS_CONNECTED (mpeg_demux->video_pad[i])) + GST_PAD_IS_USABLE (mpeg_demux->video_pad[i])) { GstEvent *discont; discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, current_time, NULL); - mpeg_demux->video_PTS[i] = mpeg_parse->current_scr; gst_pad_push (mpeg_demux->video_pad[i], GST_BUFFER (discont)); } if (mpeg_demux->audio_pad[i] && - GST_PAD_IS_CONNECTED (mpeg_demux->audio_pad[i])) + GST_PAD_IS_USABLE (mpeg_demux->audio_pad[i])) { GstEvent *discont; discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, current_time, NULL); - mpeg_demux->audio_PTS[i] = mpeg_parse->current_scr; gst_pad_push (mpeg_demux->audio_pad[i], GST_BUFFER (discont)); } } @@ -283,7 +276,7 @@ gst_mpeg_demux_parse_packhead (GstMPEGParse *mpeg_parse, GstBuffer *buffer) parent_class->parse_packhead (mpeg_parse, buffer); - GST_DEBUG (0, "mpeg_demux: in parse_packhead"); + GST_DEBUG (0, "in parse_packhead"); buf = GST_BUFFER_DATA (buffer); /* do something usefull here */ @@ -298,13 +291,13 @@ gst_mpeg_demux_parse_syshead (GstMPEGParse *mpeg_parse, GstBuffer *buffer) guint16 header_length; guchar *buf; - GST_DEBUG (0, "mpeg_demux: in parse_syshead"); + GST_DEBUG (0, "in parse_syshead"); buf = GST_BUFFER_DATA (buffer); buf += 4; header_length = GUINT16_FROM_BE (*(guint16 *) buf); - GST_DEBUG (0, "mpeg_demux: header_length %d", header_length); + GST_DEBUG (0, "header_length %d", header_length); buf += 2; /* marker:1==1 ! rate_bound:22 | marker:1==1*/ @@ -323,11 +316,10 @@ gst_mpeg_demux_parse_syshead (GstMPEGParse *mpeg_parse, GstBuffer *buffer) gint stream_count = (header_length - 6) / 3; gint i, j=0; - GST_DEBUG (0, "mpeg_demux::parse_syshead: number of streams=%d ", + GST_DEBUG (0, "number of streams=%d ", stream_count); for (i = 0; i < stream_count; i++) { - gint stream_num; guint8 stream_id; gboolean STD_buffer_bound_scale; guint16 STD_buffer_size_bound; @@ -338,14 +330,13 @@ gst_mpeg_demux_parse_syshead (GstMPEGParse *mpeg_parse, GstBuffer *buffer) stream_id = *buf++; if (!(stream_id & 0x80)) { - GST_DEBUG (0, "mpeg_demux::parse_syshead: error in system header length"); + GST_DEBUG (0, "error in system header length"); return FALSE; } /* check marker bits */ if ((*buf & 0xC0) != 0xC0) { - GST_DEBUG (0, - "mpeg_demux::parse_syshead: expecting placeholder bit values '11' after stream id\n"); + GST_DEBUG (0, "expecting placeholder bit values '11' after stream id\n"); return FALSE; } @@ -360,41 +351,43 @@ gst_mpeg_demux_parse_syshead (GstMPEGParse *mpeg_parse, GstBuffer *buffer) buf_byte_size_bound = STD_buffer_size_bound * 1024; } - /* private_stream_1 */ - if (stream_id == 0xBD) { - name = NULL; - outpad = NULL; - } - /* private_stream_2 */ - else if (stream_id == 0xBF) { - name = g_strdup_printf ("private_stream_2"); - stream_num = 0; - outpad = &mpeg_demux->private_2_pad; - newtemp = GST_PAD_TEMPLATE_GET (private2_factory); - } - /* Audio */ - else if ((stream_id >= 0xC0) && (stream_id <= 0xDF)) { - name = g_strdup_printf ("audio_%02d", stream_id & 0x1F); - stream_num = stream_id & 0x1F; - outpad = &mpeg_demux->audio_pad[stream_num]; - newtemp = GST_PAD_TEMPLATE_GET (audio_factory); - } - /* Video */ - else if ((stream_id >= 0xE0) && (stream_id <= 0xEF)) { - name = g_strdup_printf ("video_%02d", stream_id & 0x0F); - stream_num = stream_id & 0x0F; - outpad = &mpeg_demux->video_pad[stream_num]; - if (!GST_MPEG_PARSE_IS_MPEG2 (mpeg_demux)) { - newtemp = GST_PAD_TEMPLATE_GET (video_mpeg1_factory); - } - else { - newtemp = GST_PAD_TEMPLATE_GET (video_mpeg2_factory); - } + switch (stream_id) { + /* private_stream_1 */ + case 0xBD: + name = NULL; + outpad = NULL; + break; + /* private_stream_2 */ + case 0xBF: + name = g_strdup_printf ("private_stream_2"); + outpad = &mpeg_demux->private_2_pad; + newtemp = GST_PAD_TEMPLATE_GET (private2_factory); + break; + /* Audio */ + case 0xC0 ... 0xDF: + name = g_strdup_printf ("audio_%02d", stream_id & 0x1F); + outpad = &mpeg_demux->audio_pad[stream_id & 0x1F]; + newtemp = GST_PAD_TEMPLATE_GET (audio_factory); + break; + /* Video */ + case 0xE0 ... 0xEF: + name = g_strdup_printf ("video_%02d", stream_id & 0x0F); + outpad = &mpeg_demux->video_pad[stream_id & 0x0F]; + if (!GST_MPEG_PARSE_IS_MPEG2 (mpeg_demux)) { + newtemp = GST_PAD_TEMPLATE_GET (video_mpeg1_factory); + } + else { + newtemp = GST_PAD_TEMPLATE_GET (video_mpeg2_factory); + } + break; + default: + GST_DEBUG (0, "unkown stream id %d", stream_id); + break; } - GST_DEBUG (0, "mpeg_demux::parse_syshead: stream ID 0x%02X (%s)", stream_id, name); - GST_DEBUG (0, "mpeg_demux::parse_syshead: STD_buffer_bound_scale %d", STD_buffer_bound_scale); - GST_DEBUG (0, "mpeg_demux::parse_syshead: STD_buffer_size_bound %d or %d bytes", + GST_DEBUG (0, "stream ID 0x%02X (%s)", stream_id, name); + GST_DEBUG (0, "STD_buffer_bound_scale %d", STD_buffer_bound_scale); + GST_DEBUG (0, "STD_buffer_size_bound %d or %d bytes", STD_buffer_size_bound, buf_byte_size_bound); /* create the pad and add it to self if it does not yet exist @@ -413,12 +406,14 @@ gst_mpeg_demux_parse_syshead (GstMPEGParse *mpeg_parse, GstBuffer *buffer) gst_element_add_pad (GST_ELEMENT (mpeg_demux), (*outpad)); - if (GST_PAD_IS_CONNECTED (*outpad)) { + if (GST_PAD_IS_USABLE (*outpad)) { GstEvent *event; - gint64 current_time = MPEGTIME_TO_GSTTIME (mpeg_parse->current_scr); + gint64 time; + time = mpeg_parse->current_scr; + event = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, - current_time, NULL); + MPEGTIME_TO_GSTTIME (time), NULL); gst_pad_push (*outpad, GST_BUFFER (event)); } @@ -462,7 +457,7 @@ gst_mpeg_demux_parse_packet (GstMPEGParse *mpeg_parse, GstBuffer *buffer) GstBuffer *outbuf; guint8 *buf, *basebuf; - GST_DEBUG (0,"mpeg_demux::parse_packet: in parse_packet"); + GST_DEBUG (0, "in parse_packet"); basebuf = buf = GST_BUFFER_DATA (buffer); id = *(buf+3); @@ -471,7 +466,7 @@ gst_mpeg_demux_parse_packet (GstMPEGParse *mpeg_parse, GstBuffer *buffer) /* start parsing */ packet_length = GUINT16_FROM_BE (*((guint16 *)buf)); - GST_DEBUG (0,"mpeg_demux: got packet_length %d", packet_length); + GST_DEBUG (0, "got packet_length %d", packet_length); headerlen = 2; buf += 2; @@ -483,14 +478,14 @@ gst_mpeg_demux_parse_packet (GstMPEGParse *mpeg_parse, GstBuffer *buffer) switch (bits & 0xC0) { case 0xC0: if (bits == 0xff) { - GST_DEBUG (0,"mpeg_demux::parse_packet: have stuffing byte"); + GST_DEBUG (0, "have stuffing byte"); } else { - GST_DEBUG (0,"mpeg_demux::parse_packet: expected stuffing byte"); + GST_DEBUG (0, "expected stuffing byte"); } headerlen++; break; case 0x40: - GST_DEBUG (0,"mpeg_demux::parse_packet: have STD"); + GST_DEBUG (0, "have STD"); STD_buffer_bound_scale = bits & 0x20; STD_buffer_size_bound = (bits & 0x1F) << 8; @@ -508,7 +503,7 @@ gst_mpeg_demux_parse_packet (GstMPEGParse *mpeg_parse, GstBuffer *buffer) pts |= *buf++ << 7; pts |= (*buf++ & 0xFE) >> 1; - GST_DEBUG (0,"mpeg_demux::parse_packet: PTS = %llu", pts); + GST_DEBUG (0, "PTS = %llu", pts); headerlen += 5; goto done; case 0x30: @@ -526,14 +521,14 @@ gst_mpeg_demux_parse_packet (GstMPEGParse *mpeg_parse, GstBuffer *buffer) dts |= *buf++ << 7; dts |= (*buf++ & 0xFE) >> 1; - GST_DEBUG (0,"mpeg_demux::parse_packet: PTS = %llu, DTS = %llu", pts, dts); + GST_DEBUG (0, "PTS = %llu, DTS = %llu", pts, dts); headerlen += 10; goto done; case 0x00: - GST_DEBUG (0,"mpeg_demux::parse_packet: have no pts/dts"); - GST_DEBUG (0,"mpeg_demux::parse_packet: got trailer bits %x", (bits & 0x0f)); + GST_DEBUG (0, "have no pts/dts"); + GST_DEBUG (0, "got trailer bits %x", (bits & 0x0f)); if ((bits & 0x0f) != 0xf) { - GST_DEBUG (0,"mpeg_demux::parse_packet: not a valid packet time sequence"); + GST_DEBUG (0, "not a valid packet time sequence"); return FALSE; } headerlen++; @@ -544,73 +539,86 @@ gst_mpeg_demux_parse_packet (GstMPEGParse *mpeg_parse, GstBuffer *buffer) goto done; } } while (1); - GST_DEBUG (0,"mpeg_demux::parse_packet: done with header loop"); + GST_DEBUG (0, "done with header loop"); done: + /* calculate the amount of real data in this packet */ datalen = packet_length - headerlen+2; - GST_DEBUG (0,"mpeg_demux::parse_packet: headerlen is %d, datalen is %d", + GST_DEBUG (0, "headerlen is %d, datalen is %d", headerlen,datalen); - /* private_stream_1 */ - if (id == 0xBD) { - /* first find the track code */ - ps_id_code = *(basebuf + headerlen); - /* make sure it's valid */ - if ((ps_id_code >= 0x80) && (ps_id_code <= 0x87)) { - GST_DEBUG (0,"mpeg_demux::parse_packet: 0x%02X: we have a private_stream_1 (AC3) packet, track %d", - id, ps_id_code - 0x80); - outpad = &mpeg_demux->private_1_pad[ps_id_code - 0x80]; - /* scrap first 4 bytes (so-called "mystery AC3 tag") */ - headerlen += 4; - datalen -= 4; - } - /* private_stream_1 */ - } else if (id == 0xBF) { - GST_DEBUG (0,"mpeg_demux::parse_packet: 0x%02X: we have a private_stream_2 packet", id); - outpad = &mpeg_demux->private_2_pad; - /* audio */ - } else if ((id >= 0xC0) && (id <= 0xDF)) { - GST_DEBUG (0,"mpeg_demux::parse_packet: 0x%02X: we have an audio packet", id); - outpad = &mpeg_demux->audio_pad[id & 0x1F]; - /* video */ - } else if ((id >= 0xE0) && (id <= 0xEF)) { - GST_DEBUG (0,"mpeg_demux::parse_packet: 0x%02X: we have a video packet", id); - outpad = &mpeg_demux->video_pad[id & 0x0F]; - if (pts == -1) - pts = mpeg_demux->video_PTS[id & 0x1F]; - else - mpeg_demux->video_PTS[id & 0x1F] = pts; + switch (id) { + /* private_stream_1 */ + case 0xBD: + /* first find the track code */ + ps_id_code = *(basebuf + headerlen); + + switch (ps_id_code) { + /* make sure it's valid */ + case 0x80 ... 0x87: + GST_DEBUG (0, "0x%02X: we have a private_stream_1 (AC3) packet, track %d", + id, ps_id_code - 0x80); + outpad = &mpeg_demux->private_1_pad[ps_id_code - 0x80]; + /* scrap first 4 bytes (so-called "mystery AC3 tag") */ + headerlen += 4; + datalen -= 4; + break; + default: + break; + } + break; + /* private_stream_2 */ + case 0xBF: + GST_DEBUG (0, "0x%02X: we have a private_stream_2 packet", id); + outpad = &mpeg_demux->private_2_pad; + break; + /* audio */ + case 0xC0 ... 0xDF: + GST_DEBUG (0, "0x%02X: we have an audio packet", id); + outpad = &mpeg_demux->audio_pad[id & 0x1F]; + break; + /* video */ + case 0xE0 ... 0xEF: + GST_DEBUG (0, "0x%02X: we have a video packet", id); + outpad = &mpeg_demux->video_pad[id & 0x0F]; + break; + default: + break; } /* if we don't know what it is, bail */ if (outpad == NULL) { - GST_DEBUG (0,"mpeg_demux::parse_packet: unknown packet id 0x%02X !!", id); + GST_DEBUG (0, "unknown packet id 0x%02X !!", id); return FALSE; } - /* FIXME, this should be done in parse_syshead */ + /* the pad should have been created in parse_syshead */ if ((*outpad) == NULL) { - GST_DEBUG (0,"mpeg_demux::parse_packet: unexpected packet id 0x%02X!!", id); + GST_DEBUG (0, "unexpected packet id 0x%02X!!", id); return FALSE; } /* create the buffer and send it off to the Other Side */ if (GST_PAD_IS_CONNECTED(*outpad) && datalen > 0) { + GST_DEBUG (0, "creating subbuffer len %d", datalen); + /* if this is part of the buffer, create a subbuffer */ - GST_DEBUG (0,"mpeg_demux::parse_packet: creating subbuffer len %d", datalen); - - outbuf = gst_buffer_create_sub (buffer, headerlen+4, datalen); + outbuf = gst_buffer_create_sub (buffer, headerlen + 4, datalen); + /* attach pts, if any */ if (pts != -1) { - GST_BUFFER_TIMESTAMP (outbuf) = (pts * GST_SECOND)/90000LL; + pts += mpeg_parse->adjust; + + GST_BUFFER_TIMESTAMP (outbuf) = MPEGTIME_TO_GSTTIME (pts); } else { GST_BUFFER_TIMESTAMP (outbuf) = -1LL; } - GST_DEBUG (0,"mpeg_demux::parse_packet: pushing buffer of len %d id %d, ts %lld", + GST_DEBUG (0, "pushing buffer of len %d id %d, ts %lld", datalen, id, GST_BUFFER_TIMESTAMP (outbuf)); + gst_pad_push ((*outpad), outbuf); } @@ -636,7 +644,7 @@ gst_mpeg_demux_parse_pes (GstMPEGParse *mpeg_parse, GstBuffer *buffer) GstPadTemplate *newtemp = NULL; guint8 *buf, *basebuf; - GST_DEBUG (0,"mpeg_demux: in parse_pes"); + GST_DEBUG (0, "in parse_pes"); basebuf = buf = GST_BUFFER_DATA (buffer); id = *(buf+3); @@ -645,7 +653,7 @@ gst_mpeg_demux_parse_pes (GstMPEGParse *mpeg_parse, GstBuffer *buffer) /* start parsing */ packet_length = GUINT16_FROM_BE (*((guint16 *)buf)); - GST_DEBUG (0,"mpeg_demux: got packet_length %d", packet_length); + GST_DEBUG (0, "got packet_length %d", packet_length); buf += 2; /* we don't operate on: program_stream_map, padding_stream, */ @@ -662,7 +670,7 @@ gst_mpeg_demux_parse_pes (GstMPEGParse *mpeg_parse, GstBuffer *buffer) header_data_length = *buf++; - GST_DEBUG (0,"mpeg_demux: header_data_length is %d",header_data_length); + GST_DEBUG (0, "header_data_length is %d",header_data_length); /* check for PTS */ if ((flags2 & 0x80)) { @@ -672,14 +680,17 @@ gst_mpeg_demux_parse_pes (GstMPEGParse *mpeg_parse, GstBuffer *buffer) pts |= (*buf++ & 0xFE) << 14; pts |= *buf++ << 7; pts |= (*buf++ & 0xFE) >> 1; - GST_DEBUG (0, "mpeg_demux::parse_packet: %x PTS = %llu", id, (pts*GST_SECOND)/90000LL); + + GST_DEBUG (0, "%x PTS = %llu", + id, MPEGTIME_TO_GSTTIME (pts)); + } if ((flags2 & 0x40)) { - GST_DEBUG (0, "mpeg_demux::parse_packet: %x DTS found", id); + GST_DEBUG (0, "%x DTS found", id); buf += 5; } if ((flags2 & 0x20)) { - GST_DEBUG (0, "mpeg_demux::parse_packet: %x ESCR found", id); + GST_DEBUG (0, "%x ESCR found", id); buf += 6; } if ((flags2 & 0x10)) { @@ -688,7 +699,7 @@ gst_mpeg_demux_parse_pes (GstMPEGParse *mpeg_parse, GstBuffer *buffer) es_rate = (*buf++ & 0x07) << 14; es_rate |= (*buf++ ) << 7; es_rate |= (*buf++ & 0xFE) >> 1; - GST_DEBUG (0, "mpeg_demux::parse_packet: %x ES Rate found", id); + GST_DEBUG (0, "%x ES Rate found", id); } /* FIXME: lots of PES parsing missing here... */ @@ -699,57 +710,55 @@ gst_mpeg_demux_parse_pes (GstMPEGParse *mpeg_parse, GstBuffer *buffer) headerlen = 5 + header_data_length; /* constant is 2 bytes of bits, 1 byte header len */ datalen = packet_length - (3 + header_data_length); - GST_DEBUG (0,"mpeg_demux: headerlen is %d, datalen is %d", + GST_DEBUG (0, "headerlen is %d, datalen is %d", headerlen, datalen); - /* private_stream_1 */ - if (id == 0xBD) { - /* first find the track code */ - ps_id_code = *(basebuf + headerlen + 4); - /* make sure it's valid */ - if ((ps_id_code >= 0x80) && (ps_id_code <= 0x87)) { - GST_DEBUG (0,"mpeg_demux: we have a private_stream_1 (AC3) packet, track %d", - ps_id_code - 0x80); - outpad = &mpeg_demux->private_1_pad[ps_id_code - 0x80]; - /* scrap first 4 bytes (so-called "mystery AC3 tag") */ - headerlen += 4; - datalen -= 4; - if (pts == -1) - pts = mpeg_demux->private_1_PTS[ps_id_code - 0x80]; - else - mpeg_demux->private_1_PTS[ps_id_code - 0x80] = pts; - } - else if ((ps_id_code >= 0x20) && (ps_id_code <= 0x2f)) { - GST_DEBUG (0,"mpeg_demux: we have a subtitle_stream packet, track %d", - ps_id_code - 0x20); - outpad = &mpeg_demux->subtitle_pad[ps_id_code - 0x20]; - headerlen += 1; - datalen -= 1; - } - else { - GST_DEBUG (0,"mpeg_demux::parse_packet: 0x%02X: unkonwn id %x", - id, ps_id_code); - } - /* private_stream_1 */ - } else if (id == 0xBF) { - GST_DEBUG (0,"mpeg_demux: we have a private_stream_2 packet"); - outpad = &mpeg_demux->private_2_pad; - /* audio */ - } else if ((id >= 0xC0) && (id <= 0xDF)) { - GST_DEBUG (0,"mpeg_demux: we have an audio packet"); - outpad = &mpeg_demux->audio_pad[id - 0xC0]; - if (pts == -1) - pts = mpeg_demux->audio_PTS[id & 0x1F]; - else - mpeg_demux->audio_PTS[id & 0x1F] = pts; - /* video */ - } else if ((id >= 0xE0) && (id <= 0xEF)) { - GST_DEBUG (0,"mpeg_demux: we have a video packet"); - outpad = &mpeg_demux->video_pad[id - 0xE0]; - if (pts == -1) - pts = mpeg_demux->video_PTS[id & 0x1F]; - else - mpeg_demux->video_PTS[id & 0x1F] = pts; + switch (id) { + /* private_stream_1 */ + case 0xBD: + /* first find the track code */ + ps_id_code = *(basebuf + headerlen + 4); + + switch (ps_id_code) { + case 0x80 ... 0x87: + GST_DEBUG (0, "we have a private_stream_1 (AC3) packet, track %d", + ps_id_code - 0x80); + outpad = &mpeg_demux->private_1_pad[ps_id_code - 0x80]; + /* scrap first 4 bytes (so-called "mystery AC3 tag") */ + headerlen += 4; + datalen -= 4; + break; + case 0x20 ... 0x2f: + GST_DEBUG (0, "we have a subtitle_stream packet, track %d", + ps_id_code - 0x20); + outpad = &mpeg_demux->subtitle_pad[ps_id_code - 0x20]; + headerlen += 1; + datalen -= 1; + break; + default: + GST_DEBUG (0, "0x%02X: unkonwn id %x", + id, ps_id_code); + break; + } + break; + /* private_stream_2 */ + case 0xBF: + GST_DEBUG (0, "we have a private_stream_2 packet"); + outpad = &mpeg_demux->private_2_pad; + break; + /* audio */ + case 0xC0 ... 0xDF: + GST_DEBUG (0, "we have an audio packet"); + outpad = &mpeg_demux->audio_pad[id - 0xC0]; + break; + /* video */ + case 0xE0 ... 0xEF: + GST_DEBUG (0, "we have a video packet"); + outpad = &mpeg_demux->video_pad[id - 0xE0]; + break; + default: + GST_DEBUG (0, "we have a unkown packet"); + break; } /* if we don't know what it is, bail */ @@ -763,35 +772,44 @@ gst_mpeg_demux_parse_pes (GstMPEGParse *mpeg_parse, GstBuffer *buffer) gchar *name = NULL; /* we have to name the stream approriately */ - if (id == 0xBD) { - if (ps_id_code >= 0x80 && ps_id_code <= 0x87) { - name = g_strdup_printf("private_stream_1.%d",ps_id_code - 0x80); - newtemp = GST_PAD_TEMPLATE_GET (private1_factory); - } - else if (ps_id_code >= 0x20 && ps_id_code <= 0x2f) { - name = g_strdup_printf("subtitle_stream_%d",ps_id_code - 0x20); - newtemp = GST_PAD_TEMPLATE_GET (subtitle_factory); - } - else { - name = g_strdup_printf("unknown_stream_%d",ps_id_code); - } + switch (id) { + /* private_stream_1 */ + case 0xBD: + switch (ps_id_code) { + case 0x80 ... 0x87: + name = g_strdup_printf ("private_stream_1.%d",ps_id_code - 0x80); + newtemp = GST_PAD_TEMPLATE_GET (private1_factory); + break; + case 0x20 ... 0x2F: + name = g_strdup_printf ("subtitle_stream_%d",ps_id_code - 0x20); + newtemp = GST_PAD_TEMPLATE_GET (subtitle_factory); + break; + default: + name = g_strdup_printf ("unknown_stream_%d",ps_id_code); + break; + } + break; + /* private_stream_2 */ + case 0xBF: + name = g_strdup ("private_stream_2"); + newtemp = GST_PAD_TEMPLATE_GET (private2_factory); + break; + /* audio */ + case 0xC0 ... 0xDF: + name = g_strdup_printf ("audio_%02d", id - 0xC0); + newtemp = GST_PAD_TEMPLATE_GET (audio_factory); + break; + /* video */ + case 0xE0 ... 0xEF: + name = g_strdup_printf ("video_%02d", id - 0xE0); + newtemp = GST_PAD_TEMPLATE_GET (video_mpeg2_factory); + break; + /* unkown */ + default: + name = g_strdup_printf ("unknown"); + break; } - else if (id == 0xBF) { - name = g_strdup ("private_stream_2"); - newtemp = GST_PAD_TEMPLATE_GET (private2_factory); - } - else if ((id >= 0xC0) && (id <= 0xDF)) { - name = g_strdup_printf("audio_%02d",id - 0xC0); - newtemp = GST_PAD_TEMPLATE_GET (audio_factory); - } - else if ((id >= 0xE0) && (id <= 0xEF)) { - name = g_strdup_printf("video_%02d",id - 0xE0); - newtemp = GST_PAD_TEMPLATE_GET (video_mpeg2_factory); - } - else { - name = g_strdup_printf("unknown"); - } - + if (newtemp) { /* create the pad and add it to self */ (*outpad) = gst_pad_new_from_template (newtemp, name); @@ -806,19 +824,27 @@ gst_mpeg_demux_parse_pes (GstMPEGParse *mpeg_parse, GstBuffer *buffer) gst_element_add_pad(GST_ELEMENT(mpeg_demux),(*outpad)); } else { - g_warning ("mpeg_demux: cannot create pad %s, no template for %02x", name, id); + g_warning ("cannot create pad %s, no template for %02x", name, id); } if (name) g_free (name); } /* create the buffer and send it off to the Other Side */ - if (GST_PAD_IS_CONNECTED(*outpad)) { + if (GST_PAD_IS_USABLE(*outpad)) { /* if this is part of the buffer, create a subbuffer */ - GST_DEBUG (0,"mpeg_demux: creating subbuffer len %d", datalen); + GST_DEBUG (0,"creating subbuffer len %d", datalen); outbuf = gst_buffer_create_sub (buffer, headerlen+4, datalen); - GST_BUFFER_TIMESTAMP(outbuf) = (pts * GST_SECOND) / 90000LL; + + if (pts != -1) { + pts += mpeg_parse->adjust; + + GST_BUFFER_TIMESTAMP (outbuf) = MPEGTIME_TO_GSTTIME (pts); + } + else { + GST_BUFFER_TIMESTAMP (outbuf) = -1LL; + } gst_pad_push((*outpad),outbuf); } @@ -829,19 +855,12 @@ gst_mpeg_demux_parse_pes (GstMPEGParse *mpeg_parse, GstBuffer *buffer) static GstElementStateReturn gst_mpeg_demux_change_state (GstElement *element) { - GstMPEGDemux *mpeg_demux = GST_MPEG_DEMUX (element); - gint i; + /* GstMPEGDemux *mpeg_demux = GST_MPEG_DEMUX (element); */ switch (GST_STATE_TRANSITION (element)) { case GST_STATE_READY_TO_PAUSED: break; case GST_STATE_PAUSED_TO_READY: - for (i=0;ivideo_PTS[i] = 0; - } - for (i=0;iaudio_PTS[i] = 0; - } break; case GST_STATE_READY_TO_NULL: break; diff --git a/gst/mpegstream/gstmpegdemux.h b/gst/mpegstream/gstmpegdemux.h index dca16cc90b..fdb0f60fe6 100644 --- a/gst/mpegstream/gstmpegdemux.h +++ b/gst/mpegstream/gstmpegdemux.h @@ -99,20 +99,10 @@ struct _GstMPEGDemux { /* stream output pads */ GstPad *private_1_pad[NUM_PRIVATE_1_PADS]; /* up to 8 ac3 audio tracks */ - gulong private_1_PTS[NUM_PRIVATE_1_PADS]; - GstPad *subtitle_pad[NUM_SUBTITLE_PADS]; - gulong subtitle_offset[NUM_SUBTITLE_PADS]; - GstPad *private_2_pad; - gulong private_2_offset; - GstPad *video_pad[NUM_VIDEO_PADS]; - gint64 video_PTS[NUM_VIDEO_PADS]; - GstPad *audio_pad[NUM_AUDIO_PADS]; - gint64 audio_PTS[NUM_AUDIO_PADS]; - }; struct _GstMPEGDemuxClass { diff --git a/gst/mpegstream/gstmpegparse.c b/gst/mpegstream/gstmpegparse.c index 46dc3e4035..8b554f2085 100644 --- a/gst/mpegstream/gstmpegparse.c +++ b/gst/mpegstream/gstmpegparse.c @@ -174,11 +174,12 @@ gst_mpeg_parse_init (GstMPEGParse *mpeg_parse) /* initialize parser state */ mpeg_parse->packetize = NULL; mpeg_parse->current_scr = 0; - mpeg_parse->previous_scr = 0; + mpeg_parse->bytes_since_scr = 0; + mpeg_parse->adjust = 0; mpeg_parse->sync = FALSE; /* zero counters (should be done at RUNNING?) */ - mpeg_parse->bit_rate = 0; + mpeg_parse->mux_rate = 0; mpeg_parse->discont_pending = FALSE; mpeg_parse->scr_pending = TRUE; mpeg_parse->provided_clock = gst_mpeg_clock_new ("MPEGParseClock", @@ -212,7 +213,7 @@ gst_mpeg_parse_get_time (GstClock *clock, gpointer data) { GstMPEGParse *parse = GST_MPEG_PARSE (data); - return MPEGTIME_TO_GSTTIME (parse->previous_scr); + return MPEGTIME_TO_GSTTIME (parse->current_scr); } static void @@ -242,9 +243,12 @@ gst_mpeg_parse_send_data (GstMPEGParse *mpeg_parse, GstData *data, GstClockTime } GST_BUFFER_TIMESTAMP (data) = time; - GST_DEBUG (0, "mpeg_parse: current_scr %lld", time); + GST_DEBUG (0, "current_scr %lld", time); - gst_pad_push (mpeg_parse->srcpad, GST_BUFFER (data)); + if (GST_PAD_IS_USABLE (mpeg_parse->srcpad)) + gst_pad_push (mpeg_parse->srcpad, GST_BUFFER (data)); + else + gst_data_unref (data); } } @@ -256,18 +260,21 @@ gst_mpeg_parse_handle_discont (GstMPEGParse *mpeg_parse) event = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, MPEGTIME_TO_GSTTIME (mpeg_parse->current_scr), NULL); - gst_pad_push (mpeg_parse->srcpad, GST_BUFFER (event)); + if (GST_PAD_IS_USABLE (mpeg_parse->srcpad)) + gst_pad_push (mpeg_parse->srcpad, GST_BUFFER (event)); + else + gst_event_unref (event); } static gboolean gst_mpeg_parse_parse_packhead (GstMPEGParse *mpeg_parse, GstBuffer *buffer) { guint8 *buf; - guint64 scr; + guint64 scr, scr_adj; guint32 scr1, scr2; guint32 new_rate; - GST_DEBUG (0, "mpeg_parse: in parse_packhead"); + GST_DEBUG (0, "in parse_packhead"); buf = GST_BUFFER_DATA (buffer); buf += 4; @@ -276,51 +283,74 @@ gst_mpeg_parse_parse_packhead (GstMPEGParse *mpeg_parse, GstBuffer *buffer) scr2 = GUINT32_FROM_BE (*(guint32*) (buf+4)); if (GST_MPEG_PACKETIZE_IS_MPEG2 (mpeg_parse->packetize)) { + guint32 scr_ext; /* :2=01 ! scr:3 ! marker:1==1 ! scr:15 ! marker:1==1 ! scr:15 */ scr = (scr1 & 0x38000000) << 3; scr |= (scr1 & 0x03fff800) << 4; scr |= (scr1 & 0x000003ff) << 5; scr |= (scr2 & 0xf8000000) >> 27; - + + scr_ext = (scr2 & 0x03fe0000) >> 17; + + scr = (scr * 300 + scr_ext % 300) / 300; + + GST_DEBUG (0, "%lld %d, %08x %08x %lld diff: %lld", + scr, scr_ext, scr1, scr2, mpeg_parse->bytes_since_scr, + scr - mpeg_parse->current_scr); + + mpeg_parse->bytes_since_scr = 0; + buf += 6; new_rate = (GUINT32_FROM_BE ((*(guint32 *) buf)) & 0xfffffc00) >> 10; - //new_rate *= 133; /* FIXME trial and error */ - new_rate *= 223; /* FIXME trial and error */ } else { scr = (scr1 & 0x0e000000) << 5; scr |= (scr1 & 0x00fffe00) << 6; scr |= (scr1 & 0x000000ff) << 7; scr |= (scr2 & 0xfe000000) >> 25; + + mpeg_parse->bytes_since_scr = 0; buf += 5; new_rate = (GUINT32_FROM_BE ((*(guint32 *) buf)) & 0x7ffffe00) >> 9; - new_rate *= 400; } - mpeg_parse->previous_scr = mpeg_parse->current_scr; + scr_adj = scr + mpeg_parse->adjust; + + GST_DEBUG (0, "SCR is %llu (%llu) next: %lld (%lld) diff: %lld (%lld)", + scr, + MPEGTIME_TO_GSTTIME (scr), + mpeg_parse->next_scr, + MPEGTIME_TO_GSTTIME (mpeg_parse->next_scr), + scr - mpeg_parse->next_scr, + MPEGTIME_TO_GSTTIME (scr) - + MPEGTIME_TO_GSTTIME (mpeg_parse->next_scr)); + + if (ABS ((gint64)mpeg_parse->next_scr - (gint64)(scr_adj)) > 10000) { + GST_DEBUG (0, "discontinuity detected; expected: %llu got: %llu real:%lld adjust:%lld", + mpeg_parse->next_scr, scr_adj, scr, mpeg_parse->adjust); + + mpeg_parse->adjust = mpeg_parse->next_scr - scr; + scr = mpeg_parse->next_scr; + + GST_DEBUG (0, "new adjust: %lld", mpeg_parse->adjust); + } + else { + scr = scr_adj; + } + mpeg_parse->current_scr = scr; - - GST_DEBUG (0, "mpeg_parse: SCR is %llu (%llu)", scr, - MPEGTIME_TO_GSTTIME (mpeg_parse->current_scr)); - - if (mpeg_parse->previous_scr > mpeg_parse->current_scr) { - GST_DEBUG (0, "mpeg_parse: discontinuity detected %llu (%llu)", - mpeg_parse->previous_scr, mpeg_parse->current_scr); - mpeg_parse->discont_pending = TRUE; - } mpeg_parse->scr_pending = FALSE; - if (mpeg_parse->bit_rate != new_rate) { - mpeg_parse->bit_rate = new_rate; + if (mpeg_parse->mux_rate != new_rate) { + mpeg_parse->mux_rate = new_rate; g_object_notify (G_OBJECT (mpeg_parse), "bitrate"); } - GST_DEBUG (0, "mpeg_parse: stream is %1.3fMbs", - (mpeg_parse->bit_rate) / 1000000.0); + GST_DEBUG (0, "stream is %1.3fMbs", (mpeg_parse->mux_rate * 400) / 1000000.0); return TRUE; } @@ -342,7 +372,7 @@ gst_mpeg_parse_loop (GstElement *element) if (GST_IS_BUFFER (data)) { GstBuffer *buffer = GST_BUFFER (data); - GST_DEBUG (0, "mpeg2demux: have chunk 0x%02X", id); + GST_DEBUG (0, "have chunk 0x%02X", id); switch (id) { case 0xba: @@ -357,7 +387,7 @@ gst_mpeg_parse_loop (GstElement *element) break; default: if (mpeg2 && ((id < 0xBD) || (id > 0xFE))) { - g_warning ("mpeg2demux: ******** unknown id 0x%02X", id); + g_warning ("******** unknown id 0x%02X", id); } else { if (mpeg2) { @@ -415,8 +445,12 @@ gst_mpeg_parse_loop (GstElement *element) } gst_buffer_unref (GST_BUFFER (data)); return; + } + size = GST_BUFFER_SIZE (data); + mpeg_parse->bytes_since_scr += size; + if (CLASS (mpeg_parse)->send_data) CLASS (mpeg_parse)->send_data (mpeg_parse, data, time); @@ -425,10 +459,29 @@ gst_mpeg_parse_loop (GstElement *element) gst_element_clock_wait (GST_ELEMENT (mpeg_parse), mpeg_parse->clock, time, NULL); } - size = GST_BUFFER_SIZE (data); - - /* we are interpolating the scr here */ - /* mpeg_parse->current_scr += ((size * 90000LL) / (mpeg_parse->bit_rate)); */ + { + guint64 scr, bss, br; + + scr = mpeg_parse->current_scr; + bss = mpeg_parse->bytes_since_scr; + br = mpeg_parse->mux_rate * 50; + + if (GST_MPEG_PACKETIZE_IS_MPEG2 (mpeg_parse->packetize)) { + /* + * The mpeg spec says something like this, but that doesn't really work: + * + * mpeg_parse->next_scr = (scr * br + bss * 90000LL) / (90000LL + br); + */ + mpeg_parse->next_scr = scr + (bss * 90000LL) / br; + } + else { + /* we are interpolating the scr here */ + mpeg_parse->next_scr = scr + (bss * 90000LL) / br; + } + + GST_DEBUG (0, "size: %lld, total since SCR: %lld, next SCR: %lld", + size, bss, mpeg_parse->next_scr); + } } } @@ -472,7 +525,7 @@ gst_mpeg_parse_handle_src_query (GstPad *pad, GstPadQueryType type, GstFormat peer_format; gint64 peer_value; - if (mpeg_parse->bit_rate == 0) + if (mpeg_parse->mux_rate == 0) return FALSE; peer_format = GST_FORMAT_BYTES; @@ -480,7 +533,7 @@ gst_mpeg_parse_handle_src_query (GstPad *pad, GstPadQueryType type, GST_PAD_QUERY_TOTAL, &peer_format, &peer_value)) { /* multiply bywith 8 because vbr is in bits/second */ - *value = peer_value * 8 * GST_SECOND / mpeg_parse->bit_rate; + *value = peer_value * GST_SECOND / (mpeg_parse->mux_rate * 50); } else res = FALSE; @@ -543,7 +596,7 @@ gst_mpeg_parse_handle_src_event (GstPad *pad, GstEvent *event) if (GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH) { } - desired_offset = mpeg_parse->bit_rate * GST_EVENT_SEEK_OFFSET (event) / (8 * GST_SECOND); + desired_offset = mpeg_parse->mux_rate * 50 * GST_EVENT_SEEK_OFFSET (event) / (GST_SECOND); if (!gst_bytestream_seek (mpeg_parse->packetize->bs, desired_offset, GST_SEEK_METHOD_SET)) { gst_event_unref (event); @@ -596,7 +649,7 @@ gst_mpeg_parse_get_property (GObject *object, guint prop_id, GValue *value, GPar switch (prop_id) { case ARG_BIT_RATE: - g_value_set_uint (value, mpeg_parse->bit_rate); + g_value_set_uint (value, mpeg_parse->mux_rate * 400); break; case ARG_MPEG2: if (mpeg_parse->packetize) diff --git a/gst/mpegstream/gstmpegparse.h b/gst/mpegstream/gstmpegparse.h index 0ad779ba50..a388bec4cc 100644 --- a/gst/mpegstream/gstmpegparse.h +++ b/gst/mpegstream/gstmpegparse.h @@ -46,7 +46,7 @@ extern "C" { #define GST_MPEG_PARSE_IS_MPEG2(parse) (GST_MPEG_PACKETIZE_IS_MPEG2 (GST_MPEG_PARSE (parse)->packetize)) -#define MPEGTIME_TO_GSTTIME(time) (((time) * GST_SECOND) / 90000LL) +#define MPEGTIME_TO_GSTTIME(time) (((time) * (GST_MSECOND/10)) / 9LL) typedef struct _GstMPEGParse GstMPEGParse; typedef struct _GstMPEGParseClass GstMPEGParseClass; @@ -59,9 +59,12 @@ struct _GstMPEGParse { GstMPEGPacketize *packetize; /* pack header values */ - guint32 bit_rate; + guint32 mux_rate; guint64 current_scr; - guint64 previous_scr; + guint64 next_scr; + guint64 bytes_since_scr; + + gint64 adjust; gboolean discont_pending; gboolean scr_pending;