mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-30 13:41:48 +00:00
- cleanups
Original commit message from CVS: - cleanups - detect and correct SCR discontinuities, also correct PTSes
This commit is contained in:
parent
aae92a57bf
commit
ebc290ac1d
4 changed files with 315 additions and 250 deletions
|
@ -202,21 +202,16 @@ gst_mpeg_demux_init (GstMPEGDemux *mpeg_demux)
|
||||||
/* i think everything is already zero'd, but oh well*/
|
/* i think everything is already zero'd, but oh well*/
|
||||||
for (i=0;i<NUM_PRIVATE_1_PADS;i++) {
|
for (i=0;i<NUM_PRIVATE_1_PADS;i++) {
|
||||||
mpeg_demux->private_1_pad[i] = NULL;
|
mpeg_demux->private_1_pad[i] = NULL;
|
||||||
mpeg_demux->private_1_PTS[i] = 0;
|
|
||||||
}
|
}
|
||||||
for (i=0;i<NUM_SUBTITLE_PADS;i++) {
|
for (i=0;i<NUM_SUBTITLE_PADS;i++) {
|
||||||
mpeg_demux->subtitle_pad[i] = NULL;
|
mpeg_demux->subtitle_pad[i] = NULL;
|
||||||
mpeg_demux->subtitle_offset[i] = 0;
|
|
||||||
}
|
}
|
||||||
mpeg_demux->private_2_pad = NULL;
|
mpeg_demux->private_2_pad = NULL;
|
||||||
mpeg_demux->private_2_offset = 0;
|
|
||||||
for (i=0;i<NUM_VIDEO_PADS;i++) {
|
for (i=0;i<NUM_VIDEO_PADS;i++) {
|
||||||
mpeg_demux->video_pad[i] = NULL;
|
mpeg_demux->video_pad[i] = NULL;
|
||||||
mpeg_demux->video_PTS[i] = 0;
|
|
||||||
}
|
}
|
||||||
for (i=0;i<NUM_AUDIO_PADS;i++) {
|
for (i=0;i<NUM_AUDIO_PADS;i++) {
|
||||||
mpeg_demux->audio_pad[i] = NULL;
|
mpeg_demux->audio_pad[i] = NULL;
|
||||||
mpeg_demux->audio_PTS[i] = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_FLAG_SET (mpeg_demux, GST_ELEMENT_EVENT_AWARE);
|
GST_FLAG_SET (mpeg_demux, GST_ELEMENT_EVENT_AWARE);
|
||||||
|
@ -225,7 +220,7 @@ gst_mpeg_demux_init (GstMPEGDemux *mpeg_demux)
|
||||||
static void
|
static void
|
||||||
gst_mpeg_demux_send_data (GstMPEGParse *mpeg_parse, GstData *data, GstClockTime time)
|
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)) {
|
if (GST_IS_BUFFER (data)) {
|
||||||
gst_buffer_unref (GST_BUFFER (data));
|
gst_buffer_unref (GST_BUFFER (data));
|
||||||
|
@ -245,32 +240,30 @@ static void
|
||||||
gst_mpeg_demux_handle_discont (GstMPEGParse *mpeg_parse)
|
gst_mpeg_demux_handle_discont (GstMPEGParse *mpeg_parse)
|
||||||
{
|
{
|
||||||
GstMPEGDemux *mpeg_demux = GST_MPEG_DEMUX (mpeg_parse);
|
GstMPEGDemux *mpeg_demux = GST_MPEG_DEMUX (mpeg_parse);
|
||||||
gint i;
|
|
||||||
gint64 current_time = MPEGTIME_TO_GSTTIME (mpeg_parse->current_scr);
|
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;i<NUM_VIDEO_PADS;i++) {
|
for (i=0;i<NUM_VIDEO_PADS;i++) {
|
||||||
if (mpeg_demux->video_pad[i] &&
|
if (mpeg_demux->video_pad[i] &&
|
||||||
GST_PAD_IS_CONNECTED (mpeg_demux->video_pad[i]))
|
GST_PAD_IS_USABLE (mpeg_demux->video_pad[i]))
|
||||||
{
|
{
|
||||||
GstEvent *discont;
|
GstEvent *discont;
|
||||||
|
|
||||||
discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME,
|
discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME,
|
||||||
current_time, NULL);
|
current_time, NULL);
|
||||||
|
|
||||||
mpeg_demux->video_PTS[i] = mpeg_parse->current_scr;
|
|
||||||
gst_pad_push (mpeg_demux->video_pad[i], GST_BUFFER (discont));
|
gst_pad_push (mpeg_demux->video_pad[i], GST_BUFFER (discont));
|
||||||
}
|
}
|
||||||
if (mpeg_demux->audio_pad[i] &&
|
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;
|
GstEvent *discont;
|
||||||
|
|
||||||
discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME,
|
discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME,
|
||||||
current_time, NULL);
|
current_time, NULL);
|
||||||
|
|
||||||
mpeg_demux->audio_PTS[i] = mpeg_parse->current_scr;
|
|
||||||
gst_pad_push (mpeg_demux->audio_pad[i], GST_BUFFER (discont));
|
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);
|
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);
|
buf = GST_BUFFER_DATA (buffer);
|
||||||
/* do something usefull here */
|
/* do something usefull here */
|
||||||
|
@ -298,13 +291,13 @@ gst_mpeg_demux_parse_syshead (GstMPEGParse *mpeg_parse, GstBuffer *buffer)
|
||||||
guint16 header_length;
|
guint16 header_length;
|
||||||
guchar *buf;
|
guchar *buf;
|
||||||
|
|
||||||
GST_DEBUG (0, "mpeg_demux: in parse_syshead");
|
GST_DEBUG (0, "in parse_syshead");
|
||||||
|
|
||||||
buf = GST_BUFFER_DATA (buffer);
|
buf = GST_BUFFER_DATA (buffer);
|
||||||
buf += 4;
|
buf += 4;
|
||||||
|
|
||||||
header_length = GUINT16_FROM_BE (*(guint16 *) buf);
|
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;
|
buf += 2;
|
||||||
|
|
||||||
/* marker:1==1 ! rate_bound:22 | marker:1==1*/
|
/* 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 stream_count = (header_length - 6) / 3;
|
||||||
gint i, j=0;
|
gint i, j=0;
|
||||||
|
|
||||||
GST_DEBUG (0, "mpeg_demux::parse_syshead: number of streams=%d ",
|
GST_DEBUG (0, "number of streams=%d ",
|
||||||
stream_count);
|
stream_count);
|
||||||
|
|
||||||
for (i = 0; i < stream_count; i++) {
|
for (i = 0; i < stream_count; i++) {
|
||||||
gint stream_num;
|
|
||||||
guint8 stream_id;
|
guint8 stream_id;
|
||||||
gboolean STD_buffer_bound_scale;
|
gboolean STD_buffer_bound_scale;
|
||||||
guint16 STD_buffer_size_bound;
|
guint16 STD_buffer_size_bound;
|
||||||
|
@ -338,14 +330,13 @@ gst_mpeg_demux_parse_syshead (GstMPEGParse *mpeg_parse, GstBuffer *buffer)
|
||||||
|
|
||||||
stream_id = *buf++;
|
stream_id = *buf++;
|
||||||
if (!(stream_id & 0x80)) {
|
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;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check marker bits */
|
/* check marker bits */
|
||||||
if ((*buf & 0xC0) != 0xC0) {
|
if ((*buf & 0xC0) != 0xC0) {
|
||||||
GST_DEBUG (0,
|
GST_DEBUG (0, "expecting placeholder bit values '11' after stream id\n");
|
||||||
"mpeg_demux::parse_syshead: expecting placeholder bit values '11' after stream id\n");
|
|
||||||
return FALSE;
|
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;
|
buf_byte_size_bound = STD_buffer_size_bound * 1024;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* private_stream_1 */
|
switch (stream_id) {
|
||||||
if (stream_id == 0xBD) {
|
/* private_stream_1 */
|
||||||
name = NULL;
|
case 0xBD:
|
||||||
outpad = NULL;
|
name = NULL;
|
||||||
}
|
outpad = NULL;
|
||||||
/* private_stream_2 */
|
break;
|
||||||
else if (stream_id == 0xBF) {
|
/* private_stream_2 */
|
||||||
name = g_strdup_printf ("private_stream_2");
|
case 0xBF:
|
||||||
stream_num = 0;
|
name = g_strdup_printf ("private_stream_2");
|
||||||
outpad = &mpeg_demux->private_2_pad;
|
outpad = &mpeg_demux->private_2_pad;
|
||||||
newtemp = GST_PAD_TEMPLATE_GET (private2_factory);
|
newtemp = GST_PAD_TEMPLATE_GET (private2_factory);
|
||||||
}
|
break;
|
||||||
/* Audio */
|
/* Audio */
|
||||||
else if ((stream_id >= 0xC0) && (stream_id <= 0xDF)) {
|
case 0xC0 ... 0xDF:
|
||||||
name = g_strdup_printf ("audio_%02d", stream_id & 0x1F);
|
name = g_strdup_printf ("audio_%02d", stream_id & 0x1F);
|
||||||
stream_num = stream_id & 0x1F;
|
outpad = &mpeg_demux->audio_pad[stream_id & 0x1F];
|
||||||
outpad = &mpeg_demux->audio_pad[stream_num];
|
newtemp = GST_PAD_TEMPLATE_GET (audio_factory);
|
||||||
newtemp = GST_PAD_TEMPLATE_GET (audio_factory);
|
break;
|
||||||
}
|
/* Video */
|
||||||
/* Video */
|
case 0xE0 ... 0xEF:
|
||||||
else if ((stream_id >= 0xE0) && (stream_id <= 0xEF)) {
|
name = g_strdup_printf ("video_%02d", stream_id & 0x0F);
|
||||||
name = g_strdup_printf ("video_%02d", stream_id & 0x0F);
|
outpad = &mpeg_demux->video_pad[stream_id & 0x0F];
|
||||||
stream_num = stream_id & 0x0F;
|
if (!GST_MPEG_PARSE_IS_MPEG2 (mpeg_demux)) {
|
||||||
outpad = &mpeg_demux->video_pad[stream_num];
|
newtemp = GST_PAD_TEMPLATE_GET (video_mpeg1_factory);
|
||||||
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);
|
||||||
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, "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, "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, "STD_buffer_size_bound %d or %d bytes",
|
||||||
STD_buffer_size_bound, buf_byte_size_bound);
|
STD_buffer_size_bound, buf_byte_size_bound);
|
||||||
|
|
||||||
/* create the pad and add it to self if it does not yet exist
|
/* 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));
|
gst_element_add_pad (GST_ELEMENT (mpeg_demux), (*outpad));
|
||||||
|
|
||||||
if (GST_PAD_IS_CONNECTED (*outpad)) {
|
if (GST_PAD_IS_USABLE (*outpad)) {
|
||||||
GstEvent *event;
|
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,
|
event = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME,
|
||||||
current_time, NULL);
|
MPEGTIME_TO_GSTTIME (time), NULL);
|
||||||
|
|
||||||
gst_pad_push (*outpad, GST_BUFFER (event));
|
gst_pad_push (*outpad, GST_BUFFER (event));
|
||||||
}
|
}
|
||||||
|
@ -462,7 +457,7 @@ gst_mpeg_demux_parse_packet (GstMPEGParse *mpeg_parse, GstBuffer *buffer)
|
||||||
GstBuffer *outbuf;
|
GstBuffer *outbuf;
|
||||||
guint8 *buf, *basebuf;
|
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);
|
basebuf = buf = GST_BUFFER_DATA (buffer);
|
||||||
id = *(buf+3);
|
id = *(buf+3);
|
||||||
|
@ -471,7 +466,7 @@ gst_mpeg_demux_parse_packet (GstMPEGParse *mpeg_parse, GstBuffer *buffer)
|
||||||
/* start parsing */
|
/* start parsing */
|
||||||
packet_length = GUINT16_FROM_BE (*((guint16 *)buf));
|
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;
|
headerlen = 2;
|
||||||
buf += 2;
|
buf += 2;
|
||||||
|
|
||||||
|
@ -483,14 +478,14 @@ gst_mpeg_demux_parse_packet (GstMPEGParse *mpeg_parse, GstBuffer *buffer)
|
||||||
switch (bits & 0xC0) {
|
switch (bits & 0xC0) {
|
||||||
case 0xC0:
|
case 0xC0:
|
||||||
if (bits == 0xff) {
|
if (bits == 0xff) {
|
||||||
GST_DEBUG (0,"mpeg_demux::parse_packet: have stuffing byte");
|
GST_DEBUG (0, "have stuffing byte");
|
||||||
} else {
|
} else {
|
||||||
GST_DEBUG (0,"mpeg_demux::parse_packet: expected stuffing byte");
|
GST_DEBUG (0, "expected stuffing byte");
|
||||||
}
|
}
|
||||||
headerlen++;
|
headerlen++;
|
||||||
break;
|
break;
|
||||||
case 0x40:
|
case 0x40:
|
||||||
GST_DEBUG (0,"mpeg_demux::parse_packet: have STD");
|
GST_DEBUG (0, "have STD");
|
||||||
|
|
||||||
STD_buffer_bound_scale = bits & 0x20;
|
STD_buffer_bound_scale = bits & 0x20;
|
||||||
STD_buffer_size_bound = (bits & 0x1F) << 8;
|
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++ << 7;
|
||||||
pts |= (*buf++ & 0xFE) >> 1;
|
pts |= (*buf++ & 0xFE) >> 1;
|
||||||
|
|
||||||
GST_DEBUG (0,"mpeg_demux::parse_packet: PTS = %llu", pts);
|
GST_DEBUG (0, "PTS = %llu", pts);
|
||||||
headerlen += 5;
|
headerlen += 5;
|
||||||
goto done;
|
goto done;
|
||||||
case 0x30:
|
case 0x30:
|
||||||
|
@ -526,14 +521,14 @@ gst_mpeg_demux_parse_packet (GstMPEGParse *mpeg_parse, GstBuffer *buffer)
|
||||||
dts |= *buf++ << 7;
|
dts |= *buf++ << 7;
|
||||||
dts |= (*buf++ & 0xFE) >> 1;
|
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;
|
headerlen += 10;
|
||||||
goto done;
|
goto done;
|
||||||
case 0x00:
|
case 0x00:
|
||||||
GST_DEBUG (0,"mpeg_demux::parse_packet: have no pts/dts");
|
GST_DEBUG (0, "have no pts/dts");
|
||||||
GST_DEBUG (0,"mpeg_demux::parse_packet: got trailer bits %x", (bits & 0x0f));
|
GST_DEBUG (0, "got trailer bits %x", (bits & 0x0f));
|
||||||
if ((bits & 0x0f) != 0xf) {
|
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;
|
return FALSE;
|
||||||
}
|
}
|
||||||
headerlen++;
|
headerlen++;
|
||||||
|
@ -544,73 +539,86 @@ gst_mpeg_demux_parse_packet (GstMPEGParse *mpeg_parse, GstBuffer *buffer)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
} while (1);
|
} while (1);
|
||||||
GST_DEBUG (0,"mpeg_demux::parse_packet: done with header loop");
|
GST_DEBUG (0, "done with header loop");
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
|
||||||
/* calculate the amount of real data in this packet */
|
/* calculate the amount of real data in this packet */
|
||||||
datalen = packet_length - headerlen+2;
|
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);
|
headerlen,datalen);
|
||||||
|
|
||||||
/* private_stream_1 */
|
switch (id) {
|
||||||
if (id == 0xBD) {
|
/* private_stream_1 */
|
||||||
/* first find the track code */
|
case 0xBD:
|
||||||
ps_id_code = *(basebuf + headerlen);
|
/* first find the track code */
|
||||||
/* make sure it's valid */
|
ps_id_code = *(basebuf + headerlen);
|
||||||
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",
|
switch (ps_id_code) {
|
||||||
id, ps_id_code - 0x80);
|
/* make sure it's valid */
|
||||||
outpad = &mpeg_demux->private_1_pad[ps_id_code - 0x80];
|
case 0x80 ... 0x87:
|
||||||
/* scrap first 4 bytes (so-called "mystery AC3 tag") */
|
GST_DEBUG (0, "0x%02X: we have a private_stream_1 (AC3) packet, track %d",
|
||||||
headerlen += 4;
|
id, ps_id_code - 0x80);
|
||||||
datalen -= 4;
|
outpad = &mpeg_demux->private_1_pad[ps_id_code - 0x80];
|
||||||
}
|
/* scrap first 4 bytes (so-called "mystery AC3 tag") */
|
||||||
/* private_stream_1 */
|
headerlen += 4;
|
||||||
} else if (id == 0xBF) {
|
datalen -= 4;
|
||||||
GST_DEBUG (0,"mpeg_demux::parse_packet: 0x%02X: we have a private_stream_2 packet", id);
|
break;
|
||||||
outpad = &mpeg_demux->private_2_pad;
|
default:
|
||||||
/* audio */
|
break;
|
||||||
} else if ((id >= 0xC0) && (id <= 0xDF)) {
|
}
|
||||||
GST_DEBUG (0,"mpeg_demux::parse_packet: 0x%02X: we have an audio packet", id);
|
break;
|
||||||
outpad = &mpeg_demux->audio_pad[id & 0x1F];
|
/* private_stream_2 */
|
||||||
/* video */
|
case 0xBF:
|
||||||
} else if ((id >= 0xE0) && (id <= 0xEF)) {
|
GST_DEBUG (0, "0x%02X: we have a private_stream_2 packet", id);
|
||||||
GST_DEBUG (0,"mpeg_demux::parse_packet: 0x%02X: we have a video packet", id);
|
outpad = &mpeg_demux->private_2_pad;
|
||||||
outpad = &mpeg_demux->video_pad[id & 0x0F];
|
break;
|
||||||
if (pts == -1)
|
/* audio */
|
||||||
pts = mpeg_demux->video_PTS[id & 0x1F];
|
case 0xC0 ... 0xDF:
|
||||||
else
|
GST_DEBUG (0, "0x%02X: we have an audio packet", id);
|
||||||
mpeg_demux->video_PTS[id & 0x1F] = pts;
|
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 we don't know what it is, bail */
|
||||||
if (outpad == NULL) {
|
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;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME, this should be done in parse_syshead */
|
/* the pad should have been created in parse_syshead */
|
||||||
if ((*outpad) == NULL) {
|
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;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create the buffer and send it off to the Other Side */
|
/* create the buffer and send it off to the Other Side */
|
||||||
if (GST_PAD_IS_CONNECTED(*outpad) && datalen > 0) {
|
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 */
|
/* 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) {
|
if (pts != -1) {
|
||||||
GST_BUFFER_TIMESTAMP (outbuf) = (pts * GST_SECOND)/90000LL;
|
pts += mpeg_parse->adjust;
|
||||||
|
|
||||||
|
GST_BUFFER_TIMESTAMP (outbuf) = MPEGTIME_TO_GSTTIME (pts);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
GST_BUFFER_TIMESTAMP (outbuf) = -1LL;
|
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));
|
datalen, id, GST_BUFFER_TIMESTAMP (outbuf));
|
||||||
|
|
||||||
gst_pad_push ((*outpad), outbuf);
|
gst_pad_push ((*outpad), outbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -636,7 +644,7 @@ gst_mpeg_demux_parse_pes (GstMPEGParse *mpeg_parse, GstBuffer *buffer)
|
||||||
GstPadTemplate *newtemp = NULL;
|
GstPadTemplate *newtemp = NULL;
|
||||||
guint8 *buf, *basebuf;
|
guint8 *buf, *basebuf;
|
||||||
|
|
||||||
GST_DEBUG (0,"mpeg_demux: in parse_pes");
|
GST_DEBUG (0, "in parse_pes");
|
||||||
|
|
||||||
basebuf = buf = GST_BUFFER_DATA (buffer);
|
basebuf = buf = GST_BUFFER_DATA (buffer);
|
||||||
id = *(buf+3);
|
id = *(buf+3);
|
||||||
|
@ -645,7 +653,7 @@ gst_mpeg_demux_parse_pes (GstMPEGParse *mpeg_parse, GstBuffer *buffer)
|
||||||
/* start parsing */
|
/* start parsing */
|
||||||
packet_length = GUINT16_FROM_BE (*((guint16 *)buf));
|
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;
|
buf += 2;
|
||||||
|
|
||||||
/* we don't operate on: program_stream_map, padding_stream, */
|
/* 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++;
|
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 */
|
/* check for PTS */
|
||||||
if ((flags2 & 0x80)) {
|
if ((flags2 & 0x80)) {
|
||||||
|
@ -672,14 +680,17 @@ gst_mpeg_demux_parse_pes (GstMPEGParse *mpeg_parse, GstBuffer *buffer)
|
||||||
pts |= (*buf++ & 0xFE) << 14;
|
pts |= (*buf++ & 0xFE) << 14;
|
||||||
pts |= *buf++ << 7;
|
pts |= *buf++ << 7;
|
||||||
pts |= (*buf++ & 0xFE) >> 1;
|
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)) {
|
if ((flags2 & 0x40)) {
|
||||||
GST_DEBUG (0, "mpeg_demux::parse_packet: %x DTS found", id);
|
GST_DEBUG (0, "%x DTS found", id);
|
||||||
buf += 5;
|
buf += 5;
|
||||||
}
|
}
|
||||||
if ((flags2 & 0x20)) {
|
if ((flags2 & 0x20)) {
|
||||||
GST_DEBUG (0, "mpeg_demux::parse_packet: %x ESCR found", id);
|
GST_DEBUG (0, "%x ESCR found", id);
|
||||||
buf += 6;
|
buf += 6;
|
||||||
}
|
}
|
||||||
if ((flags2 & 0x10)) {
|
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++ & 0x07) << 14;
|
||||||
es_rate |= (*buf++ ) << 7;
|
es_rate |= (*buf++ ) << 7;
|
||||||
es_rate |= (*buf++ & 0xFE) >> 1;
|
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... */
|
/* 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;
|
headerlen = 5 + header_data_length;
|
||||||
/* constant is 2 bytes of bits, 1 byte header len */
|
/* constant is 2 bytes of bits, 1 byte header len */
|
||||||
datalen = packet_length - (3 + header_data_length);
|
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);
|
headerlen, datalen);
|
||||||
|
|
||||||
/* private_stream_1 */
|
switch (id) {
|
||||||
if (id == 0xBD) {
|
/* private_stream_1 */
|
||||||
/* first find the track code */
|
case 0xBD:
|
||||||
ps_id_code = *(basebuf + headerlen + 4);
|
/* first find the track code */
|
||||||
/* make sure it's valid */
|
ps_id_code = *(basebuf + headerlen + 4);
|
||||||
if ((ps_id_code >= 0x80) && (ps_id_code <= 0x87)) {
|
|
||||||
GST_DEBUG (0,"mpeg_demux: we have a private_stream_1 (AC3) packet, track %d",
|
switch (ps_id_code) {
|
||||||
ps_id_code - 0x80);
|
case 0x80 ... 0x87:
|
||||||
outpad = &mpeg_demux->private_1_pad[ps_id_code - 0x80];
|
GST_DEBUG (0, "we have a private_stream_1 (AC3) packet, track %d",
|
||||||
/* scrap first 4 bytes (so-called "mystery AC3 tag") */
|
ps_id_code - 0x80);
|
||||||
headerlen += 4;
|
outpad = &mpeg_demux->private_1_pad[ps_id_code - 0x80];
|
||||||
datalen -= 4;
|
/* scrap first 4 bytes (so-called "mystery AC3 tag") */
|
||||||
if (pts == -1)
|
headerlen += 4;
|
||||||
pts = mpeg_demux->private_1_PTS[ps_id_code - 0x80];
|
datalen -= 4;
|
||||||
else
|
break;
|
||||||
mpeg_demux->private_1_PTS[ps_id_code - 0x80] = pts;
|
case 0x20 ... 0x2f:
|
||||||
}
|
GST_DEBUG (0, "we have a subtitle_stream packet, track %d",
|
||||||
else if ((ps_id_code >= 0x20) && (ps_id_code <= 0x2f)) {
|
ps_id_code - 0x20);
|
||||||
GST_DEBUG (0,"mpeg_demux: we have a subtitle_stream packet, track %d",
|
outpad = &mpeg_demux->subtitle_pad[ps_id_code - 0x20];
|
||||||
ps_id_code - 0x20);
|
headerlen += 1;
|
||||||
outpad = &mpeg_demux->subtitle_pad[ps_id_code - 0x20];
|
datalen -= 1;
|
||||||
headerlen += 1;
|
break;
|
||||||
datalen -= 1;
|
default:
|
||||||
}
|
GST_DEBUG (0, "0x%02X: unkonwn id %x",
|
||||||
else {
|
id, ps_id_code);
|
||||||
GST_DEBUG (0,"mpeg_demux::parse_packet: 0x%02X: unkonwn id %x",
|
break;
|
||||||
id, ps_id_code);
|
}
|
||||||
}
|
break;
|
||||||
/* private_stream_1 */
|
/* private_stream_2 */
|
||||||
} else if (id == 0xBF) {
|
case 0xBF:
|
||||||
GST_DEBUG (0,"mpeg_demux: we have a private_stream_2 packet");
|
GST_DEBUG (0, "we have a private_stream_2 packet");
|
||||||
outpad = &mpeg_demux->private_2_pad;
|
outpad = &mpeg_demux->private_2_pad;
|
||||||
/* audio */
|
break;
|
||||||
} else if ((id >= 0xC0) && (id <= 0xDF)) {
|
/* audio */
|
||||||
GST_DEBUG (0,"mpeg_demux: we have an audio packet");
|
case 0xC0 ... 0xDF:
|
||||||
outpad = &mpeg_demux->audio_pad[id - 0xC0];
|
GST_DEBUG (0, "we have an audio packet");
|
||||||
if (pts == -1)
|
outpad = &mpeg_demux->audio_pad[id - 0xC0];
|
||||||
pts = mpeg_demux->audio_PTS[id & 0x1F];
|
break;
|
||||||
else
|
/* video */
|
||||||
mpeg_demux->audio_PTS[id & 0x1F] = pts;
|
case 0xE0 ... 0xEF:
|
||||||
/* video */
|
GST_DEBUG (0, "we have a video packet");
|
||||||
} else if ((id >= 0xE0) && (id <= 0xEF)) {
|
outpad = &mpeg_demux->video_pad[id - 0xE0];
|
||||||
GST_DEBUG (0,"mpeg_demux: we have a video packet");
|
break;
|
||||||
outpad = &mpeg_demux->video_pad[id - 0xE0];
|
default:
|
||||||
if (pts == -1)
|
GST_DEBUG (0, "we have a unkown packet");
|
||||||
pts = mpeg_demux->video_PTS[id & 0x1F];
|
break;
|
||||||
else
|
|
||||||
mpeg_demux->video_PTS[id & 0x1F] = pts;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if we don't know what it is, bail */
|
/* 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;
|
gchar *name = NULL;
|
||||||
|
|
||||||
/* we have to name the stream approriately */
|
/* we have to name the stream approriately */
|
||||||
if (id == 0xBD) {
|
switch (id) {
|
||||||
if (ps_id_code >= 0x80 && ps_id_code <= 0x87) {
|
/* private_stream_1 */
|
||||||
name = g_strdup_printf("private_stream_1.%d",ps_id_code - 0x80);
|
case 0xBD:
|
||||||
newtemp = GST_PAD_TEMPLATE_GET (private1_factory);
|
switch (ps_id_code) {
|
||||||
}
|
case 0x80 ... 0x87:
|
||||||
else if (ps_id_code >= 0x20 && ps_id_code <= 0x2f) {
|
name = g_strdup_printf ("private_stream_1.%d",ps_id_code - 0x80);
|
||||||
name = g_strdup_printf("subtitle_stream_%d",ps_id_code - 0x20);
|
newtemp = GST_PAD_TEMPLATE_GET (private1_factory);
|
||||||
newtemp = GST_PAD_TEMPLATE_GET (subtitle_factory);
|
break;
|
||||||
}
|
case 0x20 ... 0x2F:
|
||||||
else {
|
name = g_strdup_printf ("subtitle_stream_%d",ps_id_code - 0x20);
|
||||||
name = g_strdup_printf("unknown_stream_%d",ps_id_code);
|
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) {
|
if (newtemp) {
|
||||||
/* create the pad and add it to self */
|
/* create the pad and add it to self */
|
||||||
(*outpad) = gst_pad_new_from_template (newtemp, name);
|
(*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));
|
gst_element_add_pad(GST_ELEMENT(mpeg_demux),(*outpad));
|
||||||
}
|
}
|
||||||
else {
|
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)
|
if (name)
|
||||||
g_free (name);
|
g_free (name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create the buffer and send it off to the Other Side */
|
/* 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 */
|
/* 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);
|
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);
|
gst_pad_push((*outpad),outbuf);
|
||||||
}
|
}
|
||||||
|
@ -829,19 +855,12 @@ gst_mpeg_demux_parse_pes (GstMPEGParse *mpeg_parse, GstBuffer *buffer)
|
||||||
static GstElementStateReturn
|
static GstElementStateReturn
|
||||||
gst_mpeg_demux_change_state (GstElement *element)
|
gst_mpeg_demux_change_state (GstElement *element)
|
||||||
{
|
{
|
||||||
GstMPEGDemux *mpeg_demux = GST_MPEG_DEMUX (element);
|
/* GstMPEGDemux *mpeg_demux = GST_MPEG_DEMUX (element); */
|
||||||
gint i;
|
|
||||||
|
|
||||||
switch (GST_STATE_TRANSITION (element)) {
|
switch (GST_STATE_TRANSITION (element)) {
|
||||||
case GST_STATE_READY_TO_PAUSED:
|
case GST_STATE_READY_TO_PAUSED:
|
||||||
break;
|
break;
|
||||||
case GST_STATE_PAUSED_TO_READY:
|
case GST_STATE_PAUSED_TO_READY:
|
||||||
for (i=0;i<NUM_VIDEO_PADS;i++) {
|
|
||||||
mpeg_demux->video_PTS[i] = 0;
|
|
||||||
}
|
|
||||||
for (i=0;i<NUM_AUDIO_PADS;i++) {
|
|
||||||
mpeg_demux->audio_PTS[i] = 0;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case GST_STATE_READY_TO_NULL:
|
case GST_STATE_READY_TO_NULL:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -99,20 +99,10 @@ struct _GstMPEGDemux {
|
||||||
|
|
||||||
/* stream output pads */
|
/* stream output pads */
|
||||||
GstPad *private_1_pad[NUM_PRIVATE_1_PADS]; /* up to 8 ac3 audio tracks */
|
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];
|
GstPad *subtitle_pad[NUM_SUBTITLE_PADS];
|
||||||
gulong subtitle_offset[NUM_SUBTITLE_PADS];
|
|
||||||
|
|
||||||
GstPad *private_2_pad;
|
GstPad *private_2_pad;
|
||||||
gulong private_2_offset;
|
|
||||||
|
|
||||||
GstPad *video_pad[NUM_VIDEO_PADS];
|
GstPad *video_pad[NUM_VIDEO_PADS];
|
||||||
gint64 video_PTS[NUM_VIDEO_PADS];
|
|
||||||
|
|
||||||
GstPad *audio_pad[NUM_AUDIO_PADS];
|
GstPad *audio_pad[NUM_AUDIO_PADS];
|
||||||
gint64 audio_PTS[NUM_AUDIO_PADS];
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstMPEGDemuxClass {
|
struct _GstMPEGDemuxClass {
|
||||||
|
|
|
@ -174,11 +174,12 @@ gst_mpeg_parse_init (GstMPEGParse *mpeg_parse)
|
||||||
/* initialize parser state */
|
/* initialize parser state */
|
||||||
mpeg_parse->packetize = NULL;
|
mpeg_parse->packetize = NULL;
|
||||||
mpeg_parse->current_scr = 0;
|
mpeg_parse->current_scr = 0;
|
||||||
mpeg_parse->previous_scr = 0;
|
mpeg_parse->bytes_since_scr = 0;
|
||||||
|
mpeg_parse->adjust = 0;
|
||||||
mpeg_parse->sync = FALSE;
|
mpeg_parse->sync = FALSE;
|
||||||
|
|
||||||
/* zero counters (should be done at RUNNING?) */
|
/* zero counters (should be done at RUNNING?) */
|
||||||
mpeg_parse->bit_rate = 0;
|
mpeg_parse->mux_rate = 0;
|
||||||
mpeg_parse->discont_pending = FALSE;
|
mpeg_parse->discont_pending = FALSE;
|
||||||
mpeg_parse->scr_pending = TRUE;
|
mpeg_parse->scr_pending = TRUE;
|
||||||
mpeg_parse->provided_clock = gst_mpeg_clock_new ("MPEGParseClock",
|
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);
|
GstMPEGParse *parse = GST_MPEG_PARSE (data);
|
||||||
|
|
||||||
return MPEGTIME_TO_GSTTIME (parse->previous_scr);
|
return MPEGTIME_TO_GSTTIME (parse->current_scr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -242,9 +243,12 @@ gst_mpeg_parse_send_data (GstMPEGParse *mpeg_parse, GstData *data, GstClockTime
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_BUFFER_TIMESTAMP (data) = time;
|
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,
|
event = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME,
|
||||||
MPEGTIME_TO_GSTTIME (mpeg_parse->current_scr), NULL);
|
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
|
static gboolean
|
||||||
gst_mpeg_parse_parse_packhead (GstMPEGParse *mpeg_parse, GstBuffer *buffer)
|
gst_mpeg_parse_parse_packhead (GstMPEGParse *mpeg_parse, GstBuffer *buffer)
|
||||||
{
|
{
|
||||||
guint8 *buf;
|
guint8 *buf;
|
||||||
guint64 scr;
|
guint64 scr, scr_adj;
|
||||||
guint32 scr1, scr2;
|
guint32 scr1, scr2;
|
||||||
guint32 new_rate;
|
guint32 new_rate;
|
||||||
|
|
||||||
GST_DEBUG (0, "mpeg_parse: in parse_packhead");
|
GST_DEBUG (0, "in parse_packhead");
|
||||||
|
|
||||||
buf = GST_BUFFER_DATA (buffer);
|
buf = GST_BUFFER_DATA (buffer);
|
||||||
buf += 4;
|
buf += 4;
|
||||||
|
@ -276,51 +283,74 @@ gst_mpeg_parse_parse_packhead (GstMPEGParse *mpeg_parse, GstBuffer *buffer)
|
||||||
scr2 = GUINT32_FROM_BE (*(guint32*) (buf+4));
|
scr2 = GUINT32_FROM_BE (*(guint32*) (buf+4));
|
||||||
|
|
||||||
if (GST_MPEG_PACKETIZE_IS_MPEG2 (mpeg_parse->packetize)) {
|
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 */
|
/* :2=01 ! scr:3 ! marker:1==1 ! scr:15 ! marker:1==1 ! scr:15 */
|
||||||
scr = (scr1 & 0x38000000) << 3;
|
scr = (scr1 & 0x38000000) << 3;
|
||||||
scr |= (scr1 & 0x03fff800) << 4;
|
scr |= (scr1 & 0x03fff800) << 4;
|
||||||
scr |= (scr1 & 0x000003ff) << 5;
|
scr |= (scr1 & 0x000003ff) << 5;
|
||||||
scr |= (scr2 & 0xf8000000) >> 27;
|
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;
|
buf += 6;
|
||||||
new_rate = (GUINT32_FROM_BE ((*(guint32 *) buf)) & 0xfffffc00) >> 10;
|
new_rate = (GUINT32_FROM_BE ((*(guint32 *) buf)) & 0xfffffc00) >> 10;
|
||||||
//new_rate *= 133; /* FIXME trial and error */
|
|
||||||
new_rate *= 223; /* FIXME trial and error */
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
scr = (scr1 & 0x0e000000) << 5;
|
scr = (scr1 & 0x0e000000) << 5;
|
||||||
scr |= (scr1 & 0x00fffe00) << 6;
|
scr |= (scr1 & 0x00fffe00) << 6;
|
||||||
scr |= (scr1 & 0x000000ff) << 7;
|
scr |= (scr1 & 0x000000ff) << 7;
|
||||||
scr |= (scr2 & 0xfe000000) >> 25;
|
scr |= (scr2 & 0xfe000000) >> 25;
|
||||||
|
|
||||||
|
mpeg_parse->bytes_since_scr = 0;
|
||||||
|
|
||||||
buf += 5;
|
buf += 5;
|
||||||
new_rate = (GUINT32_FROM_BE ((*(guint32 *) buf)) & 0x7ffffe00) >> 9;
|
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;
|
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;
|
mpeg_parse->scr_pending = FALSE;
|
||||||
|
|
||||||
if (mpeg_parse->bit_rate != new_rate) {
|
if (mpeg_parse->mux_rate != new_rate) {
|
||||||
mpeg_parse->bit_rate = new_rate;
|
mpeg_parse->mux_rate = new_rate;
|
||||||
|
|
||||||
g_object_notify (G_OBJECT (mpeg_parse), "bitrate");
|
g_object_notify (G_OBJECT (mpeg_parse), "bitrate");
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_DEBUG (0, "mpeg_parse: stream is %1.3fMbs",
|
GST_DEBUG (0, "stream is %1.3fMbs", (mpeg_parse->mux_rate * 400) / 1000000.0);
|
||||||
(mpeg_parse->bit_rate) / 1000000.0);
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -342,7 +372,7 @@ gst_mpeg_parse_loop (GstElement *element)
|
||||||
if (GST_IS_BUFFER (data)) {
|
if (GST_IS_BUFFER (data)) {
|
||||||
GstBuffer *buffer = GST_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) {
|
switch (id) {
|
||||||
case 0xba:
|
case 0xba:
|
||||||
|
@ -357,7 +387,7 @@ gst_mpeg_parse_loop (GstElement *element)
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (mpeg2 && ((id < 0xBD) || (id > 0xFE))) {
|
if (mpeg2 && ((id < 0xBD) || (id > 0xFE))) {
|
||||||
g_warning ("mpeg2demux: ******** unknown id 0x%02X", id);
|
g_warning ("******** unknown id 0x%02X", id);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (mpeg2) {
|
if (mpeg2) {
|
||||||
|
@ -415,8 +445,12 @@ gst_mpeg_parse_loop (GstElement *element)
|
||||||
}
|
}
|
||||||
gst_buffer_unref (GST_BUFFER (data));
|
gst_buffer_unref (GST_BUFFER (data));
|
||||||
return;
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size = GST_BUFFER_SIZE (data);
|
||||||
|
mpeg_parse->bytes_since_scr += size;
|
||||||
|
|
||||||
if (CLASS (mpeg_parse)->send_data)
|
if (CLASS (mpeg_parse)->send_data)
|
||||||
CLASS (mpeg_parse)->send_data (mpeg_parse, data, time);
|
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);
|
gst_element_clock_wait (GST_ELEMENT (mpeg_parse), mpeg_parse->clock, time, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
size = GST_BUFFER_SIZE (data);
|
{
|
||||||
|
guint64 scr, bss, br;
|
||||||
/* we are interpolating the scr here */
|
|
||||||
/* mpeg_parse->current_scr += ((size * 90000LL) / (mpeg_parse->bit_rate)); */
|
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;
|
GstFormat peer_format;
|
||||||
gint64 peer_value;
|
gint64 peer_value;
|
||||||
|
|
||||||
if (mpeg_parse->bit_rate == 0)
|
if (mpeg_parse->mux_rate == 0)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
peer_format = GST_FORMAT_BYTES;
|
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))
|
GST_PAD_QUERY_TOTAL, &peer_format, &peer_value))
|
||||||
{
|
{
|
||||||
/* multiply bywith 8 because vbr is in bits/second */
|
/* 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
|
else
|
||||||
res = FALSE;
|
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) {
|
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)) {
|
if (!gst_bytestream_seek (mpeg_parse->packetize->bs, desired_offset, GST_SEEK_METHOD_SET)) {
|
||||||
gst_event_unref (event);
|
gst_event_unref (event);
|
||||||
|
@ -596,7 +649,7 @@ gst_mpeg_parse_get_property (GObject *object, guint prop_id, GValue *value, GPar
|
||||||
|
|
||||||
switch (prop_id) {
|
switch (prop_id) {
|
||||||
case ARG_BIT_RATE:
|
case ARG_BIT_RATE:
|
||||||
g_value_set_uint (value, mpeg_parse->bit_rate);
|
g_value_set_uint (value, mpeg_parse->mux_rate * 400);
|
||||||
break;
|
break;
|
||||||
case ARG_MPEG2:
|
case ARG_MPEG2:
|
||||||
if (mpeg_parse->packetize)
|
if (mpeg_parse->packetize)
|
||||||
|
|
|
@ -46,7 +46,7 @@ extern "C" {
|
||||||
|
|
||||||
#define GST_MPEG_PARSE_IS_MPEG2(parse) (GST_MPEG_PACKETIZE_IS_MPEG2 (GST_MPEG_PARSE (parse)->packetize))
|
#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 _GstMPEGParse GstMPEGParse;
|
||||||
typedef struct _GstMPEGParseClass GstMPEGParseClass;
|
typedef struct _GstMPEGParseClass GstMPEGParseClass;
|
||||||
|
@ -59,9 +59,12 @@ struct _GstMPEGParse {
|
||||||
GstMPEGPacketize *packetize;
|
GstMPEGPacketize *packetize;
|
||||||
|
|
||||||
/* pack header values */
|
/* pack header values */
|
||||||
guint32 bit_rate;
|
guint32 mux_rate;
|
||||||
guint64 current_scr;
|
guint64 current_scr;
|
||||||
guint64 previous_scr;
|
guint64 next_scr;
|
||||||
|
guint64 bytes_since_scr;
|
||||||
|
|
||||||
|
gint64 adjust;
|
||||||
|
|
||||||
gboolean discont_pending;
|
gboolean discont_pending;
|
||||||
gboolean scr_pending;
|
gboolean scr_pending;
|
||||||
|
|
Loading…
Reference in a new issue