【python界面源码】【小说阅读 源码】【大天使源码】ffmpeg源码剖析

1.ffplay深入解析——main函数解析篇(四)
2.深入剖析-ijkplayer框架音视频开发
3.视频和视频帧:Intel GPU(核显)的源码编解码故事
4.2024年 C++音视频开发学习路线(ffmpeg/rtsp/srs/webrtc/hls)
5.音视频开发项目:H.265播放器:视频解码篇

ffmpeg源码剖析

ffplay深入解析——main函数解析篇(四)

       深入解析 ffplay 的 main 函数,ffplay 是剖析一个基于 ffmpeg 的播放器,B站著名的源码 ijkplayer 就是基于此框架二次开发。让我们从主函数开始,剖析逐步剖析源码。源码

       代码主要处理 SDL 时间逻辑,剖析python界面源码首先会调用 SDL_Init 函数,源码传入参数,剖析比如 SDL_INIT_VIDEO 表示初始化视频子系统。源码根据上次文章提到的剖析 flags 参数,如果 audio_disable 和 video_disable 都为 false,源码则 flags 为 SDL_INIT_TIMER、剖析SDL_INIT_AUDIO 和 SDL_INIT_VIDEO 三个或运算的源码值,以此初始化计时器、剖析音频子系统和视频子系统。源码

       如果初始化失败,程序将打印错误信息并终止。在源码中,对于错误和成功的返回值分别为 -1 和 0,两者都导致程序退出,这似乎存在逻辑错误。期待高手在评论区提供解释。

       接着是 SDL_EventState 函数,用于管理和处理事件,通过参数查询事件类型和标志,用于忽略特定事件,以避免用户操作对程序的干扰。

       接下来的代码内容较多,今日先暂停解析,期待下次继续深入探讨。请关注下回分解。

深入剖析-ijkplayer框架音视频开发

       随着互联网技术的迅猛发展,移动设备上的视频播放需求日益增长,催生了一系列开源和闭源播放器。这些播放器的功能虽然强大,兼容性也颇优,但其基本模块通常包括事务处理、数据接收和解复用、音视频解码以及渲染。以下是一个简化的基本框架图。

       在众多播放器项目中,小说阅读 源码我们选择了ijkplayer进行源码分析。ijkplayer是一款基于FFPlay的轻量级Android/iOS视频播放器,支持跨平台,API易于集成,编译配置可裁剪,方便控制安装包大小。本文基于ijkplayer的k0.7.6版本,重点分析其C语言实现的核心代码,以iOS平台为例,Android平台实现类似,具体请读者自行研究。

       ijkplayer的主要目录结构如下:tool(初始化项目工程脚本)、config(编译ffmpeg使用的配置文件)、extra(存放编译ijkplayer所需的依赖源文件,如ffmpeg、openssl等)、ijkmedia(核心代码)、ijkplayer(播放器数据下载及解码相关)、ijksdl(音视频数据渲染相关)、ios(iOS平台上的上层接口封装以及平台相关方法)、android(android平台上的上层接口封装以及平台相关方法)。iOS和Android平台在功能实现上的主要差异在于视频硬件解码和音视频渲染。

       ijkplayer的初始化流程包括创建播放器对象,打开ijkplayer/ios/IJKMediaDemo/IJKMediaDemo.xcodeproj工程,在IJKMoviePlayerViewController类中viewDidLoad方法中创建了IJKFFMoviePlayerController对象,即iOS平台上的播放器对象。

       ijkplayer的初始化方法具体实现如下:创建了IjkMediaPlayer结构体实例_mediaPlayer,主要完成了以下三个动作:创建平台相关的IJKFF_Pipeline对象,包括视频解码以及音频输出部分;至此,ijkplayer播放器初始化的相关流程已经完成。

       ijkplayer实际上是基于ffplay.c实现的,本章节将以该文件为主线,从数据接收、音视频解码、音视频渲染及同步这三大方面进行讲解,要求读者具备基本的ffmpeg知识。

       当外部调用prepareToPlay启动播放后,ijkplayer内部最终会调用到ffplay.c中的stream_open方法,该方法是启动播放器的入口函数,在此会设置player选项,大天使源码打开audio output,最重要的是调用stream_open方法。

       从代码中可以看出,stream_open主要做了以下几件事情:创建上下文结构体,设置中断函数,打开文件,探测媒体类型,打开视频、音频解码器,读取媒体数据,将音视频数据分别送入相应的queue中,重复读取和送入数据步骤。

       ijkplayer在视频解码上支持软解和硬解两种方式,可在播放前配置优先使用的解码方式,播放过程中不可切换。iOS平台上硬解使用VideoToolbox,Android平台上使用MediaCodec。ijkplayer中的音频解码只支持软解,暂不支持硬解。

       ijkplayer中Android平台使用OpenSL ES或AudioTrack输出音频,iOS平台使用AudioQueue输出音频。audio output节点在ffp_prepare_async_l方法中被创建。

       iOS平台上采用OpenGL渲染解码后的YUV图像,渲染线程为video_refresh_thread,最后渲染图像的方法为video_image_display2。

       对于播放器来说,音视频同步是一个关键点,同时也是一个难点。通常音视频同步的解决方案就是选择一个参考时钟,播放时读取音视频帧上的时间戳,同时参考当前时钟参考时钟上的时间来安排播放。

       ijkplayer支持的事件比较多,具体定义在ijkplayer/ijkmedia/ijkplayer/ff_ffmsg.h中。在播放器底层上报事件时,实际上就是将待发送的消息放入消息队列,另外有一个线程会不断从队列中取出消息,上报给外部。

       本文只是粗略的分析了ijkplayer的关键代码部分,平台相关的解码、渲染以及用户事务处理部分,源码整站打包都没有具体分析到,大家可以参考代码自行分析。

视频和视频帧:Intel GPU(核显)的编解码故事

       一般提及基于“显卡或多媒体处理芯片对视频进行解码”为硬解码,本文将探讨如何利用Intel的核显,即集成GPU实现硬解码。提及QSV,全称为Quick Sync Video,Intel在年发布Sandy Bridge CPU时,一同推出了这项基于核显进行多媒体处理,包括视频编解码的技术。集成核显,官方称HD Graphics,最早在Sandy Bridge前一代制程已推出,但性能提升及充分发挥在Sandy Bridge时期。Haswell及后续制程发布更高级的Iris架构。最近Intel宣布将开发独立显卡,核显发展具体走向未知。

       接手QSV项目时,预期会有很多相关资料,实则相反。因此,将记录自己学习过程。

       本文将介绍:

       I. Intel的核显(集成GPU):

       了解核显很有必要,几个月前,作者对CPU的认识还停留在“南北桥”架构。以下内容若有不准确之处,欢迎指正。

       查看Gen CPU结构图,首先看CPU核心部分。在整块CPU芯片中,核显占比不小,算力不容小觑。在没有独立显卡的笔记本上,可以运行大量大型游戏,虽偶有卡顿、掉帧情况,整体表现已相对不错。

       接下来,看官方给出的GPU内部结构图。GPU内部远比图上所示复杂,科美源码图中介绍的仅为部分Subslice芯片结构。GPU分为Slice部分和Un-Slice部分,Slice部分已介绍,接下来介绍Un-Slice部分。

       作者找到了一张图,展示了在MFF上进行视频处理的流程:1) 首先在MFX/VDBOX模块上进行编解码;2) 接着送到VQE/VEBOX上做图像增强和矫正处理;3) 然后送到SFC上做scale和transcode;4) 最后送出到显示屏上展示。是否完全正确,作者这里做个记录。

       推荐知乎文章《转》Intel Gen8/Gen9核芯显卡微架构详细剖析,深入浅出,关于thread dispatch的说明即出自该文。

       最后,总结Intel集成GPU/核显结构图。

       注意,这是skylake架构下的GT2/GT3/GT4 GPU结构图,X数字越大,集成的Slice和Unslice芯片更多,能力越强,价格也更高。

       II. Quick Sync Video(QSV)技术:

       QSV是Intel推出的将视频处理任务直接送到GPU上进行专门负责视频处理的硬件模块处理的软件技术。与CPU或通用GPU上的视频编码不同,QSV是处理器芯片上的专用硬件核心,这使得视频处理更为高效。

       要了解QSV如何驱动GPU的MFF,首先看官方Intel® Video and Audio for Linux上的图。在介绍QSV之前,提及Intel在FFmpeg上提供的插件,包括ffmpeg-qsv、ffmpeg-vaapi和ffmpeg-ocl。详细描述如下:

       · FFmpeg-vaapi提供基于低级VAAPI接口的硬件加速,在VA API标准下在Intel GPU上执行高性能视频编解码器、视频处理和转码功能。

       · FFmpeg-qsv提供基于Intel GPU的硬件加速,基于Intel Media SDK提供高性能视频编解码器、视频处理和转码功能。

       · FFmpeg-ocl提供基于工业标准OpenCL在CPU/GPU上的硬件加速,主要用于加速视频处理过滤器。

       接下来,介绍QSV在ffmpeg2.8及以上版本的支持,经过MSDK、LibVA、UMD和LibDRM。分层进行分析:

       · MSDK:Intel的媒体开发库,支持多种图形平台,实现通用功能,可用于数字视频的预处理、编解码和不同编码格式的转换。源码地址为Intel® Media SDK,在Linux平台上编译使用。

       · VA-API:Video Acceleration API,提供类unix平台的视频硬件加速开源库和标准。Intel源码地址在Intel-vaapi-driver Project,在Linux平台上使用。

       · UMD:User Mode Driver的缩写,指VA-API Driver。Intel提供了两个工具:intel-vaapi-driver 和 intel-media-driver,推荐使用后者。

       · LibDRM:Direct Rendering Manager,解决多个程序协同使用Video Card资源问题,提供一组API访问GPU。与VA-API,LibDRM是一套通用的Linux/Unix解决方案。

       · Linux Kernel:Intel的Kernel是i driver,描述了libDRM和Kernel Driver之间的关系。

       至此,整个关系图较为清晰。

       III. FFMPEG+QSV解码:

       QSV硬解的任务主要包括:

       关于3-4步操作的详细实现,底层库会帮助完成。但作为一个优秀的工程师,研究FFMPEG源码依然十分重要。接下来,介绍如何使用FFmpeg API中的h_qsv解码器插件。

       提及FFmpeg命令行使用方法,推荐阅读官方资料《QuickSync》或《Intel_FFmpeg_plugins》。

       关于示例代码,作者曾遇到许多坑,总结为:多数中文博客不可靠,官方demo最可信。官方代码提供了两份可用:qsvdec.c和hw_decode.c。作者最早使用的是第一段代码,核心部分如下:

       然而,这段代码存在问题。测试发现,对于赛扬系列一款CPU,在p视频上MSDK达到fps,理论上h_qsv平台上限也应为fps,但实际测试不到fps。排查后发现是av_hwframe_transfer_data()性能较弱。

       最终,与Intel一起解决了性能问题。那么,性能提升方案为何是GPU-COPY技术做Memory-Mapping?

       解释GPU和CPU渲染图像的过程,包括坐标系转化、纹理叠加等,仅需了解两点:

       后者的数据组织方式能充分利用GPU的并行特性,加速图像处理、渲染。尽管存在一些纹理叠加的技术难题,但性能提升足以补偿。

       接下来,解释Memory-Mapping:从Intel CPU架构图中可见,GPU和CPU位于同一芯片上,各自寄存器/缓存区有限,视频数据主要存储在内存上。GPU和CPU的数据组织方式不同,同一帧数据存于内存同一位置,数据格式不同,因此需要做Memory-Mapping。Memory-Mapping相较于Memory-Copy,减少了数据从内存区域A移动到区域B的操作,已经是优化。进一步优化:GPU完成Memory-Mapping以及数据从GPU到内存和CPU的操作。

       在av_hwframe_transfer_data()内部,Memory-Mapping由CPU完成,性能受限于CPU,只能并行。修改后,整体性能从不到fps提升至fps,虽然与理想fps仍有差距,但满足性能需求。

       据悉,Intel将在FFmpeg 4.3开源出这个解决方案。

       写在后面:

       了解GPU底层对应用开发人员帮助不大,毕竟了解芯片布线的重新设计、制程工艺提升、GPU-COPY技术的数据I/O提升等,也不能做什么。最终,芯片架构是芯片工程师的事,底层逻辑实现是嵌入式工程师的事。应用开发人员无法做出实质贡献,但作为知识库扩充或休闲阅读,了解也无妨。

       希望有机会接触CUDA的编解码,深入学习N卡设计。

       感谢因《视频和帧》系列文章结识的朋友,热心指出文章描述不准确的地方。文中如有不严谨之处,欢迎指正。

