From patchwork Thu Nov 5 13:48:23 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zane van Iperen X-Patchwork-Id: 23401 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id 74C1C448C17 for ; Thu, 5 Nov 2020 15:48:49 +0200 (EET) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 5C03068B820; Thu, 5 Nov 2020 15:48:49 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from out1.migadu.com (out1.migadu.com [91.121.223.63]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 512B068B826 for ; Thu, 5 Nov 2020 15:48:42 +0200 (EET) X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zanevaniperen.com; s=key1; t=1604584121; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=/cCLu2om/LpOAenk7niT7PjpaZX6gUEK9NS+Jp/XaTs=; b=ZmrFVLZAAic/Xwlc4U/atC1YCzmLZPxLRLX+iOHfL1dlY/EmTx8XiCVjfZllxTvVcq89lA vlOQI7UvRkHyZoZE7kdjjhAXOPJw80nHxWBLZ999Ur1nnIzueGd8qYIuM08ZM3tmk6Erzs laNOIA+RngHSWh7a7M5z0pyreQ9OON1UbB0PL5oU8WH9NbtAWS267bdnOzUB53GXfUrNXg Zf32NDd0bALIt0DIkzSvg7tmXkI1OOwDDGTkjorXzNgFFuPjbcKXyehmLGBQN72wt25LEH L4+b8hNmHzBk2pXstRZnu+X7re0g64UECuPfjaUkmnkFYisi+CaqrcUEHFQQMg== From: Zane van Iperen To: ffmpeg-devel@ffmpeg.org Date: Thu, 5 Nov 2020 23:48:23 +1000 Message-Id: <20201105134827.25564-2-zane@zanevaniperen.com> In-Reply-To: <20201105134827.25564-1-zane@zanevaniperen.com> References: <20201105134827.25564-1-zane@zanevaniperen.com> MIME-Version: 1.0 X-Authenticated-User: git-morningstar@zanevaniperen.com X-Spam-Score: 0.00 Subject: [FFmpeg-devel] [PATCH v4 1/5] avcodec/adpcm_ima_amv: restrict to 1 channel X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 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 Cc: Zane van Iperen Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" The format doesn't allow for anything else. Signed-off-by: Zane van Iperen --- libavcodec/adpcm.c | 5 ++++- libavcodec/utils.c | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c index 701b125c47..d34fd6c6e1 100644 --- a/libavcodec/adpcm.c +++ b/libavcodec/adpcm.c @@ -110,6 +110,7 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx) unsigned int max_channels = 2; switch(avctx->codec->id) { + case AV_CODEC_ID_ADPCM_IMA_AMV: case AV_CODEC_ID_ADPCM_IMA_CUNNING: max_channels = 1; break; @@ -1684,6 +1685,8 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data, } break; case AV_CODEC_ID_ADPCM_IMA_AMV: + av_assert0(avctx->channels == 1); + c->status[0].predictor = sign_extend(bytestream2_get_le16u(&gb), 16); c->status[0].step_index = bytestream2_get_byteu(&gb); bytestream2_skipu(&gb, 5); @@ -1693,7 +1696,7 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data, return AVERROR_INVALIDDATA; } - for (n = nb_samples >> (1 - st); n > 0; n--) { + for (n = nb_samples >> 1; n > 0; n--) { int v = bytestream2_get_byteu(&gb); *samples++ = adpcm_ima_expand_nibble(&c->status[0], v >> 4, 3); diff --git a/libavcodec/utils.c b/libavcodec/utils.c index db51512e15..008e95c239 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -1696,7 +1696,7 @@ static int get_audio_frame_duration(enum AVCodecID id, int sr, int ch, int ba, case AV_CODEC_ID_ADPCM_IMA_SMJPEG: return (frame_bytes - 4) * 2 / ch; case AV_CODEC_ID_ADPCM_IMA_AMV: - return (frame_bytes - 8) * 2 / ch; + return (frame_bytes - 8) * 2; case AV_CODEC_ID_ADPCM_THP: case AV_CODEC_ID_ADPCM_THP_LE: if (extradata) From patchwork Thu Nov 5 13:48:24 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zane van Iperen X-Patchwork-Id: 23402 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id 89213448C17 for ; Thu, 5 Nov 2020 15:48:51 +0200 (EET) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 6F4D468B838; Thu, 5 Nov 2020 15:48:51 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from out1.migadu.com (out1.migadu.com [91.121.223.63]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id F092B68B829 for ; Thu, 5 Nov 2020 15:48:44 +0200 (EET) X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zanevaniperen.com; s=key1; t=1604584124; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=8GveyoHKhfDM6gPog2sv0T7GvpT0jrIn0TJqmuJ6RMk=; b=Gkt0/TWOD+krk9lihIxSKjr8zY+sKwzFqizCoBWit/tKdTpReXm92xtj5bdq/hJK4iv2k+ PBkiwZqrqfzYjj7N3JnKrUfgMqSU2NwPhew8+Ti1Nbwyb3PjBhoa3cNRgZKxh4P/XRyrsD +C3mocQ1GIu3pXznsGGi1Rei4L+ENbZFJgis0GMHtBcy1pH/TOt+ZP6JjwCIvi5pGfy0x+ 9FMXEiB87VMD1WhdKRFTlvM9RWuFDgRLuMNVH6L/r+eFAPpIt8On1SYFDUayuVPHJmJ5DQ DCA2PmHgIcFG1him1G5To3TyXbSRTW31US0cy0ZCiZq6unjuWgMFUsLz+DF0fg== From: Zane van Iperen To: ffmpeg-devel@ffmpeg.org Date: Thu, 5 Nov 2020 23:48:24 +1000 Message-Id: <20201105134827.25564-3-zane@zanevaniperen.com> In-Reply-To: <20201105134827.25564-1-zane@zanevaniperen.com> References: <20201105134827.25564-1-zane@zanevaniperen.com> MIME-Version: 1.0 X-Authenticated-User: git-morningstar@zanevaniperen.com X-Spam-Score: 0.00 Subject: [FFmpeg-devel] [PATCH v4 2/5] avcodec/adpcm_ima_amv: use coded sample count X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 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 Cc: Zane van Iperen Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Signed-off-by: Zane van Iperen --- libavcodec/adpcm.c | 19 ++- tests/ref/fate/adpcm-ima-amv | 312 +++++++++++++++++------------------ 2 files changed, 174 insertions(+), 157 deletions(-) diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c index d34fd6c6e1..80ce5b8518 100644 --- a/libavcodec/adpcm.c +++ b/libavcodec/adpcm.c @@ -775,7 +775,6 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb, case AV_CODEC_ID_ADPCM_IMA_DAT4: case AV_CODEC_ID_ADPCM_IMA_MOFLEX: case AV_CODEC_ID_ADPCM_IMA_ISS: header_size = 4 * ch; break; - case AV_CODEC_ID_ADPCM_IMA_AMV: header_size = 8; break; case AV_CODEC_ID_ADPCM_IMA_SMJPEG: header_size = 4 * ch; break; } if (header_size > 0) @@ -783,6 +782,13 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb, /* more complex formats */ switch (avctx->codec->id) { + case AV_CODEC_ID_ADPCM_IMA_AMV: + bytestream2_skip(gb, 4); + has_coded_samples = 1; + *coded_samples = bytestream2_get_le32u(gb); + nb_samples = FFMIN((buf_size - 8) * 2, *coded_samples); + bytestream2_seek(gb, -8, SEEK_CUR); + break; case AV_CODEC_ID_ADPCM_EA: has_coded_samples = 1; *coded_samples = bytestream2_get_le32(gb); @@ -1702,6 +1708,17 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data, *samples++ = adpcm_ima_expand_nibble(&c->status[0], v >> 4, 3); *samples++ = adpcm_ima_expand_nibble(&c->status[0], v & 0xf, 3); } + + if (nb_samples & 1) { + int v = bytestream2_get_byteu(&gb); + *samples++ = adpcm_ima_expand_nibble(&c->status[0], v >> 4, 3); + + if (v & 0x0F) { + /* Holds true on all the http://samples.mplayerhq.hu/amv samples. */ + av_log(avctx, AV_LOG_WARNING, "Last nibble set on packet with odd sample count.\n"); + av_log(avctx, AV_LOG_WARNING, "Sample will be skipped.\n"); + } + } break; case AV_CODEC_ID_ADPCM_IMA_SMJPEG: for (i = 0; i < avctx->channels; i++) { diff --git a/tests/ref/fate/adpcm-ima-amv b/tests/ref/fate/adpcm-ima-amv index eb174dfa81..2f8c0a2cdf 100644 --- a/tests/ref/fate/adpcm-ima-amv +++ b/tests/ref/fate/adpcm-ima-amv @@ -8,159 +8,159 @@ 0, 1378, 1378, 1378, 2756, 0x8462443f 0, 2756, 2756, 1378, 2756, 0x9f493ba6 0, 4134, 4134, 1378, 2756, 0x634e5f06 -0, 5512, 5512, 1380, 2760, 0x51f35cd4 -0, 6892, 6892, 1378, 2756, 0x011c51e5 -0, 8270, 8270, 1378, 2756, 0x8c2c198c -0, 9648, 9648, 1378, 2756, 0x2b4a3397 -0, 11026, 11026, 1378, 2756, 0x63794f22 -0, 12404, 12404, 1378, 2756, 0xfc363898 -0, 13782, 13782, 1378, 2756, 0x0da5486e -0, 15160, 15160, 1378, 2756, 0xbae17a5f -0, 16538, 16538, 1380, 2760, 0xba266e1b -0, 17918, 17918, 1378, 2756, 0xdfb61002 -0, 19296, 19296, 1378, 2756, 0x15d029da -0, 20674, 20674, 1378, 2756, 0x7bc82012 -0, 22052, 22052, 1378, 2756, 0x002e6999 -0, 23430, 23430, 1378, 2756, 0x96346ba6 -0, 24808, 24808, 1378, 2756, 0x3d54543b -0, 26186, 26186, 1380, 2760, 0x601786e1 -0, 27566, 27566, 1378, 2756, 0xf22a5793 -0, 28944, 28944, 1378, 2756, 0x21f54d49 -0, 30322, 30322, 1378, 2756, 0x0c6d4399 -0, 31700, 31700, 1378, 2756, 0x17282f8e -0, 33078, 33078, 1378, 2756, 0xeb698f75 -0, 34456, 34456, 1378, 2756, 0x935e1de2 -0, 35834, 35834, 1380, 2760, 0xb6fb4293 -0, 37214, 37214, 1378, 2756, 0x485053dc -0, 38592, 38592, 1378, 2756, 0x24c35027 -0, 39970, 39970, 1378, 2756, 0x09f323ee -0, 41348, 41348, 1378, 2756, 0xbc7d58d5 -0, 42726, 42726, 1378, 2756, 0xaefd487c -0, 44104, 44104, 1378, 2756, 0xaca16cc0 -0, 45482, 45482, 1380, 2760, 0x98a76091 -0, 46862, 46862, 1378, 2756, 0x5d357141 -0, 48240, 48240, 1378, 2756, 0x65ea2657 -0, 49618, 49618, 1378, 2756, 0xb5e1334a -0, 50996, 50996, 1378, 2756, 0x32cd5d91 -0, 52374, 52374, 1378, 2756, 0xdc23722b -0, 53752, 53752, 1378, 2756, 0x2ba34684 -0, 55130, 55130, 1378, 2756, 0xf9755ba8 -0, 56508, 56508, 1380, 2760, 0x24221ddb -0, 57888, 57888, 1378, 2756, 0xef843aa4 -0, 59266, 59266, 1378, 2756, 0x420442fe -0, 60644, 60644, 1378, 2756, 0x5a0933cb -0, 62022, 62022, 1378, 2756, 0xef5f6d61 -0, 63400, 63400, 1378, 2756, 0xe57e6dc0 -0, 64778, 64778, 1378, 2756, 0xc0f0495a -0, 66156, 66156, 1380, 2760, 0x2c3b55df -0, 67536, 67536, 1378, 2756, 0x39c2586c -0, 68914, 68914, 1378, 2756, 0x7ffc46e5 -0, 70292, 70292, 1378, 2756, 0xa2766664 -0, 71670, 71670, 1378, 2756, 0xacb50c6c -0, 73048, 73048, 1378, 2756, 0x7f659084 -0, 74426, 74426, 1378, 2756, 0xc72e6a12 -0, 75804, 75804, 1380, 2760, 0xdb6944df -0, 77184, 77184, 1378, 2756, 0x954f45c1 -0, 78562, 78562, 1378, 2756, 0xa9484240 -0, 79940, 79940, 1378, 2756, 0x1d595349 -0, 81318, 81318, 1378, 2756, 0xcf2a565e -0, 82696, 82696, 1378, 2756, 0x391028d5 -0, 84074, 84074, 1378, 2756, 0x348db7ad -0, 85452, 85452, 1380, 2760, 0xb69b5e3a -0, 86832, 86832, 1378, 2756, 0xe3635fbe -0, 88210, 88210, 1378, 2756, 0xdcad3654 -0, 89588, 89588, 1378, 2756, 0x5c17abef -0, 90966, 90966, 1378, 2756, 0xb3235184 -0, 92344, 92344, 1378, 2756, 0xdabb64a6 -0, 93722, 93722, 1378, 2756, 0xa95dc58d -0, 95100, 95100, 1380, 2760, 0x8e7ac9eb -0, 96480, 96480, 1378, 2756, 0x492b658e -0, 97858, 97858, 1378, 2756, 0x377483ab -0, 99236, 99236, 1378, 2756, 0x2c250279 -0, 100614, 100614, 1378, 2756, 0x704dbdb3 -0, 101992, 101992, 1378, 2756, 0x800d7da2 -0, 103370, 103370, 1378, 2756, 0x872aa32e -0, 104748, 104748, 1378, 2756, 0x2d4837fe -0, 106126, 106126, 1380, 2760, 0xc89ea57e -0, 107506, 107506, 1378, 2756, 0x6447d7ef -0, 108884, 108884, 1378, 2756, 0x144f59cc -0, 110262, 110262, 1378, 2756, 0xc667154e -0, 111640, 111640, 1378, 2756, 0xf0de66ae -0, 113018, 113018, 1378, 2756, 0xeabf3c32 -0, 114396, 114396, 1378, 2756, 0xe98e81d1 -0, 115774, 115774, 1380, 2760, 0x56aa5889 -0, 117154, 117154, 1378, 2756, 0x4fd34c0e -0, 118532, 118532, 1378, 2756, 0x67cf6912 -0, 119910, 119910, 1378, 2756, 0xfa944def -0, 121288, 121288, 1378, 2756, 0xc12f23b2 -0, 122666, 122666, 1378, 2756, 0x5ea325a2 -0, 124044, 124044, 1378, 2756, 0x2b245824 -0, 125422, 125422, 1380, 2760, 0x90ac533e -0, 126802, 126802, 1378, 2756, 0xcca34d26 -0, 128180, 128180, 1378, 2756, 0xb5f820d0 -0, 129558, 129558, 1378, 2756, 0x27f24335 -0, 130936, 130936, 1378, 2756, 0x4a9e87b7 -0, 132314, 132314, 1378, 2756, 0xbd076129 -0, 133692, 133692, 1378, 2756, 0x2e0e3f2e -0, 135070, 135070, 1380, 2760, 0xdf534478 -0, 136450, 136450, 1378, 2756, 0xca000a2e -0, 137828, 137828, 1378, 2756, 0x87472df3 -0, 139206, 139206, 1378, 2756, 0x16733810 -0, 140584, 140584, 1378, 2756, 0xfa0734b4 -0, 141962, 141962, 1378, 2756, 0x5eff3fc4 -0, 143340, 143340, 1378, 2756, 0xf35346bd -0, 144718, 144718, 1378, 2756, 0xac6411c5 -0, 146096, 146096, 1380, 2760, 0x478c3c56 -0, 147476, 147476, 1378, 2756, 0xebd30bdd -0, 148854, 148854, 1378, 2756, 0xaef95a31 -0, 150232, 150232, 1378, 2756, 0x8aad29d1 -0, 151610, 151610, 1378, 2756, 0x626863f0 -0, 152988, 152988, 1378, 2756, 0x68c05707 -0, 154366, 154366, 1378, 2756, 0x437c5e8d -0, 155744, 155744, 1380, 2760, 0x8eca4bdb -0, 157124, 157124, 1378, 2756, 0x62bd4162 -0, 158502, 158502, 1378, 2756, 0x9f744aa4 -0, 159880, 159880, 1378, 2756, 0x0f3f6409 -0, 161258, 161258, 1378, 2756, 0x3fee827a -0, 162636, 162636, 1378, 2756, 0x48a0ac19 -0, 164014, 164014, 1378, 2756, 0x8e4ce0d0 -0, 165392, 165392, 1380, 2760, 0xcda82236 -0, 166772, 166772, 1378, 2756, 0x0e523255 -0, 168150, 168150, 1378, 2756, 0x84103d30 -0, 169528, 169528, 1378, 2756, 0x13941cde -0, 170906, 170906, 1378, 2756, 0x9fc834c5 -0, 172284, 172284, 1378, 2756, 0xc0217a77 -0, 173662, 173662, 1378, 2756, 0x3f643659 -0, 175040, 175040, 1380, 2760, 0x9dbd6002 -0, 176420, 176420, 1378, 2756, 0x94f046fb -0, 177798, 177798, 1378, 2756, 0xab01fb12 -0, 179176, 179176, 1378, 2756, 0x04cffe5c -0, 180554, 180554, 1378, 2756, 0xef661c5e -0, 181932, 181932, 1378, 2756, 0x094c5fc5 -0, 183310, 183310, 1378, 2756, 0xe0c1486a -0, 184688, 184688, 1380, 2760, 0x8c3535b7 -0, 186068, 186068, 1378, 2756, 0x594934aa -0, 187446, 187446, 1378, 2756, 0x74007238 -0, 188824, 188824, 1378, 2756, 0x61f1394d -0, 190202, 190202, 1378, 2756, 0x72584f07 -0, 191580, 191580, 1378, 2756, 0xced9acf9 -0, 192958, 192958, 1378, 2756, 0x7d2e3ea1 -0, 194336, 194336, 1378, 2756, 0x56c06897 -0, 195714, 195714, 1380, 2760, 0x19983bbf -0, 197094, 197094, 1378, 2756, 0x4f884f27 -0, 198472, 198472, 1378, 2756, 0x81ab2f63 -0, 199850, 199850, 1378, 2756, 0x448e681d -0, 201228, 201228, 1378, 2756, 0x0ba9826e -0, 202606, 202606, 1378, 2756, 0x049f36fa -0, 203984, 203984, 1378, 2756, 0x096a2b62 -0, 205362, 205362, 1380, 2760, 0x579e2035 -0, 206742, 206742, 1378, 2756, 0xd13e30e1 -0, 208120, 208120, 1378, 2756, 0x30b6412b -0, 209498, 209498, 1378, 2756, 0xbb1c3268 -0, 210876, 210876, 1378, 2756, 0xbc175b6a -0, 212254, 212254, 1378, 2756, 0xf8d160e2 -0, 213632, 213632, 1378, 2756, 0xc1048154 -0, 215010, 215010, 1380, 2760, 0xb83548f4 -0, 216390, 216390, 1378, 2756, 0x22647962 -0, 217768, 217768, 1378, 2756, 0x14ca54d3 -0, 219146, 219146, 1354, 2708, 0x85e82e8d +0, 5512, 5512, 1379, 2758, 0x983d5ccb +0, 6891, 6891, 1378, 2756, 0x011c51e5 +0, 8269, 8269, 1378, 2756, 0x8c2c198c +0, 9647, 9647, 1378, 2756, 0x2b4a3397 +0, 11025, 11025, 1378, 2756, 0x63794f22 +0, 12403, 12403, 1378, 2756, 0xfc363898 +0, 13781, 13781, 1378, 2756, 0x0da5486e +0, 15159, 15159, 1378, 2756, 0xbae17a5f +0, 16537, 16537, 1379, 2758, 0xdde86dc6 +0, 17916, 17916, 1378, 2756, 0xdfb61002 +0, 19294, 19294, 1378, 2756, 0x15d029da +0, 20672, 20672, 1378, 2756, 0x7bc82012 +0, 22050, 22050, 1378, 2756, 0x002e6999 +0, 23428, 23428, 1378, 2756, 0x96346ba6 +0, 24806, 24806, 1378, 2756, 0x3d54543b +0, 26184, 26184, 1379, 2758, 0x5248862b +0, 27563, 27563, 1378, 2756, 0xf22a5793 +0, 28941, 28941, 1378, 2756, 0x21f54d49 +0, 30319, 30319, 1378, 2756, 0x0c6d4399 +0, 31697, 31697, 1378, 2756, 0x17282f8e +0, 33075, 33075, 1378, 2756, 0xeb698f75 +0, 34453, 34453, 1378, 2756, 0x935e1de2 +0, 35831, 35831, 1379, 2758, 0x31d5425d +0, 37210, 37210, 1378, 2756, 0x485053dc +0, 38588, 38588, 1378, 2756, 0x24c35027 +0, 39966, 39966, 1378, 2756, 0x09f323ee +0, 41344, 41344, 1378, 2756, 0xbc7d58d5 +0, 42722, 42722, 1378, 2756, 0xaefd487c +0, 44100, 44100, 1378, 2756, 0xaca16cc0 +0, 45478, 45478, 1379, 2758, 0xd8745ed3 +0, 46857, 46857, 1378, 2756, 0x5d357141 +0, 48235, 48235, 1378, 2756, 0x65ea2657 +0, 49613, 49613, 1378, 2756, 0xb5e1334a +0, 50991, 50991, 1378, 2756, 0x32cd5d91 +0, 52369, 52369, 1378, 2756, 0xdc23722b +0, 53747, 53747, 1378, 2756, 0x2ba34684 +0, 55125, 55125, 1378, 2756, 0xf9755ba8 +0, 56503, 56503, 1379, 2758, 0xe95c1ca8 +0, 57882, 57882, 1378, 2756, 0xef843aa4 +0, 59260, 59260, 1378, 2756, 0x420442fe +0, 60638, 60638, 1378, 2756, 0x5a0933cb +0, 62016, 62016, 1378, 2756, 0xef5f6d61 +0, 63394, 63394, 1378, 2756, 0xe57e6dc0 +0, 64772, 64772, 1378, 2756, 0xc0f0495a +0, 66150, 66150, 1379, 2758, 0x806e55de +0, 67529, 67529, 1378, 2756, 0x39c2586c +0, 68907, 68907, 1378, 2756, 0x7ffc46e5 +0, 70285, 70285, 1378, 2756, 0xa2766664 +0, 71663, 71663, 1378, 2756, 0xacb50c6c +0, 73041, 73041, 1378, 2756, 0x7f659084 +0, 74419, 74419, 1378, 2756, 0xc72e6a12 +0, 75797, 75797, 1379, 2758, 0x51ab446d +0, 77176, 77176, 1378, 2756, 0x954f45c1 +0, 78554, 78554, 1378, 2756, 0xa9484240 +0, 79932, 79932, 1378, 2756, 0x1d595349 +0, 81310, 81310, 1378, 2756, 0xcf2a565e +0, 82688, 82688, 1378, 2756, 0x391028d5 +0, 84066, 84066, 1378, 2756, 0x348db7ad +0, 85444, 85444, 1379, 2758, 0xfa185e28 +0, 86823, 86823, 1378, 2756, 0xe3635fbe +0, 88201, 88201, 1378, 2756, 0xdcad3654 +0, 89579, 89579, 1378, 2756, 0x5c17abef +0, 90957, 90957, 1378, 2756, 0xb3235184 +0, 92335, 92335, 1378, 2756, 0xdabb64a6 +0, 93713, 93713, 1378, 2756, 0xa95dc58d +0, 95091, 95091, 1379, 2758, 0xfa89c99b +0, 96470, 96470, 1378, 2756, 0x492b658e +0, 97848, 97848, 1378, 2756, 0x377483ab +0, 99226, 99226, 1378, 2756, 0x2c250279 +0, 100604, 100604, 1378, 2756, 0x704dbdb3 +0, 101982, 101982, 1378, 2756, 0x800d7da2 +0, 103360, 103360, 1378, 2756, 0x872aa32e +0, 104738, 104738, 1378, 2756, 0x2d4837fe +0, 106116, 106116, 1379, 2758, 0x7d93a536 +0, 107495, 107495, 1378, 2756, 0x6447d7ef +0, 108873, 108873, 1378, 2756, 0x144f59cc +0, 110251, 110251, 1378, 2756, 0xc667154e +0, 111629, 111629, 1378, 2756, 0xf0de66ae +0, 113007, 113007, 1378, 2756, 0xeabf3c32 +0, 114385, 114385, 1378, 2756, 0xe98e81d1 +0, 115763, 115763, 1379, 2758, 0xa58a57f4 +0, 117142, 117142, 1378, 2756, 0x4fd34c0e +0, 118520, 118520, 1378, 2756, 0x67cf6912 +0, 119898, 119898, 1378, 2756, 0xfa944def +0, 121276, 121276, 1378, 2756, 0xc12f23b2 +0, 122654, 122654, 1378, 2756, 0x5ea325a2 +0, 124032, 124032, 1378, 2756, 0x2b245824 +0, 125410, 125410, 1379, 2758, 0xeb1f5203 +0, 126789, 126789, 1378, 2756, 0xcca34d26 +0, 128167, 128167, 1378, 2756, 0xb5f820d0 +0, 129545, 129545, 1378, 2756, 0x27f24335 +0, 130923, 130923, 1378, 2756, 0x4a9e87b7 +0, 132301, 132301, 1378, 2756, 0xbd076129 +0, 133679, 133679, 1378, 2756, 0x2e0e3f2e +0, 135057, 135057, 1379, 2758, 0x5664442c +0, 136436, 136436, 1378, 2756, 0xca000a2e +0, 137814, 137814, 1378, 2756, 0x87472df3 +0, 139192, 139192, 1378, 2756, 0x16733810 +0, 140570, 140570, 1378, 2756, 0xfa0734b4 +0, 141948, 141948, 1378, 2756, 0x5eff3fc4 +0, 143326, 143326, 1378, 2756, 0xf35346bd +0, 144704, 144704, 1378, 2756, 0xac6411c5 +0, 146082, 146082, 1379, 2758, 0xcfcf3ae7 +0, 147461, 147461, 1378, 2756, 0xebd30bdd +0, 148839, 148839, 1378, 2756, 0xaef95a31 +0, 150217, 150217, 1378, 2756, 0x8aad29d1 +0, 151595, 151595, 1378, 2756, 0x626863f0 +0, 152973, 152973, 1378, 2756, 0x68c05707 +0, 154351, 154351, 1378, 2756, 0x437c5e8d +0, 155729, 155729, 1379, 2758, 0xf7054b53 +0, 157108, 157108, 1378, 2756, 0x62bd4162 +0, 158486, 158486, 1378, 2756, 0x9f744aa4 +0, 159864, 159864, 1378, 2756, 0x0f3f6409 +0, 161242, 161242, 1378, 2756, 0x3fee827a +0, 162620, 162620, 1378, 2756, 0x48a0ac19 +0, 163998, 163998, 1378, 2756, 0x8e4ce0d0 +0, 165376, 165376, 1379, 2758, 0x8a3b207f +0, 166755, 166755, 1378, 2756, 0x0e523255 +0, 168133, 168133, 1378, 2756, 0x84103d30 +0, 169511, 169511, 1378, 2756, 0x13941cde +0, 170889, 170889, 1378, 2756, 0x9fc834c5 +0, 172267, 172267, 1378, 2756, 0xc0217a77 +0, 173645, 173645, 1378, 2756, 0x3f643659 +0, 175023, 175023, 1379, 2758, 0xddac5fc3 +0, 176402, 176402, 1378, 2756, 0x94f046fb +0, 177780, 177780, 1378, 2756, 0xab01fb12 +0, 179158, 179158, 1378, 2756, 0x04cffe5c +0, 180536, 180536, 1378, 2756, 0xef661c5e +0, 181914, 181914, 1378, 2756, 0x094c5fc5 +0, 183292, 183292, 1378, 2756, 0xe0c1486a +0, 184670, 184670, 1379, 2758, 0x21c03448 +0, 186049, 186049, 1378, 2756, 0x594934aa +0, 187427, 187427, 1378, 2756, 0x74007238 +0, 188805, 188805, 1378, 2756, 0x61f1394d +0, 190183, 190183, 1378, 2756, 0x72584f07 +0, 191561, 191561, 1378, 2756, 0xced9acf9 +0, 192939, 192939, 1378, 2756, 0x7d2e3ea1 +0, 194317, 194317, 1378, 2756, 0x56c06897 +0, 195695, 195695, 1379, 2758, 0xa20b3b1b +0, 197074, 197074, 1378, 2756, 0x4f884f27 +0, 198452, 198452, 1378, 2756, 0x81ab2f63 +0, 199830, 199830, 1378, 2756, 0x448e681d +0, 201208, 201208, 1378, 2756, 0x0ba9826e +0, 202586, 202586, 1378, 2756, 0x049f36fa +0, 203964, 203964, 1378, 2756, 0x096a2b62 +0, 205342, 205342, 1379, 2758, 0x17361fbb +0, 206721, 206721, 1378, 2756, 0xd13e30e1 +0, 208099, 208099, 1378, 2756, 0x30b6412b +0, 209477, 209477, 1378, 2756, 0xbb1c3268 +0, 210855, 210855, 1378, 2756, 0xbc175b6a +0, 212233, 212233, 1378, 2756, 0xf8d160e2 +0, 213611, 213611, 1378, 2756, 0xc1048154 +0, 214989, 214989, 1379, 2758, 0x26564885 +0, 216368, 216368, 1378, 2756, 0x22647962 +0, 217746, 217746, 1378, 2756, 0x14ca54d3 +0, 219124, 219124, 1376, 2752, 0x2c374add From patchwork Thu Nov 5 13:48:25 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zane van Iperen X-Patchwork-Id: 23403 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id 91E01448C17 for ; Thu, 5 Nov 2020 15:48:53 +0200 (EET) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 7BAD368B860; Thu, 5 Nov 2020 15:48:53 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from out1.migadu.com (out1.migadu.com [91.121.223.63]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 3398168B205 for ; Thu, 5 Nov 2020 15:48:47 +0200 (EET) X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zanevaniperen.com; s=key1; t=1604584126; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=4TXQOetdugfzMOFZuAVvilJKCZd3kaEzbkmnQriUU3g=; b=t7Ma/Er7Y3KUlV8FP67tbTfZQmc6Ei1KZBBKWaZMBgHTKLVlZhZP73DixjQFyok2KLKf3+ fFsKMlpMId5CpsGjoyJaaEO2fl7Agj+eBnHzhuPlUpRZ1EzaKo3/EENKKVKB5NiVrFSFNp R2fYM5gvaxFPOB8O+R1CW+0qEOhXIIiEQZUffKPd8pOMcAHeg2tApSnzFJSgU/7CFK9Wme k1Vxsw0ylHbAjLG0+eC7HK18Zjm1nsQ/wrTgBe56EIeysLSqSmknUwjkOiPZl3UGOwH3FI Z9+UqVQvg9UVC14GTnAl3y5+WOzAD6KtxT3sH2gxWOKWNQ7w7euO0net2jMCEg== From: Zane van Iperen To: ffmpeg-devel@ffmpeg.org Date: Thu, 5 Nov 2020 23:48:25 +1000 Message-Id: <20201105134827.25564-4-zane@zanevaniperen.com> In-Reply-To: <20201105134827.25564-1-zane@zanevaniperen.com> References: <20201105134827.25564-1-zane@zanevaniperen.com> MIME-Version: 1.0 X-Authenticated-User: git-morningstar@zanevaniperen.com X-Spam-Score: 0.00 Subject: [FFmpeg-devel] [PATCH v4 3/5] avcodec/adpcm_ima_amv: document header format X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 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 Cc: Zane van Iperen Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Signed-off-by: Zane van Iperen --- libavcodec/adpcm.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c index 80ce5b8518..6001a2a4c8 100644 --- a/libavcodec/adpcm.c +++ b/libavcodec/adpcm.c @@ -1693,6 +1693,16 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data, case AV_CODEC_ID_ADPCM_IMA_AMV: av_assert0(avctx->channels == 1); + /* + * Header format: + * int16_t predictor; + * uint8_t step_index; + * uint8_t reserved; + * uint32_t frame_size; + * + * Some implementations have step_index as 16-bits, but others + * only use the lower 8 and store garbage in the upper 8. + */ c->status[0].predictor = sign_extend(bytestream2_get_le16u(&gb), 16); c->status[0].step_index = bytestream2_get_byteu(&gb); bytestream2_skipu(&gb, 5); From patchwork Thu Nov 5 13:48:26 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zane van Iperen X-Patchwork-Id: 23404 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id CE6A4448C17 for ; Thu, 5 Nov 2020 15:48:56 +0200 (EET) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id B62BF68B698; Thu, 5 Nov 2020 15:48:56 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from out1.migadu.com (out1.migadu.com [91.121.223.63]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id A524768B85A for ; Thu, 5 Nov 2020 15:48:49 +0200 (EET) X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zanevaniperen.com; s=key1; t=1604584129; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=aTKpOo+Hwlm5D+yLWDwCW3Bf9tF4OadHDrKm6YEmtLg=; b=HswVbQE/W0C+3n35MZ234HBPQGGVEBhhpsV1HSizQPYsenUfxwGZ4NTYtOmT6E6WH5znlh E6pSbl+gSY0SgjDEj4V4fo+byafQKhQcUCxV0iG1FlP8naPwpuKhOT9LxYx7nER7nRjKQF 0esvDbZaA6XCnFmAxueZPK/tyxyaOYKMbCqZ7ldaqx8FMAz0BtpSqBZ5NB0l27Fu2fO+0l YhO5q6eqCOFcOcetYfeBiLnmNhxwc87LIDsMvEAPlciRxDhqerLKOfJh9PwdijX3BAPtlZ c0a4o09d4Pnmbf8JOdm8zSDfGF8Q8u+P+cYA8Tp1xuBQVORGXr1W2vgmGEtojQ== From: Zane van Iperen To: ffmpeg-devel@ffmpeg.org Date: Thu, 5 Nov 2020 23:48:26 +1000 Message-Id: <20201105134827.25564-5-zane@zanevaniperen.com> In-Reply-To: <20201105134827.25564-1-zane@zanevaniperen.com> References: <20201105134827.25564-1-zane@zanevaniperen.com> MIME-Version: 1.0 X-Authenticated-User: git-morningstar@zanevaniperen.com X-Spam-Score: 0.00 Subject: [FFmpeg-devel] [PATCH v4 4/5] avcodec: add adpcm_ima_amv encoder X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 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 Cc: Zane van Iperen Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Fixes ticket #747. Signed-off-by: Zane van Iperen --- doc/general_contents.texi | 2 +- libavcodec/adpcmenc.c | 58 ++++++++++++++++++++++++++++++++++++++- libavcodec/allcodecs.c | 1 + libavcodec/utils.c | 1 + 4 files changed, 60 insertions(+), 2 deletions(-) diff --git a/doc/general_contents.texi b/doc/general_contents.texi index ab9a6a2a18..7033816b5a 100644 --- a/doc/general_contents.texi +++ b/doc/general_contents.texi @@ -1106,7 +1106,7 @@ following image formats are supported: @item ADPCM Electronic Arts XAS @tab @tab X @item ADPCM G.722 @tab X @tab X @item ADPCM G.726 @tab X @tab X -@item ADPCM IMA AMV @tab @tab X +@item ADPCM IMA AMV @tab X @tab X @tab Used in AMV files @item ADPCM IMA Cunning Developments @tab @tab X @item ADPCM IMA Electronic Arts EACS @tab @tab X diff --git a/libavcodec/adpcmenc.c b/libavcodec/adpcmenc.c index ee13faa4cb..5b58721694 100644 --- a/libavcodec/adpcmenc.c +++ b/libavcodec/adpcmenc.c @@ -74,7 +74,12 @@ static av_cold int adpcm_encode_init(AVCodecContext *avctx) return AVERROR(EINVAL); } - if (s->block_size & (s->block_size - 1)) { + /* + * AMV's block size has to match that of the corresponding video + * stream. Relax the POT requirement. + */ + if (avctx->codec->id != AV_CODEC_ID_ADPCM_IMA_AMV && + (s->block_size & (s->block_size - 1))) { av_log(avctx, AV_LOG_ERROR, "block size must be power of 2\n"); return AVERROR(EINVAL); } @@ -161,6 +166,20 @@ static av_cold int adpcm_encode_init(AVCodecContext *avctx) avctx->frame_size = s->block_size * 2 / avctx->channels; avctx->block_align = s->block_size; break; + case AV_CODEC_ID_ADPCM_IMA_AMV: + if (avctx->sample_rate != 22050) { + av_log(avctx, AV_LOG_ERROR, "Sample rate must be 22050\n"); + return AVERROR(EINVAL); + } + + if (avctx->channels != 1) { + av_log(avctx, AV_LOG_ERROR, "Only mono is supported\n"); + return AVERROR(EINVAL); + } + + avctx->frame_size = s->block_size; + avctx->block_align = 8 + (FFALIGN(avctx->frame_size, 2) / 2); + break; case AV_CODEC_ID_ADPCM_IMA_APM: avctx->frame_size = s->block_size * 2 / avctx->channels; avctx->block_align = s->block_size; @@ -338,6 +357,7 @@ static void adpcm_compress_trellis(AVCodecContext *avctx, nodes[0]->sample2 = c->sample2; if (version == AV_CODEC_ID_ADPCM_IMA_WAV || version == AV_CODEC_ID_ADPCM_IMA_QT || + version == AV_CODEC_ID_ADPCM_IMA_AMV || version == AV_CODEC_ID_ADPCM_SWF) nodes[0]->sample1 = c->prev_sample; if (version == AV_CODEC_ID_ADPCM_MS) @@ -442,6 +462,7 @@ static void adpcm_compress_trellis(AVCodecContext *avctx, } } else if (version == AV_CODEC_ID_ADPCM_IMA_WAV || version == AV_CODEC_ID_ADPCM_IMA_QT || + version == AV_CODEC_ID_ADPCM_IMA_AMV || version == AV_CODEC_ID_ADPCM_SWF) { #define LOOP_NODES(NAME, STEP_TABLE, STEP_INDEX)\ const int predictor = nodes[j]->sample1;\ @@ -834,6 +855,40 @@ static int adpcm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, flush_put_bits(&pb); break; } + case AV_CODEC_ID_ADPCM_IMA_AMV: + { + av_assert0(avctx->channels == 1); + + c->status[0].prev_sample = *samples; + bytestream_put_le16(&dst, c->status[0].prev_sample); + bytestream_put_byte(&dst, c->status[0].step_index); + bytestream_put_byte(&dst, 0); + bytestream_put_le32(&dst, avctx->frame_size); + + if (avctx->trellis > 0) { + n = frame->nb_samples >> 1; + + if (!(buf = av_malloc(2 * n))) + return AVERROR(ENOMEM); + + adpcm_compress_trellis(avctx, samples, buf, &c->status[0], 2 * n, avctx->channels); + for (i = 0; i < n; i++) + bytestream_put_byte(&dst, (buf[2 * i] << 4) | buf[2 * i + 1]); + + samples += 2 * n; + } else for (n = frame->nb_samples >> 1; n > 0; n--) { + int nibble; + nibble = adpcm_ima_compress_sample(&c->status[0], *samples++) << 4; + nibble |= adpcm_ima_compress_sample(&c->status[0], *samples++) & 0x0F; + bytestream_put_byte(&dst, nibble); + } + + if (avctx->frame_size & 1) { + int nibble = adpcm_ima_compress_sample(&c->status[0], *samples++) << 4; + bytestream_put_byte(&dst, nibble); + } + break; + } case AV_CODEC_ID_ADPCM_ARGO: { PutBitContext pb; @@ -927,6 +982,7 @@ AVCodec ff_ ## name_ ## _encoder = { \ } ADPCM_ENCODER(AV_CODEC_ID_ADPCM_ARGO, adpcm_argo, sample_fmts_p, 0, "ADPCM Argonaut Games"); +ADPCM_ENCODER(AV_CODEC_ID_ADPCM_IMA_AMV, adpcm_ima_amv, sample_fmts, 0, "ADPCM IMA AMV"); ADPCM_ENCODER(AV_CODEC_ID_ADPCM_IMA_APM, adpcm_ima_apm, sample_fmts, AV_CODEC_CAP_SMALL_LAST_FRAME, "ADPCM IMA Ubisoft APM"); ADPCM_ENCODER(AV_CODEC_ID_ADPCM_IMA_ALP, adpcm_ima_alp, sample_fmts, AV_CODEC_CAP_SMALL_LAST_FRAME, "ADPCM IMA High Voltage Software ALP"); ADPCM_ENCODER(AV_CODEC_ID_ADPCM_IMA_QT, adpcm_ima_qt, sample_fmts_p, 0, "ADPCM IMA QuickTime"); diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 16fd92b802..8bdc0d6bf7 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -614,6 +614,7 @@ extern AVCodec ff_adpcm_g726_decoder; extern AVCodec ff_adpcm_g726le_encoder; extern AVCodec ff_adpcm_g726le_decoder; extern AVCodec ff_adpcm_ima_amv_decoder; +extern AVCodec ff_adpcm_ima_amv_encoder; extern AVCodec ff_adpcm_ima_alp_decoder; extern AVCodec ff_adpcm_ima_alp_encoder; extern AVCodec ff_adpcm_ima_apc_decoder; diff --git a/libavcodec/utils.c b/libavcodec/utils.c index 008e95c239..c10539593e 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -1491,6 +1491,7 @@ int av_get_exact_bits_per_sample(enum AVCodecID codec_id) case AV_CODEC_ID_ADPCM_ARGO: case AV_CODEC_ID_ADPCM_CT: case AV_CODEC_ID_ADPCM_IMA_ALP: + case AV_CODEC_ID_ADPCM_IMA_AMV: case AV_CODEC_ID_ADPCM_IMA_APC: case AV_CODEC_ID_ADPCM_IMA_APM: case AV_CODEC_ID_ADPCM_IMA_EA_SEAD: From patchwork Thu Nov 5 13:48:27 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zane van Iperen X-Patchwork-Id: 23405 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id 82E61448C17 for ; Thu, 5 Nov 2020 15:48:59 +0200 (EET) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 6C27A68B873; Thu, 5 Nov 2020 15:48:59 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from out1.migadu.com (out1.migadu.com [91.121.223.63]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 274F368B86E for ; Thu, 5 Nov 2020 15:48:52 +0200 (EET) X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zanevaniperen.com; s=key1; t=1604584131; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=fLBkQzAP0+VhwzZybVdAmAuNcMIDzEDSvOcNg8eoNHA=; b=B/0RJ+WfS5fYIG7i6An8cF7sa+qrxN8JFIa2E4/AFL1KbdAiX/TEZan0HyTXkUVcR8JJMT qR+KP3rYjnjt2LlV4JtfsB0CH97UP7sE1uL/B0V79GTkAqHqX6jqBB8s4DhZUO4pG772P7 VbrNvGOWwhb+cXoXj4fXSFPw85pzZq7pJsWU51UsRe81xhqt/LE/B8FYbrtaaohInVKYCm REab7F2kA6sfowv69ilWGNYHntOnS5UDXlS50N6+6BI1a0RE0pBLcz/SgVHwateubMzKbU 0A86S/YdTIfJdypV+yqVoeca7+0AFPsMvQcXcBd/5urna/47Km7voBP5MuL6EA== From: Zane van Iperen To: ffmpeg-devel@ffmpeg.org Date: Thu, 5 Nov 2020 23:48:27 +1000 Message-Id: <20201105134827.25564-6-zane@zanevaniperen.com> In-Reply-To: <20201105134827.25564-1-zane@zanevaniperen.com> References: <20201105134827.25564-1-zane@zanevaniperen.com> MIME-Version: 1.0 X-Authenticated-User: git-morningstar@zanevaniperen.com X-Spam-Score: 0.00 Subject: [FFmpeg-devel] [PATCH v4 5/5] avformat: add amv muxer X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 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 Cc: Zane van Iperen Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" AMV is a hard-coded (and broken) subset of AVI. It's not worth sullying the existing AVI muxer with its filth. Fixes ticket #747. Signed-off-by: Zane van Iperen --- MAINTAINERS | 1 + libavformat/Makefile | 1 + libavformat/allformats.c | 1 + libavformat/amvenc.c | 413 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 416 insertions(+) create mode 100644 libavformat/amvenc.c diff --git a/MAINTAINERS b/MAINTAINERS index 7a4161e2e5..2464f82be3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -394,6 +394,7 @@ Muxers/Demuxers: aiffdec.c Baptiste Coudurier, Matthieu Bouron aiffenc.c Baptiste Coudurier, Matthieu Bouron alp.c Zane van Iperen + amvenc.c Zane van Iperen apm.c Zane van Iperen apngdec.c Benoit Fouet argo_asf.c Zane van Iperen diff --git a/libavformat/Makefile b/libavformat/Makefile index 25bb8b2c69..be5a482b01 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -93,6 +93,7 @@ OBJS-$(CONFIG_AMR_DEMUXER) += amr.o OBJS-$(CONFIG_AMR_MUXER) += amr.o rawenc.o OBJS-$(CONFIG_AMRNB_DEMUXER) += amr.o OBJS-$(CONFIG_AMRWB_DEMUXER) += amr.o +OBJS-$(CONFIG_AMV_MUXER) += amvenc.o OBJS-$(CONFIG_ANM_DEMUXER) += anm.o OBJS-$(CONFIG_APC_DEMUXER) += apc.o OBJS-$(CONFIG_APE_DEMUXER) += ape.o apetag.o img2.o diff --git a/libavformat/allformats.c b/libavformat/allformats.c index 9b1b611a49..53e5374255 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -54,6 +54,7 @@ extern AVInputFormat ff_amr_demuxer; extern AVOutputFormat ff_amr_muxer; extern AVInputFormat ff_amrnb_demuxer; extern AVInputFormat ff_amrwb_demuxer; +extern AVOutputFormat ff_amv_muxer; extern AVInputFormat ff_anm_demuxer; extern AVInputFormat ff_apc_demuxer; extern AVInputFormat ff_ape_demuxer; diff --git a/libavformat/amvenc.c b/libavformat/amvenc.c new file mode 100644 index 0000000000..4d4ec7a2b1 --- /dev/null +++ b/libavformat/amvenc.c @@ -0,0 +1,413 @@ +/* + * AMV muxer + * + * Copyright (C) 2020 Zane van Iperen (zane@zanevaniperen.com) + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "avformat.h" +#include "riff.h" +#include "internal.h" +#include "avio_internal.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/avassert.h" + +/* + * Things to note: + * - AMV is a hard-coded (and broken) subset of AVI. It's not worth sullying the + * existing AVI muxer with its filth. + * - No separate demuxer as the existing AVI demuxer can handle these. + * - The sizes of certain tags are deliberately set to 0 as some players break + * when they're set correctly. Ditto with some header fields. + * - There is no index. + * - Players are **very** sensitive to the frame order and sizes. + * - Frames must be strictly interleaved as V-A, any V-V or A-A will + * cause crashes. + * - Variable video frame sizes seem to be handled fine. + * - Variable audio frame sizes cause crashes. + * - If audio is shorter than video, it's padded with silence. + * - If video is shorter than audio, the most recent frame is repeated. + */ + +#define AMV_STREAM_COUNT 2 +#define AMV_STREAM_VIDEO 0 +#define AMV_STREAM_AUDIO 1 +#define AMV_VIDEO_STRH_SIZE 56 +#define AMV_VIDEO_STRF_SIZE 36 +#define AMV_AUDIO_STRH_SIZE 48 +#define AMV_AUDIO_STRF_SIZE 20 /* sizeof(WAVEFORMATEX) + 2 */ + +typedef struct AMVContext +{ + int64_t riff_start; + int64_t movi_list; + int64_t offset_duration; + int last_stream; + + int32_t us_per_frame; /* Microseconds per frame. */ + + int32_t aframe_size; /* Expected audio frame size. */ + int32_t ablock_align; /* Expected audio block align. */ + AVPacket apad; /* Dummy audio packet for padding. */ + AVPacket vpad; /* Most recent video frame, for padding. */ + + /* + * Cumulative PTS values for each stream, used for the final + * duration calculcation. + */ + int64_t lastpts[AMV_STREAM_COUNT]; +} AMVContext; + +/* ff_{start,end}_tag(), but sets the size to 0. */ +static int64_t amv_start_tag(AVIOContext *pb, const char *tag) +{ + ffio_wfourcc(pb, tag); + avio_wl32(pb, 0); + return avio_tell(pb); +} + +static void amv_end_tag(AVIOContext *pb, int64_t start) +{ + int64_t pos; + av_assert0((start&1) == 0); + + pos = avio_tell(pb); + if (pos & 1) + avio_w8(pb, 0); +} + +static av_cold int amv_init(AVFormatContext *s) +{ + AMVContext *amv = s->priv_data; + AVStream *vst, *ast; + int ret; + + amv->last_stream = -1; + + if (s->nb_streams != AMV_STREAM_COUNT) { + av_log(s, AV_LOG_ERROR, "AMV files only support 2 streams\n"); + return AVERROR(EINVAL); + } + + vst = s->streams[AMV_STREAM_VIDEO]; + ast = s->streams[AMV_STREAM_AUDIO]; + + if (vst->codecpar->codec_id != AV_CODEC_ID_AMV) { + av_log(s, AV_LOG_ERROR, "First AMV stream must be %s\n", + avcodec_get_name(AV_CODEC_ID_AMV)); + return AVERROR(EINVAL); + } + + if (ast->codecpar->codec_id != AV_CODEC_ID_ADPCM_IMA_AMV) { + av_log(s, AV_LOG_ERROR, "Second AMV stream must be %s\n", + avcodec_get_name(AV_CODEC_ID_ADPCM_IMA_AMV)); + return AVERROR(EINVAL); + } + + /* These files are broken-enough as they are. They shouldn't be streamed. */ + if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL)) { + av_log(s, AV_LOG_ERROR, "Stream not seekable, unable to write output file\n"); + return AVERROR(EINVAL); + } + + amv->us_per_frame = av_rescale(AV_TIME_BASE, vst->time_base.num, vst->time_base.den); + amv->aframe_size = av_rescale(ast->codecpar->sample_rate, amv->us_per_frame, AV_TIME_BASE); + amv->ablock_align = 8 + (FFALIGN(amv->aframe_size, 2) / 2); + + av_log(s, AV_LOG_TRACE, "us_per_frame = %d\n", amv->us_per_frame); + av_log(s, AV_LOG_TRACE, "aframe_size = %d\n", amv->aframe_size); + av_log(s, AV_LOG_TRACE, "ablock_align = %d\n", amv->ablock_align); + + /* + * Bail if the framerate's too high. Prevents the audio frame size from + * getting too small. 63fps is the closest value to 60fps that divides + * cleanly, so cap it there. + */ + if (amv->us_per_frame < 15873) { + av_log(s, AV_LOG_ERROR, "Refusing to mux >63fps video\n"); + return AVERROR(EINVAL); + } + + /* + * frame_size will be set if coming from the encoder. + * Make sure the its been configured correctly. The audio frame duration + * needs to match that of the video. + */ + if (ast->codecpar->frame_size) { + AVCodecParameters *par = ast->codecpar; + int bad = 0; + + if (par->frame_size != amv->aframe_size) { + av_log(s, AV_LOG_ERROR, "Invalid audio frame size. Got %d, wanted %d\n", + par->frame_size, amv->aframe_size); + bad = 1; + } + + if (par->block_align != amv->ablock_align) { + av_log(s, AV_LOG_ERROR, "Invalid audio block align. Got %d, wanted %d\n", + par->block_align, amv->ablock_align); + bad = 1; + } + + if (bad) { + av_log(s, AV_LOG_ERROR, "Try -block_size %d\n", amv->aframe_size); + return AVERROR(EINVAL); + } + + if (ast->codecpar->sample_rate % amv->aframe_size) { + av_log(s, AV_LOG_ERROR, "Audio sample rate not a multiple of the frame size.\n" + "Please change video frame rate. Suggested rates: 10,14,15,18,21,25,30\n"); + return AVERROR(EINVAL); + } + } else { + /* If remuxing from the same source, then this will match the video. */ + int32_t aus = av_rescale(AV_TIME_BASE, ast->time_base.num, ast->time_base.den); + if (aus != amv->us_per_frame) { + av_log(s, AV_LOG_ERROR, "Cannot remux streams with a different time base\n"); + return AVERROR(EINVAL); + } + } + + /* Allocate and fill dummy packet so we can pad the audio. */ + if ((ret = av_new_packet(&amv->apad, amv->ablock_align)) < 0) + return ret; + + amv->apad.stream_index = AMV_STREAM_AUDIO; + memset(amv->apad.data, 0, amv->ablock_align); + AV_WL32(amv->apad.data + 4, amv->aframe_size); + + av_init_packet(&amv->vpad); + amv->vpad.stream_index = AMV_STREAM_VIDEO; + amv->vpad.duration = 1; + return 0; +} + +static void amv_deinit(AVFormatContext *s) +{ + AMVContext *amv = s->priv_data; + + av_packet_unref(&amv->apad); + av_packet_unref(&amv->vpad); +} + +static void amv_write_vlist(AVFormatContext *s, AVCodecParameters *par) +{ + int64_t tag_list, tag_str; + + av_assert0(par->codec_id == AV_CODEC_ID_AMV); + + tag_list = amv_start_tag(s->pb, "LIST"); + ffio_wfourcc(s->pb, "strl"); + tag_str = ff_start_tag(s->pb, "strh"); + ffio_fill(s->pb, 0, AMV_VIDEO_STRH_SIZE); + ff_end_tag(s->pb, tag_str); + + tag_str = ff_start_tag(s->pb, "strf"); + ffio_fill(s->pb, 0, AMV_VIDEO_STRF_SIZE); + ff_end_tag(s->pb, tag_str); + + amv_end_tag(s->pb, tag_list); +} + +static void amv_write_alist(AVFormatContext *s, AVCodecParameters *par) +{ + uint8_t buf[AMV_AUDIO_STRF_SIZE]; + AVIOContext *pb = s->pb; + int64_t tag_list, tag_str; + + av_assert0(par->codec_id == AV_CODEC_ID_ADPCM_IMA_AMV); + + tag_list = amv_start_tag(pb, "LIST"); + ffio_wfourcc(pb, "strl"); + tag_str = ff_start_tag(pb, "strh"); + ffio_fill(s->pb, 0, AMV_AUDIO_STRH_SIZE); + ff_end_tag(pb, tag_str); + + /* Bodge an (incorrect) WAVEFORMATEX (+2 pad bytes) */ + tag_str = ff_start_tag(pb, "strf"); + AV_WL16(buf + 0, 1); + AV_WL16(buf + 2, par->channels); + AV_WL32(buf + 4, par->sample_rate); + AV_WL32(buf + 8, par->sample_rate * par->channels * 2); + AV_WL16(buf + 12, 2); + AV_WL16(buf + 14, 16); + AV_WL16(buf + 16, 0); + AV_WL16(buf + 18, 0); + avio_write(pb, buf, AMV_AUDIO_STRF_SIZE); + ff_end_tag(pb, tag_str); + + amv_end_tag(pb, tag_list); +} + +static int amv_write_header(AVFormatContext *s) +{ + AMVContext *amv = s->priv_data; + AVIOContext *pb = s->pb; + AVStream *vst = s->streams[AMV_STREAM_VIDEO]; + AVStream *ast = s->streams[AMV_STREAM_AUDIO]; + uint8_t amvh[56] = {0}; + int64_t list1; + + amv->riff_start = amv_start_tag(pb, "RIFF"); + ffio_wfourcc(pb, "AMV "); + list1 = amv_start_tag(pb, "LIST"); + ffio_wfourcc(pb, "hdrl"); + + ffio_wfourcc(pb, "amvh"); + avio_wl32(pb, 56); + + AV_WL32(amvh + 0, amv->us_per_frame); + AV_WL32(amvh + 32, vst->codecpar->width); + AV_WL32(amvh + 36, vst->codecpar->height); + AV_WL32(amvh + 40, vst->time_base.den); + AV_WL32(amvh + 44, vst->time_base.num); + AV_WL32(amvh + 48, 0); + AV_WL32(amvh + 52, 0); /* duration, filled in later. */ + + avio_write(pb, amvh, sizeof(amvh)); + amv->offset_duration = avio_tell(pb) - 4; + + amv_write_vlist(s, vst->codecpar); + amv_write_alist(s, ast->codecpar); + amv_end_tag(pb, list1); + + amv->movi_list = amv_start_tag(pb, "LIST"); + ffio_wfourcc(pb, "movi"); + return 0; +} + +static int amv_write_packet_internal(AVFormatContext *s, AVPacket *pkt) +{ + AMVContext *amv = s->priv_data; + + if (pkt->stream_index == AMV_STREAM_VIDEO) + ffio_wfourcc(s->pb, "00dc"); + else if (pkt->stream_index == AMV_STREAM_AUDIO) + ffio_wfourcc(s->pb, "01wb"); + else + av_assert0(0); + + if (pkt->stream_index == AMV_STREAM_AUDIO && pkt->size != amv->ablock_align) { + /* Can happen when remuxing files produced by another encoder. */ + av_log(s, AV_LOG_WARNING, "Invalid audio packet size (%d != %d)\n", + pkt->size, amv->ablock_align); + } + + avio_wl32(s->pb, pkt->size); + avio_write(s->pb, pkt->data, pkt->size); + + amv->lastpts[pkt->stream_index] += pkt->duration; + amv->last_stream = pkt->stream_index; + return 0; +} + +static int amv_pad(AVFormatContext *s, AVPacket *pkt) +{ + AMVContext *amv = s->priv_data; + int stream_index = pkt->stream_index; + + if (stream_index != amv->last_stream) + return 0; + + stream_index = (stream_index + 1) % s->nb_streams; + if (stream_index == AMV_STREAM_VIDEO) + return amv_write_packet_internal(s, &amv->vpad); + else if (stream_index == AMV_STREAM_AUDIO) + return amv_write_packet_internal(s, &amv->apad); + else + av_assert0(0); + + return AVERROR(EINVAL); +} + +static int amv_write_packet(AVFormatContext *s, AVPacket *pkt) +{ + AMVContext *amv = s->priv_data; + int ret; + + /* Add a dummy frame if we've received two of the same index. */ + if ((ret = amv_pad(s, pkt)) < 0) + return ret; + + if ((ret = amv_write_packet_internal(s, pkt)) < 0) + return ret; + + if (pkt->stream_index == AMV_STREAM_VIDEO) { + /* Save the last packet for padding. */ + av_packet_unref(&amv->vpad); + if ((ret = av_packet_ref(&amv->vpad, pkt)) < 0) + return ret; + } + + return 0; +} + +static int amv_write_trailer(AVFormatContext *s) +{ + AMVContext *amv = s->priv_data; + AVStream *vst = s->streams[AMV_STREAM_VIDEO]; + AVStream *ast = s->streams[AMV_STREAM_AUDIO]; + int64_t maxpts, ret; + int hh, mm, ss; + + /* Pad-out one last audio frame if needed. */ + if (amv->last_stream == AMV_STREAM_VIDEO) { + if ((ret = amv_write_packet_internal(s, &amv->apad)) < 0) + return ret; + } + + amv_end_tag(s->pb, amv->movi_list); + amv_end_tag(s->pb, amv->riff_start); + + ffio_wfourcc(s->pb, "AMV_"); + ffio_wfourcc(s->pb, "END_"); + + if ((ret = avio_seek(s->pb, amv->offset_duration, SEEK_SET)) < 0) + return ret; + + /* Go back and write the duration. */ + maxpts = FFMAX( + av_rescale_q(amv->lastpts[AMV_STREAM_VIDEO], vst->time_base, AV_TIME_BASE_Q), + av_rescale_q(amv->lastpts[AMV_STREAM_AUDIO], ast->time_base, AV_TIME_BASE_Q) + ); + + ss = maxpts / AV_TIME_BASE; + mm = ss / 60; + hh = mm / 60; + ss %= 60; + mm %= 60; + + avio_w8(s->pb, ss); + avio_w8(s->pb, mm); + avio_wl16(s->pb, hh); + return 0; +} + +AVOutputFormat ff_amv_muxer = { + .name = "amv", + .long_name = NULL_IF_CONFIG_SMALL("AMV"), + .mime_type = "video/amv", + .extensions = "amv", + .priv_data_size = sizeof(AMVContext), + .audio_codec = AV_CODEC_ID_ADPCM_IMA_AMV, + .video_codec = AV_CODEC_ID_AMV, + .init = amv_init, + .deinit = amv_deinit, + .write_header = amv_write_header, + .write_packet = amv_write_packet, + .write_trailer = amv_write_trailer, +};