美文网首页
ffmpeg # 怎么控制只是转封装而不需要转码

ffmpeg # 怎么控制只是转封装而不需要转码

作者: FlyingPenguin | 来源:发表于2018-11-17 15:00 被阅读48次

    有时候可能只需要转下封装,比如从flv到mkv,这时候就不涉及转码,也就是不涉及解码和编码的过程。
    ffmpeg是如何做的呢?
    答案是:
    通过以下几个参数来控制,分别是:
    InputStream中的decoding_needed
    OutputStream的encoding_needed和stream_copy

    decoding_needed

    用于控制是否解码。

    typedef struct InputStream {
        int file_index;
        AVStream *st;
        int discard;             /* true if stream data should be discarded */
        int user_set_discard;
        int decoding_needed;     /* non zero if the packets must be decoded in 'raw_fifo', see DECODING_FOR_* */
    #define DECODING_FOR_OST    1
    #define DECODING_FOR_FILTER 2
    ...
    }
    

    encoding_needed

    用于控制是否编码。

    typedef struct OutputStream {
        int file_index;          /* file index */
        int index;               /* stream index in the output file */
        int source_index;        /* InputStream index */
        AVStream *st;            /* stream in the output file */
        int encoding_needed;     /* true if encoding needed for this stream */
    ...
        int stream_copy;
    ...
    }
    
    /* 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 repeating = 0;
        int eof_reached = 0;
    
        AVPacket avpkt;
    ...
        // while we have more to decode or while the decoder did output something on EOF
        while (ist->decoding_needed) {
            int64_t duration_dts = 0;
            int64_t duration_pts = 0;
            int got_output = 0;
            int decode_failed = 0;
    
            ist->pts = ist->next_pts;
            ist->dts = ist->next_dts;
    
            switch (ist->dec_ctx->codec_type) {
            case AVMEDIA_TYPE_AUDIO:
                ret = decode_audio    (ist, repeating ? NULL : &avpkt, &got_output,
                                       &decode_failed);
                break;
            case AVMEDIA_TYPE_VIDEO:
                ret = decode_video    (ist, repeating ? NULL : &avpkt, &got_output, &duration_pts, !pkt,
                                       &decode_failed);
                if (!repeating || !pkt || got_output) {
                    if (pkt && pkt->duration) {
                        duration_dts = av_rescale_q(pkt->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_dts = ((int64_t)AV_TIME_BASE *
                                        ist->dec_ctx->framerate.den * ticks) /
                                        ist->dec_ctx->framerate.num / ist->dec_ctx->ticks_per_frame;
                    }
    
                    if(ist->dts != AV_NOPTS_VALUE && duration_dts) {
                        ist->next_dts += duration_dts;
                    }else
                        ist->next_dts = AV_NOPTS_VALUE;
                }
    
                if (got_output) {
                    if (duration_pts > 0) {
                        ist->next_pts += av_rescale_q(duration_pts, ist->st->time_base, AV_TIME_BASE_Q);
                    } else {
                        ist->next_pts += duration_dts;
                    }
                }
                break;
            case AVMEDIA_TYPE_SUBTITLE:
                if (repeating)
                    break;
                ret = transcode_subtitles(ist, &avpkt, &got_output, &decode_failed);
                if (!pkt && ret >= 0)
                    ret = AVERROR_EOF;
                break;
            default:
                return -1;
            }
    
            if (ret == AVERROR_EOF) {
                eof_reached = 1;
                break;
            }
    
            if (ret < 0) {
                if (decode_failed) {
                    av_log(NULL, AV_LOG_ERROR, "Error while decoding stream #%d:%d: %s\n",
                           ist->file_index, ist->st->index, av_err2str(ret));
                } else {
                    av_log(NULL, AV_LOG_FATAL, "Error while processing the decoded "
                           "data for stream #%d:%d\n", ist->file_index, ist->st->index);
                }
                if (!decode_failed || exit_on_error)
                    exit_program(1);
                break;
            }
    
            if (got_output)
                ist->got_output = 1;
    
            if (!got_output)
                break;
    
            // During draining, we might get multiple output frames in this loop.
            // ffmpeg.c does not drain the filter chain on configuration changes,
            // which means if we send multiple frames at once to the filters, and
            // one of those frames changes configuration, the buffered frames will
            // be lost. This can upset certain FATE tests.
            // Decode only 1 frame per call on EOF to appease these FATE tests.
            // The ideal solution would be to rewrite decoding to use the new
            // decoding API in a better way.
            if (!pkt)
                break;
    
            repeating = 1;
        }
    ...
    
        for (i = 0; i < nb_output_streams; i++) {
            OutputStream *ost = output_streams[i];
    
            if (!check_output_constraints(ist, ost) || ost->encoding_needed)
                continue;
    
            do_streamcopy(ist, ost, pkt);
        }
    
        return !eof_reached;
    }
    

    相关文章

      网友评论

          本文标题:ffmpeg # 怎么控制只是转封装而不需要转码

          本文链接:https://www.haomeiwen.com/subject/pbcavftx.html