Newer
Older
/* dump the stream mapping */
av_log(NULL, AV_LOG_INFO, "Stream mapping:\n");
for (i = 0; i < nb_input_streams; i++) {
ist = input_streams[i];
for (j = 0; j < ist->nb_filters; j++) {
if (ist->filters[j]->graph->graph_desc) {
av_log(NULL, AV_LOG_INFO, " Stream #%d:%d (%s) -> %s",
ist->file_index, ist->st->index, ist->dec ? ist->dec->name : "?",
ist->filters[j]->name);
if (nb_filtergraphs > 1)
av_log(NULL, AV_LOG_INFO, " (graph %d)", ist->filters[j]->graph->index);
av_log(NULL, AV_LOG_INFO, "\n");
}
}
}
for (i = 0; i < nb_output_streams; i++) {
ost = output_streams[i];
if (ost->attachment_filename) {
/* an attached file */
av_log(NULL, AV_LOG_INFO, " File %s -> Stream #%d:%d\n",
ost->attachment_filename, ost->file_index, ost->index);
continue;
if (ost->filter && ost->filter->graph->graph_desc) {
/* output from a complex graph */
av_log(NULL, AV_LOG_INFO, " %s", ost->filter->name);
if (nb_filtergraphs > 1)
av_log(NULL, AV_LOG_INFO, " (graph %d)", ost->filter->graph->index);
av_log(NULL, AV_LOG_INFO, " -> Stream #%d:%d (%s)\n", ost->file_index,
ost->index, ost->enc ? ost->enc->name : "?");
Fabrice Bellard
committed
}
av_log(NULL, AV_LOG_INFO, " Stream #%d:%d -> #%d:%d",
input_streams[ost->source_index]->file_index,
input_streams[ost->source_index]->st->index,
ost->file_index,
ost->index);
if (ost->sync_ist != input_streams[ost->source_index])
av_log(NULL, AV_LOG_INFO, " [sync #%d:%d]",
ost->sync_ist->file_index,
ost->sync_ist->st->index);
av_log(NULL, AV_LOG_INFO, " (copy)");
else {
const AVCodec *in_codec = input_streams[ost->source_index]->dec;
const AVCodec *out_codec = ost->enc;
const char *decoder_name = "?";
const char *in_codec_name = "?";
const char *encoder_name = "?";
const char *out_codec_name = "?";
if (in_codec) {
decoder_name = in_codec->name;
in_codec_name = avcodec_descriptor_get(in_codec->id)->name;
if (!strcmp(decoder_name, in_codec_name))
decoder_name = "native";
}
if (out_codec) {
encoder_name = out_codec->name;
out_codec_name = avcodec_descriptor_get(out_codec->id)->name;
if (!strcmp(encoder_name, out_codec_name))
encoder_name = "native";
}
av_log(NULL, AV_LOG_INFO, " (%s (%s) -> %s (%s))",
in_codec_name, decoder_name,
out_codec_name, encoder_name);
}
av_log(NULL, AV_LOG_INFO, "\n");
av_log(NULL, AV_LOG_ERROR, "%s\n", error);
return ret;
print_sdp();
Michael Niedermayer
committed
transcode_init_done = 1;
return 0;
}
/* Return 1 if there remain streams where more output is wanted, 0 otherwise. */
static int need_output(void)
{
int i;
for (i = 0; i < nb_output_streams; i++) {
OutputStream *ost = output_streams[i];
OutputFile *of = output_files[ost->file_index];
AVFormatContext *os = output_files[ost->file_index]->ctx;
if (ost->finished ||
(os->pb && avio_tell(os->pb) >= of->limit_filesize))
continue;
if (ost->frame_number >= ost->max_frames) {
int j;
for (j = 0; j < of->ctx->nb_streams; j++)
close_output_stream(output_streams[of->ost_index + j]);
continue;
}
return 1;
Michael Niedermayer
committed
return 0;
}
* Select the output stream to process.
* @return selected output stream, or NULL if none available
static OutputStream *choose_output(void)
int i;
int64_t opts_min = INT64_MAX;
OutputStream *ost_min = NULL;
for (i = 0; i < nb_output_streams; i++) {
OutputStream *ost = output_streams[i];
int64_t opts = av_rescale_q(ost->st->cur_dts, ost->st->time_base,
AV_TIME_BASE_Q);
Michael Niedermayer
committed
if (!ost->finished && opts < opts_min) {
opts_min = opts;
Michael Niedermayer
committed
ost_min = ost->unavailable ? NULL : ost;
}
return ost_min;
Fabrice Bellard
committed
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
static int check_keyboard_interaction(int64_t cur_time)
{
int i, ret, key;
static int64_t last_time;
if (received_nb_signals)
return AVERROR_EXIT;
/* read_key() returns 0 on EOF */
if(cur_time - last_time >= 100000 && !run_as_daemon){
key = read_key();
last_time = cur_time;
}else
key = -1;
if (key == 'q')
return AVERROR_EXIT;
if (key == '+') av_log_set_level(av_log_get_level()+10);
if (key == '-') av_log_set_level(av_log_get_level()-10);
if (key == 's') qp_hist ^= 1;
if (key == 'h'){
if (do_hex_dump){
do_hex_dump = do_pkt_dump = 0;
} else if(do_pkt_dump){
do_hex_dump = 1;
} else
do_pkt_dump = 1;
av_log_set_level(AV_LOG_DEBUG);
}
if (key == 'c' || key == 'C'){
char buf[4096], target[64], command[256], arg[256] = {0};
double time;
int k, n = 0;
fprintf(stderr, "\nEnter command: <target>|all <time>|-1 <command>[ <argument>]\n");
i = 0;
while ((k = read_key()) != '\n' && k != '\r' && i < sizeof(buf)-1)
if (k > 0)
buf[i++] = k;
buf[i] = 0;
if (k > 0 &&
(n = sscanf(buf, "%63[^ ] %lf %255[^ ] %255[^\n]", target, &time, command, arg)) >= 3) {
av_log(NULL, AV_LOG_DEBUG, "Processing command target:%s time:%f command:%s arg:%s",
target, time, command, arg);
for (i = 0; i < nb_filtergraphs; i++) {
FilterGraph *fg = filtergraphs[i];
if (fg->graph) {
if (time < 0) {
ret = avfilter_graph_send_command(fg->graph, target, command, arg, buf, sizeof(buf),
key == 'c' ? AVFILTER_CMD_FLAG_ONE : 0);
fprintf(stderr, "Command reply for stream %d: ret:%d res:\n%s", i, ret, buf);
Michael Niedermayer
committed
} else if (key == 'c') {
fprintf(stderr, "Queing commands only on filters supporting the specific command is unsupported\n");
ret = AVERROR_PATCHWELCOME;
} else {
ret = avfilter_graph_queue_command(fg->graph, target, command, arg, 0, time);
}
}
Fabrice Bellard
committed
}
} else {
av_log(NULL, AV_LOG_ERROR,
"Parse error, at least 3 arguments were expected, "
"only %d given in string '%s'\n", n, buf);
Fabrice Bellard
committed
}
}
if (key == 'd' || key == 'D'){
int debug=0;
if(key == 'D') {
debug = input_streams[0]->st->codec->debug<<1;
if(!debug) debug = 1;
while(debug & (FF_DEBUG_DCT_COEFF|FF_DEBUG_VIS_QP|FF_DEBUG_VIS_MB_TYPE)) //unsupported, would just crash
debug += debug;
}else
if(scanf("%d", &debug)!=1)
fprintf(stderr,"error parsing debug value\n");
for(i=0;i<nb_input_streams;i++) {
input_streams[i]->st->codec->debug = debug;
Fabrice Bellard
committed
}
for(i=0;i<nb_output_streams;i++) {
OutputStream *ost = output_streams[i];
ost->enc_ctx->debug = debug;
}
if(debug) av_log_set_level(AV_LOG_DEBUG);
fprintf(stderr,"debug=%d\n", debug);
Fabrice Bellard
committed
}
if (key == '?'){
fprintf(stderr, "key function\n"
"? show this help\n"
"+ increase verbosity\n"
"- decrease verbosity\n"
"c Send command to first matching filter supporting it\n"
"C Send/Que command to all matching filters\n"
"D cycle through available debug modes\n"
"h dump packets/hex press to cycle through the 3 states\n"
"q quit\n"
"s Show QP histogram\n"
);
}
return 0;
Fabrice Bellard
committed
}
Fabrice Bellard
committed
{
AVPacket pkt;
ret = av_read_frame(f->ctx, &pkt);
}
if (ret < 0) {
av_thread_message_queue_set_err_recv(f->in_thread_queue, ret);
ret = av_thread_message_queue_send(f->in_thread_queue, &pkt, 0);
if (ret < 0) {
if (ret != AVERROR_EOF)
av_log(f->ctx, AV_LOG_ERROR,
"Unable to send packet to main thread: %s\n",
av_err2str(ret));
av_free_packet(&pkt);
av_thread_message_queue_set_err_recv(f->in_thread_queue, ret);
break;
}
for (i = 0; i < nb_input_files; i++) {
InputFile *f = input_files[i];
AVPacket pkt;
av_thread_message_queue_set_err_send(f->in_thread_queue, AVERROR_EOF);
while (av_thread_message_queue_recv(f->in_thread_queue, &pkt, 0) >= 0)
pthread_join(f->thread, NULL);
f->joined = 1;
av_thread_message_queue_free(&f->in_thread_queue);
}
}
if (nb_input_files == 1)
return 0;
for (i = 0; i < nb_input_files; i++) {
InputFile *f = input_files[i];
if (f->ctx->pb ? !f->ctx->pb->seekable :
strcmp(f->ctx->iformat->name, "lavfi"))
f->non_blocking = 1;
ret = av_thread_message_queue_alloc(&f->in_thread_queue,
8, sizeof(AVPacket));
if (ret < 0)
return ret;
if ((ret = pthread_create(&f->thread, NULL, input_thread, f))) {
av_log(NULL, AV_LOG_ERROR, "pthread_create failed: %s. Try to increase `ulimit -v` or decrease `ulimit -s`.\n", strerror(ret));
av_thread_message_queue_free(&f->in_thread_queue);
}
return 0;
}
static int get_input_packet_mt(InputFile *f, AVPacket *pkt)
return av_thread_message_queue_recv(f->in_thread_queue, pkt,
f->non_blocking ?
AV_THREAD_MESSAGE_NONBLOCK : 0);
static int get_input_packet(InputFile *f, AVPacket *pkt)
{
if (f->rate_emu) {
int i;
for (i = 0; i < f->nb_streams; i++) {
InputStream *ist = input_streams[f->ist_index + i];
int64_t pts = av_rescale(ist->dts, 1000000, AV_TIME_BASE);
int64_t now = av_gettime_relative() - ist->start;
if (pts > now)
return AVERROR(EAGAIN);
}
}
if (nb_input_files > 1)
return get_input_packet_mt(f, pkt);
#endif
return av_read_frame(f->ctx, pkt);
static int got_eagain(void)
{
int i;
for (i = 0; i < nb_output_streams; i++)
if (output_streams[i]->unavailable)
return 1;
return 0;
}
static void reset_eagain(void)
{
int i;
for (i = 0; i < nb_input_files; i++)
input_files[i]->eagain = 0;
for (i = 0; i < nb_output_streams; i++)
output_streams[i]->unavailable = 0;
}
* - 0 -- one packet was read and processed
* - AVERROR(EAGAIN) -- no packets were available for selected file,
* this function should be called again
* - AVERROR_EOF -- this function should not be called again
*/
static int process_input(int file_index)
InputFile *ifile = input_files[file_index];
AVFormatContext *is;
InputStream *ist;
AVPacket pkt;
int ret, i, j;
is = ifile->ctx;
ret = get_input_packet(ifile, &pkt);
if (ret == AVERROR(EAGAIN)) {
ifile->eagain = 1;
return ret;
}
if (ret < 0) {
if (ret != AVERROR_EOF) {
print_error(is->filename, ret);
if (exit_on_error)
}
for (i = 0; i < ifile->nb_streams; i++) {
ist = input_streams[ifile->ist_index + i];
if (ist->decoding_needed) {
ret = process_input_packet(ist, NULL);
if (ret>0)
return 0;
}
/* mark all outputs that don't go through lavfi as finished */
for (j = 0; j < nb_output_streams; j++) {
OutputStream *ost = output_streams[j];
if (ost->source_index == ifile->ist_index + i &&
(ost->stream_copy || ost->enc->type == AVMEDIA_TYPE_SUBTITLE))
finish_output_stream(ost);
}
}
ifile->eof_reached = 1;
return AVERROR(EAGAIN);
}
reset_eagain();
if (do_pkt_dump) {
av_pkt_dump_log2(NULL, AV_LOG_DEBUG, &pkt, do_hex_dump,
is->streams[pkt.stream_index]);
}
/* the following test is needed in case new streams appear
dynamically in stream : we ignore them */
if (pkt.stream_index >= ifile->nb_streams) {
report_new_stream(file_index, &pkt);
goto discard_packet;
}
ist = input_streams[ifile->ist_index + pkt.stream_index];
ist->data_size += pkt.size;
ist->nb_packets++;
if (ist->discard)
goto discard_packet;
if (debug_ts) {
av_log(NULL, AV_LOG_INFO, "demuxer -> ist_index:%d type:%s "
"next_dts:%s next_dts_time:%s next_pts:%s next_pts_time:%s pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s off:%s off_time:%s\n",
Michael Niedermayer
committed
ifile->ist_index + pkt.stream_index, av_get_media_type_string(ist->dec_ctx->codec_type),
av_ts2str(ist->next_dts), av_ts2timestr(ist->next_dts, &AV_TIME_BASE_Q),
av_ts2str(ist->next_pts), av_ts2timestr(ist->next_pts, &AV_TIME_BASE_Q),
av_ts2str(pkt.pts), av_ts2timestr(pkt.pts, &ist->st->time_base),
av_ts2str(pkt.dts), av_ts2timestr(pkt.dts, &ist->st->time_base),
av_ts2str(input_files[ist->file_index]->ts_offset),
av_ts2timestr(input_files[ist->file_index]->ts_offset, &AV_TIME_BASE_Q));
if(!ist->wrap_correction_done && is->start_time != AV_NOPTS_VALUE && ist->st->pts_wrap_bits < 64){
int64_t stime, stime2;
// Correcting starttime based on the enabled streams
// FIXME this ideally should be done before the first use of starttime but we do not know which are the enabled streams at that point.
// so we instead do it here as part of discontinuity handling
if ( ist->next_dts == AV_NOPTS_VALUE
&& ifile->ts_offset == -is->start_time
&& (is->iformat->flags & AVFMT_TS_DISCONT)) {
int64_t new_start_time = INT64_MAX;
for (i=0; i<is->nb_streams; i++) {
AVStream *st = is->streams[i];
if(st->discard == AVDISCARD_ALL || st->start_time == AV_NOPTS_VALUE)
continue;
new_start_time = FFMIN(new_start_time, av_rescale_q(st->start_time, st->time_base, AV_TIME_BASE_Q));
}
if (new_start_time > is->start_time) {
av_log(is, AV_LOG_VERBOSE, "Correcting start time by %"PRId64"\n", new_start_time - is->start_time);
ifile->ts_offset = -new_start_time;
}
}
stime = av_rescale_q(is->start_time, AV_TIME_BASE_Q, ist->st->time_base);
stime2= stime + (1ULL<<ist->st->pts_wrap_bits);
ist->wrap_correction_done = 1;
if(stime2 > stime && pkt.dts != AV_NOPTS_VALUE && pkt.dts > stime + (1LL<<(ist->st->pts_wrap_bits-1))) {
pkt.dts -= 1ULL<<ist->st->pts_wrap_bits;
ist->wrap_correction_done = 0;
}
if(stime2 > stime && pkt.pts != AV_NOPTS_VALUE && pkt.pts > stime + (1LL<<(ist->st->pts_wrap_bits-1))) {
pkt.pts -= 1ULL<<ist->st->pts_wrap_bits;
ist->wrap_correction_done = 0;
}
}
/* add the stream-global side data to the first packet */
if (ist->nb_packets == 1) {
Michael Niedermayer
committed
if (ist->st->nb_side_data)
av_packet_split_side_data(&pkt);
for (i = 0; i < ist->st->nb_side_data; i++) {
AVPacketSideData *src_sd = &ist->st->side_data[i];
uint8_t *dst_data;
if (av_packet_get_side_data(&pkt, src_sd->type, NULL))
continue;
dst_data = av_packet_new_side_data(&pkt, src_sd->type, src_sd->size);
if (!dst_data)
exit_program(1);
memcpy(dst_data, src_sd->data, src_sd->size);
}
if (pkt.dts != AV_NOPTS_VALUE)
pkt.dts += av_rescale_q(ifile->ts_offset, AV_TIME_BASE_Q, ist->st->time_base);
if (pkt.pts != AV_NOPTS_VALUE)
pkt.pts += av_rescale_q(ifile->ts_offset, AV_TIME_BASE_Q, ist->st->time_base);
if (pkt.pts != AV_NOPTS_VALUE)
pkt.pts *= ist->ts_scale;
if (pkt.dts != AV_NOPTS_VALUE)
pkt.dts *= ist->ts_scale;
if ((ist->dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO ||
ist->dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) &&
pkt.dts != AV_NOPTS_VALUE && ist->next_dts == AV_NOPTS_VALUE && !copy_ts
&& (is->iformat->flags & AVFMT_TS_DISCONT) && ifile->last_ts != AV_NOPTS_VALUE) {
int64_t pkt_dts = av_rescale_q(pkt.dts, ist->st->time_base, AV_TIME_BASE_Q);
int64_t delta = pkt_dts - ifile->last_ts;
if (delta < -1LL*dts_delta_threshold*AV_TIME_BASE ||
delta > 1LL*dts_delta_threshold*AV_TIME_BASE){
ifile->ts_offset -= delta;
av_log(NULL, AV_LOG_DEBUG,
"Inter stream timestamp discontinuity %"PRId64", new offset= %"PRId64"\n",
delta, ifile->ts_offset);
pkt.dts -= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);
if (pkt.pts != AV_NOPTS_VALUE)
pkt.pts -= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);
}
}
if ((ist->dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO ||
ist->dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) &&
pkt.dts != AV_NOPTS_VALUE && ist->next_dts != AV_NOPTS_VALUE &&
!copy_ts) {
int64_t pkt_dts = av_rescale_q(pkt.dts, ist->st->time_base, AV_TIME_BASE_Q);
int64_t delta = pkt_dts - ist->next_dts;
if (is->iformat->flags & AVFMT_TS_DISCONT) {
if (delta < -1LL*dts_delta_threshold*AV_TIME_BASE ||
delta > 1LL*dts_delta_threshold*AV_TIME_BASE ||
pkt_dts + AV_TIME_BASE/10 < FFMAX(ist->pts, ist->dts)) {
ifile->ts_offset -= delta;
av_log(NULL, AV_LOG_DEBUG,
"timestamp discontinuity %"PRId64", new offset= %"PRId64"\n",
delta, ifile->ts_offset);
pkt.dts -= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);
if (pkt.pts != AV_NOPTS_VALUE)
pkt.pts -= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);
}
} else {
if ( delta < -1LL*dts_error_threshold*AV_TIME_BASE ||
delta > 1LL*dts_error_threshold*AV_TIME_BASE) {
av_log(NULL, AV_LOG_WARNING, "DTS %"PRId64", next:%"PRId64" st:%d invalid dropping\n", pkt.dts, ist->next_dts, pkt.stream_index);
pkt.dts = AV_NOPTS_VALUE;
}
if (pkt.pts != AV_NOPTS_VALUE){
int64_t pkt_pts = av_rescale_q(pkt.pts, ist->st->time_base, AV_TIME_BASE_Q);
delta = pkt_pts - ist->next_dts;
if ( delta < -1LL*dts_error_threshold*AV_TIME_BASE ||
delta > 1LL*dts_error_threshold*AV_TIME_BASE) {
av_log(NULL, AV_LOG_WARNING, "PTS %"PRId64", next:%"PRId64" invalid dropping st:%d\n", pkt.pts, ist->next_dts, pkt.stream_index);
pkt.pts = AV_NOPTS_VALUE;
}
}
}
}
if (pkt.dts != AV_NOPTS_VALUE)
ifile->last_ts = av_rescale_q(pkt.dts, ist->st->time_base, AV_TIME_BASE_Q);
if (debug_ts) {
Stefano Sabatini
committed
av_log(NULL, AV_LOG_INFO, "demuxer+ffmpeg -> ist_index:%d type:%s pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s off:%s off_time:%s\n",
Michael Niedermayer
committed
ifile->ist_index + pkt.stream_index, av_get_media_type_string(ist->dec_ctx->codec_type),
av_ts2str(pkt.pts), av_ts2timestr(pkt.pts, &ist->st->time_base),
av_ts2str(pkt.dts), av_ts2timestr(pkt.dts, &ist->st->time_base),
av_ts2str(input_files[ist->file_index]->ts_offset),
av_ts2timestr(input_files[ist->file_index]->ts_offset, &AV_TIME_BASE_Q));
sub2video_heartbeat(ist, pkt.pts);
ret = process_input_packet(ist, &pkt);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Error while decoding stream #%d:%d: %s\n",
ist->file_index, ist->st->index, av_err2str(ret));
}
discard_packet:
av_free_packet(&pkt);
return 0;
}
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
/**
* Perform a step of transcoding for the specified filter graph.
*
* @param[in] graph filter graph to consider
* @param[out] best_ist input stream where a frame would allow to continue
* @return 0 for success, <0 for error
*/
static int transcode_from_filter(FilterGraph *graph, InputStream **best_ist)
{
int i, ret;
int nb_requests, nb_requests_max = 0;
InputFilter *ifilter;
InputStream *ist;
*best_ist = NULL;
ret = avfilter_graph_request_oldest(graph->graph);
if (ret >= 0)
return reap_filters();
if (ret == AVERROR_EOF) {
ret = reap_filters();
for (i = 0; i < graph->nb_outputs; i++)
close_output_stream(graph->outputs[i]->ost);
return ret;
}
if (ret != AVERROR(EAGAIN))
return ret;
for (i = 0; i < graph->nb_inputs; i++) {
ifilter = graph->inputs[i];
ist = ifilter->ist;
if (input_files[ist->file_index]->eagain ||
input_files[ist->file_index]->eof_reached)
continue;
nb_requests = av_buffersrc_get_nb_failed_requests(ifilter->filter);
if (nb_requests > nb_requests_max) {
nb_requests_max = nb_requests;
*best_ist = ist;
}
}
if (!*best_ist)
for (i = 0; i < graph->nb_outputs; i++)
graph->outputs[i]->ost->unavailable = 1;
return 0;
}
/**
* Run a single step of transcoding.
*
* @return 0 for success, <0 for error
*/
static int transcode_step(void)
{
OutputStream *ost;
InputStream *ist;
int ret;
ost = choose_output();
if (!ost) {
if (got_eagain()) {
reset_eagain();
av_usleep(10000);
return 0;
}
av_log(NULL, AV_LOG_VERBOSE, "No more inputs to read from, finishing.\n");
return AVERROR_EOF;
}
if (ost->filter) {
if ((ret = transcode_from_filter(ost->filter->graph, &ist)) < 0)
return ret;
if (!ist)
return 0;
} else {
av_assert0(ost->source_index >= 0);
ist = input_streams[ost->source_index];
}
ret = process_input(ist->file_index);
if (ret == AVERROR(EAGAIN)) {
if (input_files[ist->file_index]->eagain)
ost->unavailable = 1;
return 0;
}
if (ret < 0)
return ret == AVERROR_EOF ? 0 : ret;
return reap_filters();
}
/*
* The following code is the main loop of the file converter
*/
static int transcode(void)
Fabrice Bellard
committed
{
int ret, i;
InputStream *ist;
int64_t timer_start;
ret = transcode_init();
if (ret < 0)
goto fail;
if (stdin_interaction) {
av_log(NULL, AV_LOG_INFO, "Press [q] to stop, [?] for help\n");
timer_start = av_gettime_relative();
if ((ret = init_input_threads()) < 0)
goto fail;
#endif
int64_t cur_time= av_gettime_relative();
/* if 'q' pressed, exits */
if (stdin_interaction)
if (check_keyboard_interaction(cur_time) < 0)
break;
/* check if there's any stream where output is still needed */
if (!need_output()) {
av_log(NULL, AV_LOG_VERBOSE, "No more output streams to write to, finishing.\n");
ret = transcode_step();
if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN))
av_log(NULL, AV_LOG_ERROR, "Error while filtering.\n");
break;
Michael Niedermayer
committed
}
/* dump report by using the output first video and audio streams */
print_report(0, timer_start, cur_time);
/* at the end of stream, we must flush the decoder buffers */
for (i = 0; i < nb_input_streams; i++) {
ist = input_streams[i];
if (!input_files[ist->file_index]->eof_reached && ist->decoding_needed) {
process_input_packet(ist, NULL);
Fabrice Bellard
committed
}
flush_encoders();
Fabrice Bellard
committed
/* write the trailer if needed and close file */
os = output_files[i]->ctx;
av_write_trailer(os);
/* dump report by using the first video and audio streams */
print_report(1, timer_start, av_gettime_relative());
/* close each encoder */
for (i = 0; i < nb_output_streams; i++) {
ost = output_streams[i];
if (ost->encoding_needed) {
av_freep(&ost->enc_ctx->stats_in);
/* close each decoder */
for (i = 0; i < nb_input_streams; i++) {
ist = input_streams[i];
if (ist->decoding_needed) {
avcodec_close(ist->dec_ctx);
ist->hwaccel_uninit(ist->dec_ctx);
/* finished ! */
ret = 0;
fail:
if (output_streams) {
for (i = 0; i < nb_output_streams; i++) {
ost = output_streams[i];
if (ost) {
if (ost->logfile) {
fclose(ost->logfile);
ost->logfile = NULL;
av_freep(&ost->forced_kf_pts);
Michael Niedermayer
committed
av_freep(&ost->apad);
av_dict_free(&ost->encoder_opts);
Michael Niedermayer
committed
av_dict_free(&ost->swr_opts);
av_dict_free(&ost->resample_opts);
static int64_t getutime(void)
#if HAVE_GETRUSAGE
struct rusage rusage;
getrusage(RUSAGE_SELF, &rusage);
return (rusage.ru_utime.tv_sec * 1000000LL) + rusage.ru_utime.tv_usec;
#elif HAVE_GETPROCESSTIMES
HANDLE proc;
FILETIME c, e, k, u;
proc = GetCurrentProcess();
GetProcessTimes(proc, &c, &e, &k, &u);
return ((int64_t) u.dwHighDateTime << 32 | u.dwLowDateTime) / 10;
#else
return av_gettime_relative();
static int64_t getmaxrss(void)
{
#if HAVE_GETRUSAGE && HAVE_STRUCT_RUSAGE_RU_MAXRSS
struct rusage rusage;
getrusage(RUSAGE_SELF, &rusage);
return (int64_t)rusage.ru_maxrss * 1024;
#elif HAVE_GETPROCESSMEMORYINFO
HANDLE proc;
PROCESS_MEMORY_COUNTERS memcounters;
proc = GetCurrentProcess();
memcounters.cb = sizeof(memcounters);
GetProcessMemoryInfo(proc, &memcounters, sizeof(memcounters));
return memcounters.PeakPagefileUsage;
#else
return 0;
#endif
}
static void log_callback_null(void *ptr, int level, const char *fmt, va_list vl)
{
}
register_exit(ffmpeg_cleanup);
setvbuf(stderr,NULL,_IONBF,0); /* win32 runtime needs this */
av_log_set_flags(AV_LOG_SKIP_REPEATED);
parse_loglevel(argc, argv, options);
if(argc>1 && !strcmp(argv[1], "-d")){
run_as_daemon=1;
av_log_set_callback(log_callback_null);
argc--;
argv++;
}
#if CONFIG_AVDEVICE
avformat_network_init();
show_banner(argc, argv, options);
/* parse options and open all input/output files */
ret = ffmpeg_parse_options(argc, argv);
if (nb_output_files <= 0 && nb_input_files == 0) {
av_log(NULL, AV_LOG_WARNING, "Use -h to get full help or, even better, run 'man %s'\n", program_name);
/* file converter / grab */
if (nb_output_files <= 0) {
av_log(NULL, AV_LOG_FATAL, "At least one output file must be specified\n");
// if (nb_input_files == 0) {
// av_log(NULL, AV_LOG_FATAL, "At least one input file must be specified\n");
// exit_program(1);
if (transcode() < 0)
ti = getutime() - ti;
if (do_benchmark) {
printf("bench: utime=%0.3fs\n", ti / 1000000.0);
av_log(NULL, AV_LOG_DEBUG, "%"PRIu64" frames successfully decoded, %"PRIu64" decoding errors\n",
decode_error_stat[0], decode_error_stat[1]);
Michael Niedermayer
committed
if ((decode_error_stat[0] + decode_error_stat[1]) * max_error_rate < decode_error_stat[1])
Michael Niedermayer
committed
exit_program(received_nb_signals ? 255 : main_return_code);
return main_return_code;