From patchwork Thu Sep 30 21:00:57 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul B Mahol X-Patchwork-Id: 30826 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a6b:6506:0:0:0:0:0 with SMTP id z6csp1050242iob; Thu, 30 Sep 2021 14:01:35 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzWnvPyACFOifoWMUwn+ZPln+3/cZHF/5C3MNrVIXIknw+9KSWFy/oZ2uVehqhHwzXd5B+a X-Received: by 2002:a50:becb:: with SMTP id e11mr9918430edk.161.1633035695665; Thu, 30 Sep 2021 14:01:35 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1633035695; cv=none; d=google.com; s=arc-20160816; b=ybJMkJWKwgVpDc0Vig7TF7q5ukTvg9+aJ5zsQ5rYfERJtw7qZPJmbPj1qizMDjsysl M41rR2UP3Fb2zx9Y/JOfrTHkzGgF1Jmv2EKNm2N/DGiA9SAInE3crS1WGJIstOHeW9oN yGU1UyE7/dzCZs4h94njZqtuw89QySBrUk6plx2CVYu8huT6J73gPjQ/4bMM7iohWWzp aC5kUbODshV7FMvtkFY1DIxBo7lcA3+E3JycSTZ5jdNSkxZKfydHeLtzk6Hci3TAc6+O dgjO+NMScTzJhd83B1DZxCNYgjAwPOfF317jGKN3AcNHeN6exyFbP4ME0KSdrcNR8R7G hixw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:reply-to:list-subscribe :list-help:list-post:list-archive:list-unsubscribe:list-id :precedence:subject:mime-version:references:in-reply-to:message-id :date:to:from:dkim-signature:delivered-to; bh=v1XhV5cRgBIFzLlIWDsDZbAXBH1nmOGr0JoS+tpr55I=; b=ok3qVFF7cio7y+XL87bHXG/Ysjz5c/DMEQj87yJbYYe9O/pCRCB9KSI208PSFdP9q8 HRSdovrhGhGhezaWTbO25xIsVNlQzZMThE90XekN/MILtecjsrfHhKHiNUjzgRKMGP/j lEU52syf5q/FS8pEI2CnNAT/C7bJ5IW3Y+Lepb1SX802KPJZwv9tK9O2JX74ow8nU91l FNYRTQzOI5vEhQLjx+tUtBFYehQIYZwQDgUCXW4wXqkGdSaedByp1fXN3BZS6oA6kPqt JYoO2LMi0XUxNCV8pN/jIokiH0YB5hl/86ZlNH13SHIYv/zHup3g0FpoGAuoMaIJzFil cefw== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20210112 header.b="Xg/5pOoa"; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id h5si4298694ejj.144.2021.09.30.14.01.35; Thu, 30 Sep 2021 14:01:35 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20210112 header.b="Xg/5pOoa"; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 297D668ADD4; Fri, 1 Oct 2021 00:01:21 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-ed1-f54.google.com (mail-ed1-f54.google.com [209.85.208.54]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 79EF868AA97 for ; Fri, 1 Oct 2021 00:01:13 +0300 (EEST) Received: by mail-ed1-f54.google.com with SMTP id l7so3311840edq.3 for ; Thu, 30 Sep 2021 14:01:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=MGJgCa1MzhVNMT3IvbzE9DCPO13B4JBtc+W76hcNtQM=; b=Xg/5pOoayaxZTwNvfVfl/0aos3rpPAav657gGgSUJr7YACAnce4vdZ++/2n2ND6YMq lCLGEQ8c8O8el3q+oWVpMRvAI7kqS0jRGI7vleFWM5lPoxCnibHVnrnrBP5ibZjQXYZ2 cb5/hXmxNzSeuuKt15uT/du4J++pU2UJEtSn+MvIEdlXEl1803Dtsr1pEtaPy4+nQbuA +I+Hs6tOfOVmPm9GYVad6rpixkyj0tI0SmabHaPbwRmXMKJAexhXcS+keh/aFAwgNBeR zw5hYM+akWkD8yNjuWJGqFqOfa76Ke43AebC0UwVOJcVtH8KPAaSZoFyzwd5HXSF60Wq 0MOQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=MGJgCa1MzhVNMT3IvbzE9DCPO13B4JBtc+W76hcNtQM=; b=fbOmfqDJtpw64BUHDslKeztKI9AlQoh6KXMQPY7JmSq0e13Cf7JezrwF7DKp6LLMW/ Bl3tXIgk9fW4fiPZCwdVnQrkK2IpvrHvOBdHVpuwG/9qU7Wfw2doSipWeGkk+3D5c/e1 uPAI6R/wwPfG1b5D1FsSZyG8VjpnS/S2qMCnttj4D9OVQ11IEWD5Ke+1ETYKTZHM0RGE 6HxFJUA+VxDpPikknzSlX3nLoiIFMMNzTCwvRW3GVfq8bCKuSe5PFG9FkEP0ADPnNNc2 rkIC0RPPqtKLJuCfr0iNXvaH2OPmemk/m9K+AgkEUZowhxod+l8/Ifp2pmWUQRTj+mxD Xxig== X-Gm-Message-State: AOAM532FwaIhqDGiV+Wjgho9YoluMDpHLGpiDa6j08UC3o2AfX6ZLXZ6 GUlohXR/+5CAzyjccyTjsOjGarZYUaE= X-Received: by 2002:a17:906:6b1a:: with SMTP id q26mr1598129ejr.185.1633035672916; Thu, 30 Sep 2021 14:01:12 -0700 (PDT) Received: from localhost.localdomain ([212.15.177.19]) by smtp.gmail.com with ESMTPSA id w5sm2003059ejz.25.2021.09.30.14.01.12 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 30 Sep 2021 14:01:12 -0700 (PDT) From: Paul B Mahol To: ffmpeg-devel@ffmpeg.org Date: Thu, 30 Sep 2021 23:00:57 +0200 Message-Id: <20210930210057.324478-2-onemda@gmail.com> X-Mailer: git-send-email 2.33.0 In-Reply-To: <20210930210057.324478-1-onemda@gmail.com> References: <20210930210057.324478-1-onemda@gmail.com> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 2/2] avcodec/amr*dec: add multichannel support 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 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: Yyh5LVwZKsfE Signed-off-by: Paul B Mahol --- libavcodec/amr_parser.c | 39 ++++++++++++++++++-------- libavcodec/amrnbdec.c | 54 +++++++++++++++++++++++------------- libavcodec/amrwbdec.c | 59 +++++++++++++++++++++++++-------------- libavformat/amr.c | 61 +++++++++++++++++++++++++++++------------ 4 files changed, 143 insertions(+), 70 deletions(-) diff --git a/libavcodec/amr_parser.c b/libavcodec/amr_parser.c index 2659cb40d7..222d8e05e9 100644 --- a/libavcodec/amr_parser.c +++ b/libavcodec/amr_parser.c @@ -39,6 +39,7 @@ typedef struct AMRParseContext { ParseContext pc; uint64_t cumulated_size; uint64_t block_count; + int current_channel; int remaining; } AMRParseContext; @@ -57,21 +58,35 @@ static int amr_parse(AVCodecParserContext *s1, if (s1->flags & PARSER_FLAG_COMPLETE_FRAMES) { next = buf_size; } else { - if (s->remaining) { - next = s->remaining; - } else { - int mode = (buf[0] >> 3) & 0x0F; - - if (avctx->codec_id == AV_CODEC_ID_AMR_NB) { - next = amrnb_packed_size[mode]; - } else if (avctx->codec_id == AV_CODEC_ID_AMR_WB) { - next = amrwb_packed_size[mode]; + int offset = 0; + + for (int ch = s->current_channel; ch < avctx->channels; ch++) { + if (s->remaining) { + next = s->remaining; + } else { + int mode = (buf[offset] >> 3) & 0x0F; + + if (avctx->codec_id == AV_CODEC_ID_AMR_NB) { + next = amrnb_packed_size[mode]; + } else if (avctx->codec_id == AV_CODEC_ID_AMR_WB) { + next = amrwb_packed_size[mode]; + } + } + + offset += next; + if (offset >= buf_size) { + s->remaining = offset - buf_size; + next = END_NOT_FOUND; + s->current_channel = ch; + break; + } else { + s->remaining = 0; + s->current_channel = 0; } } - s->remaining = next - FFMIN(buf_size, next); - if (s->remaining) - next = END_NOT_FOUND; + if (s->remaining == 0) + next = offset; if (next != END_NOT_FOUND) { if (s->cumulated_size < UINT64_MAX - next) { diff --git a/libavcodec/amrnbdec.c b/libavcodec/amrnbdec.c index e366a09976..472fa85f87 100644 --- a/libavcodec/amrnbdec.c +++ b/libavcodec/amrnbdec.c @@ -145,6 +145,10 @@ typedef struct AMRContext { } AMRContext; +typedef struct AMRChannelsContext { + AMRContext ch[2]; +} AMRChannelsContext; + /** Double version of ff_weighted_vector_sumf() */ static void weighted_vector_sumd(double *out, const double *in_a, const double *in_b, double weight_coeff_a, @@ -159,20 +163,24 @@ static void weighted_vector_sumd(double *out, const double *in_a, static av_cold int amrnb_decode_init(AVCodecContext *avctx) { - AMRContext *p = avctx->priv_data; + AMRChannelsContext *s = avctx->priv_data; int i; - if (avctx->channels > 1) { - avpriv_report_missing_feature(avctx, "multi-channel AMR"); + if (avctx->channels > 2) { + avpriv_report_missing_feature(avctx, ">2 channel AMR"); return AVERROR_PATCHWELCOME; } - avctx->channels = 1; - avctx->channel_layout = AV_CH_LAYOUT_MONO; + if (!avctx->channels) { + avctx->channels = 1; + avctx->channel_layout = AV_CH_LAYOUT_MONO; + } if (!avctx->sample_rate) avctx->sample_rate = 8000; - avctx->sample_fmt = AV_SAMPLE_FMT_FLT; + avctx->sample_fmt = AV_SAMPLE_FMT_FLTP; + for (int ch = 0; ch < avctx->channels; ch++) { + AMRContext *p = &s->ch[ch]; // p->excitation always points to the same position in p->excitation_buf p->excitation = &p->excitation_buf[PITCH_DELAY_MAX + LP_FILTER_ORDER + 1]; @@ -188,6 +196,7 @@ static av_cold int amrnb_decode_init(AVCodecContext *avctx) ff_acelp_vectors_init(&p->acelpv_ctx); ff_celp_filter_init(&p->celpf_ctx); ff_celp_math_init(&p->celpm_ctx); + } return 0; } @@ -949,25 +958,30 @@ static int amrnb_decode_frame(AVCodecContext *avctx, void *data, int *got_frame_ptr, AVPacket *avpkt) { - AMRContext *p = avctx->priv_data; // pointer to private data + AMRChannelsContext *s = avctx->priv_data; // pointer to private data AVFrame *frame = data; const uint8_t *buf = avpkt->data; int buf_size = avpkt->size; - float *buf_out; // pointer to the output data buffer - int i, subframe, ret; - float fixed_gain_factor; - AMRFixed fixed_sparse = {0}; // fixed vector up to anti-sparseness processing - float spare_vector[AMR_SUBFRAME_SIZE]; // extra stack space to hold result from anti-sparseness processing - float synth_fixed_gain; // the fixed gain that synthesis should use - const float *synth_fixed_vector; // pointer to the fixed vector that synthesis should use + int ret; /* get output buffer */ frame->nb_samples = AMR_BLOCK_SIZE; if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) return ret; - buf_out = (float *)frame->data[0]; + + for (int ch = 0; ch < avctx->channels; ch++) { + AMRContext *p = &s->ch[ch]; + float fixed_gain_factor; + AMRFixed fixed_sparse = {0}; // fixed vector up to anti-sparseness processing + float spare_vector[AMR_SUBFRAME_SIZE]; // extra stack space to hold result from anti-sparseness processing + float synth_fixed_gain; // the fixed gain that synthesis should use + const float *synth_fixed_vector; // pointer to the fixed vector that synthesis should use + float *buf_out = (float *)frame->extended_data[ch]; + int channel_size; + int i, subframe; p->cur_frame_mode = unpack_bitstream(p, buf, buf_size); + channel_size = frame_sizes_nb[p->cur_frame_mode] + 1; // +7 for rounding and +8 for TOC if (p->cur_frame_mode == NO_DATA) { av_log(avctx, AV_LOG_ERROR, "Corrupt bitstream\n"); return AVERROR_INVALIDDATA; @@ -1072,11 +1086,13 @@ static int amrnb_decode_frame(AVCodecContext *avctx, void *data, * qbar(n-1) rather than qbar(n) in section 6.1(4) equation 71. */ p->acelpv_ctx.weighted_vector_sumf(p->lsf_avg, p->lsf_avg, p->lsf_q[3], 0.84, 0.16, LP_FILTER_ORDER); + buf += channel_size; + buf_size -= channel_size; + } *got_frame_ptr = 1; - /* return the amount of bytes consumed if everything was OK */ - return frame_sizes_nb[p->cur_frame_mode] + 1; // +7 for rounding and +8 for TOC + return avpkt->size; } @@ -1085,10 +1101,10 @@ const AVCodec ff_amrnb_decoder = { .long_name = NULL_IF_CONFIG_SMALL("AMR-NB (Adaptive Multi-Rate NarrowBand)"), .type = AVMEDIA_TYPE_AUDIO, .id = AV_CODEC_ID_AMR_NB, - .priv_data_size = sizeof(AMRContext), + .priv_data_size = sizeof(AMRChannelsContext), .init = amrnb_decode_init, .decode = amrnb_decode_frame, .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, - .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLT, + .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }, }; diff --git a/libavcodec/amrwbdec.c b/libavcodec/amrwbdec.c index a6c1d894d7..998dd82791 100644 --- a/libavcodec/amrwbdec.c +++ b/libavcodec/amrwbdec.c @@ -93,21 +93,30 @@ typedef struct AMRWBContext { } AMRWBContext; +typedef struct AMRWBChannelsContext { + AMRWBContext ch[2]; +} AMRWBChannelsContext; + static av_cold int amrwb_decode_init(AVCodecContext *avctx) { - AMRWBContext *ctx = avctx->priv_data; + AMRWBChannelsContext *s = avctx->priv_data; int i; - if (avctx->channels > 1) { - avpriv_report_missing_feature(avctx, "multi-channel AMR"); + if (avctx->channels > 2) { + avpriv_report_missing_feature(avctx, ">2 channel AMR"); return AVERROR_PATCHWELCOME; } - avctx->channels = 1; - avctx->channel_layout = AV_CH_LAYOUT_MONO; + if (!avctx->channels) { + avctx->channels = 1; + avctx->channel_layout = AV_CH_LAYOUT_MONO; + } if (!avctx->sample_rate) avctx->sample_rate = 16000; - avctx->sample_fmt = AV_SAMPLE_FMT_FLT; + avctx->sample_fmt = AV_SAMPLE_FMT_FLTP; + + for (int ch = 0; ch < avctx->channels; ch++) { + AMRWBContext *ctx = &s->ch[ch]; av_lfg_init(&ctx->prng, 1); @@ -124,6 +133,7 @@ static av_cold int amrwb_decode_init(AVCodecContext *avctx) ff_acelp_vectors_init(&ctx->acelpv_ctx); ff_celp_filter_init(&ctx->celpf_ctx); ff_celp_math_init(&ctx->celpm_ctx); + } return 0; } @@ -1094,13 +1104,21 @@ static void update_sub_state(AMRWBContext *ctx) static int amrwb_decode_frame(AVCodecContext *avctx, void *data, int *got_frame_ptr, AVPacket *avpkt) { - AMRWBContext *ctx = avctx->priv_data; + AMRWBChannelsContext *s = avctx->priv_data; AVFrame *frame = data; - AMRWBFrame *cf = &ctx->frame; const uint8_t *buf = avpkt->data; int buf_size = avpkt->size; + int sub, i, ret; + + /* get output buffer */ + frame->nb_samples = 4 * AMRWB_SFR_SIZE_16k; + if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) + return ret; + + for (int ch = 0; ch < avctx->channels; ch++) { + AMRWBContext *ctx = &s->ch[ch]; + AMRWBFrame *cf = &ctx->frame; int expected_fr_size, header_size; - float *buf_out; float spare_vector[AMRWB_SFR_SIZE]; // extra stack space to hold result from anti-sparseness processing float fixed_gain_factor; // fixed gain correction factor (gamma) float *synth_fixed_vector; // pointer to the fixed vector that synthesis should use @@ -1110,13 +1128,7 @@ static int amrwb_decode_frame(AVCodecContext *avctx, void *data, float hb_exc[AMRWB_SFR_SIZE_16k]; // excitation for the high frequency band float hb_samples[AMRWB_SFR_SIZE_16k]; // filtered high-band samples from synthesis float hb_gain; - int sub, i, ret; - - /* get output buffer */ - frame->nb_samples = 4 * AMRWB_SFR_SIZE_16k; - if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) - return ret; - buf_out = (float *)frame->data[0]; + float *buf_out = (float *)frame->extended_data[ch]; header_size = decode_mime_header(ctx, buf); expected_fr_size = ((cf_sizes_wb[ctx->fr_cur_mode] + 7) >> 3) + 1; @@ -1127,9 +1139,10 @@ static int amrwb_decode_frame(AVCodecContext *avctx, void *data, if (ctx->fr_cur_mode == NO_DATA || !ctx->fr_quality) { /* The specification suggests a "random signal" and "a muting technique" to "gradually decrease the output level". */ - av_samples_set_silence(&frame->data[0], 0, frame->nb_samples, 1, AV_SAMPLE_FMT_FLT); - *got_frame_ptr = 1; - return expected_fr_size; + av_samples_set_silence(&frame->extended_data[ch], 0, frame->nb_samples, 1, AV_SAMPLE_FMT_FLT); + buf += expected_fr_size; + buf_size -= expected_fr_size; + continue; } if (ctx->fr_cur_mode > MODE_SID) { av_log(avctx, AV_LOG_ERROR, @@ -1270,9 +1283,13 @@ static int amrwb_decode_frame(AVCodecContext *avctx, void *data, memcpy(ctx->isp_sub4_past, ctx->isp[3], LP_ORDER * sizeof(ctx->isp[3][0])); memcpy(ctx->isf_past_final, ctx->isf_cur, LP_ORDER * sizeof(float)); + buf += expected_fr_size; + buf_size -= expected_fr_size; + } + *got_frame_ptr = 1; - return expected_fr_size; + return avpkt->size; } const AVCodec ff_amrwb_decoder = { @@ -1280,7 +1297,7 @@ const AVCodec ff_amrwb_decoder = { .long_name = NULL_IF_CONFIG_SMALL("AMR-WB (Adaptive Multi-Rate WideBand)"), .type = AVMEDIA_TYPE_AUDIO, .id = AV_CODEC_ID_AMR_WB, - .priv_data_size = sizeof(AMRWBContext), + .priv_data_size = sizeof(AMRWBChannelsContext), .init = amrwb_decode_init, .decode = amrwb_decode_frame, .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, diff --git a/libavformat/amr.c b/libavformat/amr.c index 8e79caee18..3f73c51a57 100644 --- a/libavformat/amr.c +++ b/libavformat/amr.c @@ -21,13 +21,12 @@ /* Write and read amr data according to RFC3267, http://www.ietf.org/rfc/rfc3267.txt?number=3267 - -Only mono files are supported. - */ #include "libavutil/channel_layout.h" +#include "libavutil/intreadwrite.h" #include "avformat.h" +#include "avio_internal.h" #include "internal.h" #include "rawdec.h" #include "rawenc.h" @@ -36,8 +35,10 @@ typedef struct AMRContext { FFRawDemuxerContext rawctx; } AMRContext; -static const char AMR_header[] = "#!AMR\n"; -static const char AMRWB_header[] = "#!AMR-WB\n"; +static const uint8_t AMR_header[6] = "#!AMR\x0a"; +static const uint8_t AMRMC_header[12] = "#!AMR_MC1.0\x0a"; +static const uint8_t AMRWB_header[9] = "#!AMR-WB\x0a"; +static const uint8_t AMRWBMC_header[15] = "#!AMR-WB_MC1.0\x0a"; static const uint8_t amrnb_packed_size[16] = { 13, 14, 16, 18, 20, 21, 27, 32, 6, 1, 1, 1, 1, 1, 1, 1 @@ -69,7 +70,7 @@ static int amr_probe(const AVProbeData *p) { // Only check for "#!AMR" which could be amr-wb, amr-nb. // This will also trigger multichannel files: "#!AMR_MC1.0\n" and - // "#!AMR-WB_MC1.0\n" (not supported) + // "#!AMR-WB_MC1.0\n" if (!memcmp(p->buf, AMR_header, 5)) return AVPROBE_SCORE_MAX; @@ -82,35 +83,59 @@ static int amr_read_header(AVFormatContext *s) { AVIOContext *pb = s->pb; AVStream *st; - uint8_t header[9]; + uint8_t header[19]; + int back = 0, ret; + + ret = ffio_ensure_seekback(s->pb, 19); + if (ret < 0) + return ret; - if (avio_read(pb, header, 6) != 6) + if (avio_read(pb, header, 19) != 19) return AVERROR_INVALIDDATA; st = avformat_new_stream(s, NULL); if (!st) return AVERROR(ENOMEM); - if (memcmp(header, AMR_header, 6)) { - if (avio_read(pb, header + 6, 3) != 3) - return AVERROR_INVALIDDATA; - if (memcmp(header, AMRWB_header, 9)) { - return -1; - } - + if (!memcmp(header, AMR_header, sizeof(AMR_header))) { + st->codecpar->codec_tag = MKTAG('s', 'a', 'm', 'r'); + st->codecpar->codec_id = AV_CODEC_ID_AMR_NB; + st->codecpar->sample_rate = 8000; + st->codecpar->channels = 1; + st->codecpar->channel_layout = AV_CH_LAYOUT_MONO; + back = 19 - sizeof(AMR_header); + } else if (!memcmp(header, AMRWB_header, sizeof(AMRWB_header))) { st->codecpar->codec_tag = MKTAG('s', 'a', 'w', 'b'); st->codecpar->codec_id = AV_CODEC_ID_AMR_WB; st->codecpar->sample_rate = 16000; - } else { + st->codecpar->channels = 1; + st->codecpar->channel_layout = AV_CH_LAYOUT_MONO; + back = 19 - sizeof(AMRWB_header); + } else if (!memcmp(header, AMRMC_header, sizeof(AMRMC_header))) { st->codecpar->codec_tag = MKTAG('s', 'a', 'm', 'r'); st->codecpar->codec_id = AV_CODEC_ID_AMR_NB; st->codecpar->sample_rate = 8000; + st->codecpar->channels = AV_RL32(header + 12); + back = 15 - sizeof(AMRMC_header); + } else if (!memcmp(header, AMRWBMC_header, sizeof(AMRWBMC_header))) { + st->codecpar->codec_tag = MKTAG('s', 'a', 'w', 'b'); + st->codecpar->codec_id = AV_CODEC_ID_AMR_WB; + st->codecpar->sample_rate = 16000; + st->codecpar->channels = AV_RL32(header + 15); + back = 15 - sizeof(AMRWBMC_header); + } else { + return AVERROR_INVALIDDATA; } - st->codecpar->channels = 1; - st->codecpar->channel_layout = AV_CH_LAYOUT_MONO; + + if (st->codecpar->channels < 1) + return AVERROR_INVALIDDATA; + st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; ffstream(st)->need_parsing = AVSTREAM_PARSE_FULL_RAW; avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate); + if (back > 0) + avio_seek(pb, -back, SEEK_CUR); + return 0; }