dvdepay: don't output frames until we have a header

Wait for the complete first 6 header DIF packets before outputting a frame.
Decoders need this info to correctly decode the data.

Fixes #610556
This commit is contained in:
Wim Taymans 2010-02-22 18:20:46 +01:00
parent ad05705afb
commit e43839eae9
2 changed files with 34 additions and 21 deletions

View file

@ -264,22 +264,22 @@ calculate_difblock_location (guint8 * block)
dif_sequence = block[1] >> 4;
dif_block = block[2];
location = dif_sequence * 150;
switch (block_type) {
case 0: /* Header block */
location = dif_sequence * 150 * 80;
case 0: /* Header block, no offset */
break;
case 1: /* Subcode block */
location = dif_sequence * 150 * 80 + (1 + dif_block) * 80;
location += (1 + dif_block);
break;
case 2: /* VAUX block */
location = dif_sequence * 150 * 80 + (3 + dif_block) * 80;
location += (3 + dif_block);
break;
case 3: /* Audio block */
location = dif_sequence * 150 * 80 + (6 + dif_block * 16) * 80;
location += (6 + dif_block * 16);
break;
case 4: /* Video block */
location = dif_sequence * 150 * 80 +
(7 + (dif_block / 15) + dif_block) * 80;
location += (7 + (dif_block / 15) + dif_block);
break;
default: /* Something bogus */
GST_DEBUG ("UNKNOWN BLOCK");
@ -327,28 +327,43 @@ gst_rtp_dv_depay_process (GstBaseRTPDepayload * base, GstBuffer * in)
/* copy all DIF chunks in their place. */
while (payload_len >= 80) {
guint offset;
/* Calculate where in the frame the payload should go */
location = calculate_difblock_location (payload);
/* Check if we received a header. We will not pass on frames until
* we've received a header, otherwise the DV decoder goes wacko. */
if (location == 0)
dvdepay->have_header = TRUE;
if (location < 6) {
/* part of a header, set the flag to mark that we have the header. */
dvdepay->header_mask |= (1 << location);
GST_LOG_OBJECT (dvdepay, "got header at location %d, now %02x", location,
dvdepay->header_mask);
} else {
GST_LOG_OBJECT (dvdepay, "got block at location %d", location);
}
/* get the byte offset of the dif block */
offset = location * 80;
/* And copy it in, provided the location is sane. */
if (location >= 0 && location <= dvdepay->frame_size - 80)
memcpy (GST_BUFFER_DATA (dvdepay->acc) + location, payload, 80);
if (offset >= 0 && offset <= dvdepay->frame_size - 80)
memcpy (GST_BUFFER_DATA (dvdepay->acc) + offset, payload, 80);
payload += 80;
payload_len -= 80;
}
if (marker) {
/* The marker marks the end of a frame that we need to push. The next frame
* will change the timestamp but we won't copy the accumulator again because
* we set the prev_ts to -1. */
out = gst_buffer_copy (dvdepay->acc);
GST_DEBUG_OBJECT (dvdepay, "marker bit complete frame %u", rtp_ts);
/* only copy the frame when we have a complete header */
if (dvdepay->header_mask == 0x3f) {
/* The marker marks the end of a frame that we need to push. The next frame
* will change the timestamp but we won't copy the accumulator again because
* we set the prev_ts to -1. */
out = gst_buffer_copy (dvdepay->acc);
} else {
GST_WARNING_OBJECT (dvdepay, "waiting for frame headers %02x",
dvdepay->header_mask);
}
dvdepay->prev_ts = -1;
} else {
/* save last timestamp */
@ -365,8 +380,7 @@ gst_rtp_dv_depay_reset (GstRTPDVDepay * depay)
depay->acc = NULL;
depay->prev_ts = -1;
depay->have_header = FALSE;
depay->frame_nr = 0;
depay->header_mask = 0;
}
static GstStateChangeReturn

View file

@ -45,9 +45,8 @@ struct _GstRTPDVDepay
GstBuffer *acc;
guint frame_size;
guint frame_nr;
guint32 prev_ts;
gboolean have_header;
guint8 header_mask;
gint width, height;
gint rate_num, rate_denom;