summaryrefslogtreecommitdiffstats
path: root/gst/mpeg1videoparse/gstmp1videoparse.c
diff options
context:
space:
mode:
Diffstat (limited to 'gst/mpeg1videoparse/gstmp1videoparse.c')
-rw-r--r--gst/mpeg1videoparse/gstmp1videoparse.c79
1 files changed, 67 insertions, 12 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;
+ }
}
}