| @@ -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); | |||
| } | |||
| } | |||
| } | |||