-/**
+/*
* FLAC audio encoder
* Copyright (c) 2006 Justin Ruggles <justin.ruggles@gmail.com>
*
- * This file is part of FFmpeg.
+ * This file is part of Libav.
*
- * FFmpeg is free software; you can redistribute it and/or
+ * Libav 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,
+ * Libav 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
+ * License along with Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/crc.h"
#include "libavutil/md5.h"
+#include "libavutil/opt.h"
#include "avcodec.h"
#include "get_bits.h"
-#include "dsputil.h"
#include "golomb.h"
+#include "internal.h"
#include "lpc.h"
#include "flac.h"
#include "flacdata.h"
typedef struct CompressionOptions {
int compression_level;
int block_time_ms;
- enum AVLPCType lpc_type;
+ enum FFLPCType lpc_type;
int lpc_passes;
int lpc_coeff_precision;
int min_prediction_order;
int prediction_order_method;
int min_partition_order;
int max_partition_order;
+ int ch_mode;
} CompressionOptions;
typedef struct RiceContext {
} FlacFrame;
typedef struct FlacEncodeContext {
+ AVClass *class;
PutBitContext pb;
int channels;
int samplerate;
FlacFrame frame;
CompressionOptions options;
AVCodecContext *avctx;
- DSPContext dsp;
+ LPCContext lpc_ctx;
struct AVMD5 *md5ctx;
} FlacEncodeContext;
av_log(avctx, AV_LOG_DEBUG, " compression: %d\n", opt->compression_level);
switch (opt->lpc_type) {
- case AV_LPC_TYPE_NONE:
+ case FF_LPC_TYPE_NONE:
av_log(avctx, AV_LOG_DEBUG, " lpc type: None\n");
break;
- case AV_LPC_TYPE_FIXED:
+ case FF_LPC_TYPE_FIXED:
av_log(avctx, AV_LOG_DEBUG, " lpc type: Fixed pre-defined coefficients\n");
break;
- case AV_LPC_TYPE_LEVINSON:
+ case FF_LPC_TYPE_LEVINSON:
av_log(avctx, AV_LOG_DEBUG, " lpc type: Levinson-Durbin recursion with Welch window\n");
break;
- case AV_LPC_TYPE_CHOLESKY:
+ case FF_LPC_TYPE_CHOLESKY:
av_log(avctx, AV_LOG_DEBUG, " lpc type: Cholesky factorization, %d pass%s\n",
opt->lpc_passes, opt->lpc_passes == 1 ? "" : "es");
break;
int freq = avctx->sample_rate;
int channels = avctx->channels;
FlacEncodeContext *s = avctx->priv_data;
- int i, level;
+ int i, level, ret;
uint8_t *streaminfo;
s->avctx = avctx;
- dsputil_init(&s->dsp, avctx);
-
- if (avctx->sample_fmt != SAMPLE_FMT_S16)
+ if (avctx->sample_fmt != AV_SAMPLE_FMT_S16)
return -1;
if (channels < 1 || channels > FLAC_MAX_CHANNELS)
s->options.block_time_ms = ((int[]){ 27, 27, 27,105,105,105,105,105,105,105,105,105,105})[level];
- s->options.lpc_type = ((int[]){ AV_LPC_TYPE_FIXED, AV_LPC_TYPE_FIXED, AV_LPC_TYPE_FIXED,
- AV_LPC_TYPE_LEVINSON, AV_LPC_TYPE_LEVINSON, AV_LPC_TYPE_LEVINSON,
- AV_LPC_TYPE_LEVINSON, AV_LPC_TYPE_LEVINSON, AV_LPC_TYPE_LEVINSON,
- AV_LPC_TYPE_LEVINSON, AV_LPC_TYPE_LEVINSON, AV_LPC_TYPE_LEVINSON,
- AV_LPC_TYPE_LEVINSON})[level];
+ if (s->options.lpc_type == FF_LPC_TYPE_DEFAULT)
+ s->options.lpc_type = ((int[]){ FF_LPC_TYPE_FIXED, FF_LPC_TYPE_FIXED, FF_LPC_TYPE_FIXED,
+ FF_LPC_TYPE_LEVINSON, FF_LPC_TYPE_LEVINSON, FF_LPC_TYPE_LEVINSON,
+ FF_LPC_TYPE_LEVINSON, FF_LPC_TYPE_LEVINSON, FF_LPC_TYPE_LEVINSON,
+ FF_LPC_TYPE_LEVINSON, FF_LPC_TYPE_LEVINSON, FF_LPC_TYPE_LEVINSON,
+ FF_LPC_TYPE_LEVINSON})[level];
s->options.min_prediction_order = ((int[]){ 2, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})[level];
s->options.max_prediction_order = ((int[]){ 3, 4, 4, 6, 8, 8, 8, 8, 12, 12, 12, 32, 32})[level];
- s->options.prediction_order_method = ((int[]){ ORDER_METHOD_EST, ORDER_METHOD_EST, ORDER_METHOD_EST,
- ORDER_METHOD_EST, ORDER_METHOD_EST, ORDER_METHOD_EST,
- ORDER_METHOD_4LEVEL, ORDER_METHOD_LOG, ORDER_METHOD_4LEVEL,
- ORDER_METHOD_LOG, ORDER_METHOD_SEARCH, ORDER_METHOD_LOG,
- ORDER_METHOD_SEARCH})[level];
-
- s->options.min_partition_order = ((int[]){ 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})[level];
- s->options.max_partition_order = ((int[]){ 2, 2, 3, 3, 3, 8, 8, 8, 8, 8, 8, 8, 8})[level];
-
- /* set compression option overrides from AVCodecContext */
-#if LIBAVCODEC_VERSION_MAJOR < 53
- /* for compatibility with deprecated AVCodecContext.use_lpc */
- if (avctx->use_lpc == 0) {
- s->options.lpc_type = AV_LPC_TYPE_FIXED;
- } else if (avctx->use_lpc == 1) {
- s->options.lpc_type = AV_LPC_TYPE_LEVINSON;
- } else if (avctx->use_lpc > 1) {
- s->options.lpc_type = AV_LPC_TYPE_CHOLESKY;
- s->options.lpc_passes = avctx->use_lpc - 1;
- }
-#endif
- if (avctx->lpc_type > AV_LPC_TYPE_DEFAULT) {
- if (avctx->lpc_type > AV_LPC_TYPE_CHOLESKY) {
- av_log(avctx, AV_LOG_ERROR, "unknown lpc type: %d\n", avctx->lpc_type);
- return -1;
- }
- s->options.lpc_type = avctx->lpc_type;
- if (s->options.lpc_type == AV_LPC_TYPE_CHOLESKY) {
- if (avctx->lpc_passes < 0) {
- // default number of passes for Cholesky
- s->options.lpc_passes = 2;
- } else if (avctx->lpc_passes == 0) {
- av_log(avctx, AV_LOG_ERROR, "invalid number of lpc passes: %d\n",
- avctx->lpc_passes);
- return -1;
- } else {
- s->options.lpc_passes = avctx->lpc_passes;
- }
- }
+ if (s->options.prediction_order_method < 0)
+ s->options.prediction_order_method = ((int[]){ ORDER_METHOD_EST, ORDER_METHOD_EST, ORDER_METHOD_EST,
+ ORDER_METHOD_EST, ORDER_METHOD_EST, ORDER_METHOD_EST,
+ ORDER_METHOD_4LEVEL, ORDER_METHOD_LOG, ORDER_METHOD_4LEVEL,
+ ORDER_METHOD_LOG, ORDER_METHOD_SEARCH, ORDER_METHOD_LOG,
+ ORDER_METHOD_SEARCH})[level];
+
+ if (s->options.min_partition_order > s->options.max_partition_order) {
+ av_log(avctx, AV_LOG_ERROR, "invalid partition orders: min=%d max=%d\n",
+ s->options.min_partition_order, s->options.max_partition_order);
+ return AVERROR(EINVAL);
}
+ if (s->options.min_partition_order < 0)
+ s->options.min_partition_order = ((int[]){ 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})[level];
+ if (s->options.max_partition_order < 0)
+ s->options.max_partition_order = ((int[]){ 2, 2, 3, 3, 3, 8, 8, 8, 8, 8, 8, 8, 8})[level];
- if (s->options.lpc_type == AV_LPC_TYPE_NONE) {
+ if (s->options.lpc_type == FF_LPC_TYPE_NONE) {
s->options.min_prediction_order = 0;
} else if (avctx->min_prediction_order >= 0) {
- if (s->options.lpc_type == AV_LPC_TYPE_FIXED) {
+ if (s->options.lpc_type == FF_LPC_TYPE_FIXED) {
if (avctx->min_prediction_order > MAX_FIXED_ORDER) {
av_log(avctx, AV_LOG_ERROR, "invalid min prediction order: %d\n",
avctx->min_prediction_order);
}
s->options.min_prediction_order = avctx->min_prediction_order;
}
- if (s->options.lpc_type == AV_LPC_TYPE_NONE) {
+ if (s->options.lpc_type == FF_LPC_TYPE_NONE) {
s->options.max_prediction_order = 0;
} else if (avctx->max_prediction_order >= 0) {
- if (s->options.lpc_type == AV_LPC_TYPE_FIXED) {
+ if (s->options.lpc_type == FF_LPC_TYPE_FIXED) {
if (avctx->max_prediction_order > MAX_FIXED_ORDER) {
av_log(avctx, AV_LOG_ERROR, "invalid max prediction order: %d\n",
avctx->max_prediction_order);
return -1;
}
- if (avctx->prediction_order_method >= 0) {
- if (avctx->prediction_order_method > ORDER_METHOD_LOG) {
- av_log(avctx, AV_LOG_ERROR, "invalid prediction order method: %d\n",
- avctx->prediction_order_method);
- return -1;
- }
- s->options.prediction_order_method = avctx->prediction_order_method;
- }
-
- if (avctx->min_partition_order >= 0) {
- if (avctx->min_partition_order > MAX_PARTITION_ORDER) {
- av_log(avctx, AV_LOG_ERROR, "invalid min partition order: %d\n",
- avctx->min_partition_order);
- return -1;
- }
- s->options.min_partition_order = avctx->min_partition_order;
- }
- if (avctx->max_partition_order >= 0) {
- if (avctx->max_partition_order > MAX_PARTITION_ORDER) {
- av_log(avctx, AV_LOG_ERROR, "invalid max partition order: %d\n",
- avctx->max_partition_order);
- return -1;
- }
- s->options.max_partition_order = avctx->max_partition_order;
- }
- if (s->options.max_partition_order < s->options.min_partition_order) {
- av_log(avctx, AV_LOG_ERROR, "invalid partition orders: min=%d max=%d\n",
- s->options.min_partition_order, s->options.max_partition_order);
- return -1;
- }
-
if (avctx->frame_size > 0) {
if (avctx->frame_size < FLAC_MIN_BLOCKSIZE ||
avctx->frame_size > FLAC_MAX_BLOCKSIZE) {
}
s->max_blocksize = s->avctx->frame_size;
- /* set LPC precision */
- if (avctx->lpc_coeff_precision > 0) {
- if (avctx->lpc_coeff_precision > MAX_LPC_PRECISION) {
- av_log(avctx, AV_LOG_ERROR, "invalid lpc coeff precision: %d\n",
- avctx->lpc_coeff_precision);
- return -1;
- }
- s->options.lpc_coeff_precision = avctx->lpc_coeff_precision;
- } else {
- /* default LPC precision */
- s->options.lpc_coeff_precision = 15;
- }
-
/* set maximum encoded frame size in verbatim mode */
s->max_framesize = ff_flac_get_max_frame_size(s->avctx->frame_size,
s->channels, 16);
s->frame_count = 0;
s->min_framesize = s->max_framesize;
+#if FF_API_OLD_ENCODE_AUDIO
avctx->coded_frame = avcodec_alloc_frame();
if (!avctx->coded_frame)
return AVERROR(ENOMEM);
+#endif
+
+ ret = ff_lpc_init(&s->lpc_ctx, avctx->frame_size,
+ s->options.max_prediction_order, FF_LPC_TYPE_LEVINSON);
dprint_compression_options(s);
- return 0;
+ return ret;
}
-static void init_frame(FlacEncodeContext *s)
+static void init_frame(FlacEncodeContext *s, int nb_samples)
{
int i, ch;
FlacFrame *frame;
frame = &s->frame;
for (i = 0; i < 16; i++) {
- if (s->avctx->frame_size == ff_flac_blocksize_table[i]) {
+ if (nb_samples == ff_flac_blocksize_table[i]) {
frame->blocksize = ff_flac_blocksize_table[i];
frame->bs_code[0] = i;
frame->bs_code[1] = 0;
}
}
if (i == 16) {
- frame->blocksize = s->avctx->frame_size;
+ frame->blocksize = nb_samples;
if (frame->blocksize <= 256) {
frame->bs_code[0] = 6;
frame->bs_code[1] = frame->blocksize-1;
/* FIXED */
sub->type = FLAC_SUBFRAME_FIXED;
- if (s->options.lpc_type == AV_LPC_TYPE_NONE ||
- s->options.lpc_type == AV_LPC_TYPE_FIXED || n <= max_order) {
+ if (s->options.lpc_type == FF_LPC_TYPE_NONE ||
+ s->options.lpc_type == FF_LPC_TYPE_FIXED || n <= max_order) {
uint32_t bits[MAX_FIXED_ORDER+1];
if (max_order > MAX_FIXED_ORDER)
max_order = MAX_FIXED_ORDER;
/* LPC */
sub->type = FLAC_SUBFRAME_LPC;
- opt_order = ff_lpc_calc_coefs(&s->dsp, smp, n, min_order, max_order,
+ opt_order = ff_lpc_calc_coefs(&s->lpc_ctx, smp, n, min_order, max_order,
s->options.lpc_coeff_precision, coefs, shift, s->options.lpc_type,
s->options.lpc_passes, omethod,
MAX_LPC_SHIFT, 0);
static int count_frame_header(FlacEncodeContext *s)
{
- uint8_t tmp;
+ uint8_t av_unused tmp;
int count;
/*
for (i = 1; i < 4; i++)
if (score[i] < score[best])
best = i;
- if (best == 0) {
- return FLAC_CHMODE_INDEPENDENT;
- } else if (best == 1) {
- return FLAC_CHMODE_LEFT_SIDE;
- } else if (best == 2) {
- return FLAC_CHMODE_RIGHT_SIDE;
- } else {
- return FLAC_CHMODE_MID_SIDE;
- }
+
+ return best;
}
return;
}
- frame->ch_mode = estimate_stereo_mode(left, right, n);
+ if (s->options.ch_mode < 0)
+ frame->ch_mode = estimate_stereo_mode(left, right, n);
+ else
+ frame->ch_mode = s->options.ch_mode;
/* perform decorrelation and adjust bits-per-sample */
if (frame->ch_mode == FLAC_CHMODE_INDEPENDENT)
if (frame->ch_mode == FLAC_CHMODE_INDEPENDENT)
put_bits(&s->pb, 4, s->channels-1);
else
- put_bits(&s->pb, 4, frame->ch_mode);
+ put_bits(&s->pb, 4, frame->ch_mode + FLAC_MAX_CHANNELS - 1);
put_bits(&s->pb, 3, 4); /* bits-per-sample code */
put_bits(&s->pb, 1, 0);
}
-static int write_frame(FlacEncodeContext *s, uint8_t *frame, int buf_size)
+static int write_frame(FlacEncodeContext *s, AVPacket *avpkt)
{
- init_put_bits(&s->pb, frame, buf_size);
+ init_put_bits(&s->pb, avpkt->data, avpkt->size);
write_frame_header(s);
write_subframes(s);
write_frame_footer(s);
}
-static int flac_encode_frame(AVCodecContext *avctx, uint8_t *frame,
- int buf_size, void *data)
+static int flac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
+ const AVFrame *frame, int *got_packet_ptr)
{
FlacEncodeContext *s;
- const int16_t *samples = data;
- int frame_bytes, out_bytes;
+ const int16_t *samples;
+ int frame_bytes, out_bytes, ret;
s = avctx->priv_data;
/* when the last block is reached, update the header in extradata */
- if (!data) {
+ if (!frame) {
s->max_framesize = s->max_encoded_framesize;
av_md5_final(s->md5ctx, s->md5sum);
write_streaminfo(s, avctx->extradata);
return 0;
}
+ samples = (const int16_t *)frame->data[0];
/* change max_framesize for small final frame */
- if (avctx->frame_size < s->frame.blocksize) {
- s->max_framesize = ff_flac_get_max_frame_size(avctx->frame_size,
+ if (frame->nb_samples < s->frame.blocksize) {
+ s->max_framesize = ff_flac_get_max_frame_size(frame->nb_samples,
s->channels, 16);
}
- init_frame(s);
+ init_frame(s, frame->nb_samples);
copy_samples(s, samples);
frame_bytes = encode_frame(s);
}
- if (buf_size < frame_bytes) {
- av_log(avctx, AV_LOG_ERROR, "output buffer too small\n");
- return 0;
+ if ((ret = ff_alloc_packet(avpkt, frame_bytes))) {
+ av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n");
+ return ret;
}
- out_bytes = write_frame(s, frame, buf_size);
+
+ out_bytes = write_frame(s, avpkt);
s->frame_count++;
- avctx->coded_frame->pts = s->sample_count;
- s->sample_count += avctx->frame_size;
+ s->sample_count += frame->nb_samples;
update_md5_sum(s, samples);
if (out_bytes > s->max_encoded_framesize)
s->max_encoded_framesize = out_bytes;
if (out_bytes < s->min_framesize)
s->min_framesize = out_bytes;
- return out_bytes;
+ avpkt->pts = frame->pts;
+ avpkt->duration = ff_samples_to_time_base(avctx, frame->nb_samples);
+ avpkt->size = out_bytes;
+ *got_packet_ptr = 1;
+ return 0;
}
if (avctx->priv_data) {
FlacEncodeContext *s = avctx->priv_data;
av_freep(&s->md5ctx);
+ ff_lpc_end(&s->lpc_ctx);
}
av_freep(&avctx->extradata);
avctx->extradata_size = 0;
+#if FF_API_OLD_ENCODE_AUDIO
av_freep(&avctx->coded_frame);
+#endif
return 0;
}
+#define FLAGS AV_OPT_FLAG_ENCODING_PARAM | AV_OPT_FLAG_AUDIO_PARAM
+static const AVOption options[] = {
+{ "lpc_coeff_precision", "LPC coefficient precision", offsetof(FlacEncodeContext, options.lpc_coeff_precision), AV_OPT_TYPE_INT, {.i64 = 15 }, 0, MAX_LPC_PRECISION, FLAGS },
+{ "lpc_type", "LPC algorithm", offsetof(FlacEncodeContext, options.lpc_type), AV_OPT_TYPE_INT, {.i64 = FF_LPC_TYPE_DEFAULT }, FF_LPC_TYPE_DEFAULT, FF_LPC_TYPE_NB-1, FLAGS, "lpc_type" },
+{ "none", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_LPC_TYPE_NONE }, INT_MIN, INT_MAX, FLAGS, "lpc_type" },
+{ "fixed", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_LPC_TYPE_FIXED }, INT_MIN, INT_MAX, FLAGS, "lpc_type" },
+{ "levinson", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_LPC_TYPE_LEVINSON }, INT_MIN, INT_MAX, FLAGS, "lpc_type" },
+{ "cholesky", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_LPC_TYPE_CHOLESKY }, INT_MIN, INT_MAX, FLAGS, "lpc_type" },
+{ "lpc_passes", "Number of passes to use for Cholesky factorization during LPC analysis", offsetof(FlacEncodeContext, options.lpc_passes), AV_OPT_TYPE_INT, {.i64 = -1 }, INT_MIN, INT_MAX, FLAGS },
+{ "min_partition_order", NULL, offsetof(FlacEncodeContext, options.min_partition_order), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, MAX_PARTITION_ORDER, FLAGS },
+{ "max_partition_order", NULL, offsetof(FlacEncodeContext, options.max_partition_order), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, MAX_PARTITION_ORDER, FLAGS },
+{ "prediction_order_method", "Search method for selecting prediction order", offsetof(FlacEncodeContext, options.prediction_order_method), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, ORDER_METHOD_LOG, FLAGS, "predm" },
+{ "estimation", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = ORDER_METHOD_EST }, INT_MIN, INT_MAX, FLAGS, "predm" },
+{ "2level", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = ORDER_METHOD_2LEVEL }, INT_MIN, INT_MAX, FLAGS, "predm" },
+{ "4level", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = ORDER_METHOD_4LEVEL }, INT_MIN, INT_MAX, FLAGS, "predm" },
+{ "8level", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = ORDER_METHOD_8LEVEL }, INT_MIN, INT_MAX, FLAGS, "predm" },
+{ "search", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = ORDER_METHOD_SEARCH }, INT_MIN, INT_MAX, FLAGS, "predm" },
+{ "log", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = ORDER_METHOD_LOG }, INT_MIN, INT_MAX, FLAGS, "predm" },
+{ "ch_mode", "Stereo decorrelation mode", offsetof(FlacEncodeContext, options.ch_mode), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, FLAC_CHMODE_MID_SIDE, FLAGS, "ch_mode" },
+{ "auto", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = -1 }, INT_MIN, INT_MAX, FLAGS, "ch_mode" },
+{ "indep", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FLAC_CHMODE_INDEPENDENT }, INT_MIN, INT_MAX, FLAGS, "ch_mode" },
+{ "left_side", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FLAC_CHMODE_LEFT_SIDE }, INT_MIN, INT_MAX, FLAGS, "ch_mode" },
+{ "right_side", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FLAC_CHMODE_RIGHT_SIDE }, INT_MIN, INT_MAX, FLAGS, "ch_mode" },
+{ "mid_side", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FLAC_CHMODE_MID_SIDE }, INT_MIN, INT_MAX, FLAGS, "ch_mode" },
+{ NULL },
+};
+
+static const AVClass flac_encoder_class = {
+ "FLAC encoder",
+ av_default_item_name,
+ options,
+ LIBAVUTIL_VERSION_INT,
+};
-AVCodec flac_encoder = {
- "flac",
- AVMEDIA_TYPE_AUDIO,
- CODEC_ID_FLAC,
- sizeof(FlacEncodeContext),
- flac_encode_init,
- flac_encode_frame,
- flac_encode_close,
- NULL,
- .capabilities = CODEC_CAP_SMALL_LAST_FRAME | CODEC_CAP_DELAY,
- .sample_fmts = (const enum SampleFormat[]){SAMPLE_FMT_S16,SAMPLE_FMT_NONE},
- .long_name = NULL_IF_CONFIG_SMALL("FLAC (Free Lossless Audio Codec)"),
+AVCodec ff_flac_encoder = {
+ .name = "flac",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_FLAC,
+ .priv_data_size = sizeof(FlacEncodeContext),
+ .init = flac_encode_init,
+ .encode2 = flac_encode_frame,
+ .close = flac_encode_close,
+ .capabilities = CODEC_CAP_SMALL_LAST_FRAME | CODEC_CAP_DELAY,
+ .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16,
+ AV_SAMPLE_FMT_NONE },
+ .long_name = NULL_IF_CONFIG_SMALL("FLAC (Free Lossless Audio Codec)"),
+ .priv_class = &flac_encoder_class,
};