zoukankan      html  css  js  c++  java
  • ffmpeg转码步骤源码实现的一点点浅析

    ffmpeg转码步骤源码实现的一点点浅析

    ffmpeg转码过程对解码的处理封装在process_input()中(process_input()->decode_video()->decode()->avcodec_send_packet()),转码过程中ffmpeg会通过avformat库一包一包的读取avpacket经过avcodec_send_packet()往内部解码器送原始音视频压缩包、这里也提一下,我们都知道
    avpacket 和 avframe 是ffmpeg的通用帧封装 ,
    avpacket是压缩帧,avframe是原始图像帧,
    在解码端,avpacket会送到解码器,产出avframe
    在编码端,avframe会送进编码器,产出avpacket
    在滤镜端,avframe 入,avframe 出

    4.2.1ffmpeg内部做了并行解码,简图要如下:

    avcodec->internal内部维系了一个环形线程列表,默认工作线程数量为nb_cpu + 1 个,主线程通过avcodec_send_pkt()—>...->submit_packet()通过条件变量提交一个任务给一个空闲的工作线程,空闲线程收到通知后调用对应的解码器回调函数code->decode()开始解码,同时此线程的状态机会切换到工作状态(假定为灰色格子)
    next_decoded总是指向下一个空闲线程,
    next_finnished总是指向第一个工作线程,这样解码器帧出来的顺序即帧送进解码器的顺序,
    next_finnished指向的工作线程解码完成后,会存储在avcodec->internal->buffer_frame中,avcodec_receive_frame()中会判断它是否有数据有则取走,没有则走一遍内部调用取帧,internal一般都是ffmpeg内部结构,不建议开发人员访问.

    关于ffmpeg的多线程编解码分为 frame级和slice级 两类, 当然应该不是所有的编解码器都支持.
    我在测试过程中发现 ffmpeg n4.2.1的版本 解码 h264 默认是打开了帧级多线程解码的, 类 -threads 0 -thread_type frame -i xxx.mp4

    ffmpeg -y -threads 0 -thread_type frame -i xxx.mp4  -f null -an -
    

    同时扫了一下x264编码部分,实现方式和解码形同,但测试过程中却发现-threads x -thread_type frame 即x264帧级多线程编码并不支持, 而是转成了x264内部的多线程编码参数,可见是因编解码器而异.

    另外ffmpeg transcode_step 中,即便不加filter也会毕走了一个null filter,
    add_buffersrc会将avframe添加进内部filter graph link链的一个fifo队列中、
    buffsersink_get会从自己buffsink的link fifo里面取已经产出的frame,如果还没有,则会激活跑一遍filter graph的滤镜链图再来取.
    简化如下,未经调试,实际也许有区别.

    static int get_frame_internal(AVFilterContext *ctx, AVFrame *frame, int flags, int samples)
    {
        BufferSinkContext *buf = ctx->priv;
        AVFilterLink *inlink = ctx->inputs[0];
        int status, ret;
        AVFrame *cur_frame;
        int64_t pts;
    
        if (buf->peeked_frame)
            return return_or_keep_frame(buf, frame, buf->peeked_frame, flags);
    
        while (1) {
            ret = samples ? ff_inlink_consume_samples(inlink, samples, samples, &cur_frame) :
                            ff_inlink_consume_frame(inlink, &cur_frame);
            if (ret < 0) {
                return ret;
            } else if (ret) {
                /* TODO return the frame instead of copying it */
                return return_or_keep_frame(buf, frame, cur_frame, flags);
            } else if (ff_inlink_acknowledge_status(inlink, &status, &pts)) {
                return status;
            } else if ((flags & AV_BUFFERSINK_FLAG_NO_REQUEST)) {
                return AVERROR(EAGAIN);
            } else if (inlink->frame_wanted_out) {
                ret = ff_filter_graph_run_once(ctx->graph);
                if (ret < 0)
                    return ret;
            } else {
                ff_inlink_request_frame(inlink);
            }
        }
    }
    
  • 相关阅读:
    0基础培训Web前端2个月实习一个月4000?
    amazon kindle和kindle阅读
    手动双面打印
    一分价钱一分货
    【转】cocos2d-x 开发中使用的一些工具
    怎么做网线,网线水晶头接法和线序(图文详解)
    schedule
    Match+Faq
    【转】以XML文件方式保存用户数据——2013-08-25 22
    【转】针对iOS VS. Android开发游戏的优劣——2013-08-25 17
  • 原文地址:https://www.cnblogs.com/ailumiyana/p/13034332.html
Copyright © 2011-2022 走看看