FFmpeg 是一个C程序的项目,C语言是需要手动管理内存的。内存管理有一个技巧,只要你分清楚这个变量是在栈上,还是在堆上的就可以了。在栈上的变量不需要手动释放,而在堆上的变量需要自己释放。 下面通过一个实例,通过反汇编来讲解一下 栈变量为什么不需要自己释放,代码如下: intadd_something(inta,intb,intc){intd=4;inte=5;intf=6;returna+b+c+d+e+f;}intsub_something(inta,intb,intc){intg=7;inth=8;intj=9;returna+b+cghj;}intmain(...

  1bTlX33AWdQ4   2023年11月02日   42   0   0 栈内存堆内存局部变量

内存对齐是计算机编程提高性能的一种方式,我们平时用的 ​​struct​​​,​​malloc()​​ 都会进行内存对齐,如下代码: struct{intx;chary;}s;intmain(){printf("%d\n",sizeof(s));//输出8return0;} 32位系统中,上面的代码中 ​​int​​ 占4字节,​​char​​ 占1字节,但是结果会输出8,这是因为编译器自动帮我们做了内存对齐。 而 ​​malloc()​​ 函数也会进行内存对齐,32位系统里面,​​malloc​​ 函...

  1bTlX33AWdQ4   2023年11月02日   27   0   0 字节对齐内存对齐数组

在开始分析之前,讲一个 ​​makefile​​​ 的调试技巧,推荐阅读​​《如何调试MAKEFILE变量》​​ make-fMakefile-fvars.mkHOSTPROGS 这里我对 ​​vars.mk​​ 做了点修改,因为源 ​​vars.mk​​ 没处理特殊字符,直接 ​​echo​​ 会报错。​​ffmpeg​​ 的 ​​makefile​​ 的变量有很多特殊字符。我用了 ​​warning​​ 来输出,就不会报错。​​vars.mk​​&n...

  1bTlX33AWdQ4   2023年11月02日   47   0   0 静态库动态库根目录

read_thread() 线程的主要作用从MP4里面读取 ​​AVPacket​​​,然后丢进去 ​​PacketQueue​​​ 队列。所以需要先学习一下 ​​strcutPacketQueue​​​ 跟 ​​structMyAVPacketList​​ 数据结构。如下: typedefstructMyAVPacketList{AVPacketpkt;intserial;}MyAVPacketList; typedefstructPacketQueue{AVFifoBufferpkt_list...

  1bTlX33AWdQ4   2023年11月02日   58   0   0 FFplay

​​stream_component_open()​​ 函数主要作用是打开音频流或者视频流对应的解码器,开启解码线程去解码。 流程图如下: ​​stream_component_open()​​ 的函数定义如下: /openagivenstream.Return0ifOK/staticintstream_component_open(VideoStateis,intstream_index) 可以看到,函数的参数非常简单,第一个参数是 ​​VideoStateis​​ 全局管理器,第二个参数 ​​stream_index​​&nb...

  1bTlX33AWdQ4   2023年11月02日   54   0   0 FFplay

音频流的滤镜是通过 ​​configure_audio_filters()​​​ 函数来创建的,因为 ​​ffplay​​​ 为了代码的通用性,即便命令行参数不使用滤镜,​​AVFrame​​ 也会过一遍空滤镜做下样子。 ​​configure_audio_filters()​​ 函数的流程图如下: ​​configure_audio_filters()​​ 函数的定义如下: staticintconfigure_audio_filters(VideoStateis,constcharafilters,intforc...

  1bTlX33AWdQ4   2023年11月02日   70   0   0 FFplay

​​audio_open()​​ 的作用,就如同它的名字那样,就是打开音频设备。流程图如下: SDL库播放音频数据有两种方式。 1,调用层定时往SDL接口塞数据。 2,设置SDL回调函数,让SDL来主动执行回调函数来取数据。 第二种方式的实时性更好,​​ffplay​​ 也是用的第二种。 先介绍一下 ​​audio_open()​​ 函数的各个参数,如下: staticintaudio_open(voidopaque,int64_twanted_channel_layout,intwanted_nb_channels,intwanted_sa...

  1bTlX33AWdQ4   2023年11月02日   60   0   0 FFplay

之前在 ​​stream_component_open()​​​ 里面的 ​​decode_start()​​​ 函数开启了 ​​audio_thread​​ 线程,如下: ​​audio_thread​​ 线程主要是负责 解码 ​​PacketQueue​​ 队列里面的 ​​AVPacket​​ 的,解码出来 ​​AVFrame​​,然后丢给入口滤镜,再从出口滤镜把 ​​AVFrame​​ 读出来,再插入 ​​FrameQueue​...

  1bTlX33AWdQ4   2023年11月02日   85   0   0 FFplay

​​decoder_decode_frame()​​ 其实是一个通用的解码函数,可以解码音频,视频,字幕的 ​​AVPacket​​。不过本文主要侧重于分析音频流的解码,但其他的流也是类似的逻辑。 ​​decoder_decode_frame()​​ 函数的参数如下: staticintdecoder_decode_frame(Decoderd,AVFrameframe,AVSubtitlesub) 1,​​Decoderd​​,这个 ​​Decoder​​ 结构,我把它称为解码管理实例。由于 ​​Decoder​​&nb...

  1bTlX33AWdQ4   2023年11月02日   59   0   0 FFplay

FFplay播放器有两种队列,​​PacketQueue​​​ 跟 ​​FrameQueue​​​。​​FrameQueue​​​ 的数据就是从 ​​PacketQueue​​ 里面解码出来的(会经过滤镜)。 ​​PakceQueue​​ 是用 ​​FifoBuffer​​ 来实现环形队列的,而​​FrameQueue​​ 是用数组来实现一个环形队列的,但是更复杂一些。​​FrameQueue​​ 跟 ​​PakceQueue​​ 的关系如下: FrameQueue&nb...

  1bTlX33AWdQ4   2023年11月02日   67   0   0 FFplay

在之前的几篇文章里面,都零零散散提及过序列号这个概念。但是序列号这个概念对于 ​​FFplay​​ 播放器非常重要的,很多代码都跟序列号有关。所以单独写一篇文章介绍序列号。 序列号主要是给 快进快退 这个功能准备的。如果不能快进快退,那其实就不需要序列号。只要解复用线程不断读取 ​​AVPacket​​ 放进去 ​​PacketQueue​​ 队列,解码线程不断从 ​​PacketQueue​​ 取数据来解码放进去 ​​FrameQueue​​,最后有播放线程来取 ​​Fra...

  1bTlX33AWdQ4   2023年11月02日   39   0   0 FFplay

音频播放线程是之前在 ​​audio_open()​​ 函数里面创建的,实际上就是回调函数 ( ​​wanted_spec.callback​​)。当用SDL打开音频硬件设备的时候,SDL库就会创建一个线程,来及时执行回调函数 ​​sdl_audio_callback()​​​,至于SDL线程多久回调一次函数,这个我们不需要太关心,只要调 ​​SDL_OpenAudioDevice()​​ 函数的时候设置好相关参数即可。如下: 上图中,设置了每次回调取的样本数,设置了样本数就相当于设置了回调次数,​​ffplay​​&nb...

  1bTlX33AWdQ4   2023年11月02日   50   0   0 FFplay

首先说明一下,​​audio_decode_frame()​​ 函数跟解码毫无关系,真正的解码函数是 ​​decoder_decode_frame​​ 。 ​​audio_decode_frame()​​ 函数的主要作用是从 ​​FrameQueue​​ 队列里面读取 ​​AVFrame​​ ,然后把 ​​is->audio_buf​​ 指向 ​​AVFrame​​ 的 ​​data​​。如果 ​​AVFrame​​ 的音频信息跟&nbsp...

  1bTlX33AWdQ4   2023年11月02日   52   0   0 FFplay

之前在 ​​stream_component_open()​​​ 里面的 ​​decode_start()​​​ 函数开启了 ​​video_thread​​ 线程,如下: ​​video_thread​​ 线程主要是负责 解码 ​​PacketQueue​​ 队列里面的 ​​AVPacket​​ 的,解码出来 ​​AVFrame​​,然后丢给入口滤镜,再从出口滤镜把 ​​AVFrame​​ 读出来,再插入 ​​FrameQueue​...

  1bTlX33AWdQ4   2023年11月02日   44   0   0 FFplay

视频播放线程就是 ​​main​​​ 主线程,对于 ​​FFplay​​ 播放器,就是在 主线程 里面播放视频流的,如下: 如上图所示,​​event_loop()​​ 会不断用 ​​refresh_loop_wait_event()​​ 函数检测是否有键盘事件发生,如果有键盘事件发生, ​​refresh_loop_wait_event()​​ 就会返回,然后跑到 ​​switch{event.type}{...}​​ 来处理键盘事件。 如果没有键盘事件发生,&...

  1bTlX33AWdQ4   2023年11月02日   65   0   0 FFplay

之前的文章,已经把音频,视频的解码线程,播放线程通通讲了一遍,现在到了播放器实现最复杂的功能之一,就是音视频同步。 FFplay支持3种同步方式,如下: 1,以音频时钟为主时钟,默认方式。 2,以视频时钟为主时钟。 3,以外部时钟为主时钟。 因为音频流的连续性非常强,例如一秒需要播放48000个样本。而视频流通常1秒只需播放24帧。而且人的耳朵对音频特别敏感。 所以第一种方式以音频时钟为准是最常用的,其他两种方式几乎没有应用场景。 先普及一下音视频同步的一些基本概念。 1,为什么需要进行音视频同步? 答:由于计算机系统大部分是分时系统,所以当负载过高或者设备性能差的时候,音频播放线程或者视频...

  1bTlX33AWdQ4   2023年11月02日   38   0   0 FFplay

以音频时钟为主时钟,是最常用的同步方式,也是FFplay里面默认的同步方式。当以音频时钟为主时钟,视频就会向音频同步。 视频播放线程,会缩短或者拉长当前视频帧的播放时长,或者丢弃视频帧来向音频同步。 FFplay 是用 ​​structClock​​ 数据结构记录音频流,视频流当前播放到哪里的。​​Clock​​ 结构体的定义如下: typedefstructClock{doublepts;/clockbase/单位是妙。doublepts_drift;/clockbaseminustimeatwhichweupdatedtheclock/dou...

  1bTlX33AWdQ4   2023年11月02日   55   0   0 FFplay

本文是讲解当视频时钟设置为主时钟的时候,音视频同步的逻辑。可以通过以下命令设置视频时钟为主时钟: ffplay-syncvideo-ijuren-30s.mp4 当视频时钟设置为主时钟的时候,​​is->av_sync_type​​ 等于 ​​AV_SYNC_VIDEO_MASTER​​,之前在《​​FFplay视频同步分析​​》提到的3处视频同步的代码,全部都会失效,如下: 因此当视频是主时钟的时候,视频流永远不会丢帧,即使视频播放线程卡顿,也不会丢帧。不过如果视频播放线程卡顿,可能会导致某些帧的播放时长缩短。因为一般情况是0.01s检查一次,如果...

  1bTlX33AWdQ4   2023年11月02日   20   0   0 权重音视频

FFplay播放器有3个时间: 1,视频流的播放时刻,(视频时钟) 2,音频流的播放时刻,(音频时钟) 3,预定的时间,预定的播放时刻,实际上就是物理世界的自然时间,(外部时钟) 上图中的 ​​14:00:00:123​​ 就是其中一个预定的时间,完全准确的情况下,会在 ​​14:00:00:123​​ 播放第4帧视频,播放第7帧音频。 但是,计算机系统是分时系统,大部分情况不会那么准确,有可能发生以下的情况。 在 ​​14:00:00:133​​ 的时候才播放第4帧视频。 在 ​​14:00:00:143​​ ...

  1bTlX33AWdQ4   2023年11月02日   51   0   0 视频流音频流赋值

播放器的最常用的功能之一就是快进快退,快进快退的本质就是让mp4文件跳转到另一个时间点来播放。 FFplay播放器有两种方式可以让mp4文件跳转到另一个时间点来播放。 1,在命令行里里使用 ​​-ss​​ 参数,如下,跳到到第60秒的地方开始播放。 ffplay-x400-ss60-ijuren.mp4 2,在播放过程中,按上下左右减,进行快进后退操作。 上面这两种跳转时间点播放的方式,其实都是调 ​​avformat_seek_file()​​ 来实现的,都是在 ​​read_thread()​​ 线程函数里面进行see...

  1bTlX33AWdQ4   2023年11月02日   78   0   0 FFplay
关注 更多

空空如也 ~ ~

粉丝 更多

空空如也 ~ ~