From 909865fdbe7225d6e9b4eb5da15028104a4a06da Mon Sep 17 00:00:00 2001 From: Carl Eugen Hoyos Date: Wed, 17 Nov 2010 12:22:59 +0000 Subject: Add support for IEC 61937 ("SPDIF") encapsulation for E-AC-3. Only works via HDMI. Patch by Anssi Hannula (anssi d hannula a iki d fi), based on some work by myself. Originally committed as revision 25760 to svn://svn.ffmpeg.org/ffmpeg/trunk --- libavformat/spdifenc.c | 71 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 59 insertions(+), 12 deletions(-) (limited to 'libavformat/spdifenc.c') diff --git a/libavformat/spdifenc.c b/libavformat/spdifenc.c index 78817a3930..ed02b2e8f2 100644 --- a/libavformat/spdifenc.c +++ b/libavformat/spdifenc.c @@ -48,13 +48,21 @@ typedef struct IEC958Context { enum IEC958DataType data_type; ///< burst info - reference to type of payload of the data-burst - int pkt_size; ///< length code in bits + int length_code; ///< length code in bits or bytes, depending on data type int pkt_offset; ///< data burst repetition period in bytes uint8_t *buffer; ///< allocated buffer, used for swap bytes int buffer_size; ///< size of allocated buffer + uint8_t *out_buf; ///< pointer to the outgoing data before byte-swapping + int out_bytes; ///< amount of outgoing bytes + + uint8_t *hd_buf; ///< allocated buffer to concatenate hd audio frames + int hd_buf_size; ///< size of the hd audio buffer + int hd_buf_count; ///< number of frames in the hd audio buffer + int hd_buf_filled; ///< amount of bytes in the hd audio buffer + /// function, which generates codec dependent header information. - /// Sets data_type and data_offset + /// Sets data_type and pkt_offset, and length_code, out_bytes, out_buf if necessary int (*header_info) (AVFormatContext *s, AVPacket *pkt); } IEC958Context; @@ -69,6 +77,37 @@ static int spdif_header_ac3(AVFormatContext *s, AVPacket *pkt) return 0; } +static int spdif_header_eac3(AVFormatContext *s, AVPacket *pkt) +{ + IEC958Context *ctx = s->priv_data; + static const uint8_t eac3_repeat[4] = {6, 3, 2, 1}; + int repeat = 1; + + if ((pkt->data[4] & 0xc0) != 0xc0) /* fscod */ + repeat = eac3_repeat[(pkt->data[4] & 0x30) >> 4]; /* numblkscod */ + + ctx->hd_buf = av_fast_realloc(ctx->hd_buf, &ctx->hd_buf_size, ctx->hd_buf_filled + pkt->size); + if (!ctx->hd_buf) + return AVERROR(ENOMEM); + + memcpy(&ctx->hd_buf[ctx->hd_buf_filled], pkt->data, pkt->size); + + ctx->hd_buf_filled += pkt->size; + if (++ctx->hd_buf_count < repeat){ + ctx->pkt_offset = 0; + return 0; + } + ctx->data_type = IEC958_EAC3; + ctx->pkt_offset = 24576; + ctx->out_buf = ctx->hd_buf; + ctx->out_bytes = ctx->hd_buf_filled; + ctx->length_code = ctx->hd_buf_filled; + + ctx->hd_buf_count = 0; + ctx->hd_buf_filled = 0; + return 0; +} + static int spdif_header_dts(AVFormatContext *s, AVPacket *pkt) { IEC958Context *ctx = s->priv_data; @@ -180,6 +219,9 @@ static int spdif_write_header(AVFormatContext *s) case CODEC_ID_AC3: ctx->header_info = spdif_header_ac3; break; + case CODEC_ID_EAC3: + ctx->header_info = spdif_header_eac3; + break; case CODEC_ID_MP1: case CODEC_ID_MP2: case CODEC_ID_MP3: @@ -202,6 +244,7 @@ static int spdif_write_trailer(AVFormatContext *s) { IEC958Context *ctx = s->priv_data; av_freep(&ctx->buffer); + av_freep(&ctx->hd_buf); return 0; } @@ -210,12 +253,16 @@ static int spdif_write_packet(struct AVFormatContext *s, AVPacket *pkt) IEC958Context *ctx = s->priv_data; int ret, padding; - ctx->pkt_size = FFALIGN(pkt->size, 2) << 3; + ctx->out_bytes = pkt->size; + ctx->length_code = FFALIGN(pkt->size, 2) << 3; + ret = ctx->header_info(s, pkt); if (ret < 0) return -1; + if (!ctx->pkt_offset) + return 0; - padding = (ctx->pkt_offset - BURST_HEADER_SIZE - pkt->size) >> 1; + padding = (ctx->pkt_offset - BURST_HEADER_SIZE - ctx->out_bytes) >> 1; if (padding < 0) { av_log(s, AV_LOG_ERROR, "bitrate is too high\n"); return -1; @@ -224,26 +271,26 @@ static int spdif_write_packet(struct AVFormatContext *s, AVPacket *pkt) put_le16(s->pb, SYNCWORD1); //Pa put_le16(s->pb, SYNCWORD2); //Pb put_le16(s->pb, ctx->data_type); //Pc - put_le16(s->pb, ctx->pkt_size); //Pd + put_le16(s->pb, ctx->length_code);//Pd #if HAVE_BIGENDIAN - put_buffer(s->pb, pkt->data, pkt->size & ~1); + put_buffer(s->pb, ctx->out_buf, ctx->out_bytes & ~1); #else - av_fast_malloc(&ctx->buffer, &ctx->buffer_size, pkt->size + FF_INPUT_BUFFER_PADDING_SIZE); + av_fast_malloc(&ctx->buffer, &ctx->buffer_size, ctx->out_bytes + FF_INPUT_BUFFER_PADDING_SIZE); if (!ctx->buffer) return AVERROR(ENOMEM); - ff_spdif_bswap_buf16((uint16_t *)ctx->buffer, (uint16_t *)pkt->data, pkt->size >> 1); - put_buffer(s->pb, ctx->buffer, pkt->size & ~1); + ff_spdif_bswap_buf16((uint16_t *)ctx->buffer, (uint16_t *)ctx->out_buf, ctx->out_bytes >> 1); + put_buffer(s->pb, ctx->buffer, ctx->out_bytes & ~1); #endif - if (pkt->size & 1) - put_be16(s->pb, pkt->data[pkt->size - 1]); + if (ctx->out_bytes & 1) + put_be16(s->pb, ctx->out_buf[ctx->out_bytes - 1]); for (; padding > 0; padding--) put_be16(s->pb, 0); av_log(s, AV_LOG_DEBUG, "type=%x len=%i pkt_offset=%i\n", - ctx->data_type, pkt->size, ctx->pkt_offset); + ctx->data_type, ctx->out_bytes, ctx->pkt_offset); put_flush_packet(s->pb); return 0; -- cgit v1.2.3