[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