Newer
Older
* Copyright (c) 2000-2011 The Libav developers
*
* This file is part of Libav.
*
* Libav is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* Libav is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "config.h"
#include <ctype.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#include <limits.h>
#include "libavformat/avformat.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
#include "libavutil/opt.h"
#include "libavutil/channel_layout.h"
#include "libavutil/parseutils.h"
#include "libavutil/samplefmt.h"
#include "libavutil/fifo.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/dict.h"
#include "libavutil/mathematics.h"
#include "libavutil/pixdesc.h"
#include "libavutil/avstring.h"
#include "libavutil/libm.h"
#include "libavutil/imgutils.h"
#include "libavformat/os_support.h"
# include "libavfilter/avfilter.h"
# include "libavfilter/buffersrc.h"
# include "libavfilter/buffersink.h"
#if HAVE_SYS_RESOURCE_H
#include <sys/types.h>
#include <sys/resource.h>
#elif HAVE_GETPROCESSTIMES
#include <windows.h>
#endif
#if HAVE_GETPROCESSMEMORYINFO
#include <windows.h>
#include <psapi.h>
#endif
#if HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#if HAVE_PTHREADS
#include <pthread.h>
#endif
#include "cmdutils.h"
#include "libavutil/avassert.h"
const char program_name[] = "avconv";
const int program_birth_year = 2000;
static FILE *vstats_file;
static int nb_frames_drop = 0;
/* signal to input threads that they should exit; set by the main thread */
static int transcoding_finished;
#endif
InputStream **input_streams = NULL;
int nb_input_streams = 0;
InputFile **input_files = NULL;
int nb_input_files = 0;
Anton Khirnov
committed
OutputStream **output_streams = NULL;
int nb_output_streams = 0;
OutputFile **output_files = NULL;
int nb_output_files = 0;
Anton Khirnov
committed
FilterGraph **filtergraphs;
int nb_filtergraphs;
static void term_exit(void)
{
av_log(NULL, AV_LOG_QUIET, "");
}
static volatile int received_sigterm = 0;
static volatile int received_nb_signals = 0;
static void
sigterm_handler(int sig)
{
received_sigterm = sig;
received_nb_signals++;
term_exit();
}
static void term_init(void)
{
signal(SIGINT , sigterm_handler); /* Interrupt (ANSI). */
signal(SIGTERM, sigterm_handler); /* Termination (ANSI). */
#ifdef SIGXCPU
signal(SIGXCPU, sigterm_handler);
#endif
}
Martin Storsjö
committed
static int decode_interrupt_cb(void *ctx)
{
return received_nb_signals > 1;
}
const AVIOInterruptCB int_cb = { decode_interrupt_cb, NULL };
Martin Storsjö
committed
int i, j;
for (i = 0; i < nb_filtergraphs; i++) {
FilterGraph *fg = filtergraphs[i];
avfilter_graph_free(&fg->graph);
for (j = 0; j < fg->nb_inputs; j++) {
av_freep(&fg->inputs[j]->name);
av_freep(&fg->inputs[j]);
av_freep(&fg->inputs);
for (j = 0; j < fg->nb_outputs; j++) {
av_freep(&fg->outputs[j]->name);
av_freep(&fg->outputs[j]);
av_freep(&fg->outputs);
av_freep(&fg->graph_desc);
av_freep(&filtergraphs[i]);
}
av_freep(&filtergraphs);
OutputFile *of = output_files[i];
AVFormatContext *s = of->ctx;
if (s && s->oformat && !(s->oformat->flags & AVFMT_NOFILE) && s->pb)
avio_close(s->pb);
avformat_free_context(s);
av_dict_free(&of->opts);
av_freep(&output_files[i]);
OutputStream *ost = output_streams[i];
for (j = 0; j < ost->nb_bitstream_filters; j++)
av_bsf_free(&ost->bsf_ctx[j]);
av_freep(&ost->bsf_ctx);
av_freep(&ost->bitstream_filters);
av_frame_free(&ost->filtered_frame);
av_parser_close(ost->parser);
av_freep(&ost->forced_keyframes);
av_freep(&ost->avfilter);
av_freep(&ost->logfile_prefix);
avcodec_free_context(&ost->enc_ctx);
av_freep(&output_streams[i]);
avformat_close_input(&input_files[i]->ctx);
av_freep(&input_files[i]);
for (i = 0; i < nb_input_streams; i++) {
InputStream *ist = input_streams[i];
av_frame_free(&ist->decoded_frame);
av_frame_free(&ist->filter_frame);
av_dict_free(&ist->decoder_opts);
av_freep(&ist->filters);
av_freep(&ist->hwaccel_device);
avcodec_free_context(&ist->dec_ctx);
av_freep(&input_streams[i]);
if (vstats_file)
fclose(vstats_file);
av_free(vstats_filename);
av_freep(&input_streams);
av_freep(&input_files);
av_freep(&output_streams);
Anton Khirnov
committed
av_freep(&output_files);
uninit_opts();
avformat_network_deinit();
if (received_sigterm) {
av_log(NULL, AV_LOG_INFO, "Received signal %d: terminating.\n",
(int) received_sigterm);
exit (255);
}
}
void assert_avoptions(AVDictionary *m)
{
AVDictionaryEntry *t;
if ((t = av_dict_get(m, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
av_log(NULL, AV_LOG_FATAL, "Option %s not found.\n", t->key);
static void abort_codec_experimental(AVCodec *c, int encoder)
{
const char *codec_string = encoder ? "encoder" : "decoder";
AVCodec *codec;
av_log(NULL, AV_LOG_FATAL, "%s '%s' is experimental and might produce bad "
"results.\nAdd '-strict experimental' if you want to use it.\n",
codec_string, c->name);
codec = encoder ? avcodec_find_encoder(c->id) : avcodec_find_decoder(c->id);
if (!(codec->capabilities & AV_CODEC_CAP_EXPERIMENTAL))
av_log(NULL, AV_LOG_FATAL, "Or use the non experimental %s '%s'.\n",
codec_string, codec->name);
static void write_packet(AVFormatContext *s, AVPacket *pkt, OutputStream *ost)
/*
* Audio encoders may split the packets -- #frames in != #packets out.
* But there is no reordering, so we can limit the number of output packets
* by simply dropping them here.
* Counting encoded video frames needs to be done separately because of
* reordering, see do_video_out()
*/
if (!(st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && ost->encoding_needed)) {
Justin Ruggles
committed
if (ost->frame_number >= ost->max_frames) {
av_packet_unref(pkt);
Justin Ruggles
committed
}
ost->frame_number++;
}
if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
uint8_t *sd = av_packet_get_side_data(pkt, AV_PKT_DATA_QUALITY_FACTOR,
NULL);
ost->quality = sd ? *(int *)sd : -1;
if (ost->frame_rate.num) {
pkt->duration = av_rescale_q(1, av_inv_q(ost->frame_rate),
ost->st->time_base);
}
if (!(s->oformat->flags & AVFMT_NOTIMESTAMPS) &&
ost->last_mux_dts != AV_NOPTS_VALUE &&
pkt->dts < ost->last_mux_dts + !(s->oformat->flags & AVFMT_TS_NONSTRICT)) {
av_log(NULL, AV_LOG_WARNING, "Non-monotonous DTS in output stream "
"%d:%d; previous: %"PRId64", current: %"PRId64"; ",
ost->file_index, ost->st->index, ost->last_mux_dts, pkt->dts);
if (exit_on_error) {
av_log(NULL, AV_LOG_FATAL, "aborting.\n");
}
av_log(NULL, AV_LOG_WARNING, "changing to %"PRId64". This may result "
"in incorrect timestamps in the output file.\n",
ost->last_mux_dts + 1);
pkt->dts = ost->last_mux_dts + 1;
if (pkt->pts != AV_NOPTS_VALUE)
pkt->pts = FFMAX(pkt->pts, pkt->dts);
}
ost->last_mux_dts = pkt->dts;
ost->packets_written++;
pkt->stream_index = ost->index;
ret = av_interleaved_write_frame(s, pkt);
if (ret < 0) {
print_error("av_interleaved_write_frame()", ret);
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
static void output_packet(AVFormatContext *s, AVPacket *pkt, OutputStream *ost)
{
int ret = 0;
/* apply the output bitstream filters, if any */
if (ost->nb_bitstream_filters) {
int idx;
ret = av_bsf_send_packet(ost->bsf_ctx[0], pkt);
if (ret < 0)
goto finish;
idx = 1;
while (idx) {
/* get a packet from the previous filter up the chain */
ret = av_bsf_receive_packet(ost->bsf_ctx[idx - 1], pkt);
if (ret == AVERROR(EAGAIN)) {
ret = 0;
idx--;
continue;
} else if (ret < 0)
goto finish;
/* send it to the next filter down the chain or to the muxer */
if (idx < ost->nb_bitstream_filters) {
ret = av_bsf_send_packet(ost->bsf_ctx[idx], pkt);
if (ret < 0)
goto finish;
idx++;
} else
write_packet(s, pkt, ost);
}
} else
write_packet(s, pkt, ost);
finish:
if (ret < 0 && ret != AVERROR_EOF) {
av_log(NULL, AV_LOG_FATAL, "Error applying bitstream filters to an output "
"packet for stream #%d:%d.\n", ost->file_index, ost->index);
exit_program(1);
}
}
static int check_recording_time(OutputStream *ost)
{
OutputFile *of = output_files[ost->file_index];
if (of->recording_time != INT64_MAX &&
av_compare_ts(ost->sync_opts - ost->first_pts, ost->enc_ctx->time_base, of->recording_time,
ost->finished = 1;
return 0;
}
return 1;
}
static void do_audio_out(AVFormatContext *s, OutputStream *ost,
AVFrame *frame)
AVCodecContext *enc = ost->enc_ctx;
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
if (frame->pts == AV_NOPTS_VALUE || audio_sync_method < 0)
frame->pts = ost->sync_opts;
ost->sync_opts = frame->pts + frame->nb_samples;
ost->samples_encoded += frame->nb_samples;
ost->frames_encoded++;
ret = avcodec_send_frame(enc, frame);
if (ret < 0)
goto error;
while (1) {
ret = avcodec_receive_packet(enc, &pkt);
if (ret == AVERROR(EAGAIN))
break;
if (ret < 0)
goto error;
av_packet_rescale_ts(&pkt, enc->time_base, ost->st->time_base);
return;
error:
av_log(NULL, AV_LOG_FATAL, "Audio encoding failed\n");
exit_program(1);
}
static void do_subtitle_out(AVFormatContext *s,
OutputStream *ost,
InputStream *ist,
AVSubtitle *sub,
int64_t pts)
{
static uint8_t *subtitle_out = NULL;
int subtitle_out_max_size = 1024 * 1024;
int subtitle_out_size, nb, i;
AVCodecContext *enc;
AVPacket pkt;
if (pts == AV_NOPTS_VALUE) {
av_log(NULL, AV_LOG_ERROR, "Subtitle packets must have a pts\n");
enc = ost->enc_ctx;
if (!subtitle_out) {
subtitle_out = av_malloc(subtitle_out_max_size);
}
/* Note: DVB subtitle need one packet to draw them and one other
packet to clear them */
/* XXX: signal it in the codec context ? */
if (enc->codec_id == AV_CODEC_ID_DVB_SUBTITLE)
nb = 2;
else
nb = 1;
ost->sync_opts = av_rescale_q(pts, ist->st->time_base, enc->time_base);
if (!check_recording_time(ost))
return;
sub->pts = av_rescale_q(pts, ist->st->time_base, AV_TIME_BASE_Q);
// start_display_time is required to be 0
sub->pts += av_rescale_q(sub->start_display_time, (AVRational){ 1, 1000 }, AV_TIME_BASE_Q);
sub->end_display_time -= sub->start_display_time;
sub->start_display_time = 0;
ost->frames_encoded++;
subtitle_out_size = avcodec_encode_subtitle(enc, subtitle_out,
subtitle_out_max_size, sub);
if (subtitle_out_size < 0) {
av_log(NULL, AV_LOG_FATAL, "Subtitle encoding failed\n");
}
av_init_packet(&pkt);
pkt.data = subtitle_out;
pkt.size = subtitle_out_size;
pkt.pts = av_rescale_q(sub->pts, AV_TIME_BASE_Q, ost->st->time_base);
if (enc->codec_id == AV_CODEC_ID_DVB_SUBTITLE) {
/* XXX: the pts correction is handled here. Maybe handling
it in the codec would be better */
if (i == 0)
pkt.pts += 90 * sub->start_display_time;
else
pkt.pts += 90 * sub->end_display_time;
}
static void do_video_out(AVFormatContext *s,
OutputStream *ost,
AVFrame *in_picture,
AVCodecContext *enc = ost->enc_ctx;
format_video_sync = video_sync_method;
if (format_video_sync == VSYNC_AUTO)
format_video_sync = (s->oformat->flags & AVFMT_NOTIMESTAMPS) ? VSYNC_PASSTHROUGH :
(s->oformat->flags & AVFMT_VARIABLE_FPS) ? VSYNC_VFR : VSYNC_CFR;
if (format_video_sync != VSYNC_PASSTHROUGH &&
ost->frame_number &&
in_picture->pts != AV_NOPTS_VALUE &&
in_picture->pts < ost->sync_opts) {
av_log(NULL, AV_LOG_WARNING,
"*** dropping frame %d from stream %d at ts %"PRId64"\n",
ost->frame_number, ost->st->index, in_picture->pts);
if (in_picture->pts == AV_NOPTS_VALUE)
in_picture->pts = ost->sync_opts;
ost->sync_opts = in_picture->pts;
ost->first_pts = in_picture->pts;
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
if (ost->frame_number >= ost->max_frames)
if (enc->flags & (AV_CODEC_FLAG_INTERLACED_DCT | AV_CODEC_FLAG_INTERLACED_ME) &&
ost->top_field_first >= 0)
in_picture->top_field_first = !!ost->top_field_first;
in_picture->quality = enc->global_quality;
in_picture->pict_type = 0;
if (ost->forced_kf_index < ost->forced_kf_count &&
in_picture->pts >= ost->forced_kf_pts[ost->forced_kf_index]) {
in_picture->pict_type = AV_PICTURE_TYPE_I;
ost->forced_kf_index++;
}
ret = avcodec_send_frame(enc, in_picture);
if (ret < 0)
goto error;
/*
* For video, there may be reordering, so we can't throw away frames on
* encoder flush, we need to limit them here, before they go into encoder.
*/
ost->frame_number++;
while (1) {
ret = avcodec_receive_packet(enc, &pkt);
if (ret == AVERROR(EAGAIN))
break;
if (ret < 0)
goto error;
av_packet_rescale_ts(&pkt, enc->time_base, ost->st->time_base);
/* if two pass, output log */
if (ost->logfile && enc->stats_out) {
fprintf(ost->logfile, "%s", enc->stats_out);
return;
error:
av_assert0(ret != AVERROR(EAGAIN) && ret != AVERROR_EOF);
av_log(NULL, AV_LOG_FATAL, "Video encoding failed\n");
exit_program(1);
static double psnr(double d)
{
return -10.0 * log(d) / log(10.0);
static void do_video_stats(OutputStream *ost, int frame_size)
{
AVCodecContext *enc;
int frame_number;
double ti1, bitrate, avg_bitrate;
/* this is executed just the first time do_video_stats is called */
if (!vstats_file) {
vstats_file = fopen(vstats_filename, "w");
if (!vstats_file) {
perror("fopen");
enc = ost->enc_ctx;
if (enc->codec_type == AVMEDIA_TYPE_VIDEO) {
frame_number = ost->frame_number;
fprintf(vstats_file, "frame= %5d q= %2.1f ", frame_number,
ost->quality / (float)FF_QP2LAMBDA);
#if FF_API_CODED_FRAME
FF_DISABLE_DEPRECATION_WARNINGS
fprintf(vstats_file, "PSNR= %6.2f ", psnr(enc->coded_frame->error[0] / (enc->width * enc->height * 255.0 * 255.0)));
FF_ENABLE_DEPRECATION_WARNINGS
#endif
fprintf(vstats_file,"f_size= %6d ", frame_size);
/* compute pts value */
ti1 = ost->sync_opts * av_q2d(enc->time_base);
if (ti1 < 0.01)
ti1 = 0.01;
bitrate = (frame_size * 8) / av_q2d(enc->time_base) / 1000.0;
avg_bitrate = (double)(ost->data_size * 8) / ti1 / 1000.0;
fprintf(vstats_file, "s_size= %8.0fkB time= %0.3f br= %7.1fkbits/s avg_br= %7.1fkbits/s ",
(double)ost->data_size / 1024, ti1, bitrate, avg_bitrate);
#if FF_API_CODED_FRAME
FF_DISABLE_DEPRECATION_WARNINGS
fprintf(vstats_file, "type= %c\n", av_get_picture_type_char(enc->coded_frame->pict_type));
FF_ENABLE_DEPRECATION_WARNINGS
#endif
* Read one frame for lavfi output for ost and encode it.
*/
static int poll_filter(OutputStream *ost)
OutputFile *of = output_files[ost->file_index];
if (!ost->filtered_frame && !(ost->filtered_frame = av_frame_alloc())) {
filtered_frame = ost->filtered_frame;
if (ost->enc->type == AVMEDIA_TYPE_AUDIO &&
!(ost->enc->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE))
ret = av_buffersink_get_samples(ost->filter->filter, filtered_frame,
ost->enc_ctx->frame_size);
ret = av_buffersink_get_frame(ost->filter->filter, filtered_frame);
if (filtered_frame->pts != AV_NOPTS_VALUE) {
int64_t start_time = (of->start_time == AV_NOPTS_VALUE) ? 0 : of->start_time;
filtered_frame->pts = av_rescale_q(filtered_frame->pts,
ost->filter->filter->inputs[0]->time_base,
ost->enc_ctx->time_base) -
av_rescale_q(start_time,
ost->enc_ctx->time_base);
switch (ost->filter->filter->inputs[0]->type) {
case AVMEDIA_TYPE_VIDEO:
if (!ost->frame_aspect_ratio)
ost->enc_ctx->sample_aspect_ratio = filtered_frame->sample_aspect_ratio;
do_video_out(of->ctx, ost, filtered_frame, &frame_size);
if (vstats_filename && frame_size)
do_video_stats(ost, frame_size);
break;
case AVMEDIA_TYPE_AUDIO:
do_audio_out(of->ctx, ost, filtered_frame);
break;
default:
// TODO support subtitle filters
av_assert0(0);
}
av_frame_unref(filtered_frame);
static void finish_output_stream(OutputStream *ost)
{
OutputFile *of = output_files[ost->file_index];
int i;
ost->finished = 1;
if (of->shortest) {
for (i = 0; i < of->ctx->nb_streams; i++)
output_streams[of->ost_index + i]->finished = 1;
}
}
* Read as many frames from possible from lavfi and encode them.
*
* Always read from the active stream with the lowest timestamp. If no frames
* are available for it then return EAGAIN and wait for more input. This way we
* can use lavfi sources that generate unlimited amount of frames without memory
* usage exploding.
*/
static int poll_filters(void)
{
while (ret >= 0 && !received_sigterm) {
OutputStream *ost = NULL;
int64_t min_pts = INT64_MAX;
/* choose output stream with the lowest timestamp */
for (i = 0; i < nb_output_streams; i++) {
int64_t pts = output_streams[i]->sync_opts;
if (!output_streams[i]->filter || output_streams[i]->finished)
pts = av_rescale_q(pts, output_streams[i]->enc_ctx->time_base,
AV_TIME_BASE_Q);
if (pts < min_pts) {
min_pts = pts;
ost = output_streams[i];
}
}
if (!ost)
break;
ret = poll_filter(ost);
if (ret == AVERROR_EOF) {
ret = 0;
} else if (ret == AVERROR(EAGAIN))
return 0;
}
return ret;
}
static void print_final_stats(int64_t total_size)
{
uint64_t video_size = 0, audio_size = 0, extra_size = 0, other_size = 0;
uint64_t data_size = 0;
float percent = -1.0;
for (i = 0; i < nb_output_streams; i++) {
OutputStream *ost = output_streams[i];
switch (ost->enc_ctx->codec_type) {
case AVMEDIA_TYPE_VIDEO: video_size += ost->data_size; break;
case AVMEDIA_TYPE_AUDIO: audio_size += ost->data_size; break;
default: other_size += ost->data_size; break;
}
extra_size += ost->enc_ctx->extradata_size;
data_size += ost->data_size;
}
if (data_size && total_size >= data_size)
percent = 100.0 * (total_size - data_size) / data_size;
av_log(NULL, AV_LOG_INFO, "\n");
av_log(NULL, AV_LOG_INFO, "video:%1.0fkB audio:%1.0fkB other streams:%1.0fkB global headers:%1.0fkB muxing overhead: ",
video_size / 1024.0,
audio_size / 1024.0,
other_size / 1024.0,
extra_size / 1024.0);
if (percent >= 0.0)
av_log(NULL, AV_LOG_INFO, "%f%%", percent);
else
av_log(NULL, AV_LOG_INFO, "unknown");
av_log(NULL, AV_LOG_INFO, "\n");
/* print verbose per-stream stats */
for (i = 0; i < nb_input_files; i++) {
InputFile *f = input_files[i];
uint64_t total_packets = 0, total_size = 0;
av_log(NULL, AV_LOG_VERBOSE, "Input file #%d (%s):\n",
i, f->ctx->filename);
for (j = 0; j < f->nb_streams; j++) {
InputStream *ist = input_streams[f->ist_index + j];
enum AVMediaType type = ist->dec_ctx->codec_type;
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
total_size += ist->data_size;
total_packets += ist->nb_packets;
av_log(NULL, AV_LOG_VERBOSE, " Input stream #%d:%d (%s): ",
i, j, media_type_string(type));
av_log(NULL, AV_LOG_VERBOSE, "%"PRIu64" packets read (%"PRIu64" bytes); ",
ist->nb_packets, ist->data_size);
if (ist->decoding_needed) {
av_log(NULL, AV_LOG_VERBOSE, "%"PRIu64" frames decoded",
ist->frames_decoded);
if (type == AVMEDIA_TYPE_AUDIO)
av_log(NULL, AV_LOG_VERBOSE, " (%"PRIu64" samples)", ist->samples_decoded);
av_log(NULL, AV_LOG_VERBOSE, "; ");
}
av_log(NULL, AV_LOG_VERBOSE, "\n");
}
av_log(NULL, AV_LOG_VERBOSE, " Total: %"PRIu64" packets (%"PRIu64" bytes) demuxed\n",
total_packets, total_size);
}
for (i = 0; i < nb_output_files; i++) {
OutputFile *of = output_files[i];
uint64_t total_packets = 0, total_size = 0;
av_log(NULL, AV_LOG_VERBOSE, "Output file #%d (%s):\n",
i, of->ctx->filename);
for (j = 0; j < of->ctx->nb_streams; j++) {
OutputStream *ost = output_streams[of->ost_index + j];
enum AVMediaType type = ost->enc_ctx->codec_type;
total_size += ost->data_size;
total_packets += ost->packets_written;
av_log(NULL, AV_LOG_VERBOSE, " Output stream #%d:%d (%s): ",
i, j, media_type_string(type));
if (ost->encoding_needed) {
av_log(NULL, AV_LOG_VERBOSE, "%"PRIu64" frames encoded",
ost->frames_encoded);
if (type == AVMEDIA_TYPE_AUDIO)
av_log(NULL, AV_LOG_VERBOSE, " (%"PRIu64" samples)", ost->samples_encoded);
av_log(NULL, AV_LOG_VERBOSE, "; ");
}
av_log(NULL, AV_LOG_VERBOSE, "%"PRIu64" packets muxed (%"PRIu64" bytes); ",
ost->packets_written, ost->data_size);
av_log(NULL, AV_LOG_VERBOSE, "\n");
}
av_log(NULL, AV_LOG_VERBOSE, " Total: %"PRIu64" packets (%"PRIu64" bytes) muxed\n",
total_packets, total_size);
}
}
static void print_report(int is_last_report, int64_t timer_start)
{
char buf[1024];
OutputStream *ost;
AVFormatContext *oc;
int64_t total_size;
AVCodecContext *enc;
int frame_number, vid, i;
double bitrate, ti1, pts;
static int64_t last_time = -1;
static int qp_histogram[52];
if (!print_stats && !is_last_report)
return;
if (!is_last_report) {
int64_t cur_time;
/* display the report every 0.5 seconds */
if (last_time == -1) {
last_time = cur_time;
return;
}
if ((cur_time - last_time) < 500000)
return;
last_time = cur_time;
}
oc = output_files[0]->ctx;
total_size = avio_size(oc->pb);
if (total_size <= 0) // FIXME improve avio_size() so it works with non seekable output too
if (total_size < 0) {
char errbuf[128];
av_strerror(total_size, errbuf, sizeof(errbuf));
av_log(NULL, AV_LOG_VERBOSE, "Bitrate not available, "
"avio_tell() failed: %s\n", errbuf);
total_size = 0;
}
buf[0] = '\0';
ti1 = 1e10;
vid = 0;
for (i = 0; i < nb_output_streams; i++) {
ost = output_streams[i];
enc = ost->enc_ctx;
if (!ost->stream_copy)
q = ost->quality / (float) FF_QP2LAMBDA;
if (vid && enc->codec_type == AVMEDIA_TYPE_VIDEO) {
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "q=%2.1f ", q);
}
if (!vid && enc->codec_type == AVMEDIA_TYPE_VIDEO) {
float t = (av_gettime_relative() - timer_start) / 1000000.0;
frame_number = ost->frame_number;
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "frame=%5d fps=%3d q=%3.1f ",
frame_number, (t > 1) ? (int)(frame_number / t + 0.5) : 0, q);
if (is_last_report)
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "L");
int j;
int qp = lrintf(q);
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%X", (int)lrintf(log2(qp_histogram[j] + 1)));
#if FF_API_CODED_FRAME
FF_DISABLE_DEPRECATION_WARNINGS
if (enc->flags & AV_CODEC_FLAG_PSNR) {
double error, error_sum = 0;
double scale, scale_sum = 0;
char type[3] = { 'Y','U','V' };
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "PSNR=");
for (j = 0; j < 3; j++) {
if (is_last_report) {
error = enc->error[j];
scale = enc->width * enc->height * 255.0 * 255.0 * frame_number;
} else {
error = enc->coded_frame->error[j];
scale = enc->width * enc->height * 255.0 * 255.0;
error_sum += error;
scale_sum += scale;
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%c:%2.2f ", type[j], psnr(error / scale));
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "*:%2.2f ", psnr(error_sum / scale_sum));
FF_ENABLE_DEPRECATION_WARNINGS
#endif
vid = 1;
}
/* compute min output value */
pts = (double)ost->last_mux_dts * av_q2d(ost->st->time_base);
if ((pts < ti1) && (pts > 0))
ti1 = pts;
}
if (ti1 < 0.01)
ti1 = 0.01;
bitrate = (double)(total_size * 8) / ti1 / 1000.0;
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
"size=%8.0fkB time=%0.2f bitrate=%6.1fkbits/s",
(double)total_size / 1024, ti1, bitrate);
if (nb_frames_drop)
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " drop=%d",
nb_frames_drop);
av_log(NULL, AV_LOG_INFO, "%s \r", buf);
if (is_last_report)
print_final_stats(total_size);
static void flush_encoders(void)
{
int i, ret;
for (i = 0; i < nb_output_streams; i++) {
OutputStream *ost = output_streams[i];
AVCodecContext *enc = ost->enc_ctx;
AVFormatContext *os = output_files[ost->file_index]->ctx;
if (!ost->encoding_needed)
continue;
if (enc->codec_type == AVMEDIA_TYPE_AUDIO && enc->frame_size <= 1)
continue;
if (enc->codec_type != AVMEDIA_TYPE_VIDEO && enc->codec_type != AVMEDIA_TYPE_AUDIO)
continue;
avcodec_send_frame(enc, NULL);
switch (enc->codec_type) {
case AVMEDIA_TYPE_AUDIO:
break;
case AVMEDIA_TYPE_VIDEO: