diff mbox

[FFmpeg-devel,1/2] avcodec: add HCOM decoder

Message ID 20190102185338.4910-1-onemda@gmail.com
State Accepted
Headers show

Commit Message

Paul B Mahol Jan. 2, 2019, 6:53 p.m. UTC
Signed-off-by: Paul B Mahol <onemda@gmail.com>
---
 libavcodec/Makefile     |   1 +
 libavcodec/allcodecs.c  |   1 +
 libavcodec/avcodec.h    |   1 +
 libavcodec/codec_desc.c |   7 ++
 libavcodec/hcom.c       | 137 ++++++++++++++++++++++++++++++++++++++++
 5 files changed, 147 insertions(+)
 create mode 100644 libavcodec/hcom.c

Comments

James Almer Jan. 2, 2019, 7:17 p.m. UTC | #1
On 1/2/2019 3:53 PM, Paul B Mahol wrote:
> Signed-off-by: Paul B Mahol <onemda@gmail.com>
> ---
>  libavcodec/Makefile     |   1 +
>  libavcodec/allcodecs.c  |   1 +
>  libavcodec/avcodec.h    |   1 +
>  libavcodec/codec_desc.c |   7 ++
>  libavcodec/hcom.c       | 137 ++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 147 insertions(+)
>  create mode 100644 libavcodec/hcom.c
> 
> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> index 99799ceed2..bf746c143d 100644
> --- a/libavcodec/Makefile
> +++ b/libavcodec/Makefile
> @@ -362,6 +362,7 @@ OBJS-$(CONFIG_H264_V4L2M2M_DECODER)    += v4l2_m2m_dec.o
>  OBJS-$(CONFIG_H264_V4L2M2M_ENCODER)    += v4l2_m2m_enc.o
>  OBJS-$(CONFIG_HAP_DECODER)             += hapdec.o hap.o
>  OBJS-$(CONFIG_HAP_ENCODER)             += hapenc.o hap.o
> +OBJS-$(CONFIG_HCOM_DECODER)            += hcom.o
>  OBJS-$(CONFIG_HEVC_DECODER)            += hevcdec.o hevc_mvs.o \
>                                            hevc_cabac.o hevc_refs.o hevcpred.o    \
>                                            hevcdsp.o hevc_filter.o hevc_data.o
> diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
> index 4755af71b2..fe0376e27e 100644
> --- a/libavcodec/allcodecs.c
> +++ b/libavcodec/allcodecs.c
> @@ -424,6 +424,7 @@ extern AVCodec ff_g723_1_decoder;
>  extern AVCodec ff_g729_decoder;
>  extern AVCodec ff_gsm_decoder;
>  extern AVCodec ff_gsm_ms_decoder;
> +extern AVCodec ff_hcom_decoder;
>  extern AVCodec ff_iac_decoder;
>  extern AVCodec ff_ilbc_decoder;
>  extern AVCodec ff_imc_decoder;
> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
> index 92567ec6d0..e92d7accf4 100644
> --- a/libavcodec/avcodec.h
> +++ b/libavcodec/avcodec.h
> @@ -646,6 +646,7 @@ enum AVCodecID {
>      AV_CODEC_ID_APTX_HD,
>      AV_CODEC_ID_SBC,
>      AV_CODEC_ID_ATRAC9,
> +    AV_CODEC_ID_HCOM,
>  
>      /* subtitle codecs */
>      AV_CODEC_ID_FIRST_SUBTITLE = 0x17000,          ///< A dummy ID pointing at the start of subtitle codecs.
> diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
> index 2363a53283..10a639101c 100644
> --- a/libavcodec/codec_desc.c
> +++ b/libavcodec/codec_desc.c
> @@ -2943,6 +2943,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
>          .long_name = NULL_IF_CONFIG_SMALL("ATRAC9 (Adaptive TRansform Acoustic Coding 9)"),
>          .props     = AV_CODEC_PROP_LOSSY,
>      },
> +    {
> +        .id        = AV_CODEC_ID_HCOM,
> +        .type      = AVMEDIA_TYPE_AUDIO,
> +        .name      = "hcom",
> +        .long_name = NULL_IF_CONFIG_SMALL("HCOM Audio"),
> +        .props     = AV_CODEC_PROP_LOSSY,
> +    },
>  
>      /* subtitle codecs */
>      {
> diff --git a/libavcodec/hcom.c b/libavcodec/hcom.c
> new file mode 100644
> index 0000000000..e516d20a94
> --- /dev/null
> +++ b/libavcodec/hcom.c
> @@ -0,0 +1,137 @@
> +/*
> + * HCOM audio decoder
> + *
> + * 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 "libavutil/intreadwrite.h"
> +
> +#include "avcodec.h"
> +#include "bytestream.h"
> +#include "internal.h"
> +
> +typedef struct HEntry {
> +    int16_t l, r;
> +} HEntry;
> +
> +typedef struct HCOMContext {
> +    AVCodecContext *avctx;
> +
> +    uint8_t first_sample;
> +    uint8_t sample;
> +    int dict_entries;
> +    int dict_entry;
> +    int delta_compression;
> +
> +    HEntry *dict;
> +} HCOMContext;
> +
> +static av_cold int hcom_init(AVCodecContext *avctx)
> +{
> +    HCOMContext *s = avctx->priv_data;
> +
> +    if (avctx->channels != 1) {
> +        av_log(avctx, AV_LOG_ERROR, "invalid number of channels\n");
> +        return AVERROR_INVALIDDATA;
> +    }
> +
> +    if (avctx->extradata_size <= 7)
> +        return AVERROR_INVALIDDATA;
> +    s->dict_entries = AV_RB16(avctx->extradata);
> +    if (avctx->extradata_size < s->dict_entries * 4 + 7)
> +        return AVERROR_INVALIDDATA;
> +    s->delta_compression = AV_RB32(avctx->extradata + 2);
> +    s->sample = s->first_sample = avctx->extradata[avctx->extradata_size - 1];
> +
> +    s->dict = av_calloc(s->dict_entries, sizeof(*s->dict));

You're never freeing this.

> +    if (!s->dict)
> +        return AVERROR(ENOMEM);
> +    for (int i = 0; i < s->dict_entries; i++) {
> +        s->dict[i].l = AV_RB16(avctx->extradata + 6 + 4 * i);
> +        s->dict[i].r = AV_RB16(avctx->extradata + 6 + 4 * i + 2);
> +    }
> +
> +    avctx->sample_fmt = AV_SAMPLE_FMT_U8;
> +    s->dict_entry = 0;
> +
> +    return 0;
> +}
> +
> +static int hcom_decode(AVCodecContext *avctx, void *data,
> +                       int *got_frame, AVPacket *pkt)
> +{
> +    HCOMContext *s = avctx->priv_data;
> +    AVFrame *frame = data;
> +    GetByteContext gb;
> +    uint32_t current;
> +    int ret, n = 0;
> +
> +    if (pkt->size > INT16_MAX)
> +        return AVERROR_INVALIDDATA;
> +
> +    frame->nb_samples = pkt->size * 8;
> +    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
> +        return ret;
> +
> +    bytestream2_init(&gb, pkt->data, pkt->size);
> +    while (bytestream2_get_bytes_left(&gb) >= 4) {
> +        int bits = 32;
> +
> +        current = bytestream2_get_be32(&gb);
> +
> +        while (bits-- > 0) {
> +
> +            if (current & 0x80000000) {
> +                s->dict_entry = s->dict[s->dict_entry].r;
> +            } else {
> +                s->dict_entry = s->dict[s->dict_entry].l;
> +            }
> +
> +            current = current << 1;
> +            if (s->dict[s->dict_entry].l < 0) {
> +                int16_t datum;
> +
> +                datum = s->dict[s->dict_entry].r;
> +
> +                if (!s->delta_compression)
> +                    s->sample = 0;
> +                s->sample = (s->sample + datum) & 0xFF;
> +
> +                frame->data[0][n++] = s->sample;
> +
> +                s->dict_entry = 0;
> +            }
> +        }
> +    }
> +
> +    frame->nb_samples = n;
> +
> +    *got_frame = 1;
> +
> +    return pkt->size;
> +}
> +
> +AVCodec ff_hcom_decoder = {
> +    .name           = "hcom",
> +    .long_name      = NULL_IF_CONFIG_SMALL("HCOM Audio"),
> +    .type           = AVMEDIA_TYPE_AUDIO,
> +    .id             = AV_CODEC_ID_HCOM,
> +    .priv_data_size = sizeof(HCOMContext),
> +    .init           = hcom_init,
> +    .decode         = hcom_decode,
> +    .capabilities   = AV_CODEC_CAP_DR1,
> +};
>
Paul B Mahol Jan. 2, 2019, 8:53 p.m. UTC | #2
On 1/2/19, James Almer <jamrial@gmail.com> wrote:
> On 1/2/2019 3:53 PM, Paul B Mahol wrote:
>> Signed-off-by: Paul B Mahol <onemda@gmail.com>
>> ---
>>  libavcodec/Makefile     |   1 +
>>  libavcodec/allcodecs.c  |   1 +
>>  libavcodec/avcodec.h    |   1 +
>>  libavcodec/codec_desc.c |   7 ++
>>  libavcodec/hcom.c       | 137 ++++++++++++++++++++++++++++++++++++++++
>>  5 files changed, 147 insertions(+)
>>  create mode 100644 libavcodec/hcom.c
>>
>> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
>> index 99799ceed2..bf746c143d 100644
>> --- a/libavcodec/Makefile
>> +++ b/libavcodec/Makefile
>> @@ -362,6 +362,7 @@ OBJS-$(CONFIG_H264_V4L2M2M_DECODER)    +=
>> v4l2_m2m_dec.o
>>  OBJS-$(CONFIG_H264_V4L2M2M_ENCODER)    += v4l2_m2m_enc.o
>>  OBJS-$(CONFIG_HAP_DECODER)             += hapdec.o hap.o
>>  OBJS-$(CONFIG_HAP_ENCODER)             += hapenc.o hap.o
>> +OBJS-$(CONFIG_HCOM_DECODER)            += hcom.o
>>  OBJS-$(CONFIG_HEVC_DECODER)            += hevcdec.o hevc_mvs.o \
>>                                            hevc_cabac.o hevc_refs.o
>> hevcpred.o    \
>>                                            hevcdsp.o hevc_filter.o
>> hevc_data.o
>> diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
>> index 4755af71b2..fe0376e27e 100644
>> --- a/libavcodec/allcodecs.c
>> +++ b/libavcodec/allcodecs.c
>> @@ -424,6 +424,7 @@ extern AVCodec ff_g723_1_decoder;
>>  extern AVCodec ff_g729_decoder;
>>  extern AVCodec ff_gsm_decoder;
>>  extern AVCodec ff_gsm_ms_decoder;
>> +extern AVCodec ff_hcom_decoder;
>>  extern AVCodec ff_iac_decoder;
>>  extern AVCodec ff_ilbc_decoder;
>>  extern AVCodec ff_imc_decoder;
>> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
>> index 92567ec6d0..e92d7accf4 100644
>> --- a/libavcodec/avcodec.h
>> +++ b/libavcodec/avcodec.h
>> @@ -646,6 +646,7 @@ enum AVCodecID {
>>      AV_CODEC_ID_APTX_HD,
>>      AV_CODEC_ID_SBC,
>>      AV_CODEC_ID_ATRAC9,
>> +    AV_CODEC_ID_HCOM,
>>
>>      /* subtitle codecs */
>>      AV_CODEC_ID_FIRST_SUBTITLE = 0x17000,          ///< A dummy ID
>> pointing at the start of subtitle codecs.
>> diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
>> index 2363a53283..10a639101c 100644
>> --- a/libavcodec/codec_desc.c
>> +++ b/libavcodec/codec_desc.c
>> @@ -2943,6 +2943,13 @@ static const AVCodecDescriptor codec_descriptors[]
>> = {
>>          .long_name = NULL_IF_CONFIG_SMALL("ATRAC9 (Adaptive TRansform
>> Acoustic Coding 9)"),
>>          .props     = AV_CODEC_PROP_LOSSY,
>>      },
>> +    {
>> +        .id        = AV_CODEC_ID_HCOM,
>> +        .type      = AVMEDIA_TYPE_AUDIO,
>> +        .name      = "hcom",
>> +        .long_name = NULL_IF_CONFIG_SMALL("HCOM Audio"),
>> +        .props     = AV_CODEC_PROP_LOSSY,
>> +    },
>>
>>      /* subtitle codecs */
>>      {
>> diff --git a/libavcodec/hcom.c b/libavcodec/hcom.c
>> new file mode 100644
>> index 0000000000..e516d20a94
>> --- /dev/null
>> +++ b/libavcodec/hcom.c
>> @@ -0,0 +1,137 @@
>> +/*
>> + * HCOM audio decoder
>> + *
>> + * 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 "libavutil/intreadwrite.h"
>> +
>> +#include "avcodec.h"
>> +#include "bytestream.h"
>> +#include "internal.h"
>> +
>> +typedef struct HEntry {
>> +    int16_t l, r;
>> +} HEntry;
>> +
>> +typedef struct HCOMContext {
>> +    AVCodecContext *avctx;
>> +
>> +    uint8_t first_sample;
>> +    uint8_t sample;
>> +    int dict_entries;
>> +    int dict_entry;
>> +    int delta_compression;
>> +
>> +    HEntry *dict;
>> +} HCOMContext;
>> +
>> +static av_cold int hcom_init(AVCodecContext *avctx)
>> +{
>> +    HCOMContext *s = avctx->priv_data;
>> +
>> +    if (avctx->channels != 1) {
>> +        av_log(avctx, AV_LOG_ERROR, "invalid number of channels\n");
>> +        return AVERROR_INVALIDDATA;
>> +    }
>> +
>> +    if (avctx->extradata_size <= 7)
>> +        return AVERROR_INVALIDDATA;
>> +    s->dict_entries = AV_RB16(avctx->extradata);
>> +    if (avctx->extradata_size < s->dict_entries * 4 + 7)
>> +        return AVERROR_INVALIDDATA;
>> +    s->delta_compression = AV_RB32(avctx->extradata + 2);
>> +    s->sample = s->first_sample = avctx->extradata[avctx->extradata_size
>> - 1];
>> +
>> +    s->dict = av_calloc(s->dict_entries, sizeof(*s->dict));
>
> You're never freeing this.
>

Fixed locally.
James Almer Jan. 2, 2019, 9:12 p.m. UTC | #3
On 1/2/2019 3:53 PM, Paul B Mahol wrote:
> +static int hcom_decode(AVCodecContext *avctx, void *data,
> +                       int *got_frame, AVPacket *pkt)
> +{
> +    HCOMContext *s = avctx->priv_data;
> +    AVFrame *frame = data;
> +    GetByteContext gb;
> +    uint32_t current;
> +    int ret, n = 0;
> +
> +    if (pkt->size > INT16_MAX)
> +        return AVERROR_INVALIDDATA;
> +
> +    frame->nb_samples = pkt->size * 8;
> +    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
> +        return ret;
> +
> +    bytestream2_init(&gb, pkt->data, pkt->size);
> +    while (bytestream2_get_bytes_left(&gb) >= 4) {
> +        int bits = 32;
> +
> +        current = bytestream2_get_be32(&gb);
> +
> +        while (bits-- > 0) {
> +
> +            if (current & 0x80000000) {
> +                s->dict_entry = s->dict[s->dict_entry].r;
> +            } else {
> +                s->dict_entry = s->dict[s->dict_entry].l;
> +            }
> +
> +            current = current << 1;

This sounds like get_bits is a better fit than bytestream2 for this decoder.

> +            if (s->dict[s->dict_entry].l < 0) {
> +                int16_t datum;
> +
> +                datum = s->dict[s->dict_entry].r;
> +
> +                if (!s->delta_compression)
> +                    s->sample = 0;
> +                s->sample = (s->sample + datum) & 0xFF;
> +
> +                frame->data[0][n++] = s->sample;
> +
> +                s->dict_entry = 0;
> +            }
> +        }
> +    }
> +
> +    frame->nb_samples = n;
> +
> +    *got_frame = 1;
> +
> +    return pkt->size;
> +}
Rostislav Pehlivanov Jan. 2, 2019, 11:51 p.m. UTC | #4
On Wed, 2 Jan 2019 at 19:02, Paul B Mahol <onemda@gmail.com> wrote:

> Signed-off-by: Paul B Mahol <onemda@gmail.com>
> ---
>  libavcodec/Makefile     |   1 +
>  libavcodec/allcodecs.c  |   1 +
>  libavcodec/avcodec.h    |   1 +
>  libavcodec/codec_desc.c |   7 ++
>  libavcodec/hcom.c       | 137 ++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 147 insertions(+)
>  create mode 100644 libavcodec/hcom.c
>
> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> index 99799ceed2..bf746c143d 100644
> --- a/libavcodec/Makefile
> +++ b/libavcodec/Makefile
> @@ -362,6 +362,7 @@ OBJS-$(CONFIG_H264_V4L2M2M_DECODER)    +=
> v4l2_m2m_dec.o
>  OBJS-$(CONFIG_H264_V4L2M2M_ENCODER)    += v4l2_m2m_enc.o
>  OBJS-$(CONFIG_HAP_DECODER)             += hapdec.o hap.o
>  OBJS-$(CONFIG_HAP_ENCODER)             += hapenc.o hap.o
> +OBJS-$(CONFIG_HCOM_DECODER)            += hcom.o
>  OBJS-$(CONFIG_HEVC_DECODER)            += hevcdec.o hevc_mvs.o \
>                                            hevc_cabac.o hevc_refs.o
> hevcpred.o    \
>                                            hevcdsp.o hevc_filter.o
> hevc_data.o
> diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
> index 4755af71b2..fe0376e27e 100644
> --- a/libavcodec/allcodecs.c
> +++ b/libavcodec/allcodecs.c
> @@ -424,6 +424,7 @@ extern AVCodec ff_g723_1_decoder;
>  extern AVCodec ff_g729_decoder;
>  extern AVCodec ff_gsm_decoder;
>  extern AVCodec ff_gsm_ms_decoder;
> +extern AVCodec ff_hcom_decoder;
>  extern AVCodec ff_iac_decoder;
>  extern AVCodec ff_ilbc_decoder;
>  extern AVCodec ff_imc_decoder;
> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
> index 92567ec6d0..e92d7accf4 100644
> --- a/libavcodec/avcodec.h
> +++ b/libavcodec/avcodec.h
> @@ -646,6 +646,7 @@ enum AVCodecID {
>      AV_CODEC_ID_APTX_HD,
>      AV_CODEC_ID_SBC,
>      AV_CODEC_ID_ATRAC9,
> +    AV_CODEC_ID_HCOM,
>
>      /* subtitle codecs */
>      AV_CODEC_ID_FIRST_SUBTITLE = 0x17000,          ///< A dummy ID
> pointing at the start of subtitle codecs.
> diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
> index 2363a53283..10a639101c 100644
> --- a/libavcodec/codec_desc.c
> +++ b/libavcodec/codec_desc.c
> @@ -2943,6 +2943,13 @@ static const AVCodecDescriptor codec_descriptors[]
> = {
>          .long_name = NULL_IF_CONFIG_SMALL("ATRAC9 (Adaptive TRansform
> Acoustic Coding 9)"),
>          .props     = AV_CODEC_PROP_LOSSY,
>      },
> +    {
> +        .id        = AV_CODEC_ID_HCOM,
> +        .type      = AVMEDIA_TYPE_AUDIO,
> +        .name      = "hcom",
> +        .long_name = NULL_IF_CONFIG_SMALL("HCOM Audio"),
> +        .props     = AV_CODEC_PROP_LOSSY,
> +    },
>
>      /* subtitle codecs */
>      {
> diff --git a/libavcodec/hcom.c b/libavcodec/hcom.c
> new file mode 100644
> index 0000000000..e516d20a94
> --- /dev/null
> +++ b/libavcodec/hcom.c
> @@ -0,0 +1,137 @@
> +/*
> + * HCOM audio decoder
> + *
> + * 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 "libavutil/intreadwrite.h"
> +
> +#include "avcodec.h"
> +#include "bytestream.h"
> +#include "internal.h"
> +
> +typedef struct HEntry {
> +    int16_t l, r;
> +} HEntry;
> +
> +typedef struct HCOMContext {
> +    AVCodecContext *avctx;
> +
> +    uint8_t first_sample;
> +    uint8_t sample;
> +    int dict_entries;
> +    int dict_entry;
> +    int delta_compression;
> +
> +    HEntry *dict;
> +} HCOMContext;
> +
> +static av_cold int hcom_init(AVCodecContext *avctx)
> +{
> +    HCOMContext *s = avctx->priv_data;
> +
> +    if (avctx->channels != 1) {
> +        av_log(avctx, AV_LOG_ERROR, "invalid number of channels\n");
> +        return AVERROR_INVALIDDATA;
> +    }
>

You can just set avctx->channels = 1 and the layout to mono, its a decoder.


+
> +    if (avctx->extradata_size <= 7)
> +        return AVERROR_INVALIDDATA;
> +    s->dict_entries = AV_RB16(avctx->extradata);
> +    if (avctx->extradata_size < s->dict_entries * 4 + 7)
> +        return AVERROR_INVALIDDATA;
> +    s->delta_compression = AV_RB32(avctx->extradata + 2);
> +    s->sample = s->first_sample = avctx->extradata[avctx->extradata_size
> - 1];
> +
> +    s->dict = av_calloc(s->dict_entries, sizeof(*s->dict));
> +    if (!s->dict)
> +        return AVERROR(ENOMEM);
> +    for (int i = 0; i < s->dict_entries; i++) {
> +        s->dict[i].l = AV_RB16(avctx->extradata + 6 + 4 * i);
> +        s->dict[i].r = AV_RB16(avctx->extradata + 6 + 4 * i + 2);
> +    }
> +
> +    avctx->sample_fmt = AV_SAMPLE_FMT_U8;
> +    s->dict_entry = 0;
> +
> +    return 0;
> +}
> +
> +static int hcom_decode(AVCodecContext *avctx, void *data,
> +                       int *got_frame, AVPacket *pkt)
> +{
> +    HCOMContext *s = avctx->priv_data;
> +    AVFrame *frame = data;
> +    GetByteContext gb;
> +    uint32_t current;
> +    int ret, n = 0;
> +
> +    if (pkt->size > INT16_MAX)
> +        return AVERROR_INVALIDDATA;
>

Also check the size is mod 4 or remove the check altogether if it doesn't
make the decoder blow up.


+
> +    frame->nb_samples = pkt->size * 8;
> +    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
> +        return ret;
> +
> +    bytestream2_init(&gb, pkt->data, pkt->size);
> +    while (bytestream2_get_bytes_left(&gb) >= 4) {
> +        int bits = 32;
> +
> +        current = bytestream2_get_be32(&gb);
> +
> +        while (bits-- > 0) {
> +
> +            if (current & 0x80000000) {
> +                s->dict_entry = s->dict[s->dict_entry].r;
> +            } else {
> +                s->dict_entry = s->dict[s->dict_entry].l;
> +            }
>


No need for brackets here.
Also yeah, get_bits seems like a better choice.
Carl Eugen Hoyos Jan. 6, 2019, 12:48 p.m. UTC | #5
2019-01-03 0:51 GMT+01:00, Rostislav Pehlivanov <atomnuker@gmail.com>:
> On Wed, 2 Jan 2019 at 19:02, Paul B Mahol <onemda@gmail.com> wrote:


>> +        while (bits-- > 0) {
>> +
>> +            if (current & 0x80000000) {
>> +                s->dict_entry = s->dict[s->dict_entry].r;
>> +            } else {
>> +                s->dict_entry = s->dict[s->dict_entry].l;
>> +            }
>
> No need for brackets here.

Fwiw, I believe these brackets are useful.
But that may only be me debugging.

Carl Eugen
Paul B Mahol Jan. 14, 2019, 7:32 p.m. UTC | #6
On 1/6/19, Carl Eugen Hoyos <ceffmpeg@gmail.com> wrote:
> 2019-01-03 0:51 GMT+01:00, Rostislav Pehlivanov <atomnuker@gmail.com>:
>> On Wed, 2 Jan 2019 at 19:02, Paul B Mahol <onemda@gmail.com> wrote:
>
>
>>> +        while (bits-- > 0) {
>>> +
>>> +            if (current & 0x80000000) {
>>> +                s->dict_entry = s->dict[s->dict_entry].r;
>>> +            } else {
>>> +                s->dict_entry = s->dict[s->dict_entry].l;
>>> +            }
>>
>> No need for brackets here.
>
> Fwiw, I believe these brackets are useful.
> But that may only be me debugging.
>

Locally fixed. Will apply ASAP!

This work is being sponsored by N. G. with 10 $.
Carl Eugen Hoyos Jan. 15, 2019, 11:44 a.m. UTC | #7
2019-01-14 20:32 GMT+01:00, Paul B Mahol <onemda@gmail.com>:
> On 1/6/19, Carl Eugen Hoyos <ceffmpeg@gmail.com> wrote:
>> 2019-01-03 0:51 GMT+01:00, Rostislav Pehlivanov <atomnuker@gmail.com>:
>>> On Wed, 2 Jan 2019 at 19:02, Paul B Mahol <onemda@gmail.com> wrote:
>>
>>
>>>> +        while (bits-- > 0) {
>>>> +
>>>> +            if (current & 0x80000000) {
>>>> +                s->dict_entry = s->dict[s->dict_entry].r;
>>>> +            } else {
>>>> +                s->dict_entry = s->dict[s->dict_entry].l;
>>>> +            }
>>>
>>> No need for brackets here.
>>
>> Fwiw, I believe these brackets are useful.
>> But that may only be me debugging.
>>
>
> Locally fixed.

Sad.

Carl Eugen
Michael Niedermayer Jan. 19, 2019, 11:09 p.m. UTC | #8
On Wed, Jan 02, 2019 at 06:12:08PM -0300, James Almer wrote:
> On 1/2/2019 3:53 PM, Paul B Mahol wrote:
> > +static int hcom_decode(AVCodecContext *avctx, void *data,
> > +                       int *got_frame, AVPacket *pkt)
> > +{
> > +    HCOMContext *s = avctx->priv_data;
> > +    AVFrame *frame = data;
> > +    GetByteContext gb;
> > +    uint32_t current;
> > +    int ret, n = 0;
> > +
> > +    if (pkt->size > INT16_MAX)
> > +        return AVERROR_INVALIDDATA;
> > +
> > +    frame->nb_samples = pkt->size * 8;
> > +    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
> > +        return ret;
> > +
> > +    bytestream2_init(&gb, pkt->data, pkt->size);
> > +    while (bytestream2_get_bytes_left(&gb) >= 4) {
> > +        int bits = 32;
> > +
> > +        current = bytestream2_get_be32(&gb);
> > +
> > +        while (bits-- > 0) {
> > +
> > +            if (current & 0x80000000) {
> > +                s->dict_entry = s->dict[s->dict_entry].r;
> > +            } else {
> > +                s->dict_entry = s->dict[s->dict_entry].l;
> > +            }
> > +
> > +            current = current << 1;
> 
> This sounds like get_bits is a better fit than bytestream2 for this decoder.

this looks like a standard vlc/huffman reader
and could be using the existing vlc code (init_vlc / get_vlc2 / ...)

thanks

[...]
diff mbox

Patch

diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 99799ceed2..bf746c143d 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -362,6 +362,7 @@  OBJS-$(CONFIG_H264_V4L2M2M_DECODER)    += v4l2_m2m_dec.o
 OBJS-$(CONFIG_H264_V4L2M2M_ENCODER)    += v4l2_m2m_enc.o
 OBJS-$(CONFIG_HAP_DECODER)             += hapdec.o hap.o
 OBJS-$(CONFIG_HAP_ENCODER)             += hapenc.o hap.o
+OBJS-$(CONFIG_HCOM_DECODER)            += hcom.o
 OBJS-$(CONFIG_HEVC_DECODER)            += hevcdec.o hevc_mvs.o \
                                           hevc_cabac.o hevc_refs.o hevcpred.o    \
                                           hevcdsp.o hevc_filter.o hevc_data.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 4755af71b2..fe0376e27e 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -424,6 +424,7 @@  extern AVCodec ff_g723_1_decoder;
 extern AVCodec ff_g729_decoder;
 extern AVCodec ff_gsm_decoder;
 extern AVCodec ff_gsm_ms_decoder;
+extern AVCodec ff_hcom_decoder;
 extern AVCodec ff_iac_decoder;
 extern AVCodec ff_ilbc_decoder;
 extern AVCodec ff_imc_decoder;
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 92567ec6d0..e92d7accf4 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -646,6 +646,7 @@  enum AVCodecID {
     AV_CODEC_ID_APTX_HD,
     AV_CODEC_ID_SBC,
     AV_CODEC_ID_ATRAC9,
+    AV_CODEC_ID_HCOM,
 
     /* subtitle codecs */
     AV_CODEC_ID_FIRST_SUBTITLE = 0x17000,          ///< A dummy ID pointing at the start of subtitle codecs.
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index 2363a53283..10a639101c 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -2943,6 +2943,13 @@  static const AVCodecDescriptor codec_descriptors[] = {
         .long_name = NULL_IF_CONFIG_SMALL("ATRAC9 (Adaptive TRansform Acoustic Coding 9)"),
         .props     = AV_CODEC_PROP_LOSSY,
     },
+    {
+        .id        = AV_CODEC_ID_HCOM,
+        .type      = AVMEDIA_TYPE_AUDIO,
+        .name      = "hcom",
+        .long_name = NULL_IF_CONFIG_SMALL("HCOM Audio"),
+        .props     = AV_CODEC_PROP_LOSSY,
+    },
 
     /* subtitle codecs */
     {
diff --git a/libavcodec/hcom.c b/libavcodec/hcom.c
new file mode 100644
index 0000000000..e516d20a94
--- /dev/null
+++ b/libavcodec/hcom.c
@@ -0,0 +1,137 @@ 
+/*
+ * HCOM audio decoder
+ *
+ * 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 "libavutil/intreadwrite.h"
+
+#include "avcodec.h"
+#include "bytestream.h"
+#include "internal.h"
+
+typedef struct HEntry {
+    int16_t l, r;
+} HEntry;
+
+typedef struct HCOMContext {
+    AVCodecContext *avctx;
+
+    uint8_t first_sample;
+    uint8_t sample;
+    int dict_entries;
+    int dict_entry;
+    int delta_compression;
+
+    HEntry *dict;
+} HCOMContext;
+
+static av_cold int hcom_init(AVCodecContext *avctx)
+{
+    HCOMContext *s = avctx->priv_data;
+
+    if (avctx->channels != 1) {
+        av_log(avctx, AV_LOG_ERROR, "invalid number of channels\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    if (avctx->extradata_size <= 7)
+        return AVERROR_INVALIDDATA;
+    s->dict_entries = AV_RB16(avctx->extradata);
+    if (avctx->extradata_size < s->dict_entries * 4 + 7)
+        return AVERROR_INVALIDDATA;
+    s->delta_compression = AV_RB32(avctx->extradata + 2);
+    s->sample = s->first_sample = avctx->extradata[avctx->extradata_size - 1];
+
+    s->dict = av_calloc(s->dict_entries, sizeof(*s->dict));
+    if (!s->dict)
+        return AVERROR(ENOMEM);
+    for (int i = 0; i < s->dict_entries; i++) {
+        s->dict[i].l = AV_RB16(avctx->extradata + 6 + 4 * i);
+        s->dict[i].r = AV_RB16(avctx->extradata + 6 + 4 * i + 2);
+    }
+
+    avctx->sample_fmt = AV_SAMPLE_FMT_U8;
+    s->dict_entry = 0;
+
+    return 0;
+}
+
+static int hcom_decode(AVCodecContext *avctx, void *data,
+                       int *got_frame, AVPacket *pkt)
+{
+    HCOMContext *s = avctx->priv_data;
+    AVFrame *frame = data;
+    GetByteContext gb;
+    uint32_t current;
+    int ret, n = 0;
+
+    if (pkt->size > INT16_MAX)
+        return AVERROR_INVALIDDATA;
+
+    frame->nb_samples = pkt->size * 8;
+    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
+        return ret;
+
+    bytestream2_init(&gb, pkt->data, pkt->size);
+    while (bytestream2_get_bytes_left(&gb) >= 4) {
+        int bits = 32;
+
+        current = bytestream2_get_be32(&gb);
+
+        while (bits-- > 0) {
+
+            if (current & 0x80000000) {
+                s->dict_entry = s->dict[s->dict_entry].r;
+            } else {
+                s->dict_entry = s->dict[s->dict_entry].l;
+            }
+
+            current = current << 1;
+            if (s->dict[s->dict_entry].l < 0) {
+                int16_t datum;
+
+                datum = s->dict[s->dict_entry].r;
+
+                if (!s->delta_compression)
+                    s->sample = 0;
+                s->sample = (s->sample + datum) & 0xFF;
+
+                frame->data[0][n++] = s->sample;
+
+                s->dict_entry = 0;
+            }
+        }
+    }
+
+    frame->nb_samples = n;
+
+    *got_frame = 1;
+
+    return pkt->size;
+}
+
+AVCodec ff_hcom_decoder = {
+    .name           = "hcom",
+    .long_name      = NULL_IF_CONFIG_SMALL("HCOM Audio"),
+    .type           = AVMEDIA_TYPE_AUDIO,
+    .id             = AV_CODEC_ID_HCOM,
+    .priv_data_size = sizeof(HCOMContext),
+    .init           = hcom_init,
+    .decode         = hcom_decode,
+    .capabilities   = AV_CODEC_CAP_DR1,
+};