博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ffmpeg do_video_out
阅读量:7004 次
发布时间:2019-06-27

本文共 11946 字,大约阅读时间需要 39 分钟。

hot3.png

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];    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) {        //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);    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;        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);        }        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);}

 

转载于:https://my.oschina.net/u/2326611/blog/680637

你可能感兴趣的文章