Commit ee458cb1 authored by Justin Ruggles's avatar Justin Ruggles

avconv: use avcodec_encode_audio2()

parent 05f95443
...@@ -141,8 +141,7 @@ static float dts_delta_threshold = 10; ...@@ -141,8 +141,7 @@ static float dts_delta_threshold = 10;
static int print_stats = 1; static int print_stats = 1;
static uint8_t *audio_buf; static uint8_t *audio_buf;
static uint8_t *audio_out; static unsigned int allocated_audio_buf_size;
static unsigned int allocated_audio_out_size, allocated_audio_buf_size;
#define DEFAULT_PASS_LOGFILENAME_PREFIX "av2pass" #define DEFAULT_PASS_LOGFILENAME_PREFIX "av2pass"
...@@ -208,6 +207,7 @@ typedef struct OutputStream { ...@@ -208,6 +207,7 @@ typedef struct OutputStream {
AVBitStreamFilterContext *bitstream_filters; AVBitStreamFilterContext *bitstream_filters;
AVCodec *enc; AVCodec *enc;
int64_t max_frames; int64_t max_frames;
AVFrame *output_frame;
/* video only */ /* video only */
int video_resample; int video_resample;
...@@ -680,6 +680,13 @@ void exit_program(int ret) ...@@ -680,6 +680,13 @@ void exit_program(int ret)
} }
output_streams[i].bitstream_filters = NULL; 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 #if CONFIG_AVFILTER
av_freep(&output_streams[i].avfilter); av_freep(&output_streams[i].avfilter);
#endif #endif
...@@ -705,8 +712,7 @@ void exit_program(int ret) ...@@ -705,8 +712,7 @@ void exit_program(int ret)
uninit_opts(); uninit_opts();
av_free(audio_buf); av_free(audio_buf);
av_free(audio_out); allocated_audio_buf_size = 0;
allocated_audio_buf_size = allocated_audio_out_size = 0;
#if CONFIG_AVFILTER #if CONFIG_AVFILTER
avfilter_uninit(); avfilter_uninit();
...@@ -907,18 +913,75 @@ static void generate_silence(uint8_t* buf, enum AVSampleFormat sample_fmt, size_ ...@@ -907,18 +913,75 @@ static void generate_silence(uint8_t* buf, enum AVSampleFormat sample_fmt, size_
memset(buf, fill_char, 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, static void do_audio_out(AVFormatContext *s, OutputStream *ost,
InputStream *ist, AVFrame *decoded_frame) InputStream *ist, AVFrame *decoded_frame)
{ {
uint8_t *buftmp; 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 *enc = ost->st->codec;
AVCodecContext *dec = ist->st->codec; AVCodecContext *dec = ist->st->codec;
int osize = av_get_bytes_per_sample(enc->sample_fmt); int osize = av_get_bytes_per_sample(enc->sample_fmt);
int isize = av_get_bytes_per_sample(dec->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]; uint8_t *buf = decoded_frame->data[0];
int size = decoded_frame->nb_samples * dec->channels * isize; int size = decoded_frame->nb_samples * dec->channels * isize;
int64_t allocated_for_size = size; int64_t allocated_for_size = size;
...@@ -930,19 +993,13 @@ need_realloc: ...@@ -930,19 +993,13 @@ need_realloc:
audio_buf_size = FFMAX(audio_buf_size, enc->frame_size); audio_buf_size = FFMAX(audio_buf_size, enc->frame_size);
audio_buf_size *= osize * enc->channels; audio_buf_size *= osize * enc->channels;
audio_out_size = FFMAX(audio_buf_size, enc->frame_size * osize * enc->channels); if (audio_buf_size > INT_MAX) {
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) {
av_log(NULL, AV_LOG_FATAL, "Buffer sizes too large\n"); av_log(NULL, AV_LOG_FATAL, "Buffer sizes too large\n");
exit_program(1); exit_program(1);
} }
av_fast_malloc(&audio_buf, &allocated_audio_buf_size, audio_buf_size); 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) {
if (!audio_buf || !audio_out) {
av_log(NULL, AV_LOG_FATAL, "Out of memory in do_audio_out\n"); av_log(NULL, AV_LOG_FATAL, "Out of memory in do_audio_out\n");
exit_program(1); exit_program(1);
} }
...@@ -1080,7 +1137,7 @@ need_realloc: ...@@ -1080,7 +1137,7 @@ need_realloc:
} }
/* now encode as many frames as possible */ /* 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 */ /* output resampled raw samples */
if (av_fifo_realloc2(ost->fifo, av_fifo_size(ost->fifo) + size_out) < 0) { 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"); av_log(NULL, AV_LOG_FATAL, "av_fifo_realloc2() failed\n");
...@@ -1091,62 +1148,11 @@ need_realloc: ...@@ -1091,62 +1148,11 @@ need_realloc:
frame_bytes = enc->frame_size * osize * enc->channels; frame_bytes = enc->frame_size * osize * enc->channels;
while (av_fifo_size(ost->fifo) >= frame_bytes) { 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); av_fifo_generic_read(ost->fifo, audio_buf, frame_bytes, NULL);
encode_audio_frame(s, ost, audio_buf, frame_bytes);
// 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;
} }
} else { } else {
AVPacket pkt; encode_audio_frame(s, ost, buftmp, size_out);
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);
} }
} }
...@@ -1620,6 +1626,7 @@ static void flush_encoders(OutputStream *ost_table, int nb_ostreams) ...@@ -1620,6 +1626,7 @@ static void flush_encoders(OutputStream *ost_table, int nb_ostreams)
OutputStream *ost = &ost_table[i]; OutputStream *ost = &ost_table[i];
AVCodecContext *enc = ost->st->codec; AVCodecContext *enc = ost->st->codec;
AVFormatContext *os = output_files[ost->file_index].ctx; AVFormatContext *os = output_files[ost->file_index].ctx;
int stop_encoding = 0;
if (!ost->encoding_needed) if (!ost->encoding_needed)
continue; continue;
...@@ -1633,41 +1640,35 @@ static void flush_encoders(OutputStream *ost_table, int nb_ostreams) ...@@ -1633,41 +1640,35 @@ static void flush_encoders(OutputStream *ost_table, int nb_ostreams)
AVPacket pkt; AVPacket pkt;
int fifo_bytes; int fifo_bytes;
av_init_packet(&pkt); av_init_packet(&pkt);
pkt.stream_index = ost->index; pkt.data = NULL;
pkt.size = 0;
switch (ost->st->codec->codec_type) { switch (ost->st->codec->codec_type) {
case AVMEDIA_TYPE_AUDIO: case AVMEDIA_TYPE_AUDIO:
fifo_bytes = av_fifo_size(ost->fifo); fifo_bytes = av_fifo_size(ost->fifo);
ret = 0;
/* encode any samples remaining in fifo */
if (fifo_bytes > 0) { if (fifo_bytes > 0) {
int osize = av_get_bytes_per_sample(enc->sample_fmt); /* encode any samples remaining in fifo */
int fs_tmp = enc->frame_size; int frame_bytes = fifo_bytes;
av_fifo_generic_read(ost->fifo, audio_buf, fifo_bytes, NULL); 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); /* pad last frame with silence if needed */
} else { /* pad */ if (!(enc->codec->capabilities & CODEC_CAP_SMALL_LAST_FRAME)) {
int frame_bytes = enc->frame_size*osize*enc->channels; frame_bytes = enc->frame_size * enc->channels *
av_get_bytes_per_sample(enc->sample_fmt);
if (allocated_audio_buf_size < frame_bytes) if (allocated_audio_buf_size < frame_bytes)
exit_program(1); exit_program(1);
generate_silence(audio_buf+fifo_bytes, enc->sample_fmt, frame_bytes - fifo_bytes); generate_silence(audio_buf+fifo_bytes, enc->sample_fmt, frame_bytes - fifo_bytes);
} }
encode_audio_frame(os, ost, audio_buf, frame_bytes);
ret = avcodec_encode_audio(enc, bit_buffer, bit_buffer_size, (short *)audio_buf); } else {
pkt.duration = av_rescale((int64_t)enc->frame_size*ost->st->time_base.den, /* flush encoder with NULL frames until it is done
ost->st->time_base.num, enc->sample_rate); returning packets */
enc->frame_size = fs_tmp; if (encode_audio_frame(os, ost, NULL, 0) == 0) {
} stop_encoding = 1;
if (ret <= 0) { break;
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);
} }
audio_size += ret;
pkt.flags |= AV_PKT_FLAG_KEY;
break; break;
case AVMEDIA_TYPE_VIDEO: case AVMEDIA_TYPE_VIDEO:
ret = avcodec_encode_video(enc, bit_buffer, bit_buffer_size, NULL); 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) ...@@ -1681,18 +1682,22 @@ static void flush_encoders(OutputStream *ost_table, int nb_ostreams)
if (ost->logfile && enc->stats_out) { if (ost->logfile && enc->stats_out) {
fprintf(ost->logfile, "%s", 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; break;
default: default:
ret = -1; stop_encoding = 1;
} }
if (stop_encoding)
if (ret <= 0)
break; 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);
} }
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment