diff options
Diffstat (limited to 'gst')
-rw-r--r-- | gst/mpeg1videoparse/gstmp1videoparse.c | 79 | ||||
-rw-r--r-- | gst/mpegaudioparse/gstmpegaudioparse.c | 34 |
2 files changed, 87 insertions, 26 deletions
diff --git a/gst/mpeg1videoparse/gstmp1videoparse.c b/gst/mpeg1videoparse/gstmp1videoparse.c index 645392ba..a90ed36e 100644 --- a/gst/mpeg1videoparse/gstmp1videoparse.c +++ b/gst/mpeg1videoparse/gstmp1videoparse.c @@ -155,7 +155,7 @@ gst_mp1videoparse_init (Mp1VideoParse *mp1videoparse) mp1videoparse->partialbuf = NULL; mp1videoparse->need_resync = FALSE; - mp1videoparse->last_pts = 0; + mp1videoparse->last_pts = GST_CLOCK_TIME_NONE; mp1videoparse->picture_in_buffer = 0; mp1videoparse->width = mp1videoparse->height = -1; mp1videoparse->fps = mp1videoparse->asr = 0.; @@ -259,8 +259,9 @@ mp1videoparse_find_next_gop (Mp1VideoParse *mp1videoparse, GstBuffer *buf) have_sync = TRUE; } else if (have_sync) { - if (byte == (SEQ_START_CODE & 0xff) || byte == (GOP_START_CODE & 0xff)) return offset-4; - else { + if (byte == (SEQ_START_CODE & 0xff) || byte == (GOP_START_CODE & 0xff)) { + return offset - 4; + } else { sync_zeros = 0; have_sync = FALSE; } @@ -272,6 +273,19 @@ mp1videoparse_find_next_gop (Mp1VideoParse *mp1videoparse, GstBuffer *buf) return -1; } + +static guint64 +gst_mp1videoparse_time_code (guchar *gop, + gfloat fps) +{ + guint32 data = GUINT32_FROM_BE (* (guint32 *) gop); + + return ((((data & 0xfc000000) >> 26) * 3600 * GST_SECOND) + /* hours */ + (((data & 0x03f00000) >> 20) * 60 * GST_SECOND) + /* minutes */ + (((data & 0x0007e000) >> 13) * GST_SECOND) + /* seconds */ + (((data & 0x00001f80) >> 7) * GST_SECOND / fps)); /* frames */ +} + static void gst_mp1videoparse_flush (Mp1VideoParse *mp1videoparse) { @@ -370,7 +384,7 @@ gst_mp1videoparse_real_chain (Mp1VideoParse *mp1videoparse, GstBuffer *buf, GstP mp1videoparse->partialbuf) || mp1videoparse->need_resync) { sync_pos = mp1videoparse_find_next_gop(mp1videoparse, mp1videoparse->partialbuf); - if (sync_pos != -1) { + if (sync_pos >= 0) { mp1videoparse->need_resync = FALSE; GST_DEBUG ("mp1videoparse: found new gop at %d", sync_pos); @@ -383,6 +397,14 @@ gst_mp1videoparse_real_chain (Mp1VideoParse *mp1videoparse, GstBuffer *buf, GstP size = GST_BUFFER_SIZE(mp1videoparse->partialbuf); offset = 0; } + + head = GUINT32_FROM_BE(*((guint32 *)data)); + /* re-call this function so that if we hadn't already, we can + * now read the sequence header and parse video properties, + * set caps, stream data, be happy, bla, bla, bla... */ + if (!mp1videoparse_valid_sync (mp1videoparse, head, + mp1videoparse->partialbuf)) + g_error ("Found sync but no valid sync point at pos 0x0"); } else { GST_DEBUG ("mp1videoparse: could not sync"); @@ -392,7 +414,8 @@ gst_mp1videoparse_real_chain (Mp1VideoParse *mp1videoparse, GstBuffer *buf, GstP } } - if (mp1videoparse->picture_in_buffer == 1) { + if (mp1videoparse->picture_in_buffer == 1 && + time_stamp != GST_CLOCK_TIME_NONE) { mp1videoparse->last_pts = time_stamp; } @@ -403,7 +426,6 @@ gst_mp1videoparse_real_chain (Mp1VideoParse *mp1videoparse, GstBuffer *buf, GstP while (offset < size-1) { sync_byte = *(data + offset); - /*printf(" %d %02x\n", offset, sync_byte); */ if (sync_byte == 0) { sync_state++; } @@ -412,7 +434,9 @@ gst_mp1videoparse_real_chain (Mp1VideoParse *mp1videoparse, GstBuffer *buf, GstP if (data[offset+1] == (PICTURE_START_CODE & 0xff)) { mp1videoparse->picture_in_buffer++; if (mp1videoparse->picture_in_buffer == 1) { - mp1videoparse->last_pts = time_stamp; + if (time_stamp != GST_CLOCK_TIME_NONE) { + mp1videoparse->last_pts = time_stamp; + } sync_state = 0; } else if (mp1videoparse->picture_in_buffer == 2) { @@ -424,6 +448,33 @@ gst_mp1videoparse_real_chain (Mp1VideoParse *mp1videoparse, GstBuffer *buf, GstP g_assert_not_reached(); } } + /* A new sequence (or GOP) is a valid sync too. Note that the + * sequence header should be put in the next buffer, not here. */ + else if (data[offset+1] == (SEQ_START_CODE & 0xFF) || + data[offset+1] == (GOP_START_CODE & 0xFF)) { + if (mp1videoparse->picture_in_buffer == 0 && + data[offset+1] == (GOP_START_CODE & 0xFF)) { + mp1videoparse->last_pts = gst_mp1videoparse_time_code (&data[2], + mp1videoparse->fps); + } + else if (mp1videoparse->picture_in_buffer == 1) { + have_sync = TRUE; + break; + } else { + g_assert (mp1videoparse->picture_in_buffer == 0); + } + } + /* end-of-sequence is a valid sync point and should be included + * in the current picture, not the next. */ + else if (data[offset+1] == (SEQ_END_CODE & 0xFF)) { + if (mp1videoparse->picture_in_buffer == 1) { + offset += 4; + have_sync = TRUE; + break; + } else { + g_assert (mp1videoparse->picture_in_buffer == 0); + } + } else sync_state = 0; } /* something else... */ @@ -434,12 +485,11 @@ gst_mp1videoparse_real_chain (Mp1VideoParse *mp1videoparse, GstBuffer *buf, GstP if (have_sync) { offset -= 2; - GST_DEBUG ("mp1videoparse: synced at %ld code 0x000001%02x",offset,data[offset+3]); - - outbuf = gst_buffer_create_sub(mp1videoparse->partialbuf, 0, offset+4); + outbuf = gst_buffer_create_sub(mp1videoparse->partialbuf, 0, offset); g_assert(outbuf != NULL); GST_BUFFER_TIMESTAMP(outbuf) = mp1videoparse->last_pts; GST_BUFFER_DURATION(outbuf) = GST_SECOND / mp1videoparse->fps; + mp1videoparse->last_pts += GST_BUFFER_DURATION (outbuf); if (mp1videoparse->in_flush) { /* FIXME, send a flush event here */ @@ -456,12 +506,17 @@ gst_mp1videoparse_real_chain (Mp1VideoParse *mp1videoparse, GstBuffer *buf, GstP } mp1videoparse->picture_in_buffer = 0; - temp = gst_buffer_create_sub(mp1videoparse->partialbuf, offset, size-offset); + if (size > offset) + temp = gst_buffer_create_sub(mp1videoparse->partialbuf, offset, size-offset); + else + temp = NULL; gst_buffer_unref(mp1videoparse->partialbuf); mp1videoparse->partialbuf = temp; } else { - mp1videoparse->last_pts = time_stamp; + if (time_stamp != GST_CLOCK_TIME_NONE) { + mp1videoparse->last_pts = time_stamp; + } } } diff --git a/gst/mpegaudioparse/gstmpegaudioparse.c b/gst/mpegaudioparse/gstmpegaudioparse.c index 9363dfe6..4914084c 100644 --- a/gst/mpegaudioparse/gstmpegaudioparse.c +++ b/gst/mpegaudioparse/gstmpegaudioparse.c @@ -402,6 +402,26 @@ gst_mp3parse_chain (GstPad *pad, GstData *_data) GST_DEBUG ("mp3parse: partial buffer needed %ld < %d ",(size-offset), bpf); break; } else { + guint bitrate, layer, rate, channels; + + if (!mp3_type_frame_length_from_header (header, &layer, + &channels, + &bitrate, &rate)) { + g_error("Header failed internal error"); + } + if (channels != mp3parse->channels || + rate != mp3parse->rate || + layer != mp3parse->layer || + bitrate != mp3parse->bit_rate) { + GstCaps *caps = mp3_caps_create (layer, channels, bitrate, rate); + + gst_pad_set_explicit_caps(mp3parse->srcpad, caps); + + mp3parse->channels = channels; + mp3parse->layer = layer; + mp3parse->rate = rate; + mp3parse->bit_rate = bitrate; + } outbuf = gst_buffer_create_sub(mp3parse->partialbuf,offset,bpf); @@ -460,20 +480,6 @@ bpf_from_header (GstMPEGAudioParse *parse, unsigned long header) return 0; } - if (channels != parse->channels || - rate != parse->rate || - layer != parse->layer || - bitrate != parse->bit_rate) { - GstCaps *caps = mp3_caps_create (layer, channels, bitrate, rate); - - gst_pad_set_explicit_caps(parse->srcpad, caps); - - parse->channels = channels; - parse->layer = layer; - parse->rate = rate; - parse->bit_rate = bitrate; - } - return length; } |