Hi, patches attached.
From 506e14978a831424134c63695ddb386fa56dcfc9 Mon Sep 17 00:00:00 2001 From: Paul B Mahol <one...@gmail.com> Date: Mon, 25 Apr 2016 20:42:58 +0200 Subject: [PATCH 1/2] avcodec: add Bonk decoder
Signed-off-by: Paul B Mahol <one...@gmail.com> --- libavcodec/Makefile | 1 + libavcodec/allcodecs.c | 1 + libavcodec/avcodec.h | 1 + libavcodec/bonk.c | 419 ++++++++++++++++++++++++++++++++++++++++++++++++ libavcodec/codec_desc.c | 7 + 5 files changed, 429 insertions(+) create mode 100644 libavcodec/bonk.c diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 8f63261..34006cf 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -211,6 +211,7 @@ OBJS-$(CONFIG_BMP_DECODER) += bmp.o msrledec.o OBJS-$(CONFIG_BMP_ENCODER) += bmpenc.o OBJS-$(CONFIG_BMV_AUDIO_DECODER) += bmvaudio.o OBJS-$(CONFIG_BMV_VIDEO_DECODER) += bmvvideo.o +OBJS-$(CONFIG_BONK_DECODER) += bonk.o OBJS-$(CONFIG_BRENDER_PIX_DECODER) += brenderpix.o OBJS-$(CONFIG_C93_DECODER) += c93.o OBJS-$(CONFIG_CAVS_DECODER) += cavs.o cavsdec.o cavsdsp.o \ diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 2b46a13..c5caf7e 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -386,6 +386,7 @@ void avcodec_register_all(void) REGISTER_DECODER(BINKAUDIO_DCT, binkaudio_dct); REGISTER_DECODER(BINKAUDIO_RDFT, binkaudio_rdft); REGISTER_DECODER(BMV_AUDIO, bmv_audio); + REGISTER_DECODER(BONK, bonk); REGISTER_DECODER(COOK, cook); REGISTER_ENCDEC (DCA, dca); REGISTER_DECODER(DSD_LSBF, dsd_lsbf); diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 161ee9d..f5da6e5 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -590,6 +590,7 @@ enum AVCodecID { AV_CODEC_ID_INTERPLAY_ACM, AV_CODEC_ID_XMA1, AV_CODEC_ID_XMA2, + AV_CODEC_ID_BONK, /* subtitle codecs */ AV_CODEC_ID_FIRST_SUBTITLE = 0x17000, ///< A dummy ID pointing at the start of subtitle codecs. diff --git a/libavcodec/bonk.c b/libavcodec/bonk.c new file mode 100644 index 0000000..ef1082a --- /dev/null +++ b/libavcodec/bonk.c @@ -0,0 +1,419 @@ +/* + * Bonk audio decoder + * Copyright (c) 2016 Paul B Mahol + * + * 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/avassert.h" +#include "libavutil/intreadwrite.h" +#include "avcodec.h" +#define BITSTREAM_READER_LE +#include "get_bits.h" +#include "bytestream.h" +#include "internal.h" + +typedef struct BitCount { + uint8_t bit; + unsigned count; +} BitCount; + +typedef struct BonkContext { + GetBitContext gb; + int skip; + + uint8_t *bitstream; + int max_framesize; + int bitstream_size; + int bitstream_index; + + uint64_t nb_samples; + int lossless; + int mid_side; + int n_taps; + int down_sampling; + int samples_per_packet; + + int state[2][2048], k[2048]; + int *samples; + int *input_samples; + uint8_t quant[2048]; + BitCount *bits; +} BonkContext; + +static av_cold int bonk_close(AVCodecContext *avctx) +{ + BonkContext *s = avctx->priv_data; + + av_freep(&s->bitstream); + av_freep(&s->input_samples); + av_freep(&s->samples); + av_freep(&s->bits); + s->bitstream_size = 0; + + return 0; +} + +static av_cold int bonk_init(AVCodecContext *avctx) +{ + BonkContext *s = avctx->priv_data; + int i; + + avctx->sample_fmt = AV_SAMPLE_FMT_S16; + if (avctx->extradata_size < 17) + return AVERROR(EINVAL); + + if (avctx->channels < 1 || avctx->channels > 2) + return AVERROR_INVALIDDATA; + + s->nb_samples = AV_RL32(avctx->extradata + 1) / avctx->channels; + if (!s->nb_samples) + s->nb_samples = UINT64_MAX; + s->lossless = avctx->extradata[10] != 0; + s->mid_side = avctx->extradata[11] != 0; + s->n_taps = AV_RL16(avctx->extradata + 12); + if (!s->n_taps || s->n_taps > 2048) + return AVERROR(EINVAL); + + s->down_sampling = avctx->extradata[14]; + if (!s->down_sampling) + return AVERROR(EINVAL); + if (!avctx->channels || avctx->channels > 2) + return AVERROR(EINVAL); + + s->samples_per_packet = AV_RL16(avctx->extradata + 15); + if (!s->samples_per_packet) + return AVERROR(EINVAL); + s->max_framesize = s->samples_per_packet * avctx->channels * s->down_sampling * 8; + s->bitstream = av_calloc(s->max_framesize + AV_INPUT_BUFFER_PADDING_SIZE, sizeof(*s->bitstream)); + if (!s->bitstream) + return AVERROR(ENOMEM); + + s->input_samples = av_calloc(s->samples_per_packet, sizeof(*s->input_samples)); + if (!s->input_samples) + return AVERROR(ENOMEM); + + s->samples = av_calloc(s->samples_per_packet * s->down_sampling * avctx->channels, sizeof(*s->samples)); + if (!s->samples) + return AVERROR(ENOMEM); + + s->bits = av_malloc_array(s->max_framesize * 8, sizeof(*s->bits)); + if (!s->bits) + return AVERROR(ENOMEM); + + for (i = 0; i < FF_ARRAY_ELEMS(s->quant); i++) + s->quant[i] = sqrt(i + 1); + + return 0; +} + +static int bits_to_store(uint32_t x) +{ + int res = 0; + + while (x) { + res++; + x >>= 1; + } + + return res; +} + +static unsigned read_uint_max(BonkContext *s, int max) +{ + unsigned value = 0; + int i, bits; + + if (max == 0) + return 0; + + bits = bits_to_store(max); + + for (i = 0; i < bits - 1; i++) + if (get_bits1(&s->gb)) + value += 1 << i; + + if ((value | (1 << (bits - 1))) <= max) + if (get_bits1(&s->gb)) + value += 1 << (bits - 1); + + return value; +} + +static int intlist_read(BonkContext *s, int *buf, int entries, int base_2_part) +{ + int i, low_bits = 0, x = 0; + int n_zeros = 0, step = 256, dominant = 0; + int pos = 0, level = 0; + BitCount *bits = s->bits; + + if (base_2_part) { + low_bits = get_bits(&s->gb, 4); + + if (low_bits) { + for (i = 0; i < entries; i++) + buf[i] = get_bits(&s->gb, low_bits); + } else { + memset(buf, 0, entries * sizeof(*buf)); + } + } else { + memset(buf, 0, entries * sizeof(*buf)); + } + + while (n_zeros < entries) { + int steplet = step >> 8; + + if (get_bits_left(&s->gb) <= 0) + return AVERROR_INVALIDDATA; + + if (!get_bits1(&s->gb)) { + if (steplet > 0) { + bits[x ].bit = dominant; + bits[x++].count = steplet; + } + + if (!dominant) + n_zeros += steplet; + + step += step / 8; + } else { + int actual_run = read_uint_max(s, steplet - 1); + + if (actual_run > 0) { + bits[x ].bit = dominant; + bits[x++].count = actual_run; + } + + bits[x ].bit = !dominant; + bits[x++].count = 1; + + if (!dominant) + n_zeros += actual_run; + else + n_zeros++; + + step -= step / 8; + } + + if (step < 256) { + if (step == 0) + return AVERROR_INVALIDDATA; + step = 65536 / step; + dominant = !dominant; + } + } + + x = 0; + n_zeros = 0; + for (i = 0; n_zeros < entries; i++) { + while (1) { + if (pos >= entries) { + pos = 0; + level += 1 << low_bits; + } + + if (buf[pos] >= level) + break; + + pos++; + } + + if (bits[x].bit) + buf[pos] += 1 << low_bits; + else + n_zeros++; + + bits[x].count--; + if (bits[x].count == 0) + x++; + + pos++; + } + + for (i = 0; i < entries; i++) + if (buf[i] && get_bits1(&s->gb)) + buf[i] = -buf[i]; + + return 0; +} + +static inline int shift_down(int a, int b) +{ + return (a >> b) + (a < 0); +} + +static inline int shift(int a, int b) +{ + return a + (1 << b - 1) >> b; +} + +#define LATTICE_SHIFT 10 +#define SAMPLE_SHIFT 4 +#define SAMPLE_FACTOR (1 << SAMPLE_SHIFT) + +static int predictor_calc_error(int *k, int *state, int order, int error) +{ + int i, x = error - shift_down(k[order-1] * state[order-1], LATTICE_SHIFT); + int *k_ptr = &(k[order-2]), + *state_ptr = &(state[order-2]); + + for (i = order-2; i >= 0; i--, k_ptr--, state_ptr--) { + int k_value = *k_ptr, state_value = *state_ptr; + + x -= shift_down(k_value * state_value, LATTICE_SHIFT); + state_ptr[1] = state_value + shift_down(k_value * x, LATTICE_SHIFT); + } + + // don't drift too far, to avoid overflows + av_clip(x, -(SAMPLE_FACTOR << 16), SAMPLE_FACTOR << 16); + + state[0] = x; + + return x; +} + +static void predictor_init_state(int *k, int *state, int order) +{ + int i; + + for (i = order - 2; i >= 0; i--) { + int j, p, x = state[i]; + + for (j = 0, p = i + 1; p < order; j++,p++) { + int tmp = x + shift_down(k[j] * state[p], LATTICE_SHIFT); + state[p] += shift_down(k[j] * x, LATTICE_SHIFT); + x = tmp; + } + } +} + +static int bonk_decode(AVCodecContext *avctx, void *data, + int *got_frame_ptr, AVPacket *pkt) +{ + BonkContext *s = avctx->priv_data; + GetBitContext *gb = &s->gb; + AVFrame *frame = data; + const uint8_t *buf; + int16_t *samples; + int i, j, ch, quant, ret, n, buf_size, input_buf_size; + + if ((!pkt->size && !s->bitstream_size) || s->nb_samples == 0) { + *got_frame_ptr = 0; + return 0; + } + + buf_size = FFMIN(pkt->size, s->max_framesize - s->bitstream_size); + input_buf_size = buf_size; + if (s->bitstream_index + s->bitstream_size + buf_size + AV_INPUT_BUFFER_PADDING_SIZE > s->max_framesize) { + memmove(s->bitstream, &s->bitstream[s->bitstream_index], s->bitstream_size); + s->bitstream_index = 0; + } + if (pkt->data) + memcpy(&s->bitstream[s->bitstream_index + s->bitstream_size], pkt->data, buf_size); + buf = &s->bitstream[s->bitstream_index]; + buf_size += s->bitstream_size; + s->bitstream_size = buf_size; + if (buf_size < s->max_framesize && pkt->data) { + *got_frame_ptr = 0; + return input_buf_size; + } + + frame->nb_samples = FFMIN(s->samples_per_packet * s->down_sampling, s->nb_samples); + if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) + return ret; + samples = (uint16_t *)frame->data[0]; + + init_get_bits8(gb, buf, buf_size); + skip_bits(gb, s->skip); + + if ((ret = intlist_read(s, s->k, s->n_taps, 0)) < 0) + return ret; + + for (i = 0; i < s->n_taps; i++) { + s->k[i] *= s->quant[i]; + } + quant = s->lossless ? 1 : get_bits(&s->gb, 16) * SAMPLE_FACTOR; + + for (ch = 0; ch < avctx->channels; ch++) { + int *sample = s->samples + ch; + + predictor_init_state(s->k, s->state[ch], s->n_taps); + if ((ret = intlist_read(s, s->input_samples, s->samples_per_packet, 1)) < 0) + return ret; + + for (i = 0; i < s->samples_per_packet; i++) { + for (j = 0; j < s->down_sampling - 1; j++) { + *sample = predictor_calc_error(s->k, s->state[ch], s->n_taps, 0); + sample += avctx->channels; + } + + *sample = predictor_calc_error(s->k, s->state[ch], s->n_taps, s->input_samples[i] * quant); + sample += avctx->channels; + } + + for (i = 0; i < s->n_taps; i++) + s->state[ch][i] = s->samples[s->samples_per_packet * s->down_sampling - avctx->channels + ch - i * avctx->channels]; + } + + if (s->mid_side) { + for (i = 0; i < frame->nb_samples * 2; i += 2) { + s->samples[i + 1] += shift(s->samples[i], 1); + s->samples[i] -= s->samples[i + 1]; + } + } + + if (!s->lossless) { + for (i = 0; i < frame->nb_samples * avctx->channels; i++) + s->samples[i] = shift(s->samples[i], 4); + } + + for (i = 0; i < frame->nb_samples * avctx->channels; i++) { + samples[i] = av_clip_int16(s->samples[i]); + } + + *got_frame_ptr = 1; + + s->nb_samples -= frame->nb_samples; + + s->skip = get_bits_count(gb) - 8 * (get_bits_count(gb) / 8); + n = get_bits_count(gb) / 8; + + if (n > buf_size) { + s->bitstream_size = 0; + s->bitstream_index = 0; + return AVERROR_INVALIDDATA; + } + + if (s->bitstream_size) { + s->bitstream_index += n; + s->bitstream_size -= n; + return input_buf_size; + } + return n; +} + +AVCodec ff_bonk_decoder = { + .name = "bonk", + .long_name = NULL_IF_CONFIG_SMALL("Bonk"), + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_BONK, + .init = bonk_init, + .decode = bonk_decode, + .close = bonk_close, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1, + .priv_data_size = sizeof(BonkContext), +}; diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index 7b48ee6..b338edb 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -2676,6 +2676,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("Xbox Media Audio 2"), .props = AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_BONK, + .type = AVMEDIA_TYPE_AUDIO, + .name = "bonk", + .long_name = NULL_IF_CONFIG_SMALL("Bonk"), + .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_LOSSLESS, + }, /* subtitle codecs */ { -- 2.5.0
From ff83c6a6690f571ab03c739a6c65173b320be74b Mon Sep 17 00:00:00 2001 From: Paul B Mahol <one...@gmail.com> Date: Mon, 25 Apr 2016 20:39:54 +0200 Subject: [PATCH 2/2] avformat: add Bonk demuxer Signed-off-by: Paul B Mahol <one...@gmail.com> --- libavformat/Makefile | 1 + libavformat/allformats.c | 1 + libavformat/bonk.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 libavformat/bonk.c diff --git a/libavformat/Makefile b/libavformat/Makefile index 51260f4..8d44568 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -116,6 +116,7 @@ OBJS-$(CONFIG_BIT_DEMUXER) += bit.o OBJS-$(CONFIG_BIT_MUXER) += bit.o OBJS-$(CONFIG_BMV_DEMUXER) += bmv.o OBJS-$(CONFIG_BOA_DEMUXER) += boadec.o +OBJS-$(CONFIG_BONK_DEMUXER) += bonk.o rawdec.o OBJS-$(CONFIG_BFSTM_DEMUXER) += brstm.o OBJS-$(CONFIG_BRSTM_DEMUXER) += brstm.o OBJS-$(CONFIG_C93_DEMUXER) += c93.o voc_packet.o vocdec.o voc.o diff --git a/libavformat/allformats.c b/libavformat/allformats.c index dbf2737..e4e7761 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -93,6 +93,7 @@ void av_register_all(void) REGISTER_DEMUXER (BFSTM, bfstm); REGISTER_DEMUXER (BRSTM, brstm); REGISTER_DEMUXER (BOA, boa); + REGISTER_DEMUXER (BONK, bonk); REGISTER_DEMUXER (C93, c93); REGISTER_MUXDEMUX(CAF, caf); REGISTER_MUXDEMUX(CAVSVIDEO, cavsvideo); diff --git a/libavformat/bonk.c b/libavformat/bonk.c new file mode 100644 index 0000000..2bf5cf7 --- /dev/null +++ b/libavformat/bonk.c @@ -0,0 +1,79 @@ +/* + * Bonk demuxer + * Copyright (c) 2016 Paul B Mahol + * + * 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 "avformat.h" +#include "internal.h" +#include "rawdec.h" + +static int bonk_probe(AVProbeData *p) +{ + int i; + + for (i = 0; i < p->buf_size - 5; i++) { + if (!p->buf[i] && AV_RL32(p->buf + i + 1) == MKTAG('B','O','N','K')) + return AVPROBE_SCORE_MAX; + else if (!p->buf[i]) + break; + } + + return 0; +} + +static int bonk_read_header(AVFormatContext *s) +{ + AVStream *st; + int ret, i; + + for (i = 0; !avio_feof(s->pb); i++) { + int b = avio_r8(s->pb); + if (!b && avio_rl32(s->pb) == MKTAG('B','O','N','K')) + break; + else if (!b) + return AVERROR_INVALIDDATA; + } + + st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + if ((ret = ff_get_extradata(s, st->codecpar, s->pb, 17)) < 0) + return ret; + st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; + st->codecpar->codec_id = AV_CODEC_ID_BONK; + st->codecpar->sample_rate = AV_RL32(st->codecpar->extradata + 5); + st->codecpar->channels = st->codecpar->extradata[9]; + st->duration = AV_RL32(st->codecpar->extradata + 1) / st->codecpar->channels; + st->need_parsing = AVSTREAM_PARSE_FULL_RAW; + avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate); + + return 0; +} + +AVInputFormat ff_bonk_demuxer = { + .name = "bonk", + .long_name = NULL_IF_CONFIG_SMALL("Bonk"), + .read_probe = bonk_probe, + .read_header = bonk_read_header, + .read_packet = ff_raw_read_partial_packet, + .extensions = "bonk", + .flags = AVFMT_NOBINSEARCH | AVFMT_NOGENSEARCH | AVFMT_NO_BYTE_SEEK | AVFMT_NOTIMESTAMPS, + .raw_codec_id = AV_CODEC_ID_BONK, +}; -- 2.5.0
_______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel