目录
一、引言
FFmpeg是一个强大的多媒体处理工具,广泛应用于视频录制、转换和流媒体播放等领域。在本文中,我们将讨论如何使用FFmpeg库API来播放视频文件,详细介绍播放流程、API使用以及代码示例。
二、FFmpeg解码播放主要流程
1、视频播放主要涉及以下步骤
1.1、初始化FFmpeg库:
包括注册所有的文件格式和编解码器。
1.2、打开视频文件:
打开视频文件并读取文件头信息获取流信息。
1.3、查找视频流:
在文件的多个流中找到视频流的位置。
1.4、解码视频流:
使用对应的解码器解码视频流。
1.5、读取帧数据:
从视频流中读取原始的帧数据。
1.6、转换和渲染:
将原始帧数据转换为适合输出设备的格式(如YUV转RGB),并渲染到屏幕上。
2、FFmpeg解码播放流程图
使用播放一个媒体文件时,播放流程如图1-1所示:
图1-1 FFmpeg 播放视频流程
2.1、解封装(Demuxing):
就是将输入的封装格式的数据,分离成为音频流压缩编码数据和视频流压缩编码数据。封装格式种类很多,例如MP4,MKV,RMVB,TS,FLV,AVI等等,它的作用就是将已经压缩编码的视频数据和音频数据按照一定的格式放到一起。例如,FLV格式的数据,经过解封装操作后,输出H.264编码的视频码流和AAC编码的音频码流。
2.2、解码(Decode):
就是将视频/音频压缩编码数据,解码成为非压缩的视频/音频原始数据。音频的压缩编码标准包含AAC,MP3等,视频的压缩编码标准则包含H.264,MPEG2等。解码是整个系统中最重要也是最复杂的一个环节。通过解码,压缩编码的视频数据输出成为非压缩的颜色数据,例如YUV、RGB等等;压缩编码的音频数据输出成为非压缩的音频抽样数据,例如PCM数据。
2.3、音视频同步:
就是根据解封装模块处理过程中获取到的参数信息,同步解码出来的音频和视频数据,并将音视频频数据送至系统的显卡和声卡播放出来(Render)。
3、FFMPEG音视频解码
通过上面对媒体文件播放步骤的了解,我们在解码多媒体文件的时候需要经过两个步骤,即解封装(Demuxing)和解码(Decode)。下面就来看一下FFMPEG解码媒体文件的时候是怎样做这两个步骤的。
三、FFmpeg解码播放API使用及代码示例
以下是使用FFmpeg API播放视频文件的基本步骤和代码示例:
3.1、步骤1
初始化FFmpeg库
#include <libavformat/avformat.h>
// 初始化FFmpeg并注册所有编解码器和格式
av_register_all();
3.2、步骤2
打开视频文件
AVFormatContext *pFormatCtx = NULL;
// 打开视频文件
if(avformat_open_input(&pFormatCtx, "your_video.mp4", NULL, NULL) != 0) {
// 文件打开失败
return -1;
}
3.3、步骤3
查找视频流
// 获取流信息
if(avformat_find_stream_info(pFormatCtx, NULL) < 0) {
// 获取失败
return -1;
}
AVCodecContext *pCodecCtx = NULL;
int videoStreamIndex = -1;
// 查找视频流的索引位置
for(int i=0; i<pFormatCtx->nb_streams; i++) {
if(pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
videoStreamIndex = i;
break;
}
}
if(videoStreamIndex == -1) {
// 没有找到视频流
return -1;
}
// 获取视频流的编解码器上下文
pCodecCtx = pFormatCtx->streams[videoStreamIndex]->codec;
AVCodec *pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
// 打开编解码器
if(avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
// 打开编解码器失败
return -1;
}
3.4、步骤4
解码视频流
AVFrame *pFrame = av_frame_alloc();
AVPacket packet;
while(av_read_frame(pFormatCtx, &packet) >= 0) {
if(packet.stream_index == videoStreamIndex) {
// 解码视频帧
int frameFinished;
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
if(frameFinished) {
// 这里我们已经得到了一帧视频,可以进行后续的处理
}
}
// 释放packet
av_packet_unref(&packet);
}
3.5、步骤5
转换和渲染
// 创建一个用于转换的上下文
struct SwsContext *sws_ctx = sws_getContext(
pCodecCtx->width,
pCodecCtx->height,
pCodecCtx->pix_fmt,
pCodecCtx->width,
pCodecCtx->height,
AV_PIX_FMT_RGB24,
SWS_BILINEAR,
NULL,
NULL,
NULL
);
AVFrame *pFrameRGB = av_frame_alloc();
// 分配RGB图像的内存
uint8_t *buffer = (uint8_t *)av_malloc(avpicture_get_size(AV_PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height));
avpicture_fill((AVPicture *)pFrameRGB, buffer, AV_PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height);
// 将YUV帧转换为RGB帧
sws_scale(
sws_ctx,
(uint8_t const * const *)pFrame->data,
pFrame->linesize,
0,
pCodecCtx->height,
pFrameRGB->data,
pFrameRGB->linesize
);
// 此时pFrameRGB中存储的即为RGB数据,可以用于渲染显示
3.6、步骤6
清理资源
// 释放资源
av_free(buffer);
av_frame_free(&pFrameRGB);
av_frame_free(&pFrame);
avcodec_close(pCodecCtx);
avformat_close_input(&pFormatCtx);
四、总结
利用FFmpeg播放视频需要理解视频播放的基本流程,包括初始化FFmpeg, 打开视频文件, 查找视频流, 解码视频流, 以及转换和渲染视频帧。通过本文的介绍和代码示例,大家应该能够开始使用FFmpeg进行基本的视频播放开发。
请注意,为了让代码示例尽可能简洁,本文没有包括错误处理和内存管理的全部细节。在生产环境中,应该始终对所有可能的错误情况进行检查,并且确保及时释放所有分配的资源。此外,对于复杂的应用场景,可能需要考虑多线程或异步处理,以及音视频同步等问题。
参考资料:
https://baijiahao.baidu.com/s?id=1762307958484949791&wfr=spider&for=pc