summaryrefslogtreecommitdiffstats
path: root/libavcodec/flacenc.c
diff options
context:
space:
mode:
Diffstat (limited to 'libavcodec/flacenc.c')
-rw-r--r--libavcodec/flacenc.c274
1 files changed, 203 insertions, 71 deletions
diff --git a/libavcodec/flacenc.c b/libavcodec/flacenc.c
index 804333d..29bd999 100644
--- a/libavcodec/flacenc.c
+++ b/libavcodec/flacenc.c
@@ -2,30 +2,31 @@
* FLAC audio encoder
* Copyright (c) 2006 Justin Ruggles <justin.ruggles@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * 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.
*
- * Libav is distributed in the hope that it will be useful,
+ * 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 Libav; if not, write to the Free Software
+ * 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/crc.h"
#include "libavutil/intmath.h"
#include "libavutil/md5.h"
#include "libavutil/opt.h"
#include "avcodec.h"
#include "bswapdsp.h"
-#include "get_bits.h"
+#include "put_bits.h"
#include "golomb.h"
#include "internal.h"
#include "lpc.h"
@@ -61,13 +62,14 @@ typedef struct CompressionOptions {
int min_partition_order;
int max_partition_order;
int ch_mode;
+ int exact_rice_parameters;
+ int multi_dim_quant;
} CompressionOptions;
typedef struct RiceContext {
enum CodingMode coding_mode;
int porder;
int params[MAX_PARTITIONS];
- uint32_t udata[FLAC_MAX_BLOCKSIZE];
} RiceContext;
typedef struct FlacSubframe {
@@ -78,9 +80,13 @@ typedef struct FlacSubframe {
int order;
int32_t coefs[MAX_LPC_ORDER];
int shift;
+
RiceContext rc;
+ uint32_t rc_udata[FLAC_MAX_BLOCKSIZE];
+ uint64_t rc_sums[32][MAX_PARTITIONS];
+
int32_t samples[FLAC_MAX_BLOCKSIZE];
- int32_t residual[FLAC_MAX_BLOCKSIZE+1];
+ int32_t residual[FLAC_MAX_BLOCKSIZE+11];
} FlacSubframe;
typedef struct FlacFrame {
@@ -157,7 +163,7 @@ static int select_blocksize(int samplerate, int block_time_ms)
int target;
int blocksize;
- assert(samplerate > 0);
+ av_assert0(samplerate > 0);
blocksize = ff_flac_blocksize_table[1];
target = (samplerate * block_time_ms) / 1000;
for (i = 0; i < 16; i++) {
@@ -251,8 +257,11 @@ static av_cold int flac_encode_init(AVCodecContext *avctx)
break;
}
- if (channels < 1 || channels > FLAC_MAX_CHANNELS)
- return -1;
+ if (channels < 1 || channels > FLAC_MAX_CHANNELS) {
+ av_log(avctx, AV_LOG_ERROR, "%d channels not supported (max %d)\n",
+ channels, FLAC_MAX_CHANNELS);
+ return AVERROR(EINVAL);
+ }
s->channels = channels;
/* find samplerate in table */
@@ -278,7 +287,8 @@ static av_cold int flac_encode_init(AVCodecContext *avctx)
s->sr_code[0] = 13;
s->sr_code[1] = freq;
} else {
- return -1;
+ av_log(avctx, AV_LOG_ERROR, "%d Hz not supported\n", freq);
+ return AVERROR(EINVAL);
}
s->samplerate = freq;
}
@@ -293,7 +303,7 @@ static av_cold int flac_encode_init(AVCodecContext *avctx)
if (level > 12) {
av_log(avctx, AV_LOG_ERROR, "invalid compression level: %d\n",
s->options.compression_level);
- return -1;
+ return AVERROR(EINVAL);
}
s->options.block_time_ms = ((int[]){ 27, 27, 27,105,105,105,105,105,105,105,105,105,105})[level];
@@ -332,13 +342,13 @@ static av_cold int flac_encode_init(AVCodecContext *avctx)
if (avctx->min_prediction_order > MAX_FIXED_ORDER) {
av_log(avctx, AV_LOG_ERROR, "invalid min prediction order: %d\n",
avctx->min_prediction_order);
- return -1;
+ return AVERROR(EINVAL);
}
} else if (avctx->min_prediction_order < MIN_LPC_ORDER ||
avctx->min_prediction_order > MAX_LPC_ORDER) {
av_log(avctx, AV_LOG_ERROR, "invalid min prediction order: %d\n",
avctx->min_prediction_order);
- return -1;
+ return AVERROR(EINVAL);
}
s->options.min_prediction_order = avctx->min_prediction_order;
}
@@ -349,20 +359,20 @@ static av_cold int flac_encode_init(AVCodecContext *avctx)
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;
+ return AVERROR(EINVAL);
}
} else if (avctx->max_prediction_order < MIN_LPC_ORDER ||
avctx->max_prediction_order > MAX_LPC_ORDER) {
av_log(avctx, AV_LOG_ERROR, "invalid max prediction order: %d\n",
avctx->max_prediction_order);
- return -1;
+ return AVERROR(EINVAL);
}
s->options.max_prediction_order = avctx->max_prediction_order;
}
if (s->options.max_prediction_order < s->options.min_prediction_order) {
av_log(avctx, AV_LOG_ERROR, "invalid prediction orders: min=%d max=%d\n",
s->options.min_prediction_order, s->options.max_prediction_order);
- return -1;
+ return AVERROR(EINVAL);
}
if (avctx->frame_size > 0) {
@@ -370,7 +380,7 @@ static av_cold int flac_encode_init(AVCodecContext *avctx)
avctx->frame_size > FLAC_MAX_BLOCKSIZE) {
av_log(avctx, AV_LOG_ERROR, "invalid block size: %d\n",
avctx->frame_size);
- return -1;
+ return AVERROR(EINVAL);
}
} else {
s->avctx->frame_size = select_blocksize(s->samplerate, s->options.block_time_ms);
@@ -398,11 +408,33 @@ static av_cold int flac_encode_init(AVCodecContext *avctx)
s->frame_count = 0;
s->min_framesize = s->max_framesize;
+ if (channels == 3 &&
+ avctx->channel_layout != (AV_CH_LAYOUT_STEREO|AV_CH_FRONT_CENTER) ||
+ channels == 4 &&
+ avctx->channel_layout != AV_CH_LAYOUT_2_2 &&
+ avctx->channel_layout != AV_CH_LAYOUT_QUAD ||
+ channels == 5 &&
+ avctx->channel_layout != AV_CH_LAYOUT_5POINT0 &&
+ avctx->channel_layout != AV_CH_LAYOUT_5POINT0_BACK ||
+ channels == 6 &&
+ avctx->channel_layout != AV_CH_LAYOUT_5POINT1 &&
+ avctx->channel_layout != AV_CH_LAYOUT_5POINT1_BACK) {
+ if (avctx->channel_layout) {
+ av_log(avctx, AV_LOG_ERROR, "Channel layout not supported by Flac, "
+ "output stream will have incorrect "
+ "channel layout.\n");
+ } else {
+ av_log(avctx, AV_LOG_WARNING, "No channel layout specified. The encoder "
+ "will use Flac channel layout for "
+ "%d channels.\n", channels);
+ }
+ }
+
ret = ff_lpc_init(&s->lpc_ctx, avctx->frame_size,
s->options.max_prediction_order, FF_LPC_TYPE_LEVINSON);
ff_bswapdsp_init(&s->bdsp);
- ff_flacdsp_init(&s->flac_dsp, avctx->sample_fmt,
+ ff_flacdsp_init(&s->flac_dsp, avctx->sample_fmt, channels,
avctx->bits_per_raw_sample);
dprint_compression_options(s);
@@ -478,7 +510,7 @@ static void copy_samples(FlacEncodeContext *s, const void *samples)
}
-static uint64_t rice_count_exact(int32_t *res, int n, int k)
+static uint64_t rice_count_exact(const int32_t *res, int n, int k)
{
int i;
uint64_t count = 0;
@@ -502,6 +534,9 @@ static uint64_t subframe_count_exact(FlacEncodeContext *s, FlacSubframe *sub,
/* subframe header */
count += 8;
+ if (sub->wasted)
+ count += sub->wasted;
+
/* subframe */
if (sub->type == FLAC_SUBFRAME_CONSTANT) {
count += sub->obits;
@@ -556,24 +591,44 @@ static int find_optimal_param(uint64_t sum, int n, int max_param)
return FFMIN(k, max_param);
}
+static int find_optimal_param_exact(uint64_t sums[32][MAX_PARTITIONS], int i, int max_param)
+{
+ int bestk = 0;
+ int64_t bestbits = INT64_MAX;
+ int k;
+
+ for (k = 0; k <= max_param; k++) {
+ int64_t bits = sums[k][i];
+ if (bits < bestbits) {
+ bestbits = bits;
+ bestk = k;
+ }
+ }
+
+ return bestk;
+}
static uint64_t calc_optimal_rice_params(RiceContext *rc, int porder,
- uint64_t *sums, int n, int pred_order)
+ uint64_t sums[32][MAX_PARTITIONS],
+ int n, int pred_order, int max_param, int exact)
{
int i;
- int k, cnt, part, max_param;
+ int k, cnt, part;
uint64_t all_bits;
- max_param = (1 << rc->coding_mode) - 2;
-
part = (1 << porder);
all_bits = 4 * part;
cnt = (n >> porder) - pred_order;
for (i = 0; i < part; i++) {
- k = find_optimal_param(sums[i], cnt, max_param);
+ if (exact) {
+ k = find_optimal_param_exact(sums, i, max_param);
+ all_bits += sums[k][i];
+ } else {
+ k = find_optimal_param(sums[0][i], cnt, max_param);
+ all_bits += rice_encode_count(sums[0][i], cnt, k);
+ }
rc->params[i] = k;
- all_bits += rice_encode_count(sums[i], cnt, k);
cnt = n >> porder;
}
@@ -583,61 +638,80 @@ static uint64_t calc_optimal_rice_params(RiceContext *rc, int porder,
}
-static void calc_sums(int pmin, int pmax, uint32_t *data, int n, int pred_order,
- uint64_t sums[][MAX_PARTITIONS])
+static void calc_sum_top(int pmax, int kmax, const uint32_t *data, int n, int pred_order,
+ uint64_t sums[32][MAX_PARTITIONS])
{
- int i, j;
+ int i, k;
int parts;
- uint32_t *res, *res_end;
+ const uint32_t *res, *res_end;
/* sums for highest level */
parts = (1 << pmax);
- res = &data[pred_order];
- res_end = &data[n >> pmax];
- for (i = 0; i < parts; i++) {
- uint64_t sum = 0;
- while (res < res_end)
- sum += *(res++);
- sums[pmax][i] = sum;
- res_end += n >> pmax;
- }
- /* sums for lower levels */
- for (i = pmax - 1; i >= pmin; i--) {
- parts = (1 << i);
- for (j = 0; j < parts; j++)
- sums[i][j] = sums[i+1][2*j] + sums[i+1][2*j+1];
+
+ for (k = 0; k <= kmax; k++) {
+ res = &data[pred_order];
+ res_end = &data[n >> pmax];
+ for (i = 0; i < parts; i++) {
+ if (kmax) {
+ uint64_t sum = (1LL + k) * (res_end - res);
+ while (res < res_end)
+ sum += *(res++) >> k;
+ sums[k][i] = sum;
+ } else {
+ uint64_t sum = 0;
+ while (res < res_end)
+ sum += *(res++);
+ sums[k][i] = sum;
+ }
+ res_end += n >> pmax;
+ }
}
}
+static void calc_sum_next(int level, uint64_t sums[32][MAX_PARTITIONS], int kmax)
+{
+ int i, k;
+ int parts = (1 << level);
+ for (i = 0; i < parts; i++) {
+ for (k=0; k<=kmax; k++)
+ sums[k][i] = sums[k][2*i] + sums[k][2*i+1];
+ }
+}
-static uint64_t calc_rice_params(RiceContext *rc, int pmin, int pmax,
- int32_t *data, int n, int pred_order)
+static uint64_t calc_rice_params(RiceContext *rc,
+ uint32_t udata[FLAC_MAX_BLOCKSIZE],
+ uint64_t sums[32][MAX_PARTITIONS],
+ int pmin, int pmax,
+ const int32_t *data, int n, int pred_order, int exact)
{
int i;
uint64_t bits[MAX_PARTITION_ORDER+1];
int opt_porder;
RiceContext tmp_rc;
- uint64_t sums[MAX_PARTITION_ORDER + 1][MAX_PARTITIONS] = { { 0 } };
+ int kmax = (1 << rc->coding_mode) - 2;
- assert(pmin >= 0 && pmin <= MAX_PARTITION_ORDER);
- assert(pmax >= 0 && pmax <= MAX_PARTITION_ORDER);
- assert(pmin <= pmax);
+ av_assert1(pmin >= 0 && pmin <= MAX_PARTITION_ORDER);
+ av_assert1(pmax >= 0 && pmax <= MAX_PARTITION_ORDER);
+ av_assert1(pmin <= pmax);
tmp_rc.coding_mode = rc->coding_mode;
for (i = 0; i < n; i++)
- rc->udata[i] = (2 * data[i]) ^ (data[i] >> 31);
+ udata[i] = (2 * data[i]) ^ (data[i] >> 31);
- calc_sums(pmin, pmax, rc->udata, n, pred_order, sums);
+ calc_sum_top(pmax, exact ? kmax : 0, udata, n, pred_order, sums);
opt_porder = pmin;
bits[pmin] = UINT32_MAX;
- for (i = pmin; i <= pmax; i++) {
- bits[i] = calc_optimal_rice_params(&tmp_rc, i, sums[i], n, pred_order);
- if (bits[i] <= bits[opt_porder]) {
+ for (i = pmax; ; ) {
+ bits[i] = calc_optimal_rice_params(&tmp_rc, i, sums, n, pred_order, kmax, exact);
+ if (bits[i] < bits[opt_porder] || pmax == pmin) {
opt_porder = i;
*rc = tmp_rc;
}
+ if (i == pmin)
+ break;
+ calc_sum_next(--i, sums, exact ? kmax : 0);
}
return bits[opt_porder];
@@ -664,8 +738,8 @@ static uint64_t find_subframe_rice_params(FlacEncodeContext *s,
uint64_t bits = 8 + pred_order * sub->obits + 2 + sub->rc.coding_mode;
if (sub->type == FLAC_SUBFRAME_LPC)
bits += 4 + 5 + pred_order * s->options.lpc_coeff_precision;
- bits += calc_rice_params(&sub->rc, pmin, pmax, sub->residual,
- s->frame.blocksize, pred_order);
+ bits += calc_rice_params(&sub->rc, sub->rc_udata, sub->rc_sums, pmin, pmax, sub->residual,
+ s->frame.blocksize, pred_order, s->options.exact_rice_parameters);
return bits;
}
@@ -804,8 +878,13 @@ static int encode_residual_ch(FlacEncodeContext *s, int ch)
order = av_clip(order, min_order - 1, max_order - 1);
if (order == last_order)
continue;
- s->flac_dsp.lpc_encode(res, smp, n, order+1, coefs[order],
- shift[order]);
+ if (s->bps_code * 4 + s->options.lpc_coeff_precision + av_log2(order) <= 32) {
+ s->flac_dsp.lpc16_encode(res, smp, n, order+1, coefs[order],
+ shift[order]);
+ } else {
+ s->flac_dsp.lpc32_encode(res, smp, n, order+1, coefs[order],
+ shift[order]);
+ }
bits[i] = find_subframe_rice_params(s, sub, order+1);
if (bits[i] < bits[opt_index]) {
opt_index = i;
@@ -819,7 +898,11 @@ static int encode_residual_ch(FlacEncodeContext *s, int ch)
opt_order = 0;
bits[0] = UINT32_MAX;
for (i = min_order-1; i < max_order; i++) {
- s->flac_dsp.lpc_encode(res, smp, n, i+1, coefs[i], shift[i]);
+ if (s->bps_code * 4 + s->options.lpc_coeff_precision + av_log2(i) <= 32) {
+ s->flac_dsp.lpc16_encode(res, smp, n, i+1, coefs[i], shift[i]);
+ } else {
+ s->flac_dsp.lpc32_encode(res, smp, n, i+1, coefs[i], shift[i]);
+ }
bits[i] = find_subframe_rice_params(s, sub, i+1);
if (bits[i] < bits[opt_order])
opt_order = i;
@@ -837,7 +920,11 @@ static int encode_residual_ch(FlacEncodeContext *s, int ch)
for (i = last-step; i <= last+step; i += step) {
if (i < min_order-1 || i >= max_order || bits[i] < UINT32_MAX)
continue;
- s->flac_dsp.lpc_encode(res, smp, n, i+1, coefs[i], shift[i]);
+ if (s->bps_code * 4 + s->options.lpc_coeff_precision + av_log2(i) <= 32) {
+ s->flac_dsp.lpc32_encode(res, smp, n, i+1, coefs[i], shift[i]);
+ } else {
+ s->flac_dsp.lpc16_encode(res, smp, n, i+1, coefs[i], shift[i]);
+ }
bits[i] = find_subframe_rice_params(s, sub, i+1);
if (bits[i] < bits[opt_order])
opt_order = i;
@@ -846,13 +933,60 @@ static int encode_residual_ch(FlacEncodeContext *s, int ch)
opt_order++;
}
+ if (s->options.multi_dim_quant) {
+ int allsteps = 1;
+ int i, step, improved;
+ int64_t best_score = INT64_MAX;
+ int32_t qmax;
+
+ qmax = (1 << (s->options.lpc_coeff_precision - 1)) - 1;
+
+ for (i=0; i<opt_order; i++)
+ allsteps *= 3;
+
+ do {
+ improved = 0;
+ for (step = 0; step < allsteps; step++) {
+ int tmp = step;
+ int32_t lpc_try[MAX_LPC_ORDER];
+ int64_t score = 0;
+ int diffsum = 0;
+
+ for (i=0; i<opt_order; i++) {
+ int diff = ((tmp + 1) % 3) - 1;
+ lpc_try[i] = av_clip(coefs[opt_order - 1][i] + diff, -qmax, qmax);
+ tmp /= 3;
+ diffsum += !!diff;
+ }
+ if (diffsum >8)
+ continue;
+
+ if (s->bps_code * 4 + s->options.lpc_coeff_precision + av_log2(opt_order - 1) <= 32) {
+ s->flac_dsp.lpc16_encode(res, smp, n, opt_order, lpc_try, shift[opt_order-1]);
+ } else {
+ s->flac_dsp.lpc32_encode(res, smp, n, opt_order, lpc_try, shift[opt_order-1]);
+ }
+ score = find_subframe_rice_params(s, sub, opt_order);
+ if (score < best_score) {
+ best_score = score;
+ memcpy(coefs[opt_order-1], lpc_try, sizeof(*coefs));
+ improved=1;
+ }
+ }
+ } while(improved);
+ }
+
sub->order = opt_order;
sub->type_code = sub->type | (sub->order-1);
sub->shift = shift[sub->order-1];
for (i = 0; i < sub->order; i++)
sub->coefs[i] = coefs[sub->order-1][i];
- s->flac_dsp.lpc_encode(res, smp, n, sub->order, sub->coefs, sub->shift);
+ if (s->bps_code * 4 + s->options.lpc_coeff_precision + av_log2(opt_order) <= 32) {
+ s->flac_dsp.lpc16_encode(res, smp, n, sub->order, sub->coefs, sub->shift);
+ } else {
+ s->flac_dsp.lpc32_encode(res, smp, n, sub->order, sub->coefs, sub->shift);
+ }
find_subframe_rice_params(s, sub, sub->order);
@@ -948,7 +1082,7 @@ static void remove_wasted_bits(FlacEncodeContext *s)
}
-static int estimate_stereo_mode(int32_t *left_ch, int32_t *right_ch, int n,
+static int estimate_stereo_mode(const int32_t *left_ch, const int32_t *right_ch, int n,
int max_rice_param)
{
int i, best;
@@ -1188,9 +1322,7 @@ static int update_md5_sum(FlacEncodeContext *s, const void *samples)
for (i = 0; i < s->frame.blocksize * s->channels; i++) {
int32_t v = samples0[i] >> 8;
- *tmp++ = (v ) & 0xFF;
- *tmp++ = (v >> 8) & 0xFF;
- *tmp++ = (v >> 16) & 0xFF;
+ AV_WL24(tmp + 3*i, v);
}
buf = s->md5_buffer;
}
@@ -1258,10 +1390,8 @@ static int flac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
}
}
- if ((ret = ff_alloc_packet(avpkt, frame_bytes))) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n");
+ if ((ret = ff_alloc_packet2(avctx, avpkt, frame_bytes)) < 0)
return ret;
- }
out_bytes = write_frame(s, avpkt);
@@ -1308,7 +1438,7 @@ static const AVOption options[] = {
{ "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 }, 1, INT_MAX, FLAGS },
+{ "lpc_passes", "Number of passes to use for Cholesky factorization during LPC analysis", offsetof(FlacEncodeContext, options.lpc_passes), AV_OPT_TYPE_INT, {.i64 = 2 }, 1, 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" },
@@ -1324,6 +1454,8 @@ static const AVOption options[] = {
{ "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" },
+{ "exact_rice_parameters", "Calculate rice parameters exactly", offsetof(FlacEncodeContext, options.exact_rice_parameters), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS },
+{ "multi_dim_quant", "Multi-dimensional quantization", offsetof(FlacEncodeContext, options.multi_dim_quant), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS },
{ NULL },
};
@@ -1343,7 +1475,7 @@ AVCodec ff_flac_encoder = {
.init = flac_encode_init,
.encode2 = flac_encode_frame,
.close = flac_encode_close,
- .capabilities = CODEC_CAP_SMALL_LAST_FRAME | CODEC_CAP_DELAY,
+ .capabilities = CODEC_CAP_SMALL_LAST_FRAME | CODEC_CAP_DELAY | CODEC_CAP_LOSSLESS,
.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16,
AV_SAMPLE_FMT_S32,
AV_SAMPLE_FMT_NONE },
OpenPOWER on IntegriCloud