目录
问题1:avformat_alloc_context和avcodec_alloc_context3分别作用以及区别?
问题2:av_image_get_buffer_size和av_image_fill_arrays分别作用以及区别?
问题3:sws_getContext和sws_scale的作用?
前面我们已经实现了QT 6.6.0 中基于FFmpeg + SDL2 + SDL2_mixer实现音频录音 录音功能,但是里面关于音频的解码部分并没有讲的很清楚(因为那不是重点,重点是录音),因此后期会继续去搞清楚再来讲解。文本主要是讲解使用QT 6.6.0 + FFmpeg + SDL2实现视频播放,其中采用FFmpeg对视频解码,同时也采用了SDL2多线程功能防止主线程阻塞。
实现思路
- SDL2初始化以及FFmpeg设备注册;
- 定义结构体数据,包含了创建窗口,渲染器,纹理以及上下文格式等变量(便于传入到创建的线程函数中);
- 创建窗口,渲染器,纹理以及遍历当前上下文流,找到视频流索引号,其实就是SDL2初始化指定的SDL_INIT_VIDEO变量;
- 创建线程,包含了线程函数,线程函数名以及传入的结构体变量;
- 主线程运行,显示窗口以及从事件队列中获取待处理的事件;
- 处理事件:通过
SDL_PollEvent
从事件队列中获取待处理的事件,例如鼠标移动、键盘按下等。 - 保持窗口响应:在应用程序运行时,循环不断检查和处理事件,确保窗口不会被冻结并能够即时响应用户交互。
- 程序退出的控制:通过捕捉
SDL_QUIT
事件(例如点击窗口的关闭按钮)或特定按键(如 ESC)实现安全退出,使用户能够方便地关闭程序。
注:大家想一想,如果缺少这部分,程序还能正常运行吗?答案是可以正常运行,但是不能响应鼠标移动等事件,会导致程序运行的过程中崩溃。因此,除了使用多线程解决读取视频帧以及更新视频帧之外,还需要使用上述while中的代码解决鼠标移动等事件。防止鼠标移动窗口导致程序崩溃。
- 子线程运行,读取视频帧和实时更新视频帧;
- 等待子线程结束。
//等待线程结束
SDL_WaitThread(thread,nullptr);
- 回收资源。
// 清理资源(子线程函数)
av_free(buffer);
av_frame_free(&pFrameRGB);
av_frame_free(&pFrame);
sws_freeContext(sws_ctx);
//主线程介素
SDL_DestroyTexture(texture);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
avcodec_free_context(&pCodecCtx);
avformat_close_input(&pFormatCtx);
SDL_Quit();
问题1:avformat_alloc_context和avcodec_alloc_context3分别作用以及区别?
特性/函数 | avformat_alloc_context | avcodec_alloc_context3 |
---|---|---|
对象类型 | 分配和初始化 上下文AVFormatContext | 分配和初始化 AVCodecContext |
主要用途 | 管理和处理多媒体文件及其格式 | 处理特定编解码器的编码或解码参数 |
表示方法 | 文件或流的格式信息 | 编解码器的设置和状态 |
使用场景 | 打开文件、查找流信息、处理媒体文件的上下文 | 进行音视频编解码,操作具体的编解码器设置 |
注:虽然这里并没有对其函数的具体参数进行介绍,但是读者了解其作用之后,点击进去查看具体的函数参数即可知道参数的含义(下面的介绍同样的方式)。
问题2:av_image_get_buffer_size和av_image_fill_arrays分别作用以及区别?
特性/函数 | av_image_get_buffer_size | av_image_fill_arrays |
---|---|---|
作用 | 计算图像数据需要的缓冲区大小(字节单位) | 填充 AVFrame结构体 的数据指针和行宽以及其他参数 |
输出结果 | 返回所需的内存字节数,表示存储指定格式和尺寸的图像所需字节数,用于申请空间 | 无返回值,直接修改传入的指针和行宽数组 |
大致使用场景 | 内存分配前获取缓冲区大小,并且使用av_malloc申请空间 | 初始化和准备图像帧的像素数据,比如本文用于显示视频帧 |
大致输入参数 | 图像格式、宽度、高度 | 数据指针、行宽数组、图像格式、宽度、高度 |
注:这两个函数通过看了这个表格总结之后倒是比较好理解,因为用于最终视频帧的显示,必须要有能存储视频帧信息的变量。
问题3:sws_getContext和sws_scale的作用?
第一点:sws_getContext
基本作用
sws_getContext
函数用于创建和初始化一个缩放上下文(SwsContext
),该上下文包含了进行图像缩放所需的所有信息和状态(比如从原图像大小到目标图像大小信息,原图格式到目标格式信息,具体的缩放算法信息)。- 三种缩放算法(本文主要是对图像高宽调整,使用了SWS_BILINEAR双线性插值)
- 对于SWS_BICUBIC参数[0]和[1],调整基的形状函数,参数[0]调整f(1)和参数[1]f´(1)
- 对于SWS_GAUSS参数[0]调整指数,从而切断频率;
- 对于SWS_LANCZOS, param[0]调整窗口函数的宽度
- 三种缩放算法(本文主要是对图像高宽调整,使用了SWS_BILINEAR双线性插值)
- 此函数根据输入和输出图像的格式、尺寸和缩放方法等参数,配置相应的上下文,使得图像可以在不同格式或分辨率之间转换。
使用场景
- 在处理视频流时,如果需要将图像从一种格式或分辨率转换为另一种格式或分辨率(比如像本文调整视频帧大小等),则必须先使用
sws_getContext
创建一个缩放上下文。 - 当应用程序处理输入的原始图像时,使用此函数为以后的图像缩放和格式转换做准备。
第二点:sws_scale
基本作用
sws_scale
函数用于执行图像的缩放和格式转换操作。- 使用之前创建的
SwsContext
,它根据源图像的像素数据,将图像缩放到目标尺寸,并可能进行格式转换(如图像高宽缩放)。
使用场景
- 在接收到输入帧后,使用
sws_scale
将其处理成特定输出格式和尺寸的图像数据,以便能够显示、编码、存储或用于后续处理,比如本文对读取的视频帧处理。
问题4:av_packet_unref作用?
- 释放资源:
av_packet_unref
释放AVPacket
中可能分配的内存缓冲区,特别是数据指针指向的内存。 - 重置状态:
av_packet_unref
释放了数据后,会将AVPacket
的状态重置为初始化状态,意味着可以在同一个AVPacket
实例上重新调用av_read_frame
或重新填充数据,清除之前的数据干扰。
问题5:寻找视频流索引号?
QT 6.6.0 + FFmpeg +SDL2 实现视频播放