From: Gyan Doshi <ffmpeg@gyani.pro> To: ffmpeg-devel@ffmpeg.org Subject: [FFmpeg-devel] [PATCH 1/2] avcodec/s302m: enable non-PCM decoding Date: Tue, 23 Jan 2024 12:19:47 +0530 Message-ID: <20240123064948.455-1-ffmpeg@gyani.pro> (raw) Set up framework for non-PCM decoding in-place and add support for Dolby-E decoding. Useful for direct transcoding of non-PCM audio in live inputs. --- configure | 1 + doc/decoders.texi | 40 +++ libavcodec/s302m.c | 609 +++++++++++++++++++++++++++++++++++++-------- 3 files changed, 543 insertions(+), 107 deletions(-) diff --git a/configure b/configure index c8ae0a061d..8db3fa3f4b 100755 --- a/configure +++ b/configure @@ -2979,6 +2979,7 @@ rv20_decoder_select="h263_decoder" rv20_encoder_select="h263_encoder" rv30_decoder_select="golomb h264pred h264qpel mpegvideodec rv34dsp" rv40_decoder_select="golomb h264pred h264qpel mpegvideodec rv34dsp" +s302m_decoder_select="dolby_e_decoder" screenpresso_decoder_deps="zlib" shorten_decoder_select="bswapdsp" sipr_decoder_select="lsp" diff --git a/doc/decoders.texi b/doc/decoders.texi index 293c82c2ba..9f85c876bf 100644 --- a/doc/decoders.texi +++ b/doc/decoders.texi @@ -347,6 +347,46 @@ configuration. You need to explicitly configure the build with An FFmpeg native decoder for Opus exists, so users can decode Opus without this library. +@section s302m + +SMPTE ST 302 decoder. + +SMPTE ST 302 is a method for storing AES3 data format within an MPEG Transport +Stream. AES3 streams can contain LPCM streams of 2, 4, 6 or 8 channels with a +bit depth of 16, 20 or 24-bits at a sample rate of 48 kHz. +They can also contain non-PCM codec streams such as AC-3 or Dolby-E. + +Decoding non-PCM streams directly requires that the necessary stream decoder be +present in the build. At present, only Dolby-E decoding is supported. + +@subsection Options + +The following options are supported by the s302m decoder. + +@table @option +@item non_pcm_mode @var{mode} +Specify how to process non-PCM streams + +@table @samp +@item copy +Treat data as if it were LPCM. +@item drop +Discard the stream. +@item decode_copy +Decode if possible eise treat the same as @code{copy}. +@item decode_drop +Decode if possible eise treat the same as @code{drop}. +@end table + +The default value is @code{decode_drop}. This option does not affect the processing of +LPCM streams. + +@item non_pcm_options @var{options} +Set options for non-PCM decoder using a list of key=value pairs separated by ":". +Consult the docs for the non-PCM decoder for its options. + +@end table + @c man end AUDIO DECODERS @chapter Subtitles Decoders diff --git a/libavcodec/s302m.c b/libavcodec/s302m.c index f1b41608f3..d6a75cfa73 100644 --- a/libavcodec/s302m.c +++ b/libavcodec/s302m.c @@ -24,21 +24,264 @@ #include "libavutil/intreadwrite.h" #include "libavutil/opt.h" #include "libavutil/log.h" +#include "libavutil/dict.h" #include "libavutil/reverse.h" #include "avcodec.h" #include "codec_internal.h" +#include "get_bits.h" #include "decode.h" #define AES3_HEADER_LEN 4 +#define NONPCMSYNC_16MARKER 0x4E1F0F8720 +#define NONPCMSYNC_20MARKER 0x4E1F60F872A0 +#define NONPCMSYNC_24MARKER 0x7E1F690F872A50 + +#define NONPCMSYNC_16_IN_20MARKER 0x04E1F00F8720 +#define NONPCMSYNC_20_IN_24MARKER 0x04E1F600F872A0 + +#define IS_NONPCMSYNC_16(state) ((state & 0xFFFF0FFFF0) == NONPCMSYNC_16MARKER) +#define IS_NONPCMSYNC_20(state) ((state & 0xFFFFF0FFFFF0) == NONPCMSYNC_20MARKER) +#define IS_NONPCMSYNC_24(state) ((state & 0xFFFFFF0FFFFFF0) == NONPCMSYNC_24MARKER) + +#define IS_NONPCMSYNC_16_IN_20(state) ((state & 0x0FFFF00FFFF0) == NONPCMSYNC_16_IN_20MARKER) +#define IS_NONPCMSYNC_20_IN_24(state) ((state & 0x0FFFFF00FFFFF0) == NONPCMSYNC_20_IN_24MARKER) + +#define IS_NONPCMSYNC(bit,state) ( ((bit == 16) && IS_NONPCMSYNC_16(state)) || \ + ((bit == 20) && (IS_NONPCMSYNC_20(state) || IS_NONPCMSYNC_16_IN_20(state))) || \ + ((bit == 24) && (IS_NONPCMSYNC_24(state) || IS_NONPCMSYNC_20_IN_24(state))) \ + ) + +enum non_pcm_modes { + NON_PCM_COPY, + NON_PCM_DROP, + NON_PCM_DEC_ELSE_COPY, + NON_PCM_DEC_ELSE_DROP, +}; + typedef struct S302Context { AVClass *class; + + int avctx_props_set; + + int channels; + int bits; + int non_pcm_mode; + int non_pcm_data_type; + int non_pcm_bits; + int non_pcm_dec; + + AVCodecContext *non_pcm_ctx; + AVDictionary *non_pcm_opts; + AVPacket *packet; + AVFrame *frame; } S302Context; +static av_cold int s302m_init(AVCodecContext *avctx) +{ + S302Context *s = avctx->priv_data; + + s->non_pcm_data_type = -1; + + return 0; +} + +static int s302m_non_pcm_inspect(AVCodecContext *avctx, const uint8_t *buf, int buf_size, + int *offset, int *length) +{ + S302Context *s = avctx->priv_data; + GetBitContext gb; + int ret, aes_frm_size, data_type, length_code = 0; + uint64_t state = 0; + uint32_t size; + + if (s->channels != 2) { + goto end; + } + + ret = init_get_bits8(&gb, buf, buf_size); + if (ret < 0) + return ret; + + aes_frm_size = (s->bits + 4) * 2 / 8; + if (buf_size < aes_frm_size * 2) // not enough to contain data_type & length_code + return AVERROR_INVALIDDATA; + + state = get_bits64(&gb, aes_frm_size * 8); + + while (!IS_NONPCMSYNC(s->bits,state) && (get_bits_left(&gb) >= 8)) + state = (state << 8) | get_bits(&gb, 8); + + if (IS_NONPCMSYNC(s->bits,state)) { + if (get_bits_left(&gb) < aes_frm_size * 8) { + av_log(avctx, AV_LOG_ERROR, "truncated non-pcm frame detected\n"); + return AVERROR_INVALIDDATA; + } + + if (s->bits == 16) { + s->non_pcm_bits = 16; + } else if (s->bits == 20) { + if (IS_NONPCMSYNC_16_IN_20(state)) + s->non_pcm_bits = 16; + else + s->non_pcm_bits = 20; + } else if (s->bits == 24) { + if (IS_NONPCMSYNC_20_IN_24(state)) + s->non_pcm_bits = 20; + else + s->non_pcm_bits = 24; + } + + skip_bits(&gb, s->bits - 16); + + data_type = ff_reverse[(uint8_t)get_bits(&gb, 5)] >> 3; + + if (s->non_pcm_data_type == -1) { + s->non_pcm_data_type = data_type; + av_log(avctx, AV_LOG_INFO, "stream has non-pcm data of type %d with %d-bit words in aes3 payload of size %d bits\n", data_type, s->non_pcm_bits, s->bits); + } else if (s->non_pcm_data_type != data_type) { + av_log(avctx, AV_LOG_DEBUG, "type mismatch of non-pcm type in packet %d vs stream %d. Dropping.\n", data_type, s->non_pcm_data_type); + return AVERROR_INVALIDDATA; + } + + if (s->non_pcm_mode == NON_PCM_COPY) + return 0; + else if (s->non_pcm_mode == NON_PCM_DROP) + return AVERROR_INVALIDDATA; + + skip_bits(&gb, 15); + + size = get_bits(&gb, s->bits); + + length_code = ((ff_reverse[(uint8_t)((size & 0xFF) )] << 16) | + (ff_reverse[(uint8_t)((size & 0xFF00) >> 8 )] << 8 ) | + (ff_reverse[(uint8_t)((size & 0xFF0000) >> 16)] ) ) >> (24 - s->non_pcm_bits); + + skip_bits(&gb, 4); + + *offset = get_bits_count(&gb)/8; + *length = length_code; + + av_log(avctx, AV_LOG_TRACE, "located non-pcm packet at offset %d length code %d.\n", AES3_HEADER_LEN + *offset, length_code); + + return data_type; + } + +end: + if (s->non_pcm_data_type == -1) { + s->non_pcm_data_type = 32; // indicate stream should be treated as LPCM + return 0; + } else + return AVERROR_INVALIDDATA; +} + +static int s302m_setup_non_pcm_handling(AVCodecContext *avctx, const uint8_t *buf, int buf_size) +{ + S302Context *s = avctx->priv_data; + const AVCodec *codec; + enum AVCodecID codec_id; + AVDictionary *dec_opts = NULL; + int ret; + + if (s->non_pcm_mode > NON_PCM_DROP) { + switch (s->non_pcm_data_type) { + case 0x1C: + codec_id = AV_CODEC_ID_DOLBY_E; + break; + default: + avpriv_report_missing_feature(avctx, "decode of non-pcm data type %d", s->non_pcm_data_type); + ret = AVERROR_PATCHWELCOME; + goto fail; + } + + codec = avcodec_find_decoder(codec_id); + if (!codec) { + ret = AVERROR_DECODER_NOT_FOUND; + goto fail; + } + + s->non_pcm_ctx = avcodec_alloc_context3(codec); + if (!s->non_pcm_ctx) { + ret = AVERROR(ENOMEM); + goto fail; + } + + av_dict_copy(&dec_opts, s->non_pcm_opts, 0); + + ret = avcodec_open2(s->non_pcm_ctx, codec, &dec_opts); + av_dict_free(&dec_opts); + if (ret < 0) + goto fail; + + s->packet = av_packet_alloc(); + if (!s->packet) { + ret = AVERROR(ENOMEM); + goto fail; + } + + s->frame = av_frame_alloc(); + if (!s->frame) { + ret = AVERROR(ENOMEM); + goto fail; + } + } else + return 0; + + s->non_pcm_dec = 1; + return 0; + +fail: + avcodec_free_context(&s->non_pcm_ctx); + av_packet_free(&s->packet); + av_frame_free(&s->frame); + + if (s->non_pcm_mode == NON_PCM_DEC_ELSE_COPY) + s->non_pcm_mode = NON_PCM_COPY; + else if (s->non_pcm_mode == NON_PCM_DEC_ELSE_DROP) + s->non_pcm_mode = NON_PCM_DROP; + + return ret; +} + +static int s302m_get_non_pcm_pkt_size(AVCodecContext *avctx, int buf_size, int offset, + int length_code, int *dec_pkt_size) +{ + S302Context *s = avctx->priv_data; + int nb_words, word_size, aesframe_size, s302m_read_size; + + if (offset < 0 || offset >= buf_size) + return AVERROR_INVALIDDATA; + + switch (s->non_pcm_data_type) { + case 0x1C: + goto dolby_e; + default: + return AVERROR_INVALIDDATA; + } + +dolby_e: + { + nb_words = length_code / s->non_pcm_bits; + nb_words += nb_words & 1; + + word_size = s->non_pcm_bits + 7 >> 3; + aesframe_size = (s->bits + 4) * 2 / 8; // 2 subframes, each with payload + VUCF bits + + *dec_pkt_size = nb_words * word_size; + s302m_read_size = aesframe_size * nb_words/2; + + if (offset + s302m_read_size > buf_size) + return AVERROR_INVALIDDATA; + + return s302m_read_size; + } +} + static int s302m_parse_frame_header(AVCodecContext *avctx, const uint8_t *buf, int buf_size) { + S302Context *s = avctx->priv_data; uint32_t h; int frame_size, channels, bits; @@ -66,33 +309,15 @@ static int s302m_parse_frame_header(AVCodecContext *avctx, const uint8_t *buf, return AVERROR_INVALIDDATA; } - /* Set output properties */ - avctx->bits_per_raw_sample = bits; - if (bits > 16) - avctx->sample_fmt = AV_SAMPLE_FMT_S32; - else - avctx->sample_fmt = AV_SAMPLE_FMT_S16; - - av_channel_layout_uninit(&avctx->ch_layout); - switch(channels) { - case 2: - avctx->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO; - break; - case 4: - avctx->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_QUAD; - break; - case 6: - avctx->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_5POINT1_BACK; - break; - case 8: - av_channel_layout_from_mask(&avctx->ch_layout, - AV_CH_LAYOUT_5POINT1_BACK | AV_CH_LAYOUT_STEREO_DOWNMIX); - break; - default: - avctx->ch_layout.order = AV_CHANNEL_ORDER_UNSPEC; - avctx->ch_layout.nb_channels = channels; - break; - } + if (!s->channels) + s->channels = channels; + else if (s->channels != channels) + return AVERROR_INVALIDDATA; + + if (!s->bits) + s->bits = bits; + else if (s->bits != bits) + return AVERROR_INVALIDDATA; return frame_size; } @@ -103,119 +328,286 @@ static int s302m_decode_frame(AVCodecContext *avctx, AVFrame *frame, S302Context *s = avctx->priv_data; const uint8_t *buf = avpkt->data; int buf_size = avpkt->size; - int block_size, ret, channels; - int i; - int non_pcm_data_type = -1; + int block_size, ret, channels, frame_size; + int non_pcm_offset = -1, non_pcm_length = 0; + int dec_pkt_size = 0; + + if (s->non_pcm_mode == NON_PCM_DROP && s->non_pcm_data_type != -1 && s->non_pcm_data_type != 32) + return avpkt->size; - int frame_size = s302m_parse_frame_header(avctx, buf, buf_size); + frame_size = s302m_parse_frame_header(avctx, buf, buf_size); if (frame_size < 0) return frame_size; buf_size -= AES3_HEADER_LEN; buf += AES3_HEADER_LEN; - /* get output buffer */ - block_size = (avctx->bits_per_raw_sample + 4) / 4; - channels = avctx->ch_layout.nb_channels; - frame->nb_samples = 2 * (buf_size / block_size) / channels; - if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) - return ret; + // set non-pcm status if not determined + // else extract offset and length if non-pcm can be decoded + if (s->non_pcm_data_type == -1 || s->non_pcm_dec) { + ret = s302m_non_pcm_inspect(avctx, buf, buf_size, &non_pcm_offset, &non_pcm_length); + if (ret >= 0 && s->non_pcm_data_type != 32 && !s->non_pcm_dec) + ret = s302m_setup_non_pcm_handling(avctx, buf, buf_size); + else if (ret < 0) + return avpkt->size; + } + + if (s->non_pcm_data_type == -1) + return AVERROR_INVALIDDATA; // we should know data type in order to proceed with output + + if (!s->non_pcm_dec && !s->avctx_props_set) { + /* Set output properties */ + avctx->bits_per_raw_sample = s->non_pcm_bits ? s->non_pcm_bits : s->bits; + if (avctx->bits_per_raw_sample > 16) + avctx->sample_fmt = AV_SAMPLE_FMT_S32; + else + avctx->sample_fmt = AV_SAMPLE_FMT_S16; - avctx->bit_rate = 48000 * channels * (avctx->bits_per_raw_sample + 4) + - 32 * 48000 / frame->nb_samples; - buf_size = (frame->nb_samples * channels / 2) * block_size; + av_channel_layout_uninit(&avctx->ch_layout); + switch(s->channels) { + case 2: + avctx->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO; + break; + case 4: + avctx->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_QUAD; + break; + case 6: + avctx->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_5POINT1_BACK; + break; + case 8: + av_channel_layout_from_mask(&avctx->ch_layout, + AV_CH_LAYOUT_5POINT1_BACK | AV_CH_LAYOUT_STEREO_DOWNMIX); + break; + default: + avctx->ch_layout.order = AV_CHANNEL_ORDER_UNSPEC; + avctx->ch_layout.nb_channels = channels; + break; + } + + avctx->sample_rate = 48000; + s->avctx_props_set = 1; + } + + if (s->non_pcm_dec) { + buf_size = s302m_get_non_pcm_pkt_size(avctx, buf_size, non_pcm_offset, non_pcm_length, &dec_pkt_size); + if (buf_size < 0) + return AVERROR_INVALIDDATA; + buf += non_pcm_offset; + + if (dec_pkt_size > s->packet->size) { + ret = av_grow_packet(s->packet, dec_pkt_size - s->packet->size); + if (ret < 0) + return ret; + } + ret = av_packet_make_writable(s->packet); + if (ret < 0) + return ret; + memset(s->packet->data, 0, s->packet->size); + + ret = av_packet_copy_props(s->packet, avpkt); + if (ret < 0) + return ret; + } else { + /* get output buffer */ + block_size = (s->bits + 4) / 4; + channels = s->channels; + frame->nb_samples = 2 * (buf_size / block_size) / channels; + if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) + return ret; + + buf_size = (frame->nb_samples * channels / 2) * block_size; + + avctx->bit_rate = 48000 * s->channels * ((s->non_pcm_bits ? s->non_pcm_bits : s->bits) + 4) + + 32 * 48000 / frame->nb_samples; + } + + if (s->bits == 24) { + uint8_t *p = NULL; + uint32_t *f32 = NULL; + + if (s->non_pcm_dec) + p = (uint8_t *)s->packet->data; + else + f32 = (uint32_t *)frame->data[0]; - if (avctx->bits_per_raw_sample == 24) { - uint32_t *o = (uint32_t *)frame->data[0]; for (; buf_size > 6; buf_size -= 7) { - *o++ = ((unsigned)ff_reverse[buf[2]] << 24) | - (ff_reverse[buf[1]] << 16) | - (ff_reverse[buf[0]] << 8); - *o++ = ((unsigned)ff_reverse[buf[6] & 0xf0] << 28) | - (ff_reverse[buf[5]] << 20) | - (ff_reverse[buf[4]] << 12) | - (ff_reverse[buf[3] & 0x0f] << 4); + uint8_t b[6]; + + b[0] = (ff_reverse[buf[2] ] ) ; + b[1] = (ff_reverse[buf[1] ] ) ; + b[2] = (ff_reverse[buf[0] ] ) ; + b[3] = (ff_reverse[buf[6] & 0xf0] << 4) | + (ff_reverse[buf[5] & 0x0f] >> 4) ; + b[4] = (ff_reverse[buf[5] & 0xf0] << 4) | + (ff_reverse[buf[4] & 0x0f] >> 4) ; + b[5] = (ff_reverse[buf[4] & 0xf0] << 4) | + (ff_reverse[buf[3] & 0x0f] >> 4) ; + + if (s->non_pcm_bits == 20) { + b[2] &= 0xf0; + b[5] &= 0xf0; + } + + if (s->non_pcm_dec) + for (int i = 0; i < 6; i++) + *p++ = b[i]; + else { + *f32++ = (b[0] << 24) | + (b[1] << 16) | + (b[2] << 8) ; + *f32++ = (b[3] << 24) | + (b[4] << 16) | + (b[5] << 8) ; + } buf += 7; } - o = (uint32_t *)frame->data[0]; - if (channels == 2) - for (i=0; i<frame->nb_samples * 2 - 6; i+=2) { - if (o[i] || o[i+1] || o[i+2] || o[i+3]) - break; - if (o[i+4] == 0x96F87200U && o[i+5] == 0xA54E1F00) { - non_pcm_data_type = (o[i+6] >> 16) & 0x1F; - break; + } else if (s->bits == 20) { + uint8_t *p = NULL; + uint16_t *f16 = NULL; + uint32_t *f32 = NULL; + + if (s->non_pcm_dec) + p = (uint8_t *)s->packet->data; + else if (s->non_pcm_bits == 16) + f16 = (uint16_t *)frame->data[0]; + else + f32 = (uint32_t *)frame->data[0]; + + for (; buf_size > 5; buf_size -= 6) { + uint8_t b[6]; + + b[0] = (ff_reverse[buf[2] & 0xf0] << 4) | + (ff_reverse[buf[1] & 0x0f] >> 4) ; + b[1] = (ff_reverse[buf[1] & 0xf0] << 4) | + (ff_reverse[buf[0] & 0x0f] >> 4) ; + b[2] = (ff_reverse[buf[0] & 0xf0] << 4) ; + b[3] = (ff_reverse[buf[5] & 0xf0] << 4) | + (ff_reverse[buf[4] & 0x0f] >> 4) ; + b[4] = (ff_reverse[buf[4] & 0xf0] << 4) | + (ff_reverse[buf[3] & 0x0f] >> 4) ; + b[5] = (ff_reverse[buf[3] & 0xf0] << 4) ; + + if (s->non_pcm_dec) { + for (int i = 0; i < 6; i++) { + if (s->non_pcm_bits == 16 && (i % 3 == 2)) + continue; + *p++ = b[i]; } + } else if (s->non_pcm_bits == 16) { + *f16++ = (b[0] << 8) | + (b[1] ) ; + *f16++ = (b[3] << 8) | + (b[4] ) ; + } else { + *f32++ = (b[0] << 24) | + (b[1] << 16) | + (b[2] << 8) ; + *f32++ = (b[3] << 24) | + (b[4] << 16) | + (b[5] << 8) ; } - } else if (avctx->bits_per_raw_sample == 20) { - uint32_t *o = (uint32_t *)frame->data[0]; - for (; buf_size > 5; buf_size -= 6) { - *o++ = ((unsigned)ff_reverse[buf[2] & 0xf0] << 28) | - (ff_reverse[buf[1]] << 20) | - (ff_reverse[buf[0]] << 12); - *o++ = ((unsigned)ff_reverse[buf[5] & 0xf0] << 28) | - (ff_reverse[buf[4]] << 20) | - (ff_reverse[buf[3]] << 12); buf += 6; } - o = (uint32_t *)frame->data[0]; - if (channels == 2) - for (i=0; i<frame->nb_samples * 2 - 6; i+=2) { - if (o[i] || o[i+1] || o[i+2] || o[i+3]) - break; - if (o[i+4] == 0x6F872000U && o[i+5] == 0x54E1F000) { - non_pcm_data_type = (o[i+6] >> 16) & 0x1F; - break; - } - } } else { - uint16_t *o = (uint16_t *)frame->data[0]; + uint8_t *p = NULL; + uint16_t *f16 = NULL; + + if (s->non_pcm_dec) + p = (uint8_t *)s->packet->data; + else + f16 = (uint16_t *)frame->data[0]; + for (; buf_size > 4; buf_size -= 5) { - *o++ = (ff_reverse[buf[1]] << 8) | - ff_reverse[buf[0]]; - *o++ = (ff_reverse[buf[4] & 0xf0] << 12) | - (ff_reverse[buf[3]] << 4) | - (ff_reverse[buf[2]] >> 4); + uint8_t b[4]; + + b[0] = (ff_reverse[buf[1] ] ) ; + b[1] = (ff_reverse[buf[0] ] ) ; + b[2] = (ff_reverse[buf[4] & 0xf0] << 4) | + (ff_reverse[buf[3] & 0x0f] >> 4) ; + b[3] = (ff_reverse[buf[3] & 0xf0] << 4) | + (ff_reverse[buf[2] & 0x0f] >> 4) ; + + if (s->non_pcm_dec) + for (int i = 0; i < 4; i++) + *p++ = b[i]; + else { + *f16++ = (b[0] << 8) | + (b[1] ) ; + *f16++ = (b[2] << 8) | + (b[3] ) ; + } buf += 5; } - o = (uint16_t *)frame->data[0]; - if (channels == 2) - for (i=0; i<frame->nb_samples * 2 - 6; i+=2) { - if (o[i] || o[i+1] || o[i+2] || o[i+3]) - break; - if (o[i+4] == 0xF872U && o[i+5] == 0x4E1F) { - non_pcm_data_type = (o[i+6] & 0x1F); - break; - } - } } - if (non_pcm_data_type != -1) { - if (s->non_pcm_mode == 3) { - av_log(avctx, AV_LOG_ERROR, - "S302 non PCM mode with data type %d not supported\n", - non_pcm_data_type); - return AVERROR_PATCHWELCOME; + if (s->non_pcm_dec) { + ret = avcodec_send_packet(s->non_pcm_ctx, s->packet); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "error %d submitting non-pcm packet with pts %"PRId64" for decoding\n", ret, s->packet->pts); + return ret; } - if (s->non_pcm_mode & 1) { - return avpkt->size; + ret = avcodec_receive_frame(s->non_pcm_ctx, s->frame); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "error %d receiving non-pcm decoded frame for packet with pts %"PRId64"\n", ret, s->packet->pts); + return ret; } - } - avctx->sample_rate = 48000; + if (!s->avctx_props_set) { + avctx->sample_fmt = s->non_pcm_ctx->sample_fmt; + avctx->sample_rate = s->non_pcm_ctx->sample_rate; + + av_channel_layout_uninit(&avctx->ch_layout); + ret = av_channel_layout_copy(&avctx->ch_layout, &s->non_pcm_ctx->ch_layout); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "error %d when copying channel layout from non-pcm decoder context to parent context.\n", ret); + return ret; + } + s->avctx_props_set = 1; + } + + frame->nb_samples = s->frame->nb_samples; + ret = ff_get_buffer(avctx, frame, 0); + if (ret < 0) + return ret; + + for (int ch = 0; ch < s->frame->ch_layout.nb_channels; ch++) + memcpy(frame->extended_data[ch], s->frame->extended_data[ch], + av_get_bytes_per_sample(s->non_pcm_ctx->sample_fmt) * s->frame->nb_samples); + } *got_frame_ptr = 1; return avpkt->size; } +static void s302m_flush(AVCodecContext *avctx) +{ + S302Context *s = avctx->priv_data; + + if (s->non_pcm_dec && s->non_pcm_ctx) + avcodec_flush_buffers(s->non_pcm_ctx); +} + +static av_cold int s302m_close(AVCodecContext *avctx) +{ + S302Context *s = avctx->priv_data; + + avcodec_free_context(&s->non_pcm_ctx); + av_packet_free(&s->packet); + av_frame_free(&s->frame); + av_dict_free(&s->non_pcm_opts); + + return 0; +} + #define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_DECODING_PARAM static const AVOption s302m_options[] = { - {"non_pcm_mode", "Chooses what to do with NON-PCM", offsetof(S302Context, non_pcm_mode), AV_OPT_TYPE_INT, {.i64 = 3}, 0, 3, FLAGS, "non_pcm_mode"}, - {"copy" , "Pass NON-PCM through unchanged" , 0, AV_OPT_TYPE_CONST, {.i64 = 0}, 0, 3, FLAGS, "non_pcm_mode"}, - {"drop" , "Drop NON-PCM" , 0, AV_OPT_TYPE_CONST, {.i64 = 1}, 0, 3, FLAGS, "non_pcm_mode"}, - {"decode_copy" , "Decode if possible else passthrough", 0, AV_OPT_TYPE_CONST, {.i64 = 2}, 0, 3, FLAGS, "non_pcm_mode"}, - {"decode_drop" , "Decode if possible else drop" , 0, AV_OPT_TYPE_CONST, {.i64 = 3}, 0, 3, FLAGS, "non_pcm_mode"}, + {"non_pcm_mode", "Chooses what to do with NON-PCM", offsetof(S302Context, non_pcm_mode), AV_OPT_TYPE_INT, {.i64 = NON_PCM_DEC_ELSE_DROP}, NON_PCM_COPY, NON_PCM_DEC_ELSE_DROP, FLAGS, "non_pcm_mode"}, + {"copy" , "Pass NON-PCM through unchanged" , 0, AV_OPT_TYPE_CONST, {.i64 = NON_PCM_COPY}, 0, 3, FLAGS, "non_pcm_mode"}, + {"drop" , "Drop NON-PCM" , 0, AV_OPT_TYPE_CONST, {.i64 = NON_PCM_DROP}, 0, 3, FLAGS, "non_pcm_mode"}, + {"decode_copy" , "Decode if possible else passthrough", 0, AV_OPT_TYPE_CONST, {.i64 = NON_PCM_DEC_ELSE_COPY}, 0, 3, FLAGS, "non_pcm_mode"}, + {"decode_drop" , "Decode if possible else drop" , 0, AV_OPT_TYPE_CONST, {.i64 = NON_PCM_DEC_ELSE_DROP}, 0, 3, FLAGS, "non_pcm_mode"}, + {"non_pcm_options", "Set options for non-pcm decoder", offsetof(S302Context, non_pcm_opts), AV_OPT_TYPE_DICT, {.str = NULL}, 0, 0, FLAGS}, {NULL} }; @@ -231,6 +623,9 @@ const FFCodec ff_s302m_decoder = { CODEC_LONG_NAME("SMPTE 302M"), .p.type = AVMEDIA_TYPE_AUDIO, .p.id = AV_CODEC_ID_S302M, + .init = s302m_init, + .close = s302m_close, + .flush = s302m_flush, .p.priv_class = &s302m_class, .priv_data_size = sizeof(S302Context), FF_CODEC_DECODE_CB(s302m_decode_frame), -- 2.39.1 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
next reply other threads:[~2024-01-23 6:50 UTC|newest] Thread overview: 75+ messages / expand[flat|nested] mbox.gz Atom feed top 2024-01-23 6:49 Gyan Doshi [this message] 2024-01-23 6:49 ` [FFmpeg-devel] [PATCH 2/2] fate: add tests for dolby_e decoding in s302m Gyan Doshi 2024-01-23 7:56 ` [FFmpeg-devel] [PATCH 1/2] avcodec/s302m: enable non-PCM decoding Kieran Kunhya 2024-01-23 8:32 ` Gyan Doshi 2024-01-23 9:05 ` Kieran Kunhya 2024-01-23 14:50 ` Devin Heitmueller 2024-01-23 14:53 ` Kieran Kunhya 2024-01-23 15:04 ` Devin Heitmueller 2024-01-23 10:28 ` Nicolas Gaullier 2024-01-23 11:18 ` Gyan Doshi 2024-01-25 4:59 ` Andreas Rheinhardt 2024-01-25 7:11 ` Gyan Doshi 2024-01-25 13:17 ` Andreas Rheinhardt 2024-01-26 4:23 ` Gyan Doshi 2024-01-26 6:42 ` Andreas Rheinhardt 2024-01-28 10:54 ` Anton Khirnov 2024-01-28 21:29 ` Kieran Kunhya 2024-01-29 4:00 ` Gyan Doshi via ffmpeg-devel 2024-01-29 9:27 ` Nicolas Gaullier 2024-01-29 10:17 ` Gyan Doshi 2024-01-29 10:18 ` Kieran Kunhya 2024-02-15 10:47 ` Anton Khirnov 2024-02-15 12:31 ` Gyan Doshi 2024-02-15 16:10 ` Anton Khirnov 2024-02-15 16:47 ` Gyan Doshi 2024-02-15 20:26 ` Kieran Kunhya 2024-02-16 4:12 ` Gyan Doshi 2024-02-16 9:03 ` Anton Khirnov 2024-02-17 11:46 ` Gyan Doshi 2024-02-17 12:22 ` Anton Khirnov 2024-02-17 12:37 ` Gyan Doshi 2024-02-17 19:55 ` Anton Khirnov 2024-02-18 0:43 ` Michael Niedermayer 2024-02-18 18:20 ` Anton Khirnov 2024-02-18 22:34 ` Michael Niedermayer 2024-02-18 22:47 ` Vittorio Giovara 2024-02-19 8:45 ` Nicolas George 2024-02-19 14:15 ` Vittorio Giovara 2024-02-19 14:28 ` Nicolas George 2024-02-19 14:37 ` Vittorio Giovara 2024-02-19 14:41 ` Nicolas George 2024-02-18 22:48 ` Hendrik Leppkes 2024-02-19 1:17 ` Michael Niedermayer 2024-02-19 2:26 ` Vittorio Giovara 2024-02-19 2:07 ` Ronald S. Bultje 2024-02-19 21:37 ` Anton Khirnov 2024-02-19 21:54 ` Nicolas George 2024-02-20 21:39 ` Michael Niedermayer 2024-02-20 21:56 ` Kieran Kunhya 2024-02-20 22:07 ` Nicolas George 2024-02-18 18:50 ` Rémi Denis-Courmont 2024-02-18 18:55 ` Nicolas George 2024-02-18 4:06 ` Gyan Doshi 2024-02-18 18:03 ` Anton Khirnov 2024-02-18 18:40 ` Nicolas George 2024-02-18 19:03 ` Rémi Denis-Courmont 2024-02-18 19:11 ` Nicolas George 2024-02-18 21:06 ` Vittorio Giovara 2024-02-18 21:25 ` Nicolas George 2024-02-18 21:55 ` Vittorio Giovara 2024-02-19 8:54 ` Nicolas George 2024-02-19 14:21 ` Vittorio Giovara 2024-02-19 14:30 ` Nicolas George 2024-02-19 14:33 ` Vittorio Giovara 2024-02-19 14:34 ` Nicolas George 2024-02-18 19:02 ` Gyan Doshi 2024-02-18 21:46 ` Vittorio Giovara 2024-02-19 5:10 ` Gyan Doshi 2024-02-19 14:30 ` Vittorio Giovara 2024-02-19 15:39 ` Gyan Doshi 2024-02-20 3:02 ` Vittorio Giovara 2024-02-17 12:31 ` Rémi Denis-Courmont 2024-02-19 2:16 ` epirat07 2024-02-16 13:55 ` Andreas Rheinhardt 2024-02-17 11:44 ` Gyan Doshi
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20240123064948.455-1-ffmpeg@gyani.pro \ --to=ffmpeg@gyani.pro \ --cc=ffmpeg-devel@ffmpeg.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel This inbox may be cloned and mirrored by anyone: git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \ ffmpegdev@gitmailbox.com public-inbox-index ffmpegdev Example config snippet for mirrors. AGPL code for this site: git clone https://public-inbox.org/public-inbox.git