下面是一个更新后的代码,增加了 H.264 编码的支持。在这个示例中,我使用了 OpenH264 的 ISVCEncoder
接口进行编码。请确保在项目中正确链接 OpenH264 库,并根据你的项目需要调整代码。
#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
#include <wels/codec_api.h>
class H264Codec {
public:
H264Codec() : encoder(nullptr), decoder(nullptr), vcm(nullptr) {
// 初始化 OpenH264 编码器
if (WelsCreateSVCEncoder(&encoder) != 0 || !encoder) {
std::cerr << "Failed to initialize OpenH264 encoder." << std::endl;
}
// 初始化 OpenH264 解码器
if (WelsCreateDecoder(&decoder) != 0 || !decoder) {
std::cerr << "Failed to initialize OpenH264 decoder." << std::endl;
}
}
~H264Codec() {
// 销毁编码器
if (encoder) {
WelsDestroySVCEncoder(encoder);
encoder = nullptr;
}
// 销毁解码器
if (decoder) {
WelsDestroyDecoder(decoder);
decoder = nullptr;
}
// 释放解码后的图像数据
if (vcm) {
WelsFreeMem(vcm);
vcm = nullptr;
}
}
bool encodeFile(const std::string& inputFileName, const std::string& outputFileName) {
std::ifstream inputFile(inputFileName, std::ios::binary);
if (!inputFile.is_open()) {
std::cerr << "Failed to open input file: " << inputFileName << std::endl;
return false;
}
std::ofstream outputFile(outputFileName, std::ios::binary);
if (!outputFile.is_open()) {
std::cerr << "Failed to open output file: " << outputFileName << std::endl;
return false;
}
while (!inputFile.eof()) {
// 读取 YUV 数据
uint8_t yuvFrame[1024];
inputFile.read(reinterpret_cast<char*>(yuvFrame), sizeof(yuvFrame));
size_t dataSize = static_cast<size_t>(inputFile.gcount());
if (dataSize > 0) {
// 编码 YUV 数据
encodeFrame(yuvFrame, dataSize);
// 获取编码后的 H.264 帧
getEncodedFrame(outputFile);
}
}
return true;
}
bool decodeFile(const std::string& inputFileName, const std::string& outputFileName) {
std::ifstream inputFile(inputFileName, std::ios::binary);
if (!inputFile.is_open()) {
std::cerr << "Failed to open input file: " << inputFileName << std::endl;
return false;
}
std::ofstream outputFile(outputFileName, std::ios::binary);
if (!outputFile.is_open()) {
std::cerr << "Failed to open output file: " << outputFileName << std::endl;
return false;
}
while (!inputFile.eof()) {
// 读取 H.264 数据
uint8_t nalUnit[1024];
inputFile.read(reinterpret_cast<char*>(nalUnit), sizeof(nalUnit));
size_t dataSize = static_cast<size_t>(inputFile.gcount());
if (dataSize > 0) {
// 解码 H.264 数据
decodeNALU(nalUnit, dataSize);
// 获取解码后的图像
getDecodedFrame(outputFile);
}
}
return true;
}
private:
ISVCEncoder* encoder;
ISVCDecoder* decoder;
SBufferInfo bufferInfo;
uint8_t* vcm;
void encodeFrame(const uint8_t* yuvFrame, size_t dataSize) {
SEncParamBase param;
memset(¶m, 0, sizeof(SEncParamBase));
param.iUsageType = CAMERA_VIDEO_REAL_TIME;
param.iPicWidth = 640;
param.iPicHeight = 480;
param.iTargetBitrate = 500000;
param.iRCMode = RC_QUALITY_MODE;
int ret = encoder->Initialize(¶m);
if (ret != 0) {
std::cerr << "Failed to initialize encoder. Error code: " << ret << std::endl;
return;
}
SSourcePicture pic;
memset(&pic, 0, sizeof(SSourcePicture));
pic.iPicWidth = 640;
pic.iPicHeight = 480;
pic.iColorFormat = videoFormatI420;
pic.iStride[0] = 640;
pic.iStride[1] = 320;
pic.iStride[2] = 320;
pic.pData[0] = const_cast<uint8_t*>(yuvFrame);
pic.pData[1] = const_cast<uint8_t*>(yuvFrame + 640 * 480);
pic.pData[2] = const_cast<uint8_t*>(yuvFrame + 640 * 480 + 320 * 240);
SFrameBSInfo info;
memset(&info, 0, sizeof(SFrameBSInfo));
ret = encoder->EncodeFrame(&pic, &info);
if (ret != 0) {
std::cerr << "Failed to encode frame. Error code: " << ret << std::endl;
return;
}
// 写入编码后的数据
std::ofstream encodedFile("encoded.h264", std::ios::binary | std::ios::app);
encodedFile.write(reinterpret_cast<char*>(info.sLayerInfo[0].pBsBuf), info.sLayerInfo[0].iFrameSizeInBytes);
encodedFile.close();
}
void decodeNALU(const uint8_t* nalUnit, size_t dataSize) {
SDecodingParam decParam = {};
int32_t ret = decoder->DecodeFrame2(nalUnit, static_cast<int32_t>(dataSize), &vcm, &decParam);
if (ret != 0) {
std::cerr << "Failed to decode frame. Error code: " << ret << std::endl;
}
}
void getDecodedFrame(std::ofstream& outputFile) {
if (vcm) {
// 获取解码后的图像数据
outputFile.write(reinterpret_cast<char*>(vcm), bufferInfo.iBufferStatus);
// 释放解码后的图像数据
WelsFreeMem(vcm);
vcm = nullptr;
}
}
};
int main() {
H264Codec h264Codec;
// 指定输入 YUV 文件和输出 H.264 文件
std::string inputYuvFile = "input.yuv";
std::string outputH264File = "output.h264";
// 编码 YUV 文件为 H.264 文件
if (h264Codec.encodeFile(inputYuvFile, outputH264File)) {
std::cout << "Encoding successful. Output written to " << outputH264File << std::endl;
} else {
std::cerr << "Encoding failed." << std::endl;
}
// 解码 H.264 文件为 YUV 文件
std::string inputH264File = "encoded.h264";
std::string outputYuvFile = "decoded.yuv";
if (h264Codec.decodeFile(inputH264File, outputYuvFile)) {
std::cout << "Decoding successful. Output written to " << outputYuvFile << std::endl;
} else {
std::cerr << "Decoding failed." << std::endl;
}
return 0;
}
这个示例中,encodeFile
函数用于读取 YUV 数据并进行 H.264 编码,decodeFile
函数用于读取 H.264 数据并进行 H.264 解码。请注意,这里我创建了一个 encoded.h264
文件,用于存储编码后的 H.264 数据。在实际应用中,你可能需要根据你的需求来修改这些代码。