1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2024-12-12 19:18:44 +02:00
FFmpeg/libavcodec/dolby_e.c
2021-01-25 13:19:48 +01:00

740 lines
22 KiB
C

/*
* Copyright (C) 2017 foo86
*
* 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/float_dsp.h"
#include "libavutil/thread.h"
#include "libavutil/mem.h"
#include "libavutil/mem_internal.h"
#include "internal.h"
#include "get_bits.h"
#include "put_bits.h"
#include "parser.h"
#include "dolby_e.h"
#include "dolby_edec.h"
#include "dolby_e_parser_internal.h"
#include "fft.h"
static int skip_input(DBEContext *s, int nb_words)
{
if (nb_words > s->input_size) {
av_log(s->avctx, AV_LOG_ERROR, "Packet too short\n");
return AVERROR_INVALIDDATA;
}
s->input += nb_words * s->word_bytes;
s->input_size -= nb_words;
return 0;
}
static int parse_key(DBEContext *s)
{
if (s->key_present) {
const uint8_t *key = s->input;
int ret = skip_input(s, 1);
if (ret < 0)
return ret;
return AV_RB24(key) >> 24 - s->word_bits;
}
return 0;
}
static int convert_input(DBEContext *s, int nb_words, int key)
{
const uint8_t *src = s->input;
uint8_t *dst = s->buffer;
PutBitContext pb;
int i;
av_assert0(nb_words <= 1024u);
if (nb_words > s->input_size) {
av_log(s->avctx, AV_LOG_ERROR, "Packet too short\n");
return AVERROR_INVALIDDATA;
}
switch (s->word_bits) {
case 16:
for (i = 0; i < nb_words; i++, src += 2, dst += 2)
AV_WB16(dst, AV_RB16(src) ^ key);
break;
case 20:
init_put_bits(&pb, s->buffer, sizeof(s->buffer));
for (i = 0; i < nb_words; i++, src += 3)
put_bits(&pb, 20, AV_RB24(src) >> 4 ^ key);
flush_put_bits(&pb);
break;
case 24:
for (i = 0; i < nb_words; i++, src += 3, dst += 3)
AV_WB24(dst, AV_RB24(src) ^ key);
break;
default:
av_assert0(0);
}
return init_get_bits(&s->gb, s->buffer, nb_words * s->word_bits);
}
static int parse_metadata_ext(DBEDecodeContext *s1)
{
DBEContext *s = &s1->dectx;
if (s1->metadata.mtd_ext_size)
return skip_input(s, s->key_present + s1->metadata.mtd_ext_size + 1);
return 0;
}
static void unbias_exponents(DBEContext *s, DBEChannel *c, DBEGroup *g)
{
int mstr_exp[MAX_MSTR_EXP];
int bias_exp[MAX_BIAS_EXP];
int i, j, k;
for (i = 0; i < c->nb_mstr_exp; i++)
mstr_exp[i] = get_bits(&s->gb, 2) * 6;
for (i = 0; i < g->nb_exponent; i++)
bias_exp[i] = get_bits(&s->gb, 5);
for (i = k = 0; i < c->nb_mstr_exp; i++)
for (j = 0; j < g->nb_bias_exp[i]; j++, k++)
c->exponents[g->exp_ofs + k] = mstr_exp[i] + bias_exp[k];
}
static int parse_exponents(DBEContext *s, DBEChannel *c)
{
DBEGroup *p, *g;
int i;
for (i = 0, p = NULL, g = c->groups; i < c->nb_groups; i++, p = g, g++) {
c->exp_strategy[i] = !i || g->nb_exponent != p->nb_exponent || get_bits1(&s->gb);
if (c->exp_strategy[i]) {
unbias_exponents(s, c, g);
} else {
memcpy(c->exponents + g->exp_ofs,
c->exponents + p->exp_ofs,
g->nb_exponent * sizeof(c->exponents[0]));
}
}
return 0;
}
static inline int log_add(int a, int b)
{
int c = FFABS(a - b) >> 1;
return FFMAX(a, b) + log_add_tab[FFMIN(c, 211)];
}
static void calc_lowcomp(int *msk_val)
{
int lwc_val[17] = { 0 };
int i, j, k;
for (i = 0; i < 11; i++) {
int max_j = 0;
int max_v = INT_MIN;
int thr = 0;
for (j = FFMAX(i - 3, 0), k = 0; j <= i + 3; j++, k++) {
int v = msk_val[j] + lwc_gain_tab[i][k];
if (v > max_v) {
max_j = j;
max_v = v;
}
thr = log_add(thr, v);
}
if (msk_val[i] < thr) {
for (j = FFMAX(max_j - 3, 0),
k = FFMAX(3 - max_j, 0);
j <= max_j + 3; j++, k++)
lwc_val[j] += lwc_adj_tab[k];
}
}
for (i = 0; i < 16; i++) {
int v = FFMAX(lwc_val[i], -512);
msk_val[i] = FFMAX(msk_val[i] + v, 0);
}
}
static void bit_allocate(int nb_exponent, int nb_code, int fr_code,
int *exp, int *bap,
int fg_spc, int fg_ofs, int msk_mod, int snr_ofs)
{
int msk_val[MAX_BIAS_EXP];
int psd_val[MAX_BIAS_EXP];
int fast_leak = 0;
int slow_leak = 0;
int dc_code = dc_code_tab[fr_code - 1];
int ht_code = ht_code_tab[fr_code - 1];
int fast_gain = fast_gain_tab[fg_ofs];
int slow_decay = slow_decay_tab[dc_code][msk_mod];
int misc_decay = misc_decay_tab[nb_code][dc_code][msk_mod];
const uint16_t *slow_gain = slow_gain_tab[nb_code][msk_mod];
const uint16_t *fast_decay = fast_decay_tab[nb_code][dc_code][msk_mod];
const uint16_t *fast_gain_adj = fast_gain_adj_tab[nb_code][dc_code];
const uint16_t *hearing_thresh = hearing_thresh_tab[nb_code][ht_code];
int i;
for (i = 0; i < nb_exponent; i++)
psd_val[i] = (48 - exp[i]) * 64;
fast_gain_adj += band_ofs_tab[nb_code][fg_spc];
for (i = 0; i < nb_exponent; i++) {
fast_leak = log_add(fast_leak - fast_decay[i],
psd_val[i] - fast_gain + fast_gain_adj[i]);
slow_leak = log_add(slow_leak - slow_decay,
psd_val[i] - slow_gain[i]);
msk_val[i] = FFMAX(fast_leak, slow_leak);
}
fast_leak = 0;
for (i = nb_exponent - 1; i > band_low_tab[nb_code]; i--) {
fast_leak = log_add(fast_leak - misc_decay, psd_val[i] - fast_gain);
msk_val[i] = FFMAX(msk_val[i], fast_leak);
}
for (i = 0; i < nb_exponent; i++)
msk_val[i] = FFMAX(msk_val[i], hearing_thresh[i]);
if (!nb_code)
calc_lowcomp(msk_val);
for (i = 0; i < nb_exponent; i++) {
int v = 16 * (snr_ofs - 64) + psd_val[i] - msk_val[i] >> 5;
bap[i] = bap_tab[av_clip_uintp2(v, 6)];
}
}
static int parse_bit_alloc(DBEDecodeContext *s1, DBEChannel *c)
{
DBEContext *s = &s1->dectx;
DBEGroup *p, *g;
int bap_strategy[MAX_GROUPS], fg_spc[MAX_GROUPS];
int fg_ofs[MAX_GROUPS], msk_mod[MAX_GROUPS];
int i, snr_ofs;
for (i = 0; i < c->nb_groups; i++) {
bap_strategy[i] = !i || get_bits1(&s->gb);
if (bap_strategy[i]) {
fg_spc[i] = get_bits(&s->gb, 2);
fg_ofs[i] = get_bits(&s->gb, 3);
msk_mod[i] = get_bits1(&s->gb);
} else {
fg_spc[i] = fg_spc[i - 1];
fg_ofs[i] = fg_ofs[i - 1];
msk_mod[i] = msk_mod[i - 1];
}
}
if (get_bits1(&s->gb)) {
avpriv_report_missing_feature(s->avctx, "Delta bit allocation");
return AVERROR_PATCHWELCOME;
}
snr_ofs = get_bits(&s->gb, 8);
if (!snr_ofs) {
memset(c->bap, 0, sizeof(c->bap));
return 0;
}
for (i = 0, p = NULL, g = c->groups; i < c->nb_groups; i++, p = g, g++) {
if (c->exp_strategy[i] || bap_strategy[i]) {
bit_allocate(g->nb_exponent, g->imdct_idx, s1->metadata.fr_code,
c->exponents + g->exp_ofs, c->bap + g->exp_ofs,
fg_spc[i], fg_ofs[i], msk_mod[i], snr_ofs);
} else {
memcpy(c->bap + g->exp_ofs,
c->bap + p->exp_ofs,
g->nb_exponent * sizeof(c->bap[0]));
}
}
return 0;
}
static int parse_indices(DBEContext *s, DBEChannel *c)
{
DBEGroup *p, *g;
int i, j;
for (i = 0, p = NULL, g = c->groups; i < c->nb_groups; i++, p = g, g++) {
if (get_bits1(&s->gb)) {
int start = get_bits(&s->gb, 6);
if (start > g->nb_exponent) {
av_log(s->avctx, AV_LOG_ERROR, "Invalid start index\n");
return AVERROR_INVALIDDATA;
}
for (j = 0; j < start; j++)
c->idx[g->exp_ofs + j] = 0;
for (; j < g->nb_exponent; j++)
c->idx[g->exp_ofs + j] = get_bits(&s->gb, 2);
} else if (i && g->nb_exponent == p->nb_exponent) {
memcpy(c->idx + g->exp_ofs,
c->idx + p->exp_ofs,
g->nb_exponent * sizeof(c->idx[0]));
} else {
memset(c->idx + g->exp_ofs, 0, g->nb_exponent * sizeof(c->idx[0]));
}
}
return 0;
}
static int parse_mantissas(DBEContext *s, DBEChannel *c)
{
DBEGroup *g;
int i, j, k;
for (i = 0, g = c->groups; i < c->nb_groups; i++, g++) {
float *mnt = c->mantissas + g->mnt_ofs;
for (j = 0; j < g->nb_exponent; j++) {
int bap = c->bap[g->exp_ofs + j];
int idx = c->idx[g->exp_ofs + j];
int size1 = mantissa_size1[bap][idx];
int count = g->nb_mantissa[j];
float exp = exponent_tab[c->exponents[g->exp_ofs + j]];
float scale = mantissa_tab1[size1][idx] * exp;
if (!size1) {
memset(mnt, 0, count * sizeof(*mnt));
} else if (idx) {
int values[100];
int escape = -(1 << size1 - 1);
for (k = 0; k < count; k++)
values[k] = get_sbits(&s->gb, size1);
for (k = 0; k < count; k++) {
if (values[k] != escape) {
mnt[k] = values[k] * scale;
} else {
int size2 = mantissa_size2[bap][idx];
int value = get_sbits(&s->gb, size2);
float a = mantissa_tab2[size2][idx];
float b = mantissa_tab3[size2][idx];
if (value < 0)
mnt[k] = ((value + 1) * a - b) * exp;
else
mnt[k] = (value * a + b) * exp;
}
}
} else {
for (k = 0; k < count; k++)
mnt[k] = get_sbits(&s->gb, size1) * scale;
}
mnt += count;
}
for (; j < g->nb_exponent + c->bw_code; j++) {
memset(mnt, 0, g->nb_mantissa[j] * sizeof(*mnt));
mnt += g->nb_mantissa[j];
}
}
return 0;
}
static int parse_channel(DBEDecodeContext *s1, int ch, int seg_id)
{
DBEContext *s = &s1->dectx;
DBEChannel *c = &s1->channels[seg_id][ch];
int i, ret;
if (s1->metadata.rev_id[ch] > 1) {
avpriv_report_missing_feature(s->avctx, "Encoder revision %d", s1->metadata.rev_id[ch]);
return AVERROR_PATCHWELCOME;
}
if (ch == lfe_channel_tab[s1->metadata.prog_conf]) {
c->gr_code = 3;
c->bw_code = 29;
} else {
c->gr_code = get_bits(&s->gb, 2);
c->bw_code = get_bits(&s->gb, 3);
if (c->gr_code == 3) {
av_log(s->avctx, AV_LOG_ERROR, "Invalid group type code\n");
return AVERROR_INVALIDDATA;
}
}
c->nb_groups = nb_groups_tab[c->gr_code];
c->nb_mstr_exp = nb_mstr_exp_tab[c->gr_code];
for (i = 0; i < c->nb_groups; i++) {
c->groups[i] = frm_ofs_tab[seg_id][c->gr_code][i];
if (c->nb_mstr_exp == 2) {
c->groups[i].nb_exponent -= c->bw_code;
c->groups[i].nb_bias_exp[1] -= c->bw_code;
}
}
if ((ret = parse_exponents(s, c)) < 0)
return ret;
if ((ret = parse_bit_alloc(s1, c)) < 0)
return ret;
if ((ret = parse_indices(s, c)) < 0)
return ret;
if ((ret = parse_mantissas(s, c)) < 0)
return ret;
if (get_bits_left(&s->gb) < 0) {
av_log(s->avctx, AV_LOG_ERROR, "Read past end of channel %d\n", ch);
return AVERROR_INVALIDDATA;
}
return 0;
}
static int parse_audio(DBEDecodeContext *s1, int start, int end, int seg_id)
{
DBEContext *s = &s1->dectx;
int ch, ret, key;
if ((key = parse_key(s)) < 0)
return key;
for (ch = start; ch < end; ch++) {
if (!s1->metadata.ch_size[ch]) {
s1->channels[seg_id][ch].nb_groups = 0;
continue;
}
if ((ret = convert_input(s, s1->metadata.ch_size[ch], key)) < 0)
return ret;
if ((ret = parse_channel(s1, ch, seg_id)) < 0) {
if (s1->avctx->err_recognition & AV_EF_EXPLODE)
return ret;
s1->channels[seg_id][ch].nb_groups = 0;
}
if ((ret = skip_input(s, s1->metadata.ch_size[ch])) < 0)
return ret;
}
return skip_input(s, 1);
}
static int parse_meter(DBEDecodeContext *s1)
{
DBEContext *s = &s1->dectx;
if (s1->metadata.meter_size)
return skip_input(s, s->key_present + s1->metadata.meter_size + 1);
return 0;
}
static void imdct_calc(DBEDecodeContext *s1, DBEGroup *g, float *result, float *values)
{
FFTContext *imdct = &s1->imdct[g->imdct_idx];
int n = 1 << imdct_bits_tab[g->imdct_idx];
int n2 = n >> 1;
int i;
switch (g->imdct_phs) {
case 0:
imdct->imdct_half(imdct, result, values);
for (i = 0; i < n2; i++)
result[n2 + i] = result[n2 - i - 1];
break;
case 1:
imdct->imdct_calc(imdct, result, values);
break;
case 2:
imdct->imdct_half(imdct, result + n2, values);
for (i = 0; i < n2; i++)
result[i] = -result[n - i - 1];
break;
default:
av_assert0(0);
}
}
static void transform(DBEDecodeContext *s1, DBEChannel *c, float *history, float *output)
{
LOCAL_ALIGNED_32(float, buffer, [2048]);
LOCAL_ALIGNED_32(float, result, [1152]);
DBEGroup *g;
int i;
memset(result, 0, 1152 * sizeof(float));
for (i = 0, g = c->groups; i < c->nb_groups; i++, g++) {
float *src = buffer + g->src_ofs;
float *dst = result + g->dst_ofs;
float *win = window + g->win_ofs;
imdct_calc(s1, g, buffer, c->mantissas + g->mnt_ofs);
s1->fdsp->vector_fmul_add(dst, src, win, dst, g->win_len);
}
for (i = 0; i < 256; i++)
output[i] = history[i] + result[i];
for (i = 256; i < 896; i++)
output[i] = result[i];
for (i = 0; i < 256; i++)
history[i] = result[896 + i];
}
static void apply_gain(DBEDecodeContext *s, int begin, int end, float *output)
{
if (begin == 960 && end == 960)
return;
if (begin == end) {
s->fdsp->vector_fmul_scalar(output, output, gain_tab[end], FRAME_SAMPLES);
} else {
float a = gain_tab[begin] * (1.0f / (FRAME_SAMPLES - 1));
float b = gain_tab[end ] * (1.0f / (FRAME_SAMPLES - 1));
int i;
for (i = 0; i < FRAME_SAMPLES; i++)
output[i] *= a * (FRAME_SAMPLES - i - 1) + b * i;
}
}
static int filter_frame(DBEDecodeContext *s, AVFrame *frame)
{
const uint8_t *reorder;
int ch, ret;
if (s->metadata.nb_channels == 4)
reorder = ch_reorder_4;
else if (s->metadata.nb_channels == 6)
reorder = ch_reorder_6;
else if (s->metadata.nb_programs == 1 && !(s->avctx->request_channel_layout & AV_CH_LAYOUT_NATIVE))
reorder = ch_reorder_8;
else
reorder = ch_reorder_n;
frame->nb_samples = FRAME_SAMPLES;
if ((ret = ff_get_buffer(s->avctx, frame, 0)) < 0)
return ret;
for (ch = 0; ch < s->metadata.nb_channels; ch++) {
float *output = (float *)frame->extended_data[reorder[ch]];
transform(s, &s->channels[0][ch], s->history[ch], output);
transform(s, &s->channels[1][ch], s->history[ch], output + FRAME_SAMPLES / 2);
apply_gain(s, s->metadata.begin_gain[ch], s->metadata.end_gain[ch], output);
}
return 0;
}
static int dolby_e_decode_frame(AVCodecContext *avctx, void *data,
int *got_frame_ptr, AVPacket *avpkt)
{
DBEDecodeContext *s1 = avctx->priv_data;
DBEContext *s = &s1->dectx;
int i, j, ret;
if ((ret = ff_dolby_e_parse_init(s, avpkt->data, avpkt->size)) < 0)
return ret;
if ((ret = ff_dolby_e_parse_header(s, &s1->metadata)) < 0)
return ret;
if (s1->metadata.nb_programs > 1 && !s1->metadata.multi_prog_warned) {
av_log(avctx, AV_LOG_WARNING, "Stream has %d programs (configuration %d), "
"channels will be output in native order.\n", s1->metadata.nb_programs, s1->metadata.prog_conf);
s1->metadata.multi_prog_warned = 1;
}
switch (s1->metadata.nb_channels) {
case 4:
avctx->channel_layout = AV_CH_LAYOUT_4POINT0;
break;
case 6:
avctx->channel_layout = AV_CH_LAYOUT_5POINT1;
break;
case 8:
avctx->channel_layout = AV_CH_LAYOUT_7POINT1;
break;
}
avctx->channels = s1->metadata.nb_channels;
avctx->sample_rate = sample_rate_tab[s1->metadata.fr_code];
avctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
i = s1->metadata.nb_channels / 2;
j = s1->metadata.nb_channels;
if ((ret = parse_audio(s1, 0, i, 0)) < 0)
return ret;
if ((ret = parse_audio(s1, i, j, 0)) < 0)
return ret;
if ((ret = parse_metadata_ext(s1)) < 0)
return ret;
if ((ret = parse_audio(s1, 0, i, 1)) < 0)
return ret;
if ((ret = parse_audio(s1, i, j, 1)) < 0)
return ret;
if ((ret = parse_meter(s1)) < 0)
return ret;
if ((ret = filter_frame(s1, data)) < 0)
return ret;
*got_frame_ptr = 1;
return avpkt->size;
}
static av_cold void dolby_e_flush(AVCodecContext *avctx)
{
DBEDecodeContext *s = avctx->priv_data;
memset(s->history, 0, sizeof(s->history));
}
static av_cold int dolby_e_close(AVCodecContext *avctx)
{
DBEDecodeContext *s = avctx->priv_data;
int i;
for (i = 0; i < 3; i++)
ff_mdct_end(&s->imdct[i]);
av_freep(&s->fdsp);
return 0;
}
static av_cold void init_tables(void)
{
int i, j;
for (i = 1; i < 17; i++)
mantissa_tab1[i][0] = 1.0f / (1 << i - 1);
for (i = 2; i < 16; i++) {
mantissa_tab1[i][1] = 1.0f / ((1 << i) - 1);
mantissa_tab1[i][2] = 0.5f / ((1 << i) - 1);
mantissa_tab1[i][3] = 0.25f / ((1 << i) - 1);
}
mantissa_tab1[i][1] = 0.5f / (1 << 15);
mantissa_tab1[i][2] = 0.75f / (1 << 15);
mantissa_tab1[i][3] = 0.875f / (1 << 15);
for (i = 1; i < 17; i++) {
mantissa_tab2[i][1] = mantissa_tab1[i][0] * 0.5f;
mantissa_tab2[i][2] = mantissa_tab1[i][0] * 0.75f;
mantissa_tab2[i][3] = mantissa_tab1[i][0] * 0.875f;
for (j = 1; j < 4; j++)
mantissa_tab3[i][j] = 1.0f / (1 << i) + 1.0f / (1 << j) - 1.0f / (1 << i + j);
}
mantissa_tab3[1][3] = 0.6875f;
for (i = 0; i < 25; i++) {
exponent_tab[i * 2 ] = 1.0f / (1 << i);
exponent_tab[i * 2 + 1] = M_SQRT1_2 / (1 << i);
}
for (i = 1; i < 1024; i++)
gain_tab[i] = exp2f((i - 960) / 64.0f);
// short 1
ff_kbd_window_init(window, 3.0f, 128);
for (i = 0; i < 128; i++)
window[128 + i] = window[127 - i];
// start
for (i = 0; i < 192; i++)
window[256 + i] = start_window[i];
// short 2
for (i = 0; i < 192; i++)
window[448 + i] = short_window2[i];
for (i = 0; i < 64; i++)
window[640 + i] = window[63 - i];
// short 3
for (i = 0; i < 64; i++)
window[704 + i] = short_window3[i];
for (i = 0; i < 192; i++)
window[768 + i] = window[64 + i];
// bridge
for (i = 0; i < 128; i++)
window[960 + i] = window[i];
for (i = 0; i < 64; i++)
window[1088 + i] = 1.0f;
// long
ff_kbd_window_init(window + 1408, 3.0f, 256);
for (i = 0; i < 640; i++)
window[1664 + i] = 1.0f;
for (i = 0; i < 256; i++)
window[2304 + i] = window[1152 + i] = window[1663 - i];
// reverse start
for (i = 0; i < 192; i++)
window[2560 + i] = window[447 - i];
// reverse short 2
for (i = 0; i < 256; i++)
window[2752 + i] = window[703 - i];
// reverse short 3
for (i = 0; i < 256; i++)
window[3008 + i] = window[959 - i];
// reverse bridge
for (i = 0; i < 448; i++)
window[3264 + i] = window[1407 - i];
}
static av_cold int dolby_e_init(AVCodecContext *avctx)
{
static AVOnce init_once = AV_ONCE_INIT;
DBEDecodeContext *s = avctx->priv_data;
int i;
if (ff_thread_once(&init_once, init_tables))
return AVERROR_UNKNOWN;
for (i = 0; i < 3; i++)
if (ff_mdct_init(&s->imdct[i], imdct_bits_tab[i], 1, 2.0) < 0)
return AVERROR(ENOMEM);
if (!(s->fdsp = avpriv_float_dsp_alloc(0)))
return AVERROR(ENOMEM);
s->metadata.multi_prog_warned = !!(avctx->request_channel_layout & AV_CH_LAYOUT_NATIVE);
s->dectx.avctx = s->avctx = avctx;
return 0;
}
AVCodec ff_dolby_e_decoder = {
.name = "dolby_e",
.long_name = NULL_IF_CONFIG_SMALL("Dolby E"),
.type = AVMEDIA_TYPE_AUDIO,
.id = AV_CODEC_ID_DOLBY_E,
.priv_data_size = sizeof(DBEDecodeContext),
.init = dolby_e_init,
.decode = dolby_e_decode_frame,
.close = dolby_e_close,
.flush = dolby_e_flush,
.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF,
.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE },
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP,
};