Newer
Older
AVFilterContext *first_filter = in->filter_ctx;
AVFilter *filter = avfilter_get_by_name("buffer");
InputStream *ist = ifilter->ist;
AVRational tb = ist->framerate.num ? (AVRational){ist->framerate.den,
ist->framerate.num} :
ist->st->time_base;
AVRational fr = ist->framerate.num ? ist->framerate :
ist->st->r_frame_rate;
AVRational sar;
int pad_idx = in->pad_idx;
int ret;
sar = ist->st->sample_aspect_ratio.num ?
ist->st->sample_aspect_ratio :
ist->st->codec->sample_aspect_ratio;
if(!sar.den)
sar = (AVRational){0,1};
av_bprint_init(&args, 0, 1);
av_bprintf(&args,
"video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:"
"pixel_aspect=%d/%d:sws_param=flags=%d", ist->st->codec->width,
ist->st->codec->height, ist->st->codec->pix_fmt,
tb.num, tb.den, sar.num, sar.den,
SWS_BILINEAR + ((ist->st->codec->flags&CODEC_FLAG_BITEXACT) ? SWS_BITEXACT:0));
if (fr.num && fr.den)
av_bprintf(&args, ":frame_rate=%d/%d", fr.num, fr.den);
if ((ret = avfilter_graph_create_filter(&ifilter->filter, filter, in->name,
args.str, NULL, fg->graph)) < 0)
return ret;
if (ist->framerate.num) {
AVFilterContext *setpts;
if ((ret = avfilter_graph_create_filter(&setpts,
avfilter_get_by_name("setpts"),
"setpts", "N", NULL,
fg->graph)) < 0)
return ret;
if ((ret = avfilter_link(setpts, 0, first_filter, pad_idx)) < 0)
return ret;
first_filter = setpts;
pad_idx = 0;
}
if ((ret = avfilter_link(ifilter->filter, 0, first_filter, pad_idx)) < 0)
return ret;
return 0;
}
static int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter,
AVFilterInOut *in)
{
AVFilterContext *first_filter = in->filter_ctx;
AVFilter *filter = avfilter_get_by_name("abuffer");
InputStream *ist = ifilter->ist;
int pad_idx = in->pad_idx;
char args[255];
int ret;
snprintf(args, sizeof(args), "time_base=%d/%d:sample_rate=%d:sample_fmt=%s"
":channel_layout=0x%"PRIx64,
ist->st->time_base.num, ist->st->time_base.den,
ist->st->codec->sample_rate,
av_get_sample_fmt_name(ist->st->codec->sample_fmt),
ist->st->codec->channel_layout);
if ((ret = avfilter_graph_create_filter(&ifilter->filter, filter,
in->name, args, NULL,
fg->graph)) < 0)
return ret;
#define AUTO_INSERT_FILTER_INPUT(opt_name, filter_name, arg) do { \
AVFilterContext *filt_ctx; \
\
av_log(NULL, AV_LOG_INFO, opt_name " is forwarded to lavfi " \
"similarly to -af " filter_name "=%s.\n", arg); \
\
ret = avfilter_graph_create_filter(&filt_ctx, \
avfilter_get_by_name(filter_name), \
filter_name, arg, NULL, fg->graph); \
if (ret < 0) \
return ret; \
\
ret = avfilter_link(filt_ctx, 0, first_filter, pad_idx); \
if (ret < 0) \
return ret; \
\
first_filter = filt_ctx; \
} while (0)
if (audio_sync_method > 0) {
char args[256] = {0};
av_strlcatf(args, sizeof(args), "min_comp=0.001:min_hard_comp=%f", audio_drift_threshold);
if (audio_sync_method > 1)
av_strlcatf(args, sizeof(args), ":max_soft_comp=%f", audio_sync_method/(double)ist->st->codec->sample_rate);
AUTO_INSERT_FILTER_INPUT("-async", "aresample", args);
}
// if (ost->audio_channels_mapped) {
// int i;
// AVBPrint pan_buf;
// av_bprint_init(&pan_buf, 256, 8192);
// av_bprintf(&pan_buf, "0x%"PRIx64,
// av_get_default_channel_layout(ost->audio_channels_mapped));
// for (i = 0; i < ost->audio_channels_mapped; i++)
// if (ost->audio_channels_map[i] != -1)
// av_bprintf(&pan_buf, ":c%d=c%d", i, ost->audio_channels_map[i]);
// AUTO_INSERT_FILTER_INPUT("-map_channel", "pan", pan_buf.str);
// av_bprint_finalize(&pan_buf, NULL);
// }
if (audio_volume != 256) {
char args[256];
snprintf(args, sizeof(args), "%f", audio_volume / 256.);
AUTO_INSERT_FILTER_INPUT("-vol", "volume", args);
}
if ((ret = avfilter_link(ifilter->filter, 0, first_filter, pad_idx)) < 0)
return ret;
return 0;
}
static int configure_input_filter(FilterGraph *fg, InputFilter *ifilter,
AVFilterInOut *in)
{
av_freep(&ifilter->name);
DESCRIBE_FILTER_LINK(ifilter, in, 1);
switch (avfilter_pad_get_type(in->filter_ctx->input_pads, in->pad_idx)) {
case AVMEDIA_TYPE_VIDEO: return configure_input_video_filter(fg, ifilter, in);
case AVMEDIA_TYPE_AUDIO: return configure_input_audio_filter(fg, ifilter, in);
default: av_assert0(0);
}
}
static int configure_filtergraph(FilterGraph *fg)
{
AVFilterInOut *inputs, *outputs, *cur;
int ret, i, init = !fg->graph, simple = !fg->graph_desc;
const char *graph_desc = simple ? fg->outputs[0]->ost->avfilter :
fg->graph_desc;
avfilter_graph_free(&fg->graph);
if (!(fg->graph = avfilter_graph_alloc()))
return AVERROR(ENOMEM);
if (simple) {
OutputStream *ost = fg->outputs[0]->ost;
char args[255];
snprintf(args, sizeof(args), "flags=0x%X", (unsigned)ost->sws_flags);
fg->graph->scale_sws_opts = av_strdup(args);
}
if ((ret = avfilter_graph_parse2(fg->graph, graph_desc, &inputs, &outputs)) < 0)
if (simple && (!inputs || inputs->next || !outputs || outputs->next)) {
av_log(NULL, AV_LOG_ERROR, "Simple filtergraph '%s' does not have "
"exactly one input and output.\n", graph_desc);
return AVERROR(EINVAL);
}
for (cur = inputs; !simple && init && cur; cur = cur->next)
init_input_filter(fg, cur);
for (cur = inputs, i = 0; cur; cur = cur->next, i++)
if ((ret = configure_input_filter(fg, fg->inputs[i], cur)) < 0)
return ret;
avfilter_inout_free(&inputs);
if (!init || simple) {
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
/* we already know the mappings between lavfi outputs and output streams,
* so we can finish the setup */
for (cur = outputs, i = 0; cur; cur = cur->next, i++)
configure_output_filter(fg, fg->outputs[i], cur);
avfilter_inout_free(&outputs);
if ((ret = avfilter_graph_config(fg->graph, NULL)) < 0)
return ret;
} else {
/* wait until output mappings are processed */
for (cur = outputs; cur;) {
fg->outputs = grow_array(fg->outputs, sizeof(*fg->outputs),
&fg->nb_outputs, fg->nb_outputs + 1);
if (!(fg->outputs[fg->nb_outputs - 1] = av_mallocz(sizeof(*fg->outputs[0]))))
exit_program(1);
fg->outputs[fg->nb_outputs - 1]->graph = fg;
fg->outputs[fg->nb_outputs - 1]->out_tmp = cur;
cur = cur->next;
fg->outputs[fg->nb_outputs - 1]->out_tmp->next = NULL;
}
}
return 0;
}
static int configure_complex_filters(void)
{
int i, ret = 0;
for (i = 0; i < nb_filtergraphs; i++)
if (!filtergraphs[i]->graph &&
(ret = configure_filtergraph(filtergraphs[i])) < 0)
return ret;
return 0;
}
static int ist_in_filtergraph(FilterGraph *fg, InputStream *ist)
{
int i;
for (i = 0; i < fg->nb_inputs; i++)
if (fg->inputs[i]->ist == ist)
return 1;
return 0;
}
av_log(NULL, AV_LOG_QUIET, "%s", "");
#if HAVE_TERMIOS_H
tcsetattr (0, TCSANOW, &oldtty);
static volatile int received_sigterm = 0;
Roumen Petrov
committed
static void sigterm_handler(int sig)
Roumen Petrov
committed
{
received_sigterm = sig;
received_nb_signals++;
Roumen Petrov
committed
term_exit();
if(received_nb_signals > 3)
exit(123);
Roumen Petrov
committed
}
#if HAVE_TERMIOS_H
if(!run_as_daemon){
#if HAVE_ISATTY
istty = isatty(0) && isatty(2);
#endif
if (istty && tcgetattr (0, &tty) == 0) {
oldtty = tty;
restore_tty = 1;
atexit(term_exit);
tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
|INLCR|IGNCR|ICRNL|IXON);
tty.c_oflag |= OPOST;
tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
tty.c_cflag &= ~(CSIZE|PARENB);
tty.c_cflag |= CS8;
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 0;
tcsetattr (0, TCSANOW, &tty);
}
signal(SIGQUIT, sigterm_handler); /* Quit (POSIX). */
avformat_network_deinit();
signal(SIGINT , sigterm_handler); /* Interrupt (ANSI). */
Roumen Petrov
committed
signal(SIGTERM, sigterm_handler); /* Termination (ANSI). */
#ifdef SIGXCPU
signal(SIGXCPU, sigterm_handler);
#endif
}
/* read a key without blocking */
static int read_key(void)
{
#if HAVE_TERMIOS_H
int n = 1;
struct timeval tv;
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(0, &rfds);
tv.tv_sec = 0;
tv.tv_usec = 0;
n = select(1, &rfds, NULL, NULL, &tv);
if (n > 0) {
n = read(0, &ch, 1);
if (n == 1)
return ch;
return n;
}
#elif HAVE_KBHIT
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
# if HAVE_PEEKNAMEDPIPE
static int is_pipe;
static HANDLE input_handle;
DWORD dw, nchars;
if(!input_handle){
input_handle = GetStdHandle(STD_INPUT_HANDLE);
is_pipe = !GetConsoleMode(input_handle, &dw);
}
if (stdin->_cnt > 0) {
read(0, &ch, 1);
return ch;
}
if (is_pipe) {
/* When running under a GUI, you will end here. */
if (!PeekNamedPipe(input_handle, NULL, 0, NULL, &nchars, NULL))
return -1;
//Read it
if(nchars != 0) {
read(0, &ch, 1);
return ch;
}else{
return -1;
}
}
# endif
static int decode_interrupt_cb(void *ctx)
Leon van Stuivenberg
committed
{
return received_nb_signals > 1;
Leon van Stuivenberg
committed
}
static const AVIOInterruptCB int_cb = { decode_interrupt_cb, NULL };
int i, j;
for (i = 0; i < nb_filtergraphs; i++) {
avfilter_graph_free(&filtergraphs[i]->graph);
for (j = 0; j < filtergraphs[i]->nb_inputs; j++) {
av_freep(&filtergraphs[i]->inputs[j]->name);
av_freep(&filtergraphs[i]->inputs[j]);
for (j = 0; j < filtergraphs[i]->nb_outputs; j++) {
av_freep(&filtergraphs[i]->outputs[j]->name);
av_freep(&filtergraphs[i]->outputs[j]);
av_freep(&filtergraphs[i]->outputs);
av_freep(&filtergraphs[i]);
}
av_freep(&filtergraphs);
/* close files */
for (i = 0; i < nb_output_files; i++) {
AVFormatContext *s = output_files[i]->ctx;
if (!(s->oformat->flags & AVFMT_NOFILE) && s->pb)
avformat_free_context(s);
av_dict_free(&output_files[i]->opts);
av_freep(&output_files[i]);
for (i = 0; i < nb_output_streams; i++) {
AVBitStreamFilterContext *bsfc = output_streams[i]->bitstream_filters;
while (bsfc) {
AVBitStreamFilterContext *next = bsfc->next;
av_bitstream_filter_close(bsfc);
bsfc = next;
}
output_streams[i]->bitstream_filters = NULL;
av_freep(&output_streams[i]->filtered_frame);
av_freep(&output_streams[i]);
for (i = 0; i < nb_input_files; i++) {
avformat_close_input(&input_files[i]->ctx);
av_freep(&input_files[i]);
for (i = 0; i < nb_input_streams; i++) {
av_freep(&input_streams[i]->decoded_frame);
av_dict_free(&input_streams[i]->opts);
free_buffer_pool(&input_streams[i]->buffer_pool);
av_freep(&input_streams[i]->filters);
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);
}
static 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 assert_codec_experimental(AVCodecContext *c, int encoder)
{
const char *codec_string = encoder ? "encoder" : "decoder";
AVCodec *codec;
if (c->codec->capabilities & CODEC_CAP_EXPERIMENTAL &&
c->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
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->codec->name);
codec = encoder ? avcodec_find_encoder(c->codec->id) : avcodec_find_decoder(c->codec->id);
if (!(codec->capabilities & CODEC_CAP_EXPERIMENTAL))
av_log(NULL, AV_LOG_FATAL, "Or use the non experimental %s '%s'.\n",
codec_string, codec->name);
Ronald S. Bultje
committed
static void choose_sample_fmt(AVStream *st, AVCodec *codec)
{
if (codec && codec->sample_fmts) {
const enum AVSampleFormat *p = codec->sample_fmts;
for (; *p != -1; p++) {
if (*p == st->codec->sample_fmt)
Ronald S. Bultje
committed
break;
}
if (*p == -1) {
Michael Niedermayer
committed
if((codec->capabilities & CODEC_CAP_LOSSLESS) && av_get_sample_fmt_name(st->codec->sample_fmt) > av_get_sample_fmt_name(codec->sample_fmts[0]))
av_log(NULL, AV_LOG_ERROR, "Conversion will not be lossless.\n");
if(av_get_sample_fmt_name(st->codec->sample_fmt))
av_log(NULL, AV_LOG_WARNING,
"Incompatible sample format '%s' for codec '%s', auto-selecting format '%s'\n",
av_get_sample_fmt_name(st->codec->sample_fmt),
codec->name,
av_get_sample_fmt_name(codec->sample_fmts[0]));
Ronald S. Bultje
committed
st->codec->sample_fmt = codec->sample_fmts[0];
}
Ronald S. Bultje
committed
}
}
static void write_frame(AVFormatContext *s, AVPacket *pkt, OutputStream *ost)
AVBitStreamFilterContext *bsfc = ost->bitstream_filters;
AVCodecContext *avctx = ost->st->codec;
if ((avctx->codec_type == AVMEDIA_TYPE_VIDEO && video_sync_method == VSYNC_DROP) ||
(avctx->codec_type == AVMEDIA_TYPE_AUDIO && audio_sync_method < 0))
pkt->pts = pkt->dts = AV_NOPTS_VALUE;
if (avctx->codec_type == AVMEDIA_TYPE_AUDIO && pkt->dts != AV_NOPTS_VALUE) {
int64_t max = ost->st->cur_dts + !(s->oformat->flags & AVFMT_TS_NONSTRICT);
if (ost->st->cur_dts && ost->st->cur_dts != AV_NOPTS_VALUE && max > pkt->dts) {
av_log(s, max - pkt->dts > 2 ? AV_LOG_WARNING : AV_LOG_DEBUG, "Audio timestamp %"PRId64" < %"PRId64" invalid, cliping\n", pkt->dts, max);
pkt->pts = pkt->dts = max;
}
}
/*
* 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 (!(avctx->codec_type == AVMEDIA_TYPE_VIDEO && avctx->codec)) {
Justin Ruggles
committed
if (ost->frame_number >= ost->max_frames) {
av_free_packet(pkt);
Justin Ruggles
committed
}
ost->frame_number++;
}
while (bsfc) {
AVPacket new_pkt = *pkt;
int a = av_bitstream_filter_filter(bsfc, avctx, NULL,
&new_pkt.data, &new_pkt.size,
pkt->data, pkt->size,
pkt->flags & AV_PKT_FLAG_KEY);
if (a > 0) {
Michael Niedermayer
committed
av_free_packet(pkt);
new_pkt.destruct = av_destruct_packet;
} else if (a < 0) {
Stefano Sabatini
committed
av_log(NULL, AV_LOG_ERROR, "Failed to open bitstream filter %s for stream %d with codec %s",
bsfc->filter->name, pkt->stream_index,
avctx->codec ? avctx->codec->name : "copy");
if (exit_on_error)
Michael Niedermayer
committed
}
Michael Niedermayer
committed
Michael Niedermayer
committed
}
pkt->stream_index = ost->index;
ret = av_interleaved_write_frame(s, pkt);
if (ret < 0) {
print_error("av_interleaved_write_frame()", ret);
Michael Niedermayer
committed
}
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->st->codec->time_base, of->recording_time,
AV_TIME_BASE_Q) >= 0) {
ost->is_past_recording_time = 1;
return 0;
}
return 1;
}
static void do_audio_out(AVFormatContext *s, OutputStream *ost,
AVFrame *frame)
{
AVCodecContext *enc = ost->st->codec;
AVPacket pkt;
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
#if 0
if (!check_recording_time(ost))
return;
#endif
if (frame->pts == AV_NOPTS_VALUE || audio_sync_method < 0)
frame->pts = ost->sync_opts;
ost->sync_opts = frame->pts + frame->nb_samples;
Michael Niedermayer
committed
av_assert0(pkt.size || !pkt.data);
if (avcodec_encode_audio2(enc, &pkt, frame, &got_packet) < 0) {
Michael Niedermayer
committed
av_log(NULL, AV_LOG_FATAL, "Audio encoding failed (avcodec_encode_audio2)\n");
exit_program(1);
update_benchmark("encode_audio %d.%d", ost->file_index, ost->index);
Michael Niedermayer
committed
if (got_packet) {
if (pkt.pts != AV_NOPTS_VALUE)
pkt.pts = av_rescale_q(pkt.pts, enc->time_base, ost->st->time_base);
pkt.dts = av_rescale_q(pkt.dts, 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);
if (debug_ts) {
av_log(NULL, AV_LOG_INFO, "encoder -> type:audio "
"pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s\n",
av_ts2str(pkt.pts), av_ts2timestr(pkt.pts, &ost->st->time_base),
av_ts2str(pkt.dts), av_ts2timestr(pkt.dts, &ost->st->time_base));
}
write_frame(s, &pkt, ost);
audio_size += pkt.size;
av_free_packet(&pkt);
static void pre_process_video_frame(InputStream *ist, AVPicture *picture, void **bufp)
{
AVCodecContext *dec;
AVPicture *picture2;
AVPicture picture_tmp;
Michael Niedermayer
committed
dec = ist->st->codec;
/* deinterlace : must be done before any resize */
int size;
/* create temporary picture */
size = avpicture_get_size(dec->pix_fmt, dec->width, dec->height);
buf = av_malloc(size);
if (!buf)
return;
picture2 = &picture_tmp;
avpicture_fill(picture2, buf, dec->pix_fmt, dec->width, dec->height);
if (avpicture_deinterlace(picture2, picture,
dec->pix_fmt, dec->width, dec->height) < 0) {
/* if error, do not deinterlace */
av_log(NULL, AV_LOG_WARNING, "Deinterlacing failed\n");
} else {
picture2 = picture;
}
if (picture != picture2)
*picture = *picture2;
*bufp = buf;
}
static void do_subtitle_out(AVFormatContext *s,
OutputStream *ost,
InputStream *ist,
Fabrice Bellard
committed
AVSubtitle *sub,
int64_t pts)
{
static uint8_t *subtitle_out = NULL;
int subtitle_out_max_size = 1024 * 1024;
Fabrice Bellard
committed
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");
if (exit_on_error)
Fabrice Bellard
committed
return;
}
Michael Niedermayer
committed
enc = ost->st->codec;
Fabrice Bellard
committed
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 == CODEC_ID_DVB_SUBTITLE)
nb = 2;
else
nb = 1;
for (i = 0; i < nb; i++) {
ost->sync_opts = av_rescale_q(pts, ist->st->time_base, enc->time_base);
Reimar Döffinger
committed
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;
subtitle_out_size = avcodec_encode_subtitle(enc, subtitle_out,
Fabrice Bellard
committed
subtitle_out_max_size, sub);
Reimar Döffinger
committed
if (subtitle_out_size < 0) {
av_log(NULL, AV_LOG_FATAL, "Subtitle encoding failed\n");
Reimar Döffinger
committed
}
Fabrice Bellard
committed
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);
pkt.duration = av_rescale_q(sub->end_display_time, (AVRational){ 1, 1000 }, ost->st->time_base);
Fabrice Bellard
committed
if (enc->codec_id == 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;
}
write_frame(s, &pkt, ost);
Fabrice Bellard
committed
}
}
static void do_video_out(AVFormatContext *s,
OutputStream *ost,
AVFrame *in_picture,
float quality)
int ret, format_video_sync;
AVPacket pkt;
AVCodecContext *enc = ost->st->codec;
Michael Niedermayer
committed
double duration = 0;
InputStream *ist = NULL;
if (ost->source_index >= 0)
ist = input_streams[ost->source_index];
if(ist && ist->st->start_time != AV_NOPTS_VALUE && ist->st->first_dts != AV_NOPTS_VALUE && ost->frame_rate.num)
duration = 1/(av_q2d(ost->frame_rate) * av_q2d(enc->time_base));
Michael Niedermayer
committed
sync_ipts = in_picture->pts;
delta = sync_ipts - ost->sync_opts + duration;
Fabrice Bellard
committed
/* by default, we output a single frame */
nb_frames = 1;
format_video_sync = video_sync_method;
if (format_video_sync == VSYNC_AUTO)
format_video_sync = (s->oformat->flags & AVFMT_VARIABLE_FPS) ? ((s->oformat->flags & AVFMT_NOTIMESTAMPS) ? VSYNC_PASSTHROUGH : VSYNC_VFR) : 1;
switch (format_video_sync) {
case VSYNC_CFR:
// FIXME set to 0.5 after we fix some dts/pts bugs like in avidec.c
else if (delta > 1.1)
nb_frames = lrintf(delta);
break;
case VSYNC_VFR:
if (delta <= -0.6)
nb_frames = 0;
else if (delta > 0.6)
ost->sync_opts = lrint(sync_ipts);
ost->sync_opts = lrint(sync_ipts);
break;
default:
av_assert0(0);
}
nb_frames = FFMIN(nb_frames, ost->max_frames - ost->frame_number);
if (nb_frames == 0) {
nb_frames_drop++;
av_log(NULL, AV_LOG_VERBOSE, "*** drop!\n");
} else if (nb_frames > 1) {
nb_frames_dup += nb_frames - 1;
av_log(NULL, AV_LOG_VERBOSE, "*** %d dup!\n", nb_frames - 1);
}
duplicate_frame:
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
in_picture->pts = ost->sync_opts;
if (s->oformat->flags & AVFMT_RAWPICTURE &&
enc->codec->id == CODEC_ID_RAWVIDEO) {
/* raw pictures are written as AVPicture structure to
avoid any copies. We support temporarily the older
method. */
enc->coded_frame->interlaced_frame = in_picture->interlaced_frame;
enc->coded_frame->top_field_first = in_picture->top_field_first;
pkt.data = (uint8_t *)in_picture;
pkt.size = sizeof(AVPicture);
pkt.pts = av_rescale_q(in_picture->pts, enc->time_base, ost->st->time_base);
pkt.flags |= AV_PKT_FLAG_KEY;
write_frame(s, &pkt, ost);
video_size += pkt.size;
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
} else {
int got_packet;
AVFrame big_picture;
big_picture = *in_picture;
/* better than nothing: use input picture interlaced
settings */
big_picture.interlaced_frame = in_picture->interlaced_frame;
if (ost->st->codec->flags & (CODEC_FLAG_INTERLACED_DCT|CODEC_FLAG_INTERLACED_ME)) {
if (ost->top_field_first == -1)
big_picture.top_field_first = in_picture->top_field_first;
else
big_picture.top_field_first = !!ost->top_field_first;
}
/* handles same_quant here. This is not correct because it may
not be a global option */
big_picture.quality = quality;
if (!enc->me_threshold)
big_picture.pict_type = 0;
if (ost->forced_kf_index < ost->forced_kf_count &&
big_picture.pts >= ost->forced_kf_pts[ost->forced_kf_index]) {
big_picture.pict_type = AV_PICTURE_TYPE_I;
ost->forced_kf_index++;
}
update_benchmark(NULL);
ret = avcodec_encode_video2(enc, &pkt, &big_picture, &got_packet);
update_benchmark("encode_video %d.%d", ost->file_index, ost->index);
if (ret < 0) {
av_log(NULL, AV_LOG_FATAL, "Video encoding failed\n");
exit_program(1);
}
if (got_packet) {
if (pkt.pts == AV_NOPTS_VALUE && !(enc->codec->capabilities & CODEC_CAP_DELAY))
pkt.pts = ost->sync_opts;
if (pkt.pts != AV_NOPTS_VALUE)
pkt.pts = av_rescale_q(pkt.pts, enc->time_base, ost->st->time_base);
if (pkt.dts != AV_NOPTS_VALUE)
pkt.dts = av_rescale_q(pkt.dts, enc->time_base, ost->st->time_base);
if (debug_ts) {
av_log(NULL, AV_LOG_INFO, "encoder -> type:video "
"pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s\n",
av_ts2str(pkt.pts), av_ts2timestr(pkt.pts, &ost->st->time_base),
av_ts2str(pkt.dts), av_ts2timestr(pkt.dts, &ost->st->time_base));
write_frame(s, &pkt, ost);
frame_size = pkt.size;
video_size += pkt.size;
av_free_packet(&pkt);
/* if two pass, output log */
if (ost->logfile && enc->stats_out) {
fprintf(ost->logfile, "%s", enc->stats_out);
ost->sync_opts++;
/*
* For video, number of frames in == number of packets out.
* But 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++;
if(--nb_frames)
goto duplicate_frame;
if (vstats_filename && frame_size)
do_video_stats(output_files[ost->file_index]->ctx, ost, frame_size);
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
static double psnr(double d)
{
return -10.0 * log(d) / log(10.0);
}
static void do_video_stats(AVFormatContext *os, 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");
exit_program(1);
}
}
enc = ost->st->codec;
if (enc->codec_type == AVMEDIA_TYPE_VIDEO) {
frame_number = ost->frame_number;
fprintf(vstats_file, "frame= %5d q= %2.1f ", frame_number, enc->coded_frame->quality / (float)FF_QP2LAMBDA);
if (enc->flags&CODEC_FLAG_PSNR)
fprintf(vstats_file, "PSNR= %6.2f ", psnr(enc->coded_frame->error[0] / (enc->width * enc->height * 255.0 * 255.0)));
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)(video_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)video_size / 1024, ti1, bitrate, avg_bitrate);
fprintf(vstats_file, "type= %c\n", av_get_picture_type_char(enc->coded_frame->pict_type));
}
}
/* check for new output on any of the filtergraphs */
static int poll_filters(void)
{
AVFilterBufferRef *picref;
AVFrame *filtered_frame = NULL;
int i, ret, ret_all;
unsigned nb_success, nb_eof;
Matthieu Bouron
committed
int64_t frame_pts;
while (1) {
/* Reap all buffers present in the buffer sinks */
for (i = 0; i < nb_output_streams; i++) {
OutputStream *ost = output_streams[i];
OutputFile *of = output_files[ost->file_index];
continue;
if (!ost->filtered_frame && !(ost->filtered_frame = avcodec_alloc_frame())) {
return AVERROR(ENOMEM);
} else
avcodec_get_frame_defaults(ost->filtered_frame);
filtered_frame = ost->filtered_frame;
while (!ost->is_past_recording_time) {
if (ost->enc->type == AVMEDIA_TYPE_AUDIO &&
!(ost->enc->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE))
ret = av_buffersink_read_samples(ost->filter->filter, &picref,
ost->st->codec->frame_size);
else if(ost->enc->type == AVMEDIA_TYPE_AUDIO)
ret = av_buffersink_read(ost->filter->filter, &picref);
ret = av_buffersink_get_buffer_ref(ost->filter->filter, &picref,
AV_BUFFERSINK_FLAG_NO_REQUEST);
if (ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) {
char buf[256];
av_strerror(ret, buf, sizeof(buf));
av_log(NULL, AV_LOG_WARNING,
"Error in av_buffersink_get_buffer_ref(): %s\n", buf);
}
break;
}
frame_pts = AV_NOPTS_VALUE;
if (picref->pts != AV_NOPTS_VALUE) {
filtered_frame->pts = frame_pts = av_rescale_q(picref->pts,
ost->filter->filter->inputs[0]->time_base,
ost->st->codec->time_base) -
av_rescale_q(of->start_time,
AV_TIME_BASE_Q,
ost->st->codec->time_base);
if (of->start_time && filtered_frame->pts < 0) {
avfilter_unref_buffer(picref);
continue;
}
}
//if (ost->source_index >= 0)
// *filtered_frame= *input_streams[ost->source_index]->decoded_frame; //for me_threshold
switch (ost->filter->filter->inputs[0]->type) {
case AVMEDIA_TYPE_VIDEO:
avfilter_fill_frame_from_video_buffer_ref(filtered_frame, picref);
Matthieu Bouron
committed
filtered_frame->pts = frame_pts;
if (!ost->frame_aspect_ratio)
ost->st->codec->sample_aspect_ratio = picref->video->sample_aspect_ratio;
do_video_out(of->ctx, ost, filtered_frame,
same_quant ? ost->last_quality :
ost->st->codec->global_quality);
break;
case AVMEDIA_TYPE_AUDIO:
avfilter_copy_buf_props(filtered_frame, picref);
filtered_frame->pts = frame_pts;
do_audio_out(of->ctx, ost, filtered_frame);
break;
// TODO support subtitle filters
/* Request frames through all the graphs */
ret_all = nb_success = nb_eof = 0;
for (i = 0; i < nb_filtergraphs; i++) {
ret = avfilter_graph_request_oldest(filtergraphs[i]->graph);
if (!ret) {
nb_success++;
} else if (ret == AVERROR_EOF) {
nb_eof++;
} else if (ret != AVERROR(EAGAIN)) {
char buf[256];
av_strerror(ret, buf, sizeof(buf));
av_log(NULL, AV_LOG_WARNING,
"Error in request_frame(): %s\n", buf);
ret_all = ret;
}
}
if (!nb_success)
break;
/* Try again if anything succeeded */