transcode_step()在转码过程中对pts、dts、duration的处理
2016-11-09 17:37
155 查看
简介
对pts、dts、duration的处理主要集中在两大函数里面1、process_input()读入数据并处理,放到滤镜里面
2、reap_filters()从滤镜读出数据,处理后写入文件
process_input()中对时间的处理
获取数据包
ret = get_input_packet(ifile, &pkt);
通过这条语句实际里面调用
return av_read_frame(f->ctx, pkt);
将读取到的帧放到pkt中。
处理获取的pkt中的时间
//如果pkt.dts或pkt.pts有值,而不是AV_NOPTS_VALUE时,做处理。 /* ifile->ts_offset在open_input_file函数中有处理,涉及到参数"itsoffset"(o->input_ts_offset)、 "copyts"(copy_ts)、"start_at_zero"(start_at_zero )、"ss"(ic->start_time) 语句如下。 f->ts_offset = o->input_ts_offset - (copy_ts ? (start_at_zero && ic->start_time != AV_NOPTS_VALUE ? ic->start_time : 0) : timestamp); 如果没有这些设置。f->ts_offset=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); //ist->ts_scale在add_input_streams函数中设置 /* ist->ts_scale = 1.0;//默认是1 MATCH_PER_STREAM_OPT(ts_scale, dbl, ist->ts_scale, ic, st); 涉及到的参数是"itsscale":解释为"set the input ts scale" 貌似是单位 */ if (pkt.pts != AV_NOPTS_VALUE) pkt.pts *= ist->ts_scale; if (pkt.dts != AV_NOPTS_VALUE) pkt.dts *= ist->ts_scale; //做时间基的转换 pkt_dts = av_rescale_q_rnd(pkt.dts, ist->st->time_base, AV_TIME_BASE_Q, (enum AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX)); 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 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); } } duration = av_rescale_q(ifile->duration, ifile->time_base, ist->st->time_base); if (pkt.pts != AV_NOPTS_VALUE) { pkt.pts += duration; ist->max_pts = FFMAX(pkt.pts, ist->max_pts); ist->min_pts = FFMIN(pkt.pts, ist->min_pts); } if (pkt.dts != AV_NOPTS_VALUE) pkt.dts += duration; pkt_dts = av_rescale_q_rnd(pkt.dts, ist->st->time_base, AV_TIME_BASE_Q, (enum AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX)); 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 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);
如果pkt.dts == AV_NOPTS_VALUE 并且pkt.dts == AV_NOPTS_VALUE,以上这些语句都没有起作用。
之后调用如下语句
process_input_packet(ist, &pkt, 0);
process_input_packet
/* pkt = NULL means EOF (needed to flush decoder buffers) */ static int process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eof) { int ret = 0, i; int got_output = 0; AVPacket avpkt; //如果是文件的第一次读取,就处理 if (!ist->saw_first_ts) { //有B帧的情况下dts和pts是不同的。 ist->dts = ist->st->avg_frame_rate.num ? - ist->dec_ctx->has_b_frames * AV_TIME_BASE / av_q2d(ist->st->avg_frame_rate) : 0; ist->pts = 0; if (pkt && pkt->pts != AV_NOPTS_VALUE && !ist->decoding_needed) { ist->dts += av_rescale_q(pkt->pts, ist->st->time 4000 _base, AV_TIME_BASE_Q); ist->pts = ist->dts; //unused but better to set it to a value thats not totally wrong } ist->saw_first_ts = 1; } //此时在ist中dts和pts都是有值的,第一次进来是初始值,之后进来的值 //初始化next_dts和next_pts if (ist->next_dts == AV_NOPTS_VALUE) ist->next_dts = ist->dts; if (ist->next_pts == AV_NOPTS_VALUE) ist->next_pts = ist->pts; /*如果pkt为NULL,表示流结束了。给avpkt赋值为此后在调用decode_video()->avcodec_decode_video2()时会将剩余的帧都返回。 在process_input()函数的出错处理里面有调用process_input_packet(ist, NULL, 0);就在此处处理 */ if (!pkt) { /* EOF handling */ av_init_packet(&avpkt); avpkt.data = NULL; avpkt.size = 0; goto handle_eof; } else { avpkt = *pkt; } if (pkt->dts != AV_NOPTS_VALUE) { ist->next_dts = ist->dts = av_rescale_q(pkt->dts, ist->st->time_base, AV_TIME_BASE_Q); if (ist->dec_ctx->codec_type != AVMEDIA_TYPE_VIDEO || !ist->decoding_needed) ist->next_pts = ist->pts = ist->dts; } // while we have more to decode or while the decoder did output something on EOF /*pkt里为视频是为一帧,为音频是可能为多帧。所以要一个循环*/ while (ist->decoding_needed && (avpkt.size > 0 || (!pkt && got_output))) { int duration; handle_eof: // ist->pts = ist->next_pts; ist->dts = ist->next_dts; //没什么用。 if (avpkt.size && avpkt.size != pkt->size && !(ist->dec->capabilities & AV_CODEC_CAP_SUBFRAMES)) { av_log(NULL, ist->showed_multi_packet_warning ? AV_LOG_VERBOSE : AV_LOG_WARNING, "Multiple frames in a packet from stream %d\n", pkt->stream_index); ist->showed_multi_packet_warning = 1; } //解码一个pkt switch (ist->dec_ctx->codec_type) { case AVMEDIA_TYPE_AUDIO: ret = decode_audio (ist, &avpkt, &got_output); break; case AVMEDIA_TYPE_VIDEO: ret = decode_video (ist, &avpkt, &got_output); if (avpkt.duration) { //返回的pkt中已经计算出了时长 duration = av_rescale_q(avpkt.duration, ist->st->time_base, AV_TIME_BASE_Q); } else if(ist->dec_ctx->framerate.num != 0 && ist->dec_ctx->framerate.den != 0) { //根据帧率计算时长 int ticks= av_stream_get_parser(ist->st) ? av_stream_get_parser(ist->st)->repeat_pict+1 : ist->dec_ctx->ticks_per_frame; duration = ((int64_t)AV_TIME_BASE * ist->dec_ctx->framerate.den * ticks) / ist->dec_ctx->framerate.num / ist->dec_ctx->ticks_per_frame; } else duration = 0; //dts和pts加时长,就是下一个帧的dts和pts,注意pkt中的都是临时的。只是在解码的时候用,过程当中的时间都保持在ist中。 if(ist->dts != AV_NOPTS_VALUE && duration) { ist->next_dts += duration; }else ist->next_dts = AV_NOPTS_VALUE; if (got_output) ist->next_pts += duration; //FIXME the duration is not correct in some cases break; case AVMEDIA_TYPE_SUBTITLE: ret = transcode_subtitles(ist, &avpkt, &got_output); break; default: return -1; } 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)); if (exit_on_error) exit_program(1); break; } avpkt.dts= avpkt.pts= AV_NOPTS_VALUE; // touch data and size only if not EOF if (pkt) { /*如果是视频帧,avpkt.size==0,ret==0,循环结束, 如果是音频帧,avpkt可能包含多帧,avpkt.size处理完可能不为0, 可能需要循环几次*/ if(ist->dec_ctx->codec_type != AVMEDIA_TYPE_AUDIO) ret = avpkt.size; avpkt.data += ret; avpkt.size -= ret; } if (!got_output) { continue; } if (got_output && !pkt) break; } //pkt 传入是NULL时,给滤镜传入EOF信息 /* after flushing, send an EOF on all the filter inputs attached to the stream */ /* except when looping we need to flush but not to send an EOF */ if (!pkt && ist->decoding_needed && !got_output && !no_eof) { int ret = send_filter_eof(ist); if (ret < 0) { av_log(NULL, AV_LOG_FATAL, "Error marking filters as finished\n"); exit_program(1); } } /*如果流不需要重新编解码的情况,这里处理dts和next_dts*/ /* handle stream copy */ if (!ist->decoding_needed) { ist->dts = ist->next_dts; switch (ist->dec_ctx->codec_type) { case AVMEDIA_TYPE_AUDIO: ist->next_dts += ((int64_t)AV_TIME_BASE * ist->dec_ctx->frame_size) / ist->dec_ctx->sample_rate; break; case AVMEDIA_TYPE_VIDEO: //优先按帧率计算 if (ist->framerate.num) { // TODO: Remove work-around for c99-to-c89 issue 7 AVRational time_base_q = AV_TIME_BASE_Q; //ist中的时间基是ffmpeg的内部时间基time_base_q,将next_dts转换为流本身的时间基 int64_t next_dts = av_rescale_q(ist->next_dts, time_base_q, av_inv_q(ist->framerate)); //next_dts为以帧率为时间基,+1就为下一帧的时间 ist->next_dts = av_rescale_q(next_dts + 1, av_inv_q(ist->framerate), time_base_q); } else if (pkt->duration) { //pkt->duration的时间基为流本身的ist->st->time_base,将它进行转换,并加到ist->next_dts, //含义是现在的dts加上此帧经过的时长,表示下一帧的dts ist->next_dts += av_rescale_q(pkt->duration, ist->st->time_base, AV_TIME_BASE_Q); } else if(ist->dec_ctx->framerate.num != 0) { /* AVCodecParserContext中repeat_pict的注释如下: * This field is used for proper frame duration computation in lavf. * It signals, how much longer the frame duration of the current frame * is compared to normal frame duration. * * frame_duration = (1 + repeat_pict) * time_base * * It is used by codecs like H.264 to display telecined material. * ------------------------------------------- * AVCodecContext中ticks_per_frame的注释如下: * For some codecs, the time base is closer to the field rate than the frame rate. * Most notably, H.264 and MPEG-2 specify time_base as half of frame duration * if no telecine is used ... * * Set to time_base ticks per frame. Default 1, e.g., H.264/MPEG-2 set it to 2. */ /*这里之后再分析吧。大概也是根据ist->dec_ctx->framerate算出一帧的时间加到next_dts上就是下一帧开始时间*/ int ticks= av_stream_get_parser(ist->st) ? av_stream_get_parser(ist->st)->repeat_pict + 1 : ist->dec_ctx->ticks_per_frame; ist->next_dts += ((int64_t)AV_TIME_BASE * ist->dec_ctx->framerate.den * ticks) / ist->dec_ctx->framerate.num / ist->dec_ctx->ticks_per_frame; } break; } ist->pts = ist->dts; ist->next_pts = ist->next_dts; } for (i = 0; pkt && i < nb_output_streams; i++) { OutputStream *ost = output_streams[i]; if (!check_output_constraints(ist, ost) || ost->encoding_needed) continue; //如果不需要重新编解码,就走到这里。ost->encoding_needed判断。 do_streamcopy(ist, ost, pkt); } return got_output; }
decode_video
针对时间的处理只有一句pkt->dts = av_rescale_q(ist->dts, AV_TIME_BASE_Q, ist->st->time_base);
将在ist中保存的dts给pkt中
static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output) { AVFrame *decoded_frame, *f; int i, ret = 0, err = 0, resample_changed; int64_t best_effort_timestamp; AVRational *frame_sample_aspect; if (!ist->decoded_frame && !(ist->decoded_frame = av_frame_alloc())) return AVERROR(ENOMEM); if (!ist->filter_frame && !(ist->filter_frame = av_frame_alloc())) return AVERROR(ENOMEM); //解码后的帧存放处 decoded_frame = ist->decoded_frame; //开始给pkt中的时间赋值。只对dts赋值。 pkt->dts = av_rescale_q(ist->dts, AV_TIME_BASE_Q, ist->st->time_base); update_benchmark(NULL); //实际的解码函数,got_output不为0表示解码出了帧,解码出的帧放到decoded_frame中。 ret = avcodec_decode_video2(ist->dec_ctx, decoded_frame, got_output, pkt); update_benchmark("decode_video %d.%d", ist->file_index, ist->st->index); // The following line may be required in some cases where there is no parser // or the parser does not has_b_frames correctly if (ist->st->codec->has_b_frames < ist->dec_ctx->has_b_frames) { if (ist->dec_ctx->codec_id == AV_CODEC_ID_H264) { ist->st->codec->has_b_frames = ist->dec_ctx->has_b_frames; } else av_log(ist->dec_ctx, AV_LOG_WARNING, "has_b_frames is larger in decoder than demuxer %d > %d.\n" "If you want to help, upload a sample " "of this file to ftp://upload.ffmpeg.org/incoming/ " "and contact the ffmpeg-devel mailing list. (ffmpeg-devel@ffmpeg.org)", ist->dec_ctx->has_b_frames, ist->st->codec->has_b_frames); } //判断输出结果,涉及到参数"xerror"。 check_decode_result(ist, got_output, ret); //如果解码返回成功,做个判断,看是否解码后的长宽、像素格式和最初分析的一样,不一样就输出。没啥用 if (*got_output && ret >= 0) { if (ist->dec_ctx->width != decoded_frame->width || ist->dec_ctx->height != decoded_frame->height || ist->dec_ctx->pix_fmt != decoded_frame->format) { av_log(NULL, AV_LOG_DEBUG, "Frame parameters mismatch context %d,%d,%d != %d,%d,%d\n", decoded_frame->width, decoded_frame->height, decoded_frame->format, ist->dec_ctx->width 13eab , ist->dec_ctx->height, ist->dec_ctx->pix_fmt); } } if (!*got_output || ret < 0) return ret; //对应参数"top",和场有关 if(ist->top_field_first>=0) decoded_frame->top_field_first = ist->top_field_first; //记录解码的帧数 ist->frames_decoded++; //和硬件相关 if (ist->hwaccel_retrieve_data && decoded_frame->format == ist->hwaccel_pix_fmt) { err = ist->hwaccel_retrieve_data(ist->dec_ctx, decoded_frame); if (err < 0) goto fail; } ist->hwaccel_retrieved_pix_fmt = decoded_frame->format; //此句很重要,是解码计算出的帧时间戳 best_effort_timestamp= av_frame_get_best_effort_timestamp(decoded_frame); if(best_effort_timestamp != AV_NOPTS_VALUE) { //ist中的时间单位是AV_TIME_BASE_Q,decoded_frame中的时间单位是ist->st->time_base int64_t ts = av_rescale_q(decoded_frame->pts = best_effort_timestamp, ist->st->time_base, AV_TIME_BASE_Q); if (ts != AV_NOPTS_VALUE) ist->next_pts = ist->pts = ts; } 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 time_base:%d/%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, ist->st->time_base.num, ist->st->time_base.den); } /*表示视频就一帧。解完这次就不解了。处理音频时就没有这一句。在process_input_packet中会对此值做处理。 如果处理完还有值就需要在解码*/ pkt->size = 0; if (ist->st->sample_aspect_ratio.num) decoded_frame->sample_aspect_ratio = ist->st->sample_aspect_ratio; //判断判断为真,需要重新设置滤镜链表。 resample_changed = ist->resample_width != decoded_frame->width || ist->resample_height != decoded_frame->height || ist->resample_pix_fmt != decoded_frame->format; if (resample_changed) { av_log(NULL, AV_LOG_INFO, "Input stream #%d:%d frame changed from size:%dx%d fmt:%s to size:%dx%d fmt:%s\n", ist->file_index, ist->st->index, ist->resample_width, ist->resample_height, av_get_pix_fmt_name(ist->resample_pix_fmt), decoded_frame->width, decoded_frame->height, av_get_pix_fmt_name(decoded_frame->format)); ist->resample_width = decoded_frame->width; ist->resample_height = decoded_frame->height; ist->resample_pix_fmt = decoded_frame->format; for (i = 0; i < nb_filtergraphs; i++) { if (ist_in_filtergraph(filtergraphs[i], ist) && ist->reinit_filters && configure_filtergraph(filtergraphs[i]) < 0) { av_log(NULL, AV_LOG_FATAL, "Error reinitializing filters!\n"); exit_program(1); } } } frame_sample_aspect= av_opt_ptr(avcodec_get_frame_class(), decoded_frame, "sample_aspect_ratio"); for (i = 0; i < ist->nb_filters; i++) { if (!frame_sample_aspect->num) *frame_sample_aspect = ist->st->sample_aspect_ratio; if (i < ist->nb_filters - 1) { f = ist->filter_frame; err = av_frame_ref(f, decoded_frame); if (err < 0) break; } else f = decoded_frame; //放到滤镜里面 ret = av_buffersrc_add_frame_flags(ist->filters[i]->filter, f, AV_BUFFERSRC_FLAG_PUSH); if (ret == AVERROR_EOF) { ret = 0; /* ignore */ } else if (ret < 0) { av_log(NULL, AV_LOG_FATAL, "Failed to inject frame into filter network: %s\n", av_err2str(ret)); exit_program(1); } } fail: av_frame_unref(ist->filter_frame); av_frame_unref(decoded_frame); return err < 0 ? err : ret; }
reap_filters
/** * Get and encode new output from any of the filtergraphs, without causing * activity. * * @return 0 for success, <0 for severe errors */ static int reap_filters(int flush) { AVFrame *filtered_frame = NULL; int i; /* 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]; AVFilterContext *filter; AVCodecContext *enc = ost->enc_ctx; int ret = 0; if (!ost->filter) continue; filter = ost->filter->filter; if (!ost->filtered_frame && !(ost->filtered_frame = av_frame_alloc())) { return AVERROR(ENOMEM); } //从滤镜处理后的帧存放在这里 filtered_frame = ost->filtered_frame; while (1) { double float_pts = AV_NOPTS_VALUE; // this is identical to filtered_frame.pts but with higher precision //从滤镜获取帧 ret = av_buffersink_get_frame_flags(filter, filtered_frame, AV_BUFFERSINK_FLAG_NO_REQUEST); if (ret < 0) { if (ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) { av_log(NULL, AV_LOG_WARNING, "Error in av_buffersink_get_frame_flags(): %s\n", av_err2str(ret)); } else if (flush && ret == AVERROR_EOF) { //没有数据了。已经到了滤镜的结束。 if (filter->inputs[0]->type == AVMEDIA_TYPE_VIDEO) do_video_out(of->ctx, ost, NULL, AV_NOPTS_VALUE); } break; } //如果设置了此值,获取到的帧丢弃 if (ost->finished) { av_frame_unref(filtered_frame); continue; } //下面这段不知道啥意思 if (filtered_frame->pts != AV_NOPTS_VALUE) { int64_t start_time = (of->start_time == AV_NOPTS_VALUE) ? 0 : of->start_time; AVRational tb = enc->time_base; int extra_bits = av_clip(29 - av_log2(tb.den), 0, 16); tb.den <<= extra_bits; float_pts = av_rescale_q(filtered_frame->pts, filter->inputs[0]->time_base, tb) - av_rescale_q(start_time, AV_TIME_BASE_Q, tb); float_pts /= 1 << extra_bits; // avoid exact midoints to reduce the chance of rounding differences, this can be removed in case the fps code is changed to work with integers float_pts += FFSIGN(float_pts) * 1.0 / (1<<17); filtered_frame->pts = av_rescale_q(filtered_frame->pts, filter->inputs[0]->time_base, enc->time_base) - av_rescale_q(start_time, AV_TIME_BASE_Q, enc->time_base); } //if (ost->source_index >= 0) // *filtered_frame= *input_streams[ost->source_index]->decoded_frame; //for me_threshold switch (filter->inputs[0]->type) { case AVMEDIA_TYPE_VIDEO: //设置宽高比 if (!ost->frame_aspect_ratio.num) enc->sample_aspect_ratio = filtered_frame->sample_aspect_ratio; if (debug_ts) { av_log(NULL, AV_LOG_INFO, "filter -> pts:%s pts_time:%s exact:%f time_base:%d/%d\n", av_ts2str(filtered_frame->pts), av_ts2timestr(filtered_frame->pts, &enc->time_base), float_pts, enc->time_base.num, enc->time_base.den); } //编码并输出到文件 do_video_out(of->ctx, ost, filtered_frame, float_pts); break; case AVMEDIA_TYPE_AUDIO: if (!(enc->codec->capabilities & AV_CODEC_CAP_PARAM_CHANGE) && enc->channels != av_frame_get_channels(filtered_frame)) { av_log(NULL, AV_LOG_ERROR, "Audio filter graph output is not normalized and encoder does not support parameter changes\n"); break; } do_audio_out(of->ctx, ost, filtered_frame); break; default: // TODO support subtitle filters av_assert0(0); } av_frame_unref(filtered_frame); } } return 0; }
do_video_out
static void do_video_out(AVFormatContext *s, OutputStream *ost, AVFrame *next_picture, double sync_ipts) { int ret, format_video_sync; AVPacket pkt; AVCodecContext *enc = ost->enc_ctx; AVCodecContext *mux_enc = ost->st->codec; int nb_frames, nb0_frames, i; double delta, delta0; double duration = 0; int frame_size = 0; InputStream *ist = NULL; AVFilterContext *filter = ost->filter->filter; if (ost->source_index >= 0) ist = input_streams[ost->source_index]; /*求duration的值*/ if (filter->inputs[0]->frame_rate.num > 0 && filter->inputs[0]->frame_rate.den > 0) duration = 1/(av_q2d(filter->inputs[0]->frame_rate) * av_q2d(enc->time_base)); if(ist && ist->st->start_time != AV_NOPTS_VALUE && ist->st->first_dts != AV_NOPTS_VALUE && ost->frame_rate.num) duration = FFMIN(duration, 1/(av_q2d(ost->frame_rate) * av_q2d(enc->time_base))); if (!ost->filters_script && !ost->filters && next_picture && ist && lrintf(av_frame_get_pkt_duration(next_picture) * av_q2d(ist->st->time_base) / av_q2d(enc->time_base)) > 0) { duration = lrintf(av_frame_get_pkt_duration(next_picture) * av_q2d(ist->st->time_base) / av_q2d(enc->time_base)); } if (!next_picture) { //reap_filters函数中在从滤镜中取数据结束后调用do_video_out(of->ctx, ost, NULL, AV_NOPTS_VALUE);会走到这里 //end, flushing nb0_frames = nb_frames = mid_pred(ost->last_nb0_frames[0], ost->last_nb0_frames[1], ost->last_nb0_frames[2]); } else { delta0 = sync_ipts - ost->sync_opts; // delta0 is the "drift" between the input frame (next_picture) and where it would fall in the output. delta = delta0 + duration; /* by default, we output a single frame */ nb0_frames = 0; // tracks the number of times the PREVIOUS frame should be duplicated, mostly for variable framerate (VFR) nb_frames = 1; format_video_sync = video_sync_method; if (format_video_sync == VSYNC_AUTO) { if(!strcmp(s->oformat->name, "avi")) { format_video_sync = VSYNC_VFR; } else format_video_sync = (s->oformat->flags & AVFMT_VARIABLE_FPS) ? ((s->oformat->flags & AVFMT_NOTIMESTAMPS) ? VSYNC_PASSTHROUGH : VSYNC_VFR) : VSYNC_CFR; if ( ist && format_video_sync == VSYNC_CFR && input_files[ist->file_index]->ctx->nb_streams == 1 && input_files[ist->file_index]->input_ts_offset == 0) { format_video_sync = VSYNC_VSCFR; } if (format_video_sync == VSYNC_CFR && copy_ts) { format_video_sync = VSYNC_VSCFR; } } ost->is_cfr = (format_video_sync == VSYNC_CFR || format_video_sync == VSYNC_VSCFR); if (delta0 < 0 && delta > 0 && format_video_sync != VSYNC_PASSTHROUGH && format_video_sync != VSYNC_DROP) { if (delta0 < -0.6) { av_log(NULL, AV_LOG_WARNING, "Past duration %f too large\n", -delta0); } else av_log(NULL, AV_LOG_DEBUG, "Clipping frame in rate conversion by %f\n", -delta0); sync_ipts = ost->sync_opts; duration += delta0; delta0 = 0; } switch (format_video_sync) { case VSYNC_VSCFR: if (ost->frame_number == 0 && delta0 >= 0.5) { av_log(NULL, AV_LOG_DEBUG, "Not duplicating %d initial frames\n", (int)lrintf(delta0)); delta = duration; delta0 = 0; ost->sync_opts = lrint(sync_ipts); } case VSYNC_CFR: // FIXME set to 0.5 after we fix some dts/pts bugs like in avidec.c if (frame_drop_threshold && delta < frame_drop_threshold && ost->frame_number) { nb_frames = 0; } else if (delta < -1.1) nb_frames = 0; else if (delta > 1.1) { nb_frames = lrintf(delta); if (delta0 > 1.1) nb0_frames = lrintf(delta0 - 0.6); } break; case VSYNC_VFR: if (delta <= -0.6) nb_frames = 0; else if (delta > 0.6) ost->sync_opts = lrint(sync_ipts); break; case VSYNC_DROP: case VSYNC_PASSTHROUGH: ost->sync_opts = lrint(sync_ipts); break; default: av_assert0(0); } } //之前的都是在算包含几个帧 nb_frames = FFMIN(nb_frames, ost->max_frames - ost->frame_number); nb0_frames = FFMIN(nb0_frames, nb_frames); //缓存有三个nb0_frames在last_nb0_frames中,每次[0]是最新的。写之前都向后移。 memmove(ost->last_nb0_frames + 1, ost->last_nb0_frames, sizeof(ost->last_nb0_frames[0]) * (FF_ARRAY_ELEMS(ost->last_nb0_frames) - 1)); ost->last_nb0_frames[0] = nb0_frames; if (nb0_frames == 0 && ost->last_dropped) { nb_frames_drop++; av_log(NULL, AV_LOG_VERBOSE, "*** dropping frame %d from stream %d at ts %"PRId64"\n", ost->frame_number, ost->st->index, ost->last_frame->pts); } if (nb_frames > (nb0_frames && ost->last_dropped) + (nb_frames > nb0_frames)) { if (nb_frames > dts_error_threshold * 30) { av_log(NULL, AV_LOG_ERROR, "%d frame duplication too large, skipping\n", nb_frames - 1); nb_frames_drop++; return; } nb_frames_dup += nb_frames - (nb0_frames && ost->last_dropped) - (nb_frames > nb0_frames); av_log(NULL, AV_LOG_VERBOSE, "*** %d dup!\n", nb_frames - 1); } ost->last_dropped = nb_frames == nb0_frames && next_picture; /* duplicates frame if needed */ for (i = 0; i < nb_frames; i++) { AVFrame *in_picture; av_init_packet(&pkt); pkt.data = NULL; pkt.size = 0; if (i < nb0_frames && ost->last_frame) { in_picture = ost->last_frame; } else in_picture = next_picture; if (!in_picture) return; in_picture->pts = ost->sync_opts; #if 1 if (!check_recording_time(ost)) #else if (ost->frame_number >= ost->max_frames) #endif return; #if FF_API_LAVF_FMT_RAWPICTURE if (s->oformat->flags & AVFMT_RAWPICTURE && enc->codec->id == AV_CODEC_ID_RAWVIDEO) { /* raw pictures are written as AVPicture structure to avoid any copies. We support temporarily the older method. */ if (in_picture->interlaced_frame) mux_enc->field_order = in_picture->top_field_first ? AV_FIELD_TB:AV_FIELD_BT; else mux_enc->field_order = AV_FIELD_PROGRESSIVE; 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); } else #endif { int got_packet, forced_keyframe = 0; double pts_time; 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; if (in_picture->interlaced_frame) { //对场帧的处理 if (enc->codec->id == AV_CODEC_ID_MJPEG) mux_enc->field_order = in_picture->top_field_first ? AV_FIELD_TT:AV_FIELD_BB; else mux_enc->field_order = in_picture->top_field_first ? AV_FIELD_TB:AV_FIELD_BT; } else mux_enc->field_order = AV_FIELD_PROGRESSIVE; in_picture->quality = enc->global_quality; in_picture->pict_type = 0; pts_time = in_picture->pts != AV_NOPTS_VALUE ? in_picture->pts * av_q2d(enc->time_base) : NAN; //对应参数"force_key_frames",指定时间戳强制I帧 if (ost->forced_kf_index < ost->forced_kf_count && in_picture->pts >= ost->forced_kf_pts[ost->forced_kf_index]) { ost->forced_kf_index++; forced_keyframe = 1; } else if (ost->forced_keyframes_pexpr) { double res; ost->forced_keyframes_expr_const_values[FKF_T] = pts_time; res = av_expr_eval(ost->forced_keyframes_pexpr, ost->forced_keyframes_expr_const_values, NULL); ff_dlog(NULL, "force_key_frame: n:%f n_forced:%f prev_forced_n:%f t:%f prev_forced_t:%f -> res:%f\n", ost->forced_keyframes_expr_const_values[FKF_N], ost->forced_keyframes_expr_const_values[FKF_N_FORCED], ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_N], ost->forced_keyframes_expr_const_values[FKF_T], ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_T], res); if (res) { forced_keyframe = 1; ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_N] = ost->forced_keyframes_expr_const_values[FKF_N]; ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_T] = ost->forced_keyframes_expr_const_values[FKF_T]; ost->forced_keyframes_expr_const_values[FKF_N_FORCED] += 1; } ost->forced_keyframes_expr_const_values[FKF_N] += 1; } else if ( ost->forced_keyframes && !strncmp(ost->forced_keyframes, "source", 6) && in_picture->key_frame==1) { forced_keyframe = 1; } if (forced_keyframe) { in_picture->pict_type = AV_PICTURE_TYPE_I; av_log(NULL, AV_LOG_DEBUG, "Forced keyframe at time %f\n", pts_time); } update_benchmark(NULL); if (debug_ts) { av_log(NULL, AV_LOG_INFO, "encoder <- type:video " "frame_pts:%s frame_pts_time:%s time_base:%d/%d\n", av_ts2str(in_picture->pts), av_ts2timestr(in_picture->pts, &enc->time_base), enc->time_base.num, enc->time_base.den); } ost->frames_encoded++; ret = avcodec_encode_video2(enc, &pkt, in_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); } //got_packet为1表示有数据编出。不是每次调用编码器都有帧输出 if (got_packet) { 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, &enc->time_base), av_ts2str(pkt.dts), av_ts2timestr(pkt.dts, &enc->time_base)); } if (pkt.pts == AV_NOPTS_VALUE && !(enc->codec->capabilities & AV_CODEC_CAP_DELAY)) pkt.pts = ost->sync_opts; //转换时间基 av_packet_rescale_ts(&pkt, 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)); } frame_size = pkt.size; write_frame(s, &pkt, ost); /* 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 (vstats_filename && frame_size) do_video_stats(ost, frame_size); } if (!ost->last_frame) ost->last_frame = av_frame_alloc(); av_frame_unref(ost->last_frame); if (next_picture && ost->last_frame) av_frame_ref(ost->last_frame, next_picture); else av_frame_free(&ost->last_frame); }
write_frame
void Cffmpeg::write_frame(AVFormatContext *s, AVPacket *pkt, OutputStream *ost) { AVBitStreamFilterContext *bsfc = ost->bitstream_filters; AVCodecContext *avctx = ost->encoding_needed ? ost->enc_ctx : ost->st->codec; int ret; if (!ost->st->codec->extradata_size && ost->enc_ctx->extradata_size) { ost->st->codec->extradata = (uint8_t *)av_mallocz(ost->enc_ctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); if (ost->st->codec->extradata) { memcpy(ost->st->codec->extradata, ost->enc_ctx->extradata, ost->enc_ctx->extradata_size); ost->st->codec->extradata_size = ost->enc_ctx->extradata_size; } } 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; /* * 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)) { if (ost->frame_number >= ost->max_frames) { av_packet_unref(pkt); return; } ost->frame_number++; } if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) { int i; uint8_t *sd = av_packet_get_side_data(pkt, AV_PKT_DATA_QUALITY_STATS, NULL); ost->quality = sd ? AV_RL32(sd) : -1; ost->pict_type = sd ? sd[4] : AV_PICTURE_TYPE_NONE; for (i = 0; i<FF_ARRAY_ELEMS(ost->error); i++) { if (sd && i < sd[5]) ost->error[i] = AV_RL64(sd + 8 + 8*i); else ost->error[i] = -1; } if (ost->frame_rate.num && ost->is_cfr) { if (pkt->duration > 0) av_log(NULL, AV_LOG_WARNING, "Overriding packet duration by frame rate, this should not happen\n"); pkt->duration = av_rescale_q(1, av_inv_q(ost->frame_rate), ost->st->time_base); } } //对应参数"bsf" if (bsfc) av_packet_split_side_data(pkt); //对应参数"bsf" if ((ret = av_apply_bitstream_filters(avctx, pkt, bsfc)) < 0) { print_error("", ret); if (exit_on_error) exit_program(1); } if (pkt->size == 0 && pkt->side_data_elems == 0) return; if (!ost->st->codecpar->extradata && avctx->extradata) { ost->st->codecpar->extradata = (uint8_t *)av_malloc(avctx->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); if (!ost->st->codecpar->extradata) { av_log(NULL, AV_LOG_ERROR, "Could not allocate extradata buffer to copy parser data.\n"); exit_program(1); } ost->st->codecpar->extradata_size = avctx->extradata_size; memcpy(ost->st->codecpar->extradata, avctx->extradata, avctx->extradata_size); } if (!(s->oformat->flags & AVFMT_NOTIMESTAMPS)) { if (pkt->dts != AV_NOPTS_VALUE && pkt->pts != AV_NOPTS_VALUE && pkt->dts > pkt->pts) { av_log(s, AV_LOG_WARNING, "Invalid DTS: %"PRId64" PTS: %"PRId64" in output stream %d:%d, replacing by guess\n", pkt->dts, pkt->pts, ost->file_index, ost->st->index); pkt->pts = pkt->dts = pkt->pts + pkt->dts + ost->last_mux_dts + 1 - FFMIN3(pkt->pts, pkt->dts, ost->last_mux_dts + 1) - FFMAX3(pkt->pts, pkt->dts, ost->last_mux_dts + 1); } if( (avctx->codec_type == AVMEDIA_TYPE_AUDIO || avctx->codec_type == AVMEDIA_TYPE_VIDEO) && pkt->dts != AV_NOPTS_VALUE && !(avctx->codec_id == AV_CODEC_ID_VP9 && ost->stream_copy) && ost->last_mux_dts != AV_NOPTS_VALUE) { int64_t max = ost->last_mux_dts + !(s->oformat->flags & AVFMT_TS_NONSTRICT); if (pkt->dts < max) { int loglevel = max - pkt->dts > 2 || avctx->codec_type == AVMEDIA_TYPE_VIDEO ? AV_LOG_WARNING : AV_LOG_DEBUG; av_log(s, loglevel, "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"); exit_program(1); } av_log(s, loglevel, "changing to %"PRId64". This may result " "in incorrect timestamps in the output file.\n", max); if(pkt->pts >= pkt->dts) pkt->pts = FFMAX(pkt->pts, max); pkt->dts = max; } } } ost->last_mux_dts = pkt->dts; ost->data_size += pkt->size; ost->packets_written++; pkt->stream_index = ost->index; if (debug_ts) { av_log(NULL, AV_LOG_INFO, "muxer <- type:%s " "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s size:%d\n", av_get_media_type_string(ost->enc_ctx->codec_type), av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &ost->st->time_base), av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &ost->st->time_base), pkt->size ); } ret = av_interleaved_write_frame(s, pkt); if (ret < 0) { print_error("av_interleaved_write_frame()", ret); main_return_code = 1; close_all_output_streams(ost, (OSTFinished)(MUXER_FINISHED | ENCODER_FINISHED), ENCODER_FINISHED); } av_packet_unref(pkt); }
相关文章推荐
- TS流的解码过程-ES-PES-DTS-PTS-PCR
- TS流的解码过程-ES-PES-DTS-PTS-PCR
- 将es打包成pes时,处理PTS和DTS的方法
- TS流的解码过程-ES-PES-DTS-PTS-PCR
- pes时处理PTS和DTS的方法
- TS流的解码过程-ES-PES-DTS-PTS-PCR
- TS流的解码过程-ES-PES-DTS-PTS-PCR
- 【转】 TS流的解码过程-ES-PES-DTS-PTS-PCR
- TS流的解码过程-ES-PES-DTS-PTS-PCR
- H264 TS流的解码过程-ES-PES-DTS-PTS-PCR
- TS流的解码过程-ES-PES-DTS-PTS-PCR 2
- TS流的解码过程-ES-PES-DTS-PTS-PCR
- TS流的解码过程-ES-PES-DTS-PTS-PCR
- 将es打包成pes时,处理PTS和DTS的方法
- 将es打包成pes时,处理PTS和DTS的方法
- 在处理URL时对中文的转码过程
- TS流的解码过程-ES-PES-DTS-PTS-PCR
- TS流的解码过程-ES-PES-DTS-PTS-PCR
- TS流的解码过程-ES-PES-DTS-PTS-PCR
- TS流的解码过程-ES-PES-DTS-PTS-PCR