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

下面是一个更新后的代码,增加了 H.264 编码的支持。在这个示例中,我使用了 OpenH264 的 ISVCEncoder 接口进行编码。请确保在项目中正确链接 OpenH264 库,并根据你的项目需要调整代码。

#include 
#include 
#include 
#include 
#include 

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(yuvFrame), sizeof(yuvFrame));
            size_t dataSize = static_cast(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(nalUnit), sizeof(nalUnit));
            size_t dataSize = static_cast(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(yuvFrame);
        pic.pData[1] = const_cast(yuvFrame + 640 * 480);
        pic.pData[2] = const_cast(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(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(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(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 数据。在实际应用中,你可能需要根据你的需求来修改这些代码。

你可能感兴趣的:(音视频开发,编解码,h264,h.264)