diff dv.c @ 3790:a8a70ae19206 libavformat

Intial implementation of the DV100 (AKA DVCPRO HD) decoder and demuxer as specified in SMPTE 370M
author romansh
date Thu, 28 Aug 2008 22:41:00 +0000
parents 6f3cdf5fb948
children bf1b4748cd2e
line wrap: on
line diff
--- a/dv.c	Thu Aug 28 12:00:58 2008 +0000
+++ b/dv.c	Thu Aug 28 22:41:00 2008 +0000
@@ -8,8 +8,9 @@
  * Raw DV format
  * Copyright (c) 2002 Fabrice Bellard.
  *
- * 50 Mbps (DVCPRO50) support
+ * 50 Mbps (DVCPRO50) and 100 Mbps (DVCPRO HD) support
  * Copyright (c) 2006 Daniel Maas <dmaas@maasdigital.com>
+ * Funded by BBC Research & Development
  *
  * This file is part of FFmpeg.
  *
@@ -36,9 +37,9 @@
     const DVprofile*  sys;    /* Current DV profile. E.g.: 525/60, 625/50 */
     AVFormatContext* fctx;
     AVStream*        vst;
-    AVStream*        ast[2];
-    AVPacket         audio_pkt[2];
-    uint8_t          audio_buf[2][8192];
+    AVStream*        ast[4];
+    AVPacket         audio_pkt[4];
+    uint8_t          audio_buf[4][8192];
     int              ach;
     int              frames;
     uint64_t         abytes;
@@ -98,12 +99,13 @@
  * 3. Audio is always returned as 16bit linear samples: 12bit nonlinear samples
  *    are converted into 16bit linear ones.
  */
-static int dv_extract_audio(uint8_t* frame, uint8_t* pcm, uint8_t* pcm2,
+static int dv_extract_audio(uint8_t* frame, uint8_t* ppcm[4],
                             const DVprofile *sys)
 {
     int size, chan, i, j, d, of, smpls, freq, quant, half_ch;
     uint16_t lc, rc;
     const uint8_t* as_pack;
+    uint8_t *pcm, ipcm;
 
     as_pack = dv_extract_pack(frame, dv_audio_source);
     if (!as_pack)    /* No audio ? */
@@ -119,6 +121,10 @@
     size = (sys->audio_min_samples[freq] + smpls) * 4; /* 2ch, 2bytes */
     half_ch = sys->difseg_size/2;
 
+    /* We work with 720p frames split in half, thus even frames have channels 0,1 and odd 2,3 */
+    ipcm = (sys->height == 720 && ((frame[1]>>2)&0x3) == 0)?2:0;
+    pcm = ppcm[ipcm++];
+
     /* for each DIF channel */
     for (chan = 0; chan < sys->n_difchan; chan++) {
         /* for each DIF segment */
@@ -126,10 +132,9 @@
             frame += 6 * 80; /* skip DIF segment header */
             if (quant == 1 && i == half_ch) {
                 /* next stereo channel (12bit mode only) */
-                if (!pcm2)
+                pcm = ppcm[ipcm++];
+                if (!pcm)
                     break;
-                else
-                    pcm = pcm2;
             }
 
             /* for each AV sequence */
@@ -170,10 +175,10 @@
             }
         }
 
-        /* next stereo channel (50Mbps only) */
-        if(!pcm2)
+        /* next stereo channel (50Mbps and 100Mbps only) */
+        pcm = ppcm[ipcm++];
+        if (!pcm)
             break;
-        pcm = pcm2;
     }
 
     return size;
@@ -196,6 +201,9 @@
     quant = as_pack[4] & 0x07; /* 0 - 16bit linear, 1 - 12bit nonlinear */
 
     /* note: ach counts PAIRS of channels (i.e. stereo channels) */
+    if (stype == 3) {
+        ach = 4;
+    } else
     ach = (stype == 2 || (quant && (freq == 2))) ? 2 : 1;
 
     /* Dynamic handling of the audio streams in DV */
@@ -310,6 +318,7 @@
                       uint8_t* buf, int buf_size)
 {
     int size, i;
+    uint8_t *ppcm[4] = {0};
 
     if (buf_size < DV_PROFILE_BYTES ||
         !(c->sys = dv_frame_profile(buf)) ||
@@ -323,10 +332,19 @@
     for (i=0; i<c->ach; i++) {
        c->audio_pkt[i].size = size;
        c->audio_pkt[i].pts  = c->abytes * 30000*8 / c->ast[i]->codec->bit_rate;
+       ppcm[i] = c->audio_buf[i];
     }
-    dv_extract_audio(buf, c->audio_buf[0], c->audio_buf[1], c->sys);
+    dv_extract_audio(buf, ppcm, c->sys);
     c->abytes += size;
 
+    /* We work with 720p frames split in half, thus even frames have channels 0,1 and odd 2,3 */
+    if (c->sys->height == 720) {
+        if (((buf[1]>>2)&0x3))
+            c->audio_pkt[2].size = c->audio_pkt[3].size = 0;
+        else
+            c->audio_pkt[0].size = c->audio_pkt[1].size = 0;
+    }
+
     /* Now it's time to return video packet */
     size = dv_extract_video_info(c, buf);
     av_init_packet(pkt);
@@ -366,6 +384,7 @@
                           c->ast[0]->codec->bit_rate * (int64_t)c->sys->frame_rate_base,
                           8*c->sys->frame_rate);
     c->audio_pkt[0].size = c->audio_pkt[1].size = 0;
+    c->audio_pkt[2].size = c->audio_pkt[3].size = 0;
 }
 
 /************************************************************
@@ -391,6 +410,11 @@
         return AVERROR(EIO);
 
     c->dv_demux->sys = dv_frame_profile(c->buf);
+    if (!c->dv_demux->sys) {
+        av_log(s, AV_LOG_ERROR, "Can't determine profile of DV input stream.\n");
+        return -1;
+    }
+
     s->bit_rate = av_rescale(c->dv_demux->sys->frame_size * 8,
                              c->dv_demux->sys->frame_rate,
                              c->dv_demux->sys->frame_rate_base);