From e43839eae9da88fdc90d70367d0e16b335ce5f1d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 22 Feb 2010 18:20:46 +0100 Subject: [PATCH] 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 --- gst/rtp/gstrtpdvdepay.c | 52 ++++++++++++++++++++++++++--------------- gst/rtp/gstrtpdvdepay.h | 3 +-- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/gst/rtp/gstrtpdvdepay.c b/gst/rtp/gstrtpdvdepay.c index d1c2744840..50b1a418fe 100644 --- a/gst/rtp/gstrtpdvdepay.c +++ b/gst/rtp/gstrtpdvdepay.c @@ -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 diff --git a/gst/rtp/gstrtpdvdepay.h b/gst/rtp/gstrtpdvdepay.h index c972ec9705..08544f581e 100644 --- a/gst/rtp/gstrtpdvdepay.h +++ b/gst/rtp/gstrtpdvdepay.h @@ -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;