说明:
该代码只是一个简单的示例,仅演示了在 C++ 中如何使用FFmpeg库进行音视频编解码,实现了一个简单的视频解码器,用于将视频文件解码为原始视频帧数据。它打开一个输入文件(input.mp4),查找视频流并获取相关的流信息。然后找到对应的视频解码器并打开解码器。代码通过循环读取视频帧,并将每个视频帧解码后写入输出文件(output.yuv)。在处理解码后的帧数据时,代码只是简单地将原始视频帧写入输出文件。
需要注意的是,该示例只处理视频流,而没有处理音频流。如果你需要处理音频流,你需要根据具体需求进行相应的修改。
源码展示
#include <iostream>
#include <string>
extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
}
int main() {
// 注册所有的FFmpeg组件
av_register_all();
std::string inputFilePath = "input.mp4";
std::string outputFilePath = "output.yuv";
// 打开输入文件
AVFormatContext* formatContext = nullptr;
if (avformat_open_input(&formatContext, inputFilePath.c_str(), nullptr, nullptr) != 0) {
std::cerr << "无法打开输入文件" << std::endl;
return -1;
}
// 获取流信息
if (avformat_find_stream_info(formatContext, nullptr) < 0) {
std::cerr << "无法获取流信息" << std::endl;
avformat_close_input(&formatContext);
return -1;
}
int videoStreamIndex = -1;
AVCodecContext* videoCodecContext = nullptr;
// 查找视频流索引和解码器
for (unsigned int i = 0; i < formatContext->nb_streams; i++) {
if (formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
videoStreamIndex = i;
AVCodec* codec = avcodec_find_decoder(formatContext->streams[i]->codecpar->codec_id);
if (!codec) {
std::cerr << "无法找到视频解码器" << std::endl;
avformat_close_input(&formatContext);
return -1;
}
videoCodecContext = avcodec_alloc_context3(codec);
avcodec_parameters_to_context(videoCodecContext, formatContext->streams[i]->codecpar);
if (avcodec_open2(videoCodecContext, codec, nullptr) < 0) {
std::cerr << "无法打开视频解码器" << std::endl;
avcodec_free_context(&videoCodecContext);
avformat_close_input(&formatContext);
return -1;
}
break;
}
}
// 创建输出文件
FILE* outputFile = fopen(outputFilePath.c_str(), "wb");
if (!outputFile) {
std::cerr << "无法创建输出文件" << std::endl;
avcodec_free_context(&videoCodecContext);
avformat_close_input(&formatContext);
return -1;
}
AVPacket packet;
av_init_packet(&packet);
packet.data = nullptr;
packet.size = 0;
// 读取视频帧并进行解码
while (av_read_frame(formatContext, &packet) >= 0) {
if (packet.stream_index == videoStreamIndex) {
AVFrame* frame = av_frame_alloc();
int response = avcodec_send_packet(videoCodecContext, &packet);
if (response < 0) {
std::cerr << "视频解码错误" << std::endl;
av_frame_free(&frame);
break;
}
while (response >= 0) {
response = avcodec_receive_frame(videoCodecContext, frame);
if (response == AVERROR(EAGAIN) || response == AVERROR_EOF)
break;
else if (response < 0) {
std::cerr << "视频解码错误" << std::endl;
av_frame_free(&frame);
break;
}
// 处理解码后的帧数据
fwrite(frame->data[0], 1, videoCodecContext->width * videoCodecContext->height, outputFile);
av_frame_unref(frame);
}
av_frame_free(&frame);
}
av_packet_unref(&packet);
}
// 清理资源
fclose(outputFile);
avcodec_free_context(&videoCodecContext);
avformat_close_input(&formatContext);
return 0;
}
编译执行:
g++ -o test test.cpp -lavformat -lavcodec -lavutil
./test