transcode_step()介绍

来源:互联网 发布:金十数据官网财经报告 编辑:程序博客网 时间:2024/06/05 05:17

transcode_step()

transcode_step()

static int transcode_step(void){    OutputStream *ost;    InputStream  *ist;    int ret;    //选出一路输出流中dts(解码时间戳)最小的。    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(0);}

choose_output()

选出一路输出流中dts(解码时间戳)最小的。
其中av_rescale_q的解释参考ffmpeg中的时间
简单的说就是做一个不同时间基之间的转换

/** * 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 = ost->st->cur_dts == AV_NOPTS_VALUE ? INT64_MIN :                       av_rescale_q(ost->st->cur_dts, ost->st->time_base,                                    AV_TIME_BASE_Q);        if (ost->st->cur_dts == AV_NOPTS_VALUE)            av_log(NULL, AV_LOG_DEBUG, "cur_dts is invalid (this is harmless if it occurs once at the start per stream)\n");        /*find the stream that opts is Minimum */        if (!ost->finished && opts < opts_min) {            opts_min = opts;            ost_min  = ost->unavailable ? NULL : ost;        }    }    return ost_min;}

transcode_from_filter

对指定的滤镜做一步转码。
这个函数需要再分析完滤镜整体结构后才能解释。先放到这里。

/** * 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(0);    if (ret == AVERROR_EOF) {        ret = reap_filters(1);        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;}

process_input()

/* * 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 */int Cffmpeg::process_input(int file_index){    InputFile *ifile = input_files[file_index];    AVFormatContext *is;    InputStream *ist;    AVPacket pkt;    int ret, i, j;    int64_t duration;    int64_t pkt_dts;    is  = ifile->ctx;    //也就是调用av_read_frame(),其中对帧率仿真做了处理    ret = get_input_packet(ifile, &pkt);    if (ret == AVERROR(EAGAIN)) {        ifile->eagain = 1;        return ret;    }    /*ifile->loop针对参数"stream_loop",在open_input_file()中有赋值    *表示"set number of times input stream shall be looped"    *get_input_packet函数出错,就seek到文件的开始,ifile->loop表示循环次数,    *在seek_to_start中递减    */    if (ret < 0 && ifile->loop) {        if ((ret = seek_to_start(ifile, is)) < 0)            return ret;        ret = get_input_packet(ifile, &pkt);    }    if (ret < 0) {        //出错        if (ret != AVERROR_EOF) {            print_error(is->filename, ret);            if (exit_on_error)                exit_program(1);        }        //文件结束        for (i = 0; i < ifile->nb_streams; i++) {            ist = input_streams[ifile->ist_index + i];            if (ist->decoding_needed) {                /*                调用流程如下:                process_input_packet()->decode_video()->avcodec_decode_video2();                在avcodec_decode_video2()函数的注释中有这样一段                * @note Codecs which have the AV_CODEC_CAP_DELAY capability set have a delay                * between input and output, these need to be fed with avpkt->data=NULL,                * avpkt->size=0 at the end to return the remaining frames.                *                 * process_input_packet中将一个avpkt->data=NULL,avpkt->size=0的avpkt传给了avcodec_decode_video2                * 以返回剩余的帧。结束这路流的输入                */                ret = process_input_packet(ist, NULL, 0);                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();    //对应参数"dump","dump each input packet"    if (do_pkt_dump) {        av_pkt_dump_log2(NULL, AV_LOG_INFO, &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;    }    //找到读取的帧对应的流信息结构体。ifile->ist_index表示这个文件的流在input_streams中的开始小标    ist = input_streams[ifile->ist_index + pkt.stream_index];    ist->data_size += pkt.size;    ist->nb_packets++;    //配置中让丢弃的流就丢弃    if (ist->discard)        goto discard_packet;    //读取的帧损坏退出    if (exit_on_error && (pkt.flags & AV_PKT_FLAG_CORRUPT)) {        av_log(NULL, AV_LOG_FATAL, "%s: corrupt input packet in stream %d\n", is->filename, pkt.stream_index);        exit_program(1);    }    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",               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));    }    //在设置了is->start_time的情况下才执行这里。对应参数"ss"    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) {        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;            if (ist->autorotate && src_sd->type == AV_PKT_DATA_DISPLAYMATRIX)                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;    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);    if (debug_ts) {        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",               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);    process_input_packet(ist, &pkt, 0);discard_packet:    av_packet_unref(&pkt);    return 0;}

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;}

av_frame_get_best_effort_timestamp(const AVFrame *frame)

声明在libavutil\frame.h中
定义在libavutil\frame.c中

MAKE_ACCESSORS(AVFrame, frame, int64_t, best_effort_timestamp)
//libavutil\internal.h#define MAKE_ACCESSORS(str, name, type, field) \    type av_##name##_get_##field(const str *s) { return s->field; } \    void av_##name##_set_##field(str *s, type v) { s->field = v; }

功能可见,就是获取和设置一个结构体中的一个成员的值。

0 0
原创粉丝点击