+/*
+ * DTS type IV (DTS-HD) can be transmitted with various frame repetition
+ * periods; longer repetition periods allow for longer packets and therefore
+ * higher bitrate. Longer repetition periods mean that the constant bitrate of
+ * the outputted IEC 61937 stream is higher.
+ * The repetition period is measured in IEC 60958 frames (4 bytes).
+ */
+static int spdif_dts4_subtype(int period)
+{
+ switch (period) {
+ case 512: return 0x0;
+ case 1024: return 0x1;
+ case 2048: return 0x2;
+ case 4096: return 0x3;
+ case 8192: return 0x4;
+ case 16384: return 0x5;
+ }
+ return -1;
+}
+
+static int spdif_header_dts4(AVFormatContext *s, AVPacket *pkt, int core_size,
+ int sample_rate, int blocks)
+{
+ IEC61937Context *ctx = s->priv_data;
+ static const char dtshd_start_code[10] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe };
+ int pkt_size = pkt->size;
+ int period;
+ int subtype;
+
+ if (!core_size) {
+ av_log(s, AV_LOG_ERROR, "HD mode not supported for this format\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (!sample_rate) {
+ av_log(s, AV_LOG_ERROR, "Unknown DTS sample rate for HD\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ period = ctx->dtshd_rate * (blocks << 5) / sample_rate;
+ subtype = spdif_dts4_subtype(period);
+
+ if (subtype < 0) {
+ av_log(s, AV_LOG_ERROR, "Specified HD rate of %d Hz would require an "
+ "impossible repetition period of %d for the current DTS stream"
+ " (blocks = %d, sample rate = %d)\n", ctx->dtshd_rate, period,
+ blocks << 5, sample_rate);
+ return AVERROR(EINVAL);
+ }
+
+ /* set pkt_offset and DTS IV subtype according to the requested output
+ * rate */
+ ctx->pkt_offset = period * 4;
+ ctx->data_type = IEC61937_DTSHD | subtype << 8;
+
+ /* If the bitrate is too high for transmitting at the selected
+ * repetition period setting, strip DTS-HD until a good amount
+ * of consecutive non-overflowing HD frames have been observed.
+ * This generally only happens if the caller is cramming a Master
+ * Audio stream into 192kHz IEC 60958 (which may or may not fit). */
+ if (sizeof(dtshd_start_code) + 2 + pkt_size
+ > ctx->pkt_offset - BURST_HEADER_SIZE && core_size) {
+ if (!ctx->dtshd_skip)
+ av_log(s, AV_LOG_WARNING, "DTS-HD bitrate too high, "
+ "temporarily sending core only\n");
+ if (ctx->dtshd_fallback > 0)
+ ctx->dtshd_skip = sample_rate * ctx->dtshd_fallback / (blocks << 5);
+ else
+ /* skip permanently (dtshd_fallback == -1) or just once
+ * (dtshd_fallback == 0) */
+ ctx->dtshd_skip = 1;
+ }
+ if (ctx->dtshd_skip && core_size) {
+ pkt_size = core_size;
+ if (ctx->dtshd_fallback >= 0)
+ --ctx->dtshd_skip;
+ }
+
+ ctx->out_bytes = sizeof(dtshd_start_code) + 2 + pkt_size;
+ ctx->length_code = ctx->out_bytes;
+
+ av_fast_malloc(&ctx->hd_buf, &ctx->hd_buf_size, ctx->out_bytes);
+ if (!ctx->hd_buf)
+ return AVERROR(ENOMEM);
+
+ ctx->out_buf = ctx->hd_buf;
+
+ 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);
+
+ return 0;
+}
+