1/* 2 * HCOM audio decoder 3 * 4 * This file is part of FFmpeg. 5 * 6 * FFmpeg is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * FFmpeg is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with FFmpeg; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 21#include "libavutil/intreadwrite.h" 22 23#include "avcodec.h" 24#include "codec_internal.h" 25#include "get_bits.h" 26#include "internal.h" 27 28typedef struct HEntry { 29 int16_t l, r; 30} HEntry; 31 32typedef struct HCOMContext { 33 AVCodecContext *avctx; 34 35 uint8_t first_sample; 36 uint8_t sample; 37 int dict_entries; 38 int dict_entry; 39 int delta_compression; 40 41 HEntry *dict; 42} HCOMContext; 43 44static av_cold int hcom_init(AVCodecContext *avctx) 45{ 46 HCOMContext *s = avctx->priv_data; 47 48 if (avctx->ch_layout.nb_channels != 1) { 49 av_log(avctx, AV_LOG_ERROR, "invalid number of channels\n"); 50 return AVERROR_INVALIDDATA; 51 } 52 53 if (avctx->extradata_size <= 7) 54 return AVERROR_INVALIDDATA; 55 s->dict_entries = AV_RB16(avctx->extradata); 56 if (avctx->extradata_size < s->dict_entries * 4 + 7 || 57 s->dict_entries == 0) 58 return AVERROR_INVALIDDATA; 59 s->delta_compression = AV_RB32(avctx->extradata + 2); 60 s->sample = s->first_sample = avctx->extradata[avctx->extradata_size - 1]; 61 62 s->dict = av_calloc(s->dict_entries, sizeof(*s->dict)); 63 if (!s->dict) 64 return AVERROR(ENOMEM); 65 for (int i = 0; i < s->dict_entries; i++) { 66 s->dict[i].l = AV_RB16(avctx->extradata + 6 + 4 * i); 67 s->dict[i].r = AV_RB16(avctx->extradata + 6 + 4 * i + 2); 68 if (s->dict[i].l >= 0 && 69 (s->dict[i].l >= s->dict_entries || 70 s->dict[i].r >= s->dict_entries || 71 s->dict[i].r < 0 )) 72 return AVERROR_INVALIDDATA; 73 } 74 if (s->dict[0].l < 0) 75 return AVERROR_INVALIDDATA; 76 77 avctx->sample_fmt = AV_SAMPLE_FMT_U8; 78 s->dict_entry = 0; 79 80 return 0; 81} 82 83static int hcom_decode(AVCodecContext *avctx, AVFrame *frame, 84 int *got_frame, AVPacket *pkt) 85{ 86 HCOMContext *s = avctx->priv_data; 87 GetBitContext gb; 88 int ret, n = 0; 89 90 if (pkt->size > INT16_MAX) 91 return AVERROR_INVALIDDATA; 92 93 frame->nb_samples = pkt->size * 8; 94 if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) 95 return ret; 96 97 if ((ret = init_get_bits8(&gb, pkt->data, pkt->size)) < 0) 98 return ret; 99 100 while (get_bits_left(&gb) > 0) { 101 if (get_bits1(&gb)) 102 s->dict_entry = s->dict[s->dict_entry].r; 103 else 104 s->dict_entry = s->dict[s->dict_entry].l; 105 106 if (s->dict[s->dict_entry].l < 0) { 107 int16_t datum; 108 109 datum = s->dict[s->dict_entry].r; 110 111 if (!s->delta_compression) 112 s->sample = 0; 113 s->sample = (s->sample + datum) & 0xFF; 114 115 frame->data[0][n++] = s->sample; 116 117 s->dict_entry = 0; 118 } 119 } 120 121 frame->nb_samples = n; 122 123 *got_frame = 1; 124 125 return pkt->size; 126} 127 128static av_cold int hcom_close(AVCodecContext *avctx) 129{ 130 HCOMContext *s = avctx->priv_data; 131 132 av_freep(&s->dict); 133 134 return 0; 135} 136 137const FFCodec ff_hcom_decoder = { 138 .p.name = "hcom", 139 .p.long_name = NULL_IF_CONFIG_SMALL("HCOM Audio"), 140 .p.type = AVMEDIA_TYPE_AUDIO, 141 .p.id = AV_CODEC_ID_HCOM, 142 .priv_data_size = sizeof(HCOMContext), 143 .init = hcom_init, 144 .close = hcom_close, 145 FF_CODEC_DECODE_CB(hcom_decode), 146 .p.capabilities = AV_CODEC_CAP_DR1, 147 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, 148}; 149