/**
* FLAC audio encoder
- * Copyright (c) 2006 Justin Ruggles <jruggle@earthlink.net>
+ * Copyright (c) 2006 Justin Ruggles <justin.ruggles@gmail.com>
*
* This file is part of FFmpeg.
*
#include "libavutil/crc.h"
#include "libavutil/lls.h"
+#include "libavutil/md5.h"
#include "avcodec.h"
#include "bitstream.h"
#include "dsputil.h"
int ch_code;
int samplerate;
int sr_code[2];
+ int min_framesize;
+ int min_encoded_framesize;
int max_framesize;
+ int max_encoded_framesize;
uint32_t frame_count;
+ uint64_t sample_count;
+ uint8_t md5sum[16];
FlacFrame frame;
CompressionOptions options;
AVCodecContext *avctx;
DSPContext dsp;
+ struct AVMD5 *md5ctx;
} FlacEncodeContext;
static const int flac_samplerates[16] = {
/* streaminfo metadata block */
put_bits(&pb, 16, s->avctx->frame_size);
put_bits(&pb, 16, s->avctx->frame_size);
- put_bits(&pb, 24, 0);
+ put_bits(&pb, 24, s->min_framesize);
put_bits(&pb, 24, s->max_framesize);
put_bits(&pb, 20, s->samplerate);
put_bits(&pb, 3, s->channels-1);
put_bits(&pb, 5, 15); /* bits per sample - 1 */
+ /* write 36-bit sample count in 2 put_bits() calls */
+ put_bits(&pb, 24, (s->sample_count & 0xFFFFFF000LL) >> 12);
+ put_bits(&pb, 12, s->sample_count & 0x000000FFFLL);
flush_put_bits(&pb);
- /* total samples = 0 */
- /* MD5 signature = 0 */
+ memcpy(&header[18], s->md5sum, 16);
}
/**
} else {
s->max_framesize = 14 + (s->avctx->frame_size * s->channels * 2);
}
+ s->min_encoded_framesize = 0xFFFFFF;
+
+ /* initialize MD5 context */
+ s->md5ctx = av_malloc(av_md5_size);
+ if(!s->md5ctx)
+ return AVERROR_NOMEM;
+ av_md5_init(s->md5ctx);
streaminfo = av_malloc(FLAC_STREAMINFO_SIZE);
write_streaminfo(s, streaminfo);
for(i=0; i<order; i++) {
res[i] = smp[i];
}
-#ifdef CONFIG_SMALL
+#if CONFIG_SMALL
for(i=order; i<n; i+=2) {
int j;
int s = smp[i];
}
/* LPC */
- opt_order = ff_lpc_calc_coefs(&ctx->dsp, smp, n, min_order, max_order, precision, coefs,
- shift, ctx->options.use_lpc, omethod, MAX_LPC_SHIFT, 0);
+ opt_order = ff_lpc_calc_coefs(&ctx->dsp, smp, n, min_order, max_order,
+ precision, coefs, shift, ctx->options.use_lpc,
+ omethod, MAX_LPC_SHIFT, 0);
if(omethod == ORDER_METHOD_2LEVEL ||
omethod == ORDER_METHOD_4LEVEL ||
flush_put_bits(&s->pb);
}
+static void update_md5_sum(FlacEncodeContext *s, int16_t *samples)
+{
+#ifdef WORDS_BIGENDIAN
+ int i;
+ for(i = 0; i < s->frame.blocksize*s->channels; i++) {
+ int16_t smp = le2me_16(samples[i]);
+ av_md5_update(s->md5ctx, (uint8_t *)&smp, 2);
+ }
+#else
+ av_md5_update(s->md5ctx, (uint8_t *)samples, s->frame.blocksize*s->channels*2);
+#endif
+}
+
static int flac_encode_frame(AVCodecContext *avctx, uint8_t *frame,
int buf_size, void *data)
{
FlacEncodeContext *s;
int16_t *samples = data;
int out_bytes;
+ int reencoded=0;
s = avctx->priv_data;
+ if(buf_size < s->max_framesize*2) {
+ av_log(avctx, AV_LOG_ERROR, "output buffer too small\n");
+ return 0;
+ }
+
+ /* when the last block is reached, update the header in extradata */
+ if (!data) {
+ s->min_framesize = s->min_encoded_framesize;
+ s->max_framesize = s->max_encoded_framesize;
+ av_md5_final(s->md5ctx, s->md5sum);
+ write_streaminfo(s, avctx->extradata);
+ return 0;
+ }
+
init_frame(s);
copy_samples(s, samples);
for(ch=0; ch<s->channels; ch++) {
encode_residual(s, ch);
}
+
+write_frame:
init_put_bits(&s->pb, frame, buf_size);
output_frame_header(s);
output_subframes(s);
output_frame_footer(s);
out_bytes = put_bits_count(&s->pb) >> 3;
- if(out_bytes > s->max_framesize || out_bytes >= buf_size) {
- /* frame too large. use verbatim mode */
- for(ch=0; ch<s->channels; ch++) {
- encode_residual_v(s, ch);
- }
- init_put_bits(&s->pb, frame, buf_size);
- output_frame_header(s);
- output_subframes(s);
- output_frame_footer(s);
- out_bytes = put_bits_count(&s->pb) >> 3;
-
- if(out_bytes > s->max_framesize || out_bytes >= buf_size) {
+ if(out_bytes > s->max_framesize) {
+ if(reencoded) {
/* still too large. must be an error. */
av_log(avctx, AV_LOG_ERROR, "error encoding frame\n");
return -1;
}
+
+ /* frame too large. use verbatim mode */
+ for(ch=0; ch<s->channels; ch++) {
+ encode_residual_v(s, ch);
+ }
+ reencoded = 1;
+ goto write_frame;
}
s->frame_count++;
+ s->sample_count += avctx->frame_size;
+ update_md5_sum(s, samples);
+ if (out_bytes > s->max_encoded_framesize)
+ s->max_encoded_framesize = out_bytes;
+ if (out_bytes < s->min_encoded_framesize)
+ s->min_encoded_framesize = out_bytes;
+
return out_bytes;
}
static av_cold int flac_encode_close(AVCodecContext *avctx)
{
+ if (avctx->priv_data) {
+ FlacEncodeContext *s = avctx->priv_data;
+ av_freep(&s->md5ctx);
+ }
av_freep(&avctx->extradata);
avctx->extradata_size = 0;
av_freep(&avctx->coded_frame);
flac_encode_frame,
flac_encode_close,
NULL,
- .capabilities = CODEC_CAP_SMALL_LAST_FRAME,
+ .capabilities = CODEC_CAP_SMALL_LAST_FRAME | CODEC_CAP_DELAY,
.sample_fmts = (enum SampleFormat[]){SAMPLE_FMT_S16,SAMPLE_FMT_NONE},
.long_name = NULL_IF_CONFIG_SMALL("FLAC (Free Lossless Audio Codec)"),
};