avcodec_get_frame_defaults(ist->decoded_frame);
decoded_frame = ist->decoded_frame;
+ update_benchmark(NULL);
ret = avcodec_decode_audio4(avctx, decoded_frame, got_output, pkt);
- if (ret < 0) {
- return ret;
- }
- if (avctx->sample_rate <= 0) {
+ update_benchmark("decode_audio %d.%d", ist->file_index, ist->st->index);
- if (!*got_output) {
- /* no audio frame */
- if (!pkt->size)
++
++ if (ret >= 0 && avctx->sample_rate <= 0) {
+ av_log(avctx, AV_LOG_ERROR, "Sample rate %d invalid\n", avctx->sample_rate);
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (!*got_output || ret < 0) {
+ if (!pkt->size) {
for (i = 0; i < ist->nb_filters; i++)
- av_buffersrc_buffer(ist->filters[i]->filter, NULL);
+ av_buffersrc_add_ref(ist->filters[i]->filter, NULL,
+ AV_BUFFERSRC_FLAG_NO_COPY);
+ }
return ret;
}
else
avcodec_get_frame_defaults(ist->decoded_frame);
decoded_frame = ist->decoded_frame;
+ pkt->dts = av_rescale_q(ist->dts, AV_TIME_BASE_Q, ist->st->time_base);
+ update_benchmark(NULL);
ret = avcodec_decode_video2(ist->st->codec,
decoded_frame, got_output, pkt);
- if (ret < 0)
- return ret;
-
- quality = same_quant ? decoded_frame->quality : 0;
- if (!*got_output) {
- /* no picture yet */
- if (!pkt->size)
+ update_benchmark("decode_video %d.%d", ist->file_index, ist->st->index);
+ if (!*got_output || ret < 0) {
+ if (!pkt->size) {
for (i = 0; i < ist->nb_filters; i++)
- av_buffersrc_buffer(ist->filters[i]->filter, NULL);
+ av_buffersrc_add_ref(ist->filters[i]->filter, NULL, AV_BUFFERSRC_FLAG_NO_COPY);
+ }
return ret;
}
- decoded_frame->pts = guess_correct_pts(&ist->pts_ctx, decoded_frame->pkt_pts,
- decoded_frame->pkt_dts);
+ quality = same_quant ? decoded_frame->quality : 0;
++
+ if(ist->top_field_first>=0)
+ decoded_frame->top_field_first = ist->top_field_first;
+
+ best_effort_timestamp= av_frame_get_best_effort_timestamp(decoded_frame);
+ if(best_effort_timestamp != AV_NOPTS_VALUE)
+ ist->next_pts = ist->pts = av_rescale_q(decoded_frame->pts = best_effort_timestamp, ist->st->time_base, AV_TIME_BASE_Q);
+
+ if (debug_ts) {
+ av_log(NULL, AV_LOG_INFO, "decoder -> ist_index:%d type:video "
+ "frame_pts:%s frame_pts_time:%s best_effort_ts:%"PRId64" best_effort_ts_time:%s keyframe:%d frame_type:%d \n",
+ ist->st->index, av_ts2str(decoded_frame->pts),
+ av_ts2timestr(decoded_frame->pts, &ist->st->time_base),
+ best_effort_timestamp,
+ av_ts2timestr(best_effort_timestamp, &ist->st->time_base),
+ decoded_frame->key_frame, decoded_frame->pict_type);
+ }
+
pkt->size = 0;
pre_process_video_frame(ist, (AVPicture *)decoded_frame, &buffer_to_free);
return 0;
}
-static InputFile *select_input_file(void)
+static int input_acceptable(InputStream *ist)
{
- InputFile *ifile = NULL;
- int64_t ipts_min = INT64_MAX;
- int i;
+ av_assert1(!ist->discard);
- return !input_files[ist->file_index]->unavailable &&
++ return !input_files[ist->file_index]->eagain &&
+ !input_files[ist->file_index]->eof_reached;
+}
- for (i = 0; i < nb_input_streams; i++) {
- InputStream *ist = input_streams[i];
- int64_t ipts = ist->last_dts;
+static int find_graph_input(FilterGraph *graph)
+{
+ int i, nb_req_max = 0, file_index = -1;
+
+ for (i = 0; i < graph->nb_inputs; i++) {
+ int nb_req = av_buffersrc_get_nb_failed_requests(graph->inputs[i]->filter);
+ if (nb_req > nb_req_max) {
+ InputStream *ist = graph->inputs[i]->ist;
+ if (input_acceptable(ist)) {
+ nb_req_max = nb_req;
+ file_index = ist->file_index;
+ }
+ }
+ }
- if (ist->discard || input_files[ist->file_index]->eagain)
- continue;
- if (!input_files[ist->file_index]->eof_reached) {
- if (ipts < ipts_min) {
- ipts_min = ipts;
- ifile = input_files[ist->file_index];
+ return file_index;
+}
+
+/**
+ * Select the input file to read from.
+ *
+ * @return >=0 index of the input file to use;
+ * -1 if no file is acceptable;
+ * -2 to read from filters without reading from a file
+ */
+static int select_input_file(void)
+{
+ int i, ret, nb_active_out = nb_output_streams, ost_index = -1;
+ int64_t opts_min;
+ OutputStream *ost;
+ AVFilterBufferRef *dummy;
+
+ for (i = 0; i < nb_output_streams; i++)
+ nb_active_out -= output_streams[i]->unavailable =
+ output_streams[i]->is_past_recording_time;
+ while (nb_active_out) {
+ opts_min = INT64_MAX;
+ ost_index = -1;
+ 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);
+ if (!ost->unavailable && opts < opts_min) {
+ opts_min = opts;
+ ost_index = i;
}
}
+ if (ost_index < 0)
+ return -1;
+
+ ost = output_streams[ost_index];
+ if (ost->source_index >= 0) {
+ /* ost is directly connected to an input */
+ InputStream *ist = input_streams[ost->source_index];
+ if (input_acceptable(ist))
+ return ist->file_index;
+ } else {
+ /* ost is connected to a complex filtergraph */
+ av_assert1(ost->filter);
+ ret = av_buffersink_get_buffer_ref(ost->filter->filter, &dummy,
+ AV_BUFFERSINK_FLAG_PEEK);
+ if (ret >= 0)
+ return -2;
+ ret = find_graph_input(ost->filter->graph);
+ if (ret >= 0)
+ return ret;
+ }
+ ost->unavailable = 1;
+ nb_active_out--;
}
+ return -1;
+}
- return ifile;
+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> <time> <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:%s\n", i, ret, buf);
+ } else {
+ ret = avfilter_graph_queue_command(fg->graph, target, command, arg, 0, time);
+ }
+ }
+ }
+ } else {
+ av_log(NULL, AV_LOG_ERROR,
+ "Parse error, at least 3 arguments were expected, "
+ "only %d given in string '%s'\n", n, buf);
+ }
+ }
+ 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;
+ }
+ for(i=0;i<nb_output_streams;i++) {
+ OutputStream *ost = output_streams[i];
+ ost->st->codec->debug = debug;
+ }
+ if(debug) av_log_set_level(AV_LOG_DEBUG);
+ fprintf(stderr,"debug=%d\n", debug);
+ }
+ if (key == '?'){
+ fprintf(stderr, "key function\n"
+ "? show this help\n"
+ "+ increase verbosity\n"
+ "- decrease verbosity\n"
+ "c Send command to filtergraph\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;
}
#if HAVE_PTHREADS
goto fail;
#endif
- for (; received_sigterm == 0;) {
- int file_index, ist_index;
+ while (!received_sigterm) {
+ InputFile *ifile;
AVPacket pkt;
++ int file_index;
+ int64_t cur_time= av_gettime();
+
+ /* 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()) {
}
/* select the stream that we must read now */
- ifile = select_input_file();
+ file_index = select_input_file();
/* if none, if is finished */
- if (!ifile) {
+ if (file_index == -2) {
+ poll_filters() ;
+ continue;
+ }
+ if (file_index < 0) {
- if (no_packet_count) {
- no_packet_count = 0;
- for (i = 0; i < nb_input_files; i++)
- input_files[i]->unavailable = 0;
+ if (got_eagain()) {
+ reset_eagain();
av_usleep(10000);
continue;
}
av_log(NULL, AV_LOG_VERBOSE, "No more inputs to read from, finishing.\n");
break;
}
++ ifile = input_files[file_index];
- is = input_files[file_index]->ctx;
- ret = get_input_packet(input_files[file_index], &pkt);
+ is = ifile->ctx;
+ ret = get_input_packet(ifile, &pkt);
if (ret == AVERROR(EAGAIN)) {
- input_files[file_index]->unavailable = 1;
- no_packet_count++;
+ ifile->eagain = 1;
continue;
}
if (ret < 0) {
if (exit_on_error)
exit_program(1);
}
- input_files[file_index]->eof_reached = 1;
+ ifile->eof_reached = 1;
- for (i = 0; i < input_files[file_index]->nb_streams; i++) {
- ist = input_streams[input_files[file_index]->ist_index + i];
+ for (i = 0; i < ifile->nb_streams; i++) {
+ ist = input_streams[ifile->ist_index + i];
if (ist->decoding_needed)
output_packet(ist, NULL);
+ poll_filters();
}
if (opt_shortest)
}
/* the following test is needed in case new streams appear
dynamically in stream : we ignore them */
- if (pkt.stream_index >= input_files[file_index]->nb_streams) {
- if (pkt.stream_index >= ifile->nb_streams)
++ if (pkt.stream_index >= ifile->nb_streams) {
+ report_new_stream(file_index, &pkt);
goto discard_packet;
- ist_index = input_files[file_index]->ist_index + pkt.stream_index;
- ist = input_streams[ist_index];
+ }
+
+ ist = input_streams[ifile->ist_index + pkt.stream_index];
if (ist->discard)
goto discard_packet;
+ if(!ist->wrap_correction_done && input_files[file_index]->ctx->start_time != AV_NOPTS_VALUE && ist->st->pts_wrap_bits < 64){
+ uint64_t stime = av_rescale_q(input_files[file_index]->ctx->start_time, AV_TIME_BASE_Q, ist->st->time_base);
+ uint64_t stime2= stime + (1LL<<ist->st->pts_wrap_bits);
+ ist->wrap_correction_done = 1;
+ if(pkt.dts != AV_NOPTS_VALUE && pkt.dts > stime && pkt.dts - stime > stime2 - pkt.dts) {
+ pkt.dts -= 1LL<<ist->st->pts_wrap_bits;
+ ist->wrap_correction_done = 0;
+ }
+ if(pkt.pts != AV_NOPTS_VALUE && pkt.pts > stime && pkt.pts - stime > stime2 - pkt.pts) {
+ pkt.pts -= 1LL<<ist->st->pts_wrap_bits;
+ ist->wrap_correction_done = 0;
+ }
+ }
+
if (pkt.dts != AV_NOPTS_VALUE)
- pkt.dts += av_rescale_q(input_files[ist->file_index]->ts_offset, AV_TIME_BASE_Q, ist->st->time_base);
+ 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(input_files[ist->file_index]->ts_offset, AV_TIME_BASE_Q, ist->st->time_base);
+ 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 (pkt.dts != AV_NOPTS_VALUE && ist->next_dts != AV_NOPTS_VALUE
- && (is->iformat->flags & AVFMT_TS_DISCONT)) {
+ 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:%"PRId64"\n",
- ist_index, av_get_media_type_string(ist->st->codec->codec_type),
++ ifile->ist_index + pkt.stream_index, av_get_media_type_string(ist->st->codec->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),
+ input_files[ist->file_index]->ts_offset);
+ }
+
+ if (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 ((FFABS(delta) > 1LL * dts_delta_threshold * AV_TIME_BASE || pkt_dts + 1 < ist->last_dts) && !copy_ts) {
+ if (is->iformat->flags & AVFMT_TS_DISCONT) {
+ if(delta < -1LL*dts_delta_threshold*AV_TIME_BASE ||
+ (delta > 1LL*dts_delta_threshold*AV_TIME_BASE &&
+ ist->st->codec->codec_type != AVMEDIA_TYPE_SUBTITLE) ||
+ pkt_dts+1<ist->pts){
- input_files[ist->file_index]->ts_offset -= delta;
+ ifile->ts_offset -= delta;
av_log(NULL, AV_LOG_DEBUG,
"timestamp discontinuity %"PRId64", new offset= %"PRId64"\n",
- delta, input_files[ist->file_index]->ts_offset);
+ 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 && ist->st->codec->codec_type != AVMEDIA_TYPE_SUBTITLE) ||
+ pkt_dts+1<ist->pts){
+ 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 && ist->st->codec->codec_type != AVMEDIA_TYPE_SUBTITLE) ||
+ pkt_pts+1<ist->pts) {
+ 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 (output_packet(ist, &pkt) < 0 || poll_filters() < 0) {
- av_log(NULL, AV_LOG_ERROR, "Error while decoding stream #%d:%d\n",
- ist->file_index, ist->st->index);
+ sub2video_heartbeat(ist, pkt.pts);
+
- // fprintf(stderr,"read #%d.%d size=%d\n", ist->file_index, ist->st->index, pkt.size);
+ if ((ret = output_packet(ist, &pkt)) < 0 ||
+ ((ret = poll_filters()) < 0 && ret != AVERROR_EOF)) {
+ char buf[128];
+ av_strerror(ret, buf, sizeof(buf));
+ av_log(NULL, AV_LOG_ERROR, "Error while decoding stream #%d:%d: %s\n",
+ ist->file_index, ist->st->index, buf);
if (exit_on_error)
exit_program(1);
av_free_packet(&pkt);