mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
avcodec/binkaudio: add support for >2 channels dct codec
As presented in .binka files.
This commit is contained in:
parent
fa989df1c6
commit
902ee9cafc
@ -44,6 +44,7 @@
|
|||||||
#include "rdft.h"
|
#include "rdft.h"
|
||||||
#include "wma_freqs.h"
|
#include "wma_freqs.h"
|
||||||
|
|
||||||
|
#define MAX_DCT_CHANNELS 6
|
||||||
#define MAX_CHANNELS 2
|
#define MAX_CHANNELS 2
|
||||||
#define BINK_BLOCK_MAX_SIZE (MAX_CHANNELS << 11)
|
#define BINK_BLOCK_MAX_SIZE (MAX_CHANNELS << 11)
|
||||||
|
|
||||||
@ -52,13 +53,14 @@ typedef struct BinkAudioContext {
|
|||||||
int version_b; ///< Bink version 'b'
|
int version_b; ///< Bink version 'b'
|
||||||
int first;
|
int first;
|
||||||
int channels;
|
int channels;
|
||||||
|
int ch_offset;
|
||||||
int frame_len; ///< transform size (samples)
|
int frame_len; ///< transform size (samples)
|
||||||
int overlap_len; ///< overlap size (samples)
|
int overlap_len; ///< overlap size (samples)
|
||||||
int block_size;
|
int block_size;
|
||||||
int num_bands;
|
int num_bands;
|
||||||
float root;
|
float root;
|
||||||
unsigned int bands[26];
|
unsigned int bands[26];
|
||||||
float previous[MAX_CHANNELS][BINK_BLOCK_MAX_SIZE / 16]; ///< coeffs from previous audio block
|
float previous[MAX_DCT_CHANNELS][BINK_BLOCK_MAX_SIZE / 16]; ///< coeffs from previous audio block
|
||||||
float quant_table[96];
|
float quant_table[96];
|
||||||
AVPacket *pkt;
|
AVPacket *pkt;
|
||||||
union {
|
union {
|
||||||
@ -75,6 +77,7 @@ static av_cold int decode_init(AVCodecContext *avctx)
|
|||||||
int sample_rate_half;
|
int sample_rate_half;
|
||||||
int i, ret;
|
int i, ret;
|
||||||
int frame_len_bits;
|
int frame_len_bits;
|
||||||
|
int max_channels = avctx->codec->id == AV_CODEC_ID_BINKAUDIO_RDFT ? MAX_CHANNELS : MAX_DCT_CHANNELS;
|
||||||
int channels = avctx->ch_layout.nb_channels;
|
int channels = avctx->ch_layout.nb_channels;
|
||||||
|
|
||||||
/* determine frame length */
|
/* determine frame length */
|
||||||
@ -86,7 +89,7 @@ static av_cold int decode_init(AVCodecContext *avctx)
|
|||||||
frame_len_bits = 11;
|
frame_len_bits = 11;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (channels < 1 || channels > MAX_CHANNELS) {
|
if (channels < 1 || channels > max_channels) {
|
||||||
av_log(avctx, AV_LOG_ERROR, "invalid number of channels: %d\n", channels);
|
av_log(avctx, AV_LOG_ERROR, "invalid number of channels: %d\n", channels);
|
||||||
return AVERROR_INVALIDDATA;
|
return AVERROR_INVALIDDATA;
|
||||||
}
|
}
|
||||||
@ -111,7 +114,7 @@ static av_cold int decode_init(AVCodecContext *avctx)
|
|||||||
|
|
||||||
s->frame_len = 1 << frame_len_bits;
|
s->frame_len = 1 << frame_len_bits;
|
||||||
s->overlap_len = s->frame_len / 16;
|
s->overlap_len = s->frame_len / 16;
|
||||||
s->block_size = (s->frame_len - s->overlap_len) * s->channels;
|
s->block_size = (s->frame_len - s->overlap_len) * FFMIN(MAX_CHANNELS, s->channels);
|
||||||
sample_rate_half = (sample_rate + 1LL) / 2;
|
sample_rate_half = (sample_rate + 1LL) / 2;
|
||||||
if (avctx->codec->id == AV_CODEC_ID_BINKAUDIO_RDFT)
|
if (avctx->codec->id == AV_CODEC_ID_BINKAUDIO_RDFT)
|
||||||
s->root = 2.0 / (sqrt(s->frame_len) * 32768.0);
|
s->root = 2.0 / (sqrt(s->frame_len) * 32768.0);
|
||||||
@ -167,7 +170,8 @@ static const uint8_t rle_length_tab[16] = {
|
|||||||
* @param[out] out Output buffer (must contain s->block_size elements)
|
* @param[out] out Output buffer (must contain s->block_size elements)
|
||||||
* @return 0 on success, negative error code on failure
|
* @return 0 on success, negative error code on failure
|
||||||
*/
|
*/
|
||||||
static int decode_block(BinkAudioContext *s, float **out, int use_dct)
|
static int decode_block(BinkAudioContext *s, float **out, int use_dct,
|
||||||
|
int channels, int ch_offset)
|
||||||
{
|
{
|
||||||
int ch, i, j, k;
|
int ch, i, j, k;
|
||||||
float q, quant[25];
|
float q, quant[25];
|
||||||
@ -177,8 +181,8 @@ static int decode_block(BinkAudioContext *s, float **out, int use_dct)
|
|||||||
if (use_dct)
|
if (use_dct)
|
||||||
skip_bits(gb, 2);
|
skip_bits(gb, 2);
|
||||||
|
|
||||||
for (ch = 0; ch < s->channels; ch++) {
|
for (ch = 0; ch < channels; ch++) {
|
||||||
FFTSample *coeffs = out[ch];
|
FFTSample *coeffs = out[ch + ch_offset];
|
||||||
|
|
||||||
if (s->version_b) {
|
if (s->version_b) {
|
||||||
if (get_bits_left(gb) < 64)
|
if (get_bits_left(gb) < 64)
|
||||||
@ -253,17 +257,17 @@ static int decode_block(BinkAudioContext *s, float **out, int use_dct)
|
|||||||
s->trans.rdft.rdft_calc(&s->trans.rdft, coeffs);
|
s->trans.rdft.rdft_calc(&s->trans.rdft, coeffs);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (ch = 0; ch < s->channels; ch++) {
|
for (ch = 0; ch < channels; ch++) {
|
||||||
int j;
|
int j;
|
||||||
int count = s->overlap_len * s->channels;
|
int count = s->overlap_len * channels;
|
||||||
if (!s->first) {
|
if (!s->first) {
|
||||||
j = ch;
|
j = ch;
|
||||||
for (i = 0; i < s->overlap_len; i++, j += s->channels)
|
for (i = 0; i < s->overlap_len; i++, j += channels)
|
||||||
out[ch][i] = (s->previous[ch][i] * (count - j) +
|
out[ch + ch_offset][i] = (s->previous[ch + ch_offset][i] * (count - j) +
|
||||||
out[ch][i] * j) / count;
|
out[ch + ch_offset][i] * j) / count;
|
||||||
}
|
}
|
||||||
memcpy(s->previous[ch], &out[ch][s->frame_len - s->overlap_len],
|
memcpy(s->previous[ch + ch_offset], &out[ch + ch_offset][s->frame_len - s->overlap_len],
|
||||||
s->overlap_len * sizeof(*s->previous[ch]));
|
s->overlap_len * sizeof(*s->previous[ch + ch_offset]));
|
||||||
}
|
}
|
||||||
|
|
||||||
s->first = 0;
|
s->first = 0;
|
||||||
@ -294,6 +298,7 @@ static int binkaudio_receive_frame(AVCodecContext *avctx, AVFrame *frame)
|
|||||||
GetBitContext *gb = &s->gb;
|
GetBitContext *gb = &s->gb;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
again:
|
||||||
if (!s->pkt->data) {
|
if (!s->pkt->data) {
|
||||||
ret = ff_decode_get_packet(avctx, s->pkt);
|
ret = ff_decode_get_packet(avctx, s->pkt);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
@ -314,22 +319,31 @@ static int binkaudio_receive_frame(AVCodecContext *avctx, AVFrame *frame)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* get output buffer */
|
/* get output buffer */
|
||||||
|
if (s->ch_offset == 0) {
|
||||||
frame->nb_samples = s->frame_len;
|
frame->nb_samples = s->frame_len;
|
||||||
if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
|
if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
if (decode_block(s, (float **)frame->extended_data,
|
if (decode_block(s, (float **)frame->extended_data,
|
||||||
avctx->codec->id == AV_CODEC_ID_BINKAUDIO_DCT)) {
|
avctx->codec->id == AV_CODEC_ID_BINKAUDIO_DCT,
|
||||||
|
FFMIN(MAX_CHANNELS, s->channels - s->ch_offset), s->ch_offset)) {
|
||||||
av_log(avctx, AV_LOG_ERROR, "Incomplete packet\n");
|
av_log(avctx, AV_LOG_ERROR, "Incomplete packet\n");
|
||||||
return AVERROR_INVALIDDATA;
|
return AVERROR_INVALIDDATA;
|
||||||
}
|
}
|
||||||
|
s->ch_offset += MAX_CHANNELS;
|
||||||
get_bits_align32(gb);
|
get_bits_align32(gb);
|
||||||
if (!get_bits_left(gb)) {
|
if (!get_bits_left(gb)) {
|
||||||
memset(gb, 0, sizeof(*gb));
|
memset(gb, 0, sizeof(*gb));
|
||||||
av_packet_unref(s->pkt);
|
av_packet_unref(s->pkt);
|
||||||
}
|
}
|
||||||
|
if (s->ch_offset >= s->channels) {
|
||||||
|
s->ch_offset = 0;
|
||||||
|
} else {
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
|
||||||
frame->nb_samples = s->block_size / avctx->ch_layout.nb_channels;
|
frame->nb_samples = s->block_size / FFMIN(avctx->ch_layout.nb_channels, MAX_CHANNELS);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
fail:
|
fail:
|
||||||
@ -344,6 +358,7 @@ static void decode_flush(AVCodecContext *avctx)
|
|||||||
/* s->pkt coincides with avctx->internal->in_pkt
|
/* s->pkt coincides with avctx->internal->in_pkt
|
||||||
* and is unreferenced generically when flushing. */
|
* and is unreferenced generically when flushing. */
|
||||||
s->first = 1;
|
s->first = 1;
|
||||||
|
s->ch_offset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FFCodec ff_binkaudio_rdft_decoder = {
|
const FFCodec ff_binkaudio_rdft_decoder = {
|
||||||
|
Loading…
Reference in New Issue
Block a user