年 C++音视频开发学习路线(ffmpeg/rtsp/srs/webrtc/hls)

       音视频工作领域繁复多样,自学时易陷入迷茫。本文整理出九个前景不错的方向:直播、传输、算法、视频播放器、流媒体后端、短视频、音频播放、视频编辑、图像处理。以下为详细学习路线:

       音视频基础

音频基础知识

视频基础知识

解复用基础知识

FFmpeg开发环境搭建

音视频开发常用工具

       FFmpeg实战教程

FFmpeg命令

SDL跨平台

FFmpeg基石精讲

FFmpeg过滤器

FFmpeg音视频解复用+解码

ffplay播放器

FFmpeg音视频编码+复用合成视频

ffmpeg多媒体

FFmpeg+ QT播放器

       流媒体客户端

RTMP推拉流项目实战

RTSP流媒体实战

HLS拉流分析

       流媒体服务器

SRS源码剖析协程

ZLMediaKit源码剖析

       WebRTC项目实战

WebRTC中级开发实践指南

WebRTC高级开发-SRS 4.0/5.0源码分析

WebRTC高级开发-MESH模型多人通话

WebRTC高级开发-Janus SFU模型多人通话

       Android NDK

Android NDK开发基础

Android FFmpeg编译和应用

Android RTMP推拉流

