[FFmpeg-devel] [PATCH 3/3] spdifenc: add support for DTS-HD

Anssi Hannula anssi.hannula
Tue Nov 16 02:44:47 CET 2010


---
 Changelog              |    2 +-
 libavformat/spdifenc.c |   93 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 94 insertions(+), 1 deletions(-)

diff --git a/Changelog b/Changelog
index d644984..5d19904 100644
--- a/Changelog
+++ b/Changelog
@@ -55,7 +55,7 @@ version <next>:
 - Win64 support for optimized asm functions
 - MJPEG/AVI1 to JPEG/JFIF bitstream filter
 - ASS subtitle encoder and decoder
-- IEC 61937 encapsulation for E-AC3, TrueHD (for HDMI passthrough)
+- IEC 61937 encapsulation for E-AC3, TrueHD, DTS-HD (for HDMI passthrough)
 
 
 version 0.6:
diff --git a/libavformat/spdifenc.c b/libavformat/spdifenc.c
index 41bc2a8..b21cbbf 100644
--- a/libavformat/spdifenc.c
+++ b/libavformat/spdifenc.c
@@ -1,6 +1,7 @@
 /*
  * IEC958 muxer
  * Copyright (c) 2009 Bartlomiej Wolowiec
+ * Copyright (c) 2010 Anssi Hannula <anssi.hannula at iki.fi>
  *
  * This file is part of FFmpeg.
  *
@@ -23,6 +24,7 @@
  * @file
  * IEC-61937 encapsulation of various formats, used by S/PDIF
  * @author Bartlomiej Wolowiec
+ * @author Anssi Hannula
  */
 
 /*
@@ -61,6 +63,8 @@ typedef struct IEC958Context {
     int hd_buf_count;               ///< number of frames in the hd audio buffer
     int hd_buf_filled;              ///< amount of bytes in the hd audio buffer
 
+    int hd_retry;                   ///< counter used for skipping DTS-HD frames
+
     /// function, which generates codec dependent header information.
     /// Sets data_type and pkt_offset, and length_code, out_bytes, out_buf if necessary
     int (*header_info) (AVFormatContext *s, AVPacket *pkt);
@@ -108,15 +112,35 @@ static int spdif_header_eac3(AVFormatContext *s, AVPacket *pkt)
     return 0;
 }
 
+/*
+ * DTS type IV (DTS-HD) can be transmitted with various frame repetition
+ * periods; longer repetition periods allow for longer packets and therefore
+ * higher bitrate. We don't have information about the maximum bitrate of the
+ * incoming DTS-HD stream, so we use a repetition period which uses a stream
+ * bitrate of 24.5 Mbps (which is the maximum allowed bitrate on bluray and
+ * HDMI, 768 kHz IEC 60958 link) whenever possible.
+ * The repetition period is measured in IEC 60958 frames (4 bytes).
+ */
+enum {
+    DTS4_REP_PER_512   = 0x0,
+    DTS4_REP_PER_1024  = 0x1,
+    DTS4_REP_PER_2048  = 0x2,
+    DTS4_REP_PER_4096  = 0x3,
+    DTS4_REP_PER_8192  = 0x4,
+    DTS4_REP_PER_16384 = 0x5,
+};
+
 static int spdif_header_dts(AVFormatContext *s, AVPacket *pkt)
 {
     IEC958Context *ctx = s->priv_data;
     uint32_t syncword_dts = AV_RB32(pkt->data);
     int blocks;
+    int core_size = 0;
 
     switch (syncword_dts) {
     case DCA_MARKER_RAW_BE:
         blocks = (AV_RB16(pkt->data + 4) >> 2) & 0x7f;
+        core_size = ((AV_RB24(pkt->data + 5) >> 4) & 0x3fff) + 1;
         break;
     case DCA_MARKER_RAW_LE:
         blocks = (AV_RL16(pkt->data + 4) >> 2) & 0x7f;
@@ -129,10 +153,16 @@ static int spdif_header_dts(AVFormatContext *s, AVPacket *pkt)
         blocks =
             (((pkt->data[4] & 0x07) << 4) | ((pkt->data[7] & 0x3f) >> 2));
         break;
+    case DCA_HD_MARKER:
+        /* DCA-HD frames are only valid when paired with DCA core */
+        av_log(s, AV_LOG_DEBUG, "ignoring stray DCA HD frame\n");
+        ctx->pkt_offset = 0;
+        return 0;
     default:
         av_log(s, AV_LOG_ERROR, "bad DTS syncword 0x%x\n", syncword_dts);
         return -1;
     }
+
     blocks++;
     switch (blocks) {
     case  512 >> 5: ctx->data_type = IEC958_DTS1; break;
@@ -141,8 +171,71 @@ static int spdif_header_dts(AVFormatContext *s, AVPacket *pkt)
     default:
         av_log(s, AV_LOG_ERROR, "%i samples in DTS frame not supported\n",
                blocks << 5);
+        /* if such streams really exist, it might be possible to handle them
+         * as low bitrate DTS type IV (i.e. like DTS-HD) */
+        av_log_ask_for_sample(s, NULL);
         return -1;
     }
+
+    /* check for a DTS-HD stream */
+    if (core_size && core_size + 3 < pkt->size
+        && AV_RB32(pkt->data + core_size) == DCA_HD_MARKER) {
+        const char dtshd_start_code[10] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe };
+        int pkt_size = pkt->size;
+        int bitrate_too_high;
+
+        ctx->data_type = IEC958_DTSHD;
+        ctx->pkt_offset = blocks << 11;
+
+        switch (blocks) {
+            case  512 >> 5: ctx->data_type |= DTS4_REP_PER_8192 << 8; break; /* 768 kHz */
+            case 1024 >> 5: ctx->data_type |= DTS4_REP_PER_16384 << 8; break; /* 768 kHz */
+            case 2048 >> 5: ctx->data_type |= DTS4_REP_PER_16384 << 8; break; /* 384 kHz */
+        }
+
+        /* 192 kHz mode for (blocks == (512 >> 5)) - max bitrate 6.1 Mbps.
+         * Most DTS-HD streams fit into 6.1 Mbps, and this can be transmitted
+         * in HDMI without High Bit Rate support. */
+        if (0) {
+            ctx->pkt_offset = 2048*4;
+            ctx->data_type = IEC958_DTSHD | (DTS4_REP_PER_2048 << 8);
+        }
+
+        /* If the bitrate is too high for transmitting at the selected
+         * repetition period setting, strip DTS-HD header until a good amount
+         * of consecutive non-overflowing HD frames have been observed */
+
+        bitrate_too_high = sizeof(dtshd_start_code) + 2 + pkt_size
+                           > ctx->pkt_offset - BURST_HEADER_SIZE;
+
+        if (ctx->hd_retry) {
+            pkt_size = core_size;
+            if (!bitrate_too_high)
+                --ctx->hd_retry;
+        }
+
+        if (bitrate_too_high) {
+            if (!ctx->hd_retry)
+                av_log(s, AV_LOG_WARNING, "DTS bitrate too high, temporarily sending core only\n");
+            pkt_size = core_size;
+            ctx->hd_retry = 500;
+        }
+
+        ctx->hd_buf = av_fast_realloc(ctx->hd_buf, &ctx->hd_buf_size, sizeof(dtshd_start_code) + 2 + pkt_size);
+        if (!ctx->hd_buf)
+            return AVERROR(ENOMEM);
+
+        memcpy(ctx->hd_buf, dtshd_start_code, sizeof(dtshd_start_code));
+        AV_WB16(ctx->hd_buf + sizeof(dtshd_start_code), pkt_size);
+        memcpy(ctx->hd_buf + sizeof(dtshd_start_code) + 2, pkt->data, pkt_size);
+
+        ctx->out_buf     = ctx->hd_buf;
+        ctx->out_bytes   = sizeof(dtshd_start_code) + 2 + pkt_size;
+        ctx->length_code = ctx->out_bytes;
+
+        return 0;
+    }
+
     ctx->pkt_offset = blocks << 7;
 
     return 0;
-- 
1.7.3




More information about the ffmpeg-devel mailing list