diff options
author | Justin Ruggles <justin.ruggles@gmail.com> | 2011-12-31 09:36:25 -0500 |
---|---|---|
committer | Justin Ruggles <justin.ruggles@gmail.com> | 2012-01-15 21:24:18 -0500 |
commit | ee458cb1fa3faa006785d725fb3e386174793000 (patch) | |
tree | cd7dc5569c948ef557ca631d2cca7a160ab4db11 | |
parent | 05f95443cac79eba959d7a1a919d77e8f401ea6f (diff) | |
download | ffmpeg-ee458cb1fa3faa006785d725fb3e386174793000.tar.gz |
avconv: use avcodec_encode_audio2()
-rw-r--r-- | avconv.c | 205 |
1 files changed, 105 insertions, 100 deletions
@@ -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); } } } |