Android Ijkplayer源码分析

       iOS音视频开发

iOS FFmpeg 6.0编译和应用

iOS FFmpeg RTMP推拉流

VideoToolbox硬件编解码

iOS jkplayer编译和应用

iOS ijkplayer编译和应用

       音视频项目实战

       相关开源网站与地址

       本文涵盖音视频全栈开发技术,适合各类技术人员。

音视频开发项目:H.播放器:视频解码篇

       探索音视频开发的前沿技术,让我们深入剖析一款H.播放器的视频解码优化过程。在这款高性能播放器中,新版以惊人的效率展示了其解码能力,1分钟内处理p/fps的H. MP4视频,内存占用仅为4.6GB,而CPU占用率在极限条件下也保持在+。单帧解码p的速度已经优化到了惊人的毫秒,相较于旧版p的毫秒,无疑展示了技术的飞跃。

       播放器的架构设计巧妙,由Loader、Demuxer、Renderer(核心模块)和UI View等模块构成,各部分独立却又协同工作。让我们走进DEMO架构示例:Loader负责从Annex-B码流中读取数据,WASM技术则高效地解码YUV数据,而FFmpeg经过精简编译后,被转化为轻量级的WASM包,实现资源优化。

       要实现这一优化,首先从FFmpeg官网获取emsdk和源码版本(4.1),然后通过定制的make_decoder.sh脚本,去除不必要的模块,如swresample和postproc,专注于关键的hevc-decoder模块。这个过程包括禁用非必要的FFmpeg功能,生成简化库和.h文件,为后续的WASM编译做准备。

       接下来,编写自定义的C语言入口文件(如decoder.c),运用C语言基础,创建一个初始化解码器的接口,如init_decoder,它接受一个JS回调函数,传递解码数据的地址、长度,以及可选的时间戳(pts)。附赠的学习资料包,包含FFmpeg、webRTC等技术,可通过企鹅裙获取,助你快速上手。

       解码的核心在于处理AVPacket和AVFrame,视频中每个压缩帧需要通过demuxers和decoders逐一解析。decode_buffer函数负责数据解析和解码,将解码后的AVPacket传递给解码器,可能需要多次循环以接收完整的AVFrame。而在3.x和4.x版本中,avcodec_send_packet和avcodec_decode_video2/avcodec_decode_audio4的调用方法有所不同。

       解码后的YUV数据通常以紧缩格式(如YUVp)和平面格式存储,需要转换后供JS使用。在这个过程中,采样率决定了数据处理的复杂度,例如4个Y分量对应1个U和V分量。将解码后的AVFrame复制到yuv_buffer,然后通过decoder_callback传递给JavaScript。

       通过Emscripten构建WASM包,我们编写build_decoder.sh脚本,设置出口函数和内存配置,最终生成wasm/libffmpeg.js。在JS和Worker中,我们加载并调用WASM函数,构建Decoder类,扩展EventEmitter,处理数据的异步加载和解码。在主线程中,通过webpack和worker-loader,数据从主线程传输到Worker,解码器负责解码并返回处理后的数据。

       H.视频解码的挑战在于高效处理AVPacket和AVFrame,音频解码则可能需要复用解码链路或者利用浏览器内置的解码器。音频播放则依赖于AudioContext,确保主流音频编码格式在浏览器中的兼容性。通过这个案例,我们了解了如何避免常见问题,以及FFmpeg在视频处理中的强大能力。H.播放器的应用场景广泛,为创新提供无限可能。

更多内容请点击【休闲】专栏

精彩资讯