|
|
|
@ -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); |
|
|
|
|
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; |
|
|
|
|
} |
|
|
|
|
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; |
|
|
|
|
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; |
|
|
|
|
default: |
|
|
|
|
ret = -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (ret <= 0) |
|
|
|
|
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: |
|
|
|
|
stop_encoding = 1; |
|
|
|
|
} |
|
|
|
|
if (stop_encoding) |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|