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

ffmpeg转码步骤源码实现的一点点浅析的更多相关文章

  1. FFmpeg的HEVC解码器源码简单分析:解码器主干部分

    ===================================================== HEVC源码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpeg ...

  2. FFmpeg的HEVC解码器源码简单分析:解析器(Parser)部分

    ===================================================== HEVC源码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpeg ...

  3. FFmpeg的HEVC解码器源码简单分析:概述

    ===================================================== HEVC源码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpeg ...

  4. Flink源码分析 - 源码构建

    原文地址:https://mp.weixin.qq.com/s?__biz=MzU2Njg5Nzk0NQ==&mid=2247483692&idx=1&sn=18cddc1ee ...

  5. Elasticsearch源码分析 - 源码构建

    原文地址:https://mp.weixin.qq.com/s?__biz=MzU2Njg5Nzk0NQ==&mid=2247483694&idx=1&sn=bd03afe5a ...

  6. EventBus源码解析 源码阅读记录

    EventBus源码阅读记录 repo地址: greenrobot/EventBus EventBus的构造 双重加锁的单例. static volatile EventBus defaultInst ...

  7. ios源码-ios游戏源码-ios源码下载

    游戏源码   一款休闲类的音乐小游戏源码 该源码实现了一款休闲类的音乐小游戏源码,该游戏的源码很简单,而且游戏的玩法也很容易学会,只要我们点击视图中的grid,就可以 人气:2943运行环境:/Xco ...

  8. C#UDP(接收和发送源码)源码完整

    C#UDP(接收和发送源码)源码完整 最近做了一个UDP的服务接收和发送的东西.希望能对初学的朋友一点帮助. 源码如下: 一.逻辑--UdpServer.cs using System;using S ...

  9. 二维码zxing源码分析(五)精简代码

    由于工作的需要,我并不是需要二维码扫描的所有的功能,我只是需要扫一扫,并显示出来图片和url就行,于是我们就要精简代码了,源码已经分析完了,精简起来就方便多了,源码分析请看 二维码zxing源码分析( ...

随机推荐

  1. CC2530ADC应用

    ADC单通道外部电压采集 需要设置一个上机位命令控制字符. 系统时钟初始化——32MHZ晶振 串口0函数初始化——设置串口对应引脚,波特率,清楚中断标志 串口0接收中断响应函数——U0DBUF将控制命 ...

  2. EChart将timeline图标设置为加号

    一 要实现的效果 二 官方文档 看一下官方文档上,替换symbol的描述: timeline.symbol string [ default: 'emptyCircle' ] timeline标记的图 ...

  3. MongoDB最佳安全实践

    在前文[15分钟从零开始搭建支持10w+用户的生产环境(二)]中提了一句MongoDB的安全,有小伙伴留心了,在公众号后台问.所以今天专门开个文,写一下关于MongoDB的安全. 一.我的一次Mong ...

  4. 【漫画】JAVA并发编程 J.U.C Lock包之ReentrantLock互斥锁

    在如何解决原子性问题的最后,我们卖了个关子,互斥锁不仅仅只有synchronized关键字,还可以用什么来实现呢? J.U.C包中还提供了一个叫做Locks的包,我好歹英语过了四级,听名字我就能马上大 ...

  5. 配置类为什么要添加@Configuration注解呢?

    配置类为什么要添加@Configuration注解呢? 本系列文章: 读源码,我们可以从第一行读起 你知道Spring是怎么解析配置类的吗? 推荐阅读: Spring官网阅读 | 总结篇 Spring ...

  6. c#得出两个列表的交集

    c#提供了Intersect来得到两个列表的交集,它是通过使用默认的相等比较器对值进行比较生成两个序列的交集,定义为: public static IEnumerable<TSource> ...

  7. 使用 PyCharm 添加 Django 项目

    一.前置准备(PyCharm与Python的下载,已有的跳过) 1.首先下载PyCharm 地址:http://www.jetbrains.com/pycharm/ 2.然后下载Python 地址:h ...

  8. java经典问题 byte b=1、b=b+1、b+=1

    直接问题: 首先 byte的范围 [-128,127] byte 类型可以自动转为int类型 int类型不能自动转为byte类型. 超过byte的范围,就会变成int类型了 byte b=1:正确, ...

  9. mybatis部分sql技巧

    1.mybatis中没有<=号,必须用<![CDATA[<=]]>表示.<update id="reduceNumber"> UPDATE se ...

  10. mysql+redis缓存策略常见的错误

    什么时候应该更新缓存 应该是从数据库读取数据后,再更新缓存,从缓存读取到数据,就不需要再重新写缓存了,一个常见的错误是,每次访问接口都更新缓存,这样的话,如果接口一直有流量,那么db中的数据,就一直没 ...