From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by master.gitmailbox.com (Postfix) with ESMTP id 5B4EE495C4 for ; Tue, 13 Feb 2024 16:40:41 +0000 (UTC) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id BB88C68D173; Tue, 13 Feb 2024 18:40:39 +0200 (EET) Received: from mout-p-102.mailbox.org (mout-p-102.mailbox.org [80.241.56.152]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 080CE68C58B for ; Tue, 13 Feb 2024 18:40:33 +0200 (EET) Received: from smtp202.mailbox.org (smtp202.mailbox.org [10.196.197.202]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-p-102.mailbox.org (Postfix) with ESMTPS id 4TZ6Wf3tG8z9sqs for ; Tue, 13 Feb 2024 17:40:30 +0100 (CET) Message-ID: Date: Tue, 13 Feb 2024 22:10:27 +0530 MIME-Version: 1.0 To: ffmpeg-devel@ffmpeg.org References: <20240127103854.9971-1-ffmpeg@gyani.pro> Content-Language: en-US From: Gyan Doshi In-Reply-To: <20240127103854.9971-1-ffmpeg@gyani.pro> Subject: Re: [FFmpeg-devel] [PATCH v2 1/2] avcodec/s302m: enable non-PCM decoding X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="us-ascii"; Format="flowed" Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Archived-At: List-Archive: List-Post: On 2024-01-27 04:08 pm, Gyan Doshi wrote: > 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. Plan to push in 3 days, barring objections. Regards, Gyan > --- > configure | 1 + > doc/decoders.texi | 40 +++ > libavcodec/s302m.c | 596 +++++++++++++++++++++++++++++++++++++-------- > 3 files changed, 530 insertions(+), 107 deletions(-) > > v2: > switch to pointer for non-pcm sync search > use intreadwrite macro for writing frame data > remove unneeded free of non-pcm dec opts > > diff --git a/configure b/configure > index 21663000f8..4d7cd83247 100755 > --- a/configure > +++ b/configure > @@ -2980,6 +2980,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..d890b6f117 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; > + const uint8_t *pos = buf; > + int ret, aes_frm_size, data_type, length_code = 0, pkt_left = buf_size; > + uint64_t state = 0; > + uint32_t size; > + > + if (s->channels != 2) { > + goto end; > + } > + > + aes_frm_size = (s->bits + 4) * 2 / 8; > + if (pkt_left < aes_frm_size * 2) // not enough to contain data_type & length_code > + return AVERROR_INVALIDDATA; > + > + while (!IS_NONPCMSYNC(s->bits,state) && pkt_left-- >= 1) > + state = (state << 8) | *pos++; > + > + if (IS_NONPCMSYNC(s->bits,state)) { > + GetBitContext gb; > + > + if (pkt_left < aes_frm_size * 8) { > + av_log(avctx, AV_LOG_ERROR, "truncated non-pcm frame detected\n"); > + return AVERROR_INVALIDDATA; > + } > + > + ret = init_get_bits8(&gb, pos, aes_frm_size); > + if (ret < 0) > + return ret; > + > + 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 + buf_size - pkt_left; > + *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,273 @@ 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; > > - int frame_size = s302m_parse_frame_header(avctx, buf, buf_size); > + if (s->non_pcm_mode == NON_PCM_DROP && s->non_pcm_data_type != -1 && s->non_pcm_data_type != 32) > + return avpkt->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++ = AV_RB24(&b[0]) << 8; > + *f32++ = AV_RB24(&b[3]) << 8; > + } > buf += 7; > } > - o = (uint32_t *)frame->data[0]; > - if (channels == 2) > - for (i=0; inb_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++ = AV_RB16(&b[0]); > + *f16++ = AV_RB16(&b[3]); > + } else { > + *f32++ = AV_RB24(&b[0]) << 8; > + *f32++ = AV_RB24(&b[3]) << 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; inb_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++ = AV_RB16(&b[0]); > + *f16++ = AV_RB16(&b[2]); > + } > buf += 5; > } > - o = (uint16_t *)frame->data[0]; > - if (channels == 2) > - for (i=0; inb_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); > + > + 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 +610,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), _______________________________________________ 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".