X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=ffmpeg.c;h=662e84af66fa73221ae634a4c72e1bdc57f2a0b5;hb=b2bc48ae22969256334988238f284c78e73c89e4;hp=cb019b215fdd897b99921e72f05a0bb2a50ef772;hpb=11a1033c9fcae380f4da06b2b0253ab0eb82b026;p=ffmpeg diff --git a/ffmpeg.c b/ffmpeg.c index cb019b215fd..662e84af66f 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -107,7 +107,6 @@ static void do_video_stats(AVFormatContext *os, OutputStream *ost, int frame_siz static int64_t getutime(void); static int run_as_daemon = 0; -static volatile int received_nb_signals = 0; static int64_t video_size = 0; static int64_t audio_size = 0; static int64_t subtitle_size = 0; @@ -262,8 +261,10 @@ void term_exit(void) } static volatile int received_sigterm = 0; +static volatile int received_nb_signals = 0; -static void sigterm_handler(int sig) +static void +sigterm_handler(int sig) { received_sigterm = sig; received_nb_signals++; @@ -411,8 +412,8 @@ void av_noreturn exit_program(int ret) output_streams[i]->bitstream_filters = NULL; av_freep(&output_streams[i]->forced_keyframes); - av_freep(&output_streams[i]->filtered_frame); av_freep(&output_streams[i]->avfilter); + av_freep(&output_streams[i]->filtered_frame); av_freep(&output_streams[i]); } for (i = 0; i < nb_input_files; i++) { @@ -533,6 +534,16 @@ static void write_frame(AVFormatContext *s, AVPacket *pkt, OutputStream *ost) &new_pkt.data, &new_pkt.size, pkt->data, pkt->size, pkt->flags & AV_PKT_FLAG_KEY); + if(a == 0 && new_pkt.data != pkt->data && new_pkt.destruct) { + uint8_t *t = av_malloc(new_pkt.size + FF_INPUT_BUFFER_PADDING_SIZE); //the new should be a subset of the old so cannot overflow + if(t) { + memcpy(t, new_pkt.data, new_pkt.size); + memset(t + new_pkt.size, 0, FF_INPUT_BUFFER_PADDING_SIZE); + new_pkt.data = t; + a = 1; + } else + a = AVERROR(ENOMEM); + } if (a > 0) { av_free_packet(pkt); new_pkt.destruct = av_destruct_packet; @@ -564,7 +575,7 @@ static int check_recording_time(OutputStream *ost) 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; + ost->finished = 1; return 0; } return 1; @@ -702,6 +713,8 @@ static void do_subtitle_out(AVFormatContext *s, 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; + if (i == 1) + sub->num_rects = 0; subtitle_out_size = avcodec_encode_subtitle(enc, subtitle_out, subtitle_out_max_size, sub); if (subtitle_out_size < 0) { @@ -1312,7 +1325,7 @@ static void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *p if (of->recording_time != INT64_MAX && ist->pts >= of->recording_time + of->start_time) { - ost->is_past_recording_time = 1; + ost->finished = 1; return; } @@ -1410,20 +1423,18 @@ static int decode_audio(InputStream *ist, AVPacket *pkt, int *got_output) update_benchmark(NULL); ret = avcodec_decode_audio4(avctx, decoded_frame, got_output, pkt); update_benchmark("decode_audio %d.%d", ist->file_index, ist->st->index); - if (ret < 0) { - return ret; - } - if (avctx->sample_rate <= 0) { + + 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) { - /* no audio frame */ - if (!pkt->size) + if (!*got_output || ret < 0) { + if (!pkt->size) { for (i = 0; i < ist->nb_filters; i++) av_buffersrc_add_ref(ist->filters[i]->filter, NULL, AV_BUFFERSRC_FLAG_NO_COPY); + } return ret; } @@ -1538,18 +1549,16 @@ static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output) ret = avcodec_decode_video2(ist->st->codec, decoded_frame, got_output, pkt); update_benchmark("decode_video %d.%d", ist->file_index, ist->st->index); - if (ret < 0) - return ret; - - quality = same_quant ? decoded_frame->quality : 0; - if (!*got_output) { - /* no picture yet */ - if (!pkt->size) + if (!*got_output || ret < 0) { + if (!pkt->size) { for (i = 0; i < ist->nb_filters; i++) av_buffersrc_add_ref(ist->filters[i]->filter, NULL, AV_BUFFERSRC_FLAG_NO_COPY); + } return ret; } + quality = same_quant ? decoded_frame->quality : 0; + if(ist->top_field_first>=0) decoded_frame->top_field_first = ist->top_field_first; @@ -1912,7 +1921,7 @@ static int transcode_init(void) { int ret = 0, i, j, k; AVFormatContext *oc; - AVCodecContext *codec, *icodec = NULL; + AVCodecContext *codec; OutputStream *ost; InputStream *ist; char error[1024]; @@ -1943,6 +1952,7 @@ static int transcode_init(void) /* for each output stream, we compute the right encoding parameters */ for (i = 0; i < nb_output_streams; i++) { + AVCodecContext *icodec = NULL; ost = output_streams[i]; oc = output_files[ost->file_index]->ctx; ist = get_input_stream(ost); @@ -2368,13 +2378,13 @@ static int need_output(void) OutputFile *of = output_files[ost->file_index]; AVFormatContext *os = output_files[ost->file_index]->ctx; - if (ost->is_past_recording_time || + 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++) - output_streams[of->ost_index + j]->is_past_recording_time = 1; + output_streams[of->ost_index + j]->finished = 1; continue; } @@ -2387,7 +2397,7 @@ static int need_output(void) static int input_acceptable(InputStream *ist) { 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; } @@ -2425,7 +2435,7 @@ static int select_input_file(void) for (i = 0; i < nb_output_streams; i++) nb_active_out -= output_streams[i]->unavailable = - output_streams[i]->is_past_recording_time; + output_streams[i]->finished; while (nb_active_out) { opts_min = INT64_MAX; ost_index = -1; @@ -2676,16 +2686,202 @@ static int get_input_packet(InputFile *f, AVPacket *pkt) return av_read_frame(f->ctx, pkt); } +static int got_eagain(void) +{ + int i; + for (i = 0; i < nb_input_files; i++) + if (input_files[i]->eagain) + return 1; + return 0; +} + +static void reset_eagain(void) +{ + int i; + for (i = 0; i < nb_input_files; i++) + input_files[i]->eagain = 0; +} + +/** + * @return + * - 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(void) +{ + InputFile *ifile; + AVFormatContext *is; + InputStream *ist; + AVPacket pkt; + int ret, i, j; + int file_index; + + /* select the stream that we must read now */ + file_index = select_input_file(); + /* if none, if is finished */ + if (file_index == -2) { + poll_filters() ; + return AVERROR(EAGAIN); + } + if (file_index < 0) { + if (got_eagain()) { + reset_eagain(); + av_usleep(10000); + return AVERROR(EAGAIN); + } + av_log(NULL, AV_LOG_VERBOSE, "No more inputs to read from, finishing.\n"); + return AVERROR_EOF; + } + ifile = input_files[file_index]; + + 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) + exit_program(1); + } + ifile->eof_reached = 1; + + 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) + return AVERROR_EOF; + else + 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]; + 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<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<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<st->pts_wrap_bits; + ist->wrap_correction_done = 0; + } + } + + 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 (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", + 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 (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+1pts){ + 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 && ist->st->codec->codec_type != AVMEDIA_TYPE_SUBTITLE) || + pkt_dts+1pts){ + 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+1pts) { + 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; + } + } + } + } + + sub2video_heartbeat(ist, pkt.pts); + + 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); + return AVERROR(EAGAIN); + } + +discard_packet: + av_free_packet(&pkt); + + return 0; +} + /* * The following code is the main loop of the file converter */ static int transcode(void) { int ret, i; - AVFormatContext *is, *os; + AVFormatContext *os; OutputStream *ost; InputStream *ist; - int no_packet_count = 0; int64_t timer_start; ret = transcode_init(); @@ -2703,9 +2899,7 @@ static int transcode(void) goto fail; #endif - for (; received_sigterm == 0;) { - int file_index, ist_index; - AVPacket pkt; + while (!received_sigterm) { int64_t cur_time= av_gettime(); /* if 'q' pressed, exits */ @@ -2719,162 +2913,16 @@ static int transcode(void) break; } - /* select the stream that we must read now */ - file_index = select_input_file(); - /* if none, if is finished */ - 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; - av_usleep(10000); - continue; - } - av_log(NULL, AV_LOG_VERBOSE, "No more inputs to read from, finishing.\n"); - break; - } - - is = input_files[file_index]->ctx; - ret = get_input_packet(input_files[file_index], &pkt); - - if (ret == AVERROR(EAGAIN)) { - input_files[file_index]->unavailable = 1; - no_packet_count++; - continue; - } + ret = process_input(); if (ret < 0) { - if (ret != AVERROR_EOF) { - print_error(is->filename, ret); - if (exit_on_error) - exit_program(1); - } - input_files[file_index]->eof_reached = 1; - - for (i = 0; i < input_files[file_index]->nb_streams; i++) { - ist = input_streams[input_files[file_index]->ist_index + i]; - if (ist->decoding_needed) - output_packet(ist, NULL); - poll_filters(); - } - - if (opt_shortest) - break; - else + if (ret == AVERROR(EAGAIN)) continue; + if (ret == AVERROR_EOF) + break; + av_log(NULL, AV_LOG_ERROR, "Error while filtering.\n"); + break; } - no_packet_count = 0; - for (i = 0; i < nb_input_files; i++) - input_files[i]->unavailable = 0; - - 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 >= input_files[file_index]->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]; - 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<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<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<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); - 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); - - if (pkt.pts != AV_NOPTS_VALUE) - pkt.pts *= ist->ts_scale; - if (pkt.dts != AV_NOPTS_VALUE) - pkt.dts *= ist->ts_scale; - - 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), - 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 (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+1pts){ - input_files[ist->file_index]->ts_offset -= delta; - av_log(NULL, AV_LOG_DEBUG, - "timestamp discontinuity %"PRId64", new offset= %"PRId64"\n", - delta, input_files[ist->file_index]->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+1pts){ - 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+1pts) { - 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; - } - } - } - } - - 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); - continue; - } - - discard_packet: - av_free_packet(&pkt); - /* dump report by using the output first video and audio streams */ print_report(0, timer_start, cur_time); } @@ -3041,10 +3089,10 @@ int main(int argc, char **argv) exit_program(1); } - if (nb_input_files == 0) { - av_log(NULL, AV_LOG_FATAL, "At least one input file must be specified\n"); - exit_program(1); - } +// if (nb_input_files == 0) { +// av_log(NULL, AV_LOG_FATAL, "At least one input file must be specified\n"); +// exit_program(1); +// } current_time = ti = getutime(); if (transcode() < 0)