aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustin Ruggles <justin.ruggles@gmail.com>2011-12-31 09:36:25 -0500
committerJustin Ruggles <justin.ruggles@gmail.com>2012-01-15 21:24:18 -0500
commitee458cb1fa3faa006785d725fb3e386174793000 (patch)
treecd7dc5569c948ef557ca631d2cca7a160ab4db11
parent05f95443cac79eba959d7a1a919d77e8f401ea6f (diff)
downloadffmpeg-ee458cb1fa3faa006785d725fb3e386174793000.tar.gz
avconv: use avcodec_encode_audio2()
-rw-r--r--avconv.c205
1 files changed, 105 insertions, 100 deletions
diff --git a/avconv.c b/avconv.c
index 817c0cf928..2246851301 100644
--- a/avconv.c
+++ b/avconv.c
@@ -141,8 +141,7 @@ static float dts_delta_threshold = 10;
static int print_stats = 1;
static uint8_t *audio_buf;
-static uint8_t *audio_out;
-static unsigned int allocated_audio_out_size, allocated_audio_buf_size;
+static unsigned int allocated_audio_buf_size;
#define DEFAULT_PASS_LOGFILENAME_PREFIX "av2pass"
@@ -208,6 +207,7 @@ typedef struct OutputStream {
AVBitStreamFilterContext *bitstream_filters;
AVCodec *enc;
int64_t max_frames;
+ AVFrame *output_frame;
/* video only */
int video_resample;
@@ -680,6 +680,13 @@ void exit_program(int ret)
}
output_streams[i].bitstream_filters = NULL;
+ if (output_streams[i].output_frame) {
+ AVFrame *frame = output_streams[i].output_frame;
+ if (frame->extended_data != frame->data)
+ av_freep(&frame->extended_data);
+ av_freep(&frame);
+ }
+
#if CONFIG_AVFILTER
av_freep(&output_streams[i].avfilter);
#endif
@@ -705,8 +712,7 @@ void exit_program(int ret)
uninit_opts();
av_free(audio_buf);
- av_free(audio_out);
- allocated_audio_buf_size = allocated_audio_out_size = 0;
+ allocated_audio_buf_size = 0;
#if CONFIG_AVFILTER
avfilter_uninit();
@@ -907,18 +913,75 @@ static void generate_silence(uint8_t* buf, enum AVSampleFormat sample_fmt, size_
memset(buf, fill_char, size);
}
+static int encode_audio_frame(AVFormatContext *s, OutputStream *ost,
+ const uint8_t *buf, int buf_size)
+{
+ AVCodecContext *enc = ost->st->codec;
+ AVFrame *frame = NULL;
+ AVPacket pkt;
+ int ret, got_packet;
+
+ av_init_packet(&pkt);
+ pkt.data = NULL;
+ pkt.size = 0;
+
+ if (buf) {
+ if (!ost->output_frame) {
+ ost->output_frame = avcodec_alloc_frame();
+ if (!ost->output_frame) {
+ av_log(NULL, AV_LOG_FATAL, "out-of-memory in encode_audio_frame()\n");
+ exit_program(1);
+ }
+ }
+ frame = ost->output_frame;
+ if (frame->extended_data != frame->data)
+ av_freep(&frame->extended_data);
+ avcodec_get_frame_defaults(frame);
+
+ frame->nb_samples = buf_size /
+ (enc->channels * av_get_bytes_per_sample(enc->sample_fmt));
+ if ((ret = avcodec_fill_audio_frame(frame, enc->channels, enc->sample_fmt,
+ buf, buf_size, 1)) < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Audio encoding failed\n");
+ exit_program(1);
+ }
+ }
+
+ got_packet = 0;
+ if (avcodec_encode_audio2(enc, &pkt, frame, &got_packet) < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Audio encoding failed\n");
+ exit_program(1);
+ }
+
+ if (got_packet) {
+ pkt.stream_index = ost->index;
+ if (pkt.pts != AV_NOPTS_VALUE)
+ pkt.pts = av_rescale_q(pkt.pts, enc->time_base, ost->st->time_base);
+ if (pkt.duration > 0)
+ pkt.duration = av_rescale_q(pkt.duration, enc->time_base, ost->st->time_base);
+
+ write_frame(s, &pkt, ost);
+
+ audio_size += pkt.size;
+ }
+
+ if (frame)
+ ost->sync_opts += frame->nb_samples;
+
+ return pkt.size;
+}
+
static void do_audio_out(AVFormatContext *s, OutputStream *ost,
InputStream *ist, AVFrame *decoded_frame)
{
uint8_t *buftmp;
- int64_t audio_out_size, audio_buf_size;
+ int64_t audio_buf_size;
- int size_out, frame_bytes, ret, resample_changed;
+ int size_out, frame_bytes, resample_changed;
AVCodecContext *enc = ost->st->codec;
AVCodecContext *dec = ist->st->codec;
int osize = av_get_bytes_per_sample(enc->sample_fmt);
int isize = av_get_bytes_per_sample(dec->sample_fmt);
- const int coded_bps = av_get_bits_per_sample(enc->codec->id);
uint8_t *buf = decoded_frame->data[0];
int size = decoded_frame->nb_samples * dec->channels * isize;
int64_t allocated_for_size = size;
@@ -930,19 +993,13 @@ need_realloc:
audio_buf_size = FFMAX(audio_buf_size, enc->frame_size);
audio_buf_size *= osize * enc->channels;
- audio_out_size = FFMAX(audio_buf_size, enc->frame_size * osize * enc->channels);
- if (coded_bps > 8 * osize)
- audio_out_size = audio_out_size * coded_bps / (8*osize);
- audio_out_size += FF_MIN_BUFFER_SIZE;
-
- if (audio_out_size > INT_MAX || audio_buf_size > INT_MAX) {
+ if (audio_buf_size > INT_MAX) {
av_log(NULL, AV_LOG_FATAL, "Buffer sizes too large\n");
exit_program(1);
}
av_fast_malloc(&audio_buf, &allocated_audio_buf_size, audio_buf_size);
- av_fast_malloc(&audio_out, &allocated_audio_out_size, audio_out_size);
- if (!audio_buf || !audio_out) {
+ if (!audio_buf) {
av_log(NULL, AV_LOG_FATAL, "Out of memory in do_audio_out\n");
exit_program(1);
}
@@ -1080,7 +1137,7 @@ need_realloc:
}
/* now encode as many frames as possible */
- if (enc->frame_size > 1) {
+ if (!(enc->codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE)) {
/* output resampled raw samples */
if (av_fifo_realloc2(ost->fifo, av_fifo_size(ost->fifo) + size_out) < 0) {
av_log(NULL, AV_LOG_FATAL, "av_fifo_realloc2() failed\n");
@@ -1091,62 +1148,11 @@ need_realloc:
frame_bytes = enc->frame_size * osize * enc->channels;
while (av_fifo_size(ost->fifo) >= frame_bytes) {
- AVPacket pkt;
- av_init_packet(&pkt);
-
av_fifo_generic_read(ost->fifo, audio_buf, frame_bytes, NULL);
-
- // FIXME pass ost->sync_opts as AVFrame.pts in avcodec_encode_audio()
-
- ret = avcodec_encode_audio(enc, audio_out, audio_out_size,
- (short *)audio_buf);
- if (ret < 0) {
- av_log(NULL, AV_LOG_FATAL, "Audio encoding failed\n");
- exit_program(1);
- }
- audio_size += ret;
- pkt.stream_index = ost->index;
- pkt.data = audio_out;
- pkt.size = ret;
- if (enc->coded_frame && enc->coded_frame->pts != AV_NOPTS_VALUE)
- pkt.pts = av_rescale_q(enc->coded_frame->pts, enc->time_base, ost->st->time_base);
- pkt.flags |= AV_PKT_FLAG_KEY;
- write_frame(s, &pkt, ost);
-
- ost->sync_opts += enc->frame_size;
+ encode_audio_frame(s, ost, audio_buf, frame_bytes);
}
} else {
- AVPacket pkt;
- av_init_packet(&pkt);
-
- ost->sync_opts += size_out / (osize * enc->channels);
-
- /* output a pcm frame */
- /* determine the size of the coded buffer */
- size_out /= osize;
- if (coded_bps)
- size_out = size_out * coded_bps / 8;
-
- if (size_out > audio_out_size) {
- av_log(NULL, AV_LOG_FATAL, "Internal error, buffer size too small\n");
- exit_program(1);
- }
-
- // FIXME pass ost->sync_opts as AVFrame.pts in avcodec_encode_audio()
- ret = avcodec_encode_audio(enc, audio_out, size_out,
- (short *)buftmp);
- if (ret < 0) {
- av_log(NULL, AV_LOG_FATAL, "Audio encoding failed\n");
- exit_program(1);
- }
- audio_size += ret;
- pkt.stream_index = ost->index;
- pkt.data = audio_out;
- pkt.size = ret;
- if (enc->coded_frame && enc->coded_frame->pts != AV_NOPTS_VALUE)
- pkt.pts = av_rescale_q(enc->coded_frame->pts, enc->time_base, ost->st->time_base);
- pkt.flags |= AV_PKT_FLAG_KEY;
- write_frame(s, &pkt, ost);
+ encode_audio_frame(s, ost, buftmp, size_out);
}
}
@@ -1620,6 +1626,7 @@ static void flush_encoders(OutputStream *ost_table, int nb_ostreams)
OutputStream *ost = &ost_table[i];
AVCodecContext *enc = ost->st->codec;
AVFormatContext *os = output_files[ost->file_index].ctx;
+ int stop_encoding = 0;
if (!ost->encoding_needed)
continue;
@@ -1633,41 +1640,35 @@ static void flush_encoders(OutputStream *ost_table, int nb_ostreams)
AVPacket pkt;
int fifo_bytes;
av_init_packet(&pkt);
- pkt.stream_index = ost->index;
+ pkt.data = NULL;
+ pkt.size = 0;
switch (ost->st->codec->codec_type) {
case AVMEDIA_TYPE_AUDIO:
fifo_bytes = av_fifo_size(ost->fifo);
- ret = 0;
- /* encode any samples remaining in fifo */
if (fifo_bytes > 0) {
- int osize = av_get_bytes_per_sample(enc->sample_fmt);
- int fs_tmp = enc->frame_size;
+ /* encode any samples remaining in fifo */
+ int frame_bytes = fifo_bytes;
av_fifo_generic_read(ost->fifo, audio_buf, fifo_bytes, NULL);
- if (enc->codec->capabilities & CODEC_CAP_SMALL_LAST_FRAME) {
- enc->frame_size = fifo_bytes / (osize * enc->channels);
- } else { /* pad */
- int frame_bytes = enc->frame_size*osize*enc->channels;
+
+ /* pad last frame with silence if needed */
+ if (!(enc->codec->capabilities & CODEC_CAP_SMALL_LAST_FRAME)) {
+ frame_bytes = enc->frame_size * enc->channels *
+ av_get_bytes_per_sample(enc->sample_fmt);
if (allocated_audio_buf_size < frame_bytes)
exit_program(1);
generate_silence(audio_buf+fifo_bytes, enc->sample_fmt, frame_bytes - fifo_bytes);
}
-
- ret = avcodec_encode_audio(enc, bit_buffer, bit_buffer_size, (short *)audio_buf);
- pkt.duration = av_rescale((int64_t)enc->frame_size*ost->st->time_base.den,
- ost->st->time_base.num, enc->sample_rate);
- enc->frame_size = fs_tmp;
- }
- if (ret <= 0) {
- ret = avcodec_encode_audio(enc, bit_buffer, bit_buffer_size, NULL);
- }
- if (ret < 0) {
- av_log(NULL, AV_LOG_FATAL, "Audio encoding failed\n");
- exit_program(1);
+ encode_audio_frame(os, ost, audio_buf, frame_bytes);
+ } else {
+ /* flush encoder with NULL frames until it is done
+ returning packets */
+ if (encode_audio_frame(os, ost, NULL, 0) == 0) {
+ stop_encoding = 1;
+ break;
+ }
}
- audio_size += ret;
- pkt.flags |= AV_PKT_FLAG_KEY;
break;
case AVMEDIA_TYPE_VIDEO:
ret = avcodec_encode_video(enc, bit_buffer, bit_buffer_size, NULL);
@@ -1681,18 +1682,22 @@ static void flush_encoders(OutputStream *ost_table, int nb_ostreams)
if (ost->logfile && enc->stats_out) {
fprintf(ost->logfile, "%s", enc->stats_out);
}
+ if (ret <= 0) {
+ stop_encoding = 1;
+ break;
+ }
+ pkt.stream_index = ost->index;
+ pkt.data = bit_buffer;
+ pkt.size = ret;
+ if (enc->coded_frame && enc->coded_frame->pts != AV_NOPTS_VALUE)
+ pkt.pts = av_rescale_q(enc->coded_frame->pts, enc->time_base, ost->st->time_base);
+ write_frame(os, &pkt, ost);
break;
default:
- ret = -1;
+ stop_encoding = 1;
}
-
- if (ret <= 0)
+ if (stop_encoding)
break;
- pkt.data = bit_buffer;
- pkt.size = ret;
- if (enc->coded_frame && enc->coded_frame->pts != AV_NOPTS_VALUE)
- pkt.pts = av_rescale_q(enc->coded_frame->pts, enc->time_base, ost->st->time_base);
- write_frame(os, &pkt, ost);
}
}
}