封装一个OpenH264 编解码H264视频文件的类

下面是一个更新后的代码,增加了 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(&param, 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(&param);
        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 数据。在实际应用中,你可能需要根据你的需求来修改这些代码。

  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

telllong

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值