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

2023-12-04

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

  • 通过 MP4 进行直播

    我正在从事在线电视服务工作 目标之一是无需任何额外的浏览器插件 Flash 除外 即可播放视频 我决定使用 MP4 因为大多数 HTML5 浏览器和 Flash 作为后备 都支持它 这些视频由 FFMpeg 从服务器上的 ASF 进行转码
  • ffmpeg API h264编码的视频不能在所有平台上播放

    Edit 在之前的版本中 我使用了非常旧的 ffmpeg API 我现在使用最新的库 问题仅略有变化 从 主要 变为 高 我正在使用 ffmpeg C API 在 C 中创建 mp4 视频 我希望生成的视频具有 约束基线 配置文件 以便生成
  • H.264 中的 VBV(视频缓冲验证器)是什么?

    我不明白什么是 VBV 视频缓冲验证器 以及它与 maxrate 有什么关系 当我使用这个命令时 ffmpeg i input mp4 crf 21 maxrate 750k bufsize 750k codec v 0 libx264 s
  • 取自 .mp4 的 H.264 解码器配置记录的格式

    我正在检查从 Android 设备录制的 mp4 视频文件中包含的解码器配置记录 有些设备的解码器配置记录中写入了奇怪或不正确的参数 以下是来自 Galaxy Player 4 0 的示例 该示例是不正确的 DecoderConfigura
  • 无法播放某些视频

    我正在尝试通过我们的服务器在 Android 设备上播放电影 它不是一个媒体服务器 只是一个普通的 Apache 服务器 我们使用相同的 API 来访问 iPhone 上的视频 效果很好 在 Android 设备上 某些视频可以播放 而另一
  • 如何在 Windows 中使用 H264 视频编码器 MFT 编码位图

    我的应用程序对从 GDI 或 DXGI 方法捕获的帧进行编码 目前我正在使用帮助 x264 库进行编码 AFAIK x264 是基于软件的库 我想在 GPU 的帮助下进行编码 这样它可以节省 CPU 周期 并且希望速度也会更快 经过搜索 我
  • 将 FFMPEG 编码为 MPEG-DASH – 或使用关键帧簇的 WebM – 用于 MediaSource API

    我目前正在将视频流发送到 Chrome 以通过 MediaSource API 进行播放 据我了解 MediaSource 仅支持使用 MPEG DASH 编码的 MP4 文件 或具有以关键帧开头的簇的 WebM 文件 否则会引发错误 媒体
  • 使用 ffmpeg 将视频从 .264 转换为 .265 (HEVC)

    我看到关于这个主题的一些问题 但我仍然收到错误 我想要做的就是将库中的视频转换为 HEVC 以便它们占用更少的空间 我试过这个 ffmpeg i input mp4 c v libx265 output mp4 ffmpeg 似乎需要很长时
  • 检测到损坏的 ffmpeg 默认设置

    我在使用 X264 Fourcc 编解码器的 VideoWrite 时遇到 ffmpeg 错误 我已经安装了所有依赖项 如何纠正此问题 我一直在使用的示例代码如下 VideoWriter oVideoWriter path mp4 CV F
  • 为什么 AVSampleBufferDisplayLayer 会失败并出现操作中断 (-11847)?

    我正在使用一个AVSampleBufferDisplayLayer解码并显示从服务器流式传输的 H 264 视频 当我的应用程序进入后台然后返回前台时 解码过程就会搞砸 并且AVSampleBufferDisplayLayer失败 我看到的
  • MFCreateFMPEG4MediaSink 不生成 MSE 兼容的 MP4

    我正在尝试将 H 264 视频源流式传输到网络浏览器 Media Foundation 用于编码分段的 MPEG4 流 MFCreateFMPEG4MediaSink with MFTranscodeContainerType FMPEG4
  • Gstreamer - Android 上的硬件加速视频解码

    我在 Android 手机上通过 RTP UDP 接收视频 但我发现 CPU 使用率非常高 几乎 100 的一个核心都用于解码视频 在高端设备上 视频播放几乎流畅 但在中低端设备上 我几乎每秒无法获得 1 帧 这是一个 H 264 视频流
  • H264解析-切片头检测

    我知道在 h264 中我们可以通过位模式检测 NAL 单元0x000001 是否有等效的方法来检测 NAL 单元中的切片标头 如何处理多切片 NAL 单元 目前我正在使用 h264 的解析代码并获取相应结构中的切片标头 切片头语法在第 36
  • 使用 Android MediaCodec 从摄像头编码 H.264

    我正在尝试让它在 Android 4 1 上运行 使用升级的 Asus Transformer 平板电脑 谢谢亚历克斯对我之前问题的回答 https stackoverflow com a 13420558 726156 我已经能够将一些原
  • 使用 libx264 压缩一组图像时,为什么帧速率会影响最终输出大小?

    我正在使用 ffmpeg 使用 libx264 编解码器将一组图像编码为短延时视频 我的第一次尝试以 30 FPS 的速度进行编码 使用 ffmpeg r 30 pattern type glob i jpg vcodec libx264
  • 我的视频没有关键帧,怎么可能?

    当我在视频上运行以下行时 它仅输出 P 帧和 B 帧 没有 I 帧 ffprobe select streams v show frames show entries frame pict type of csv 00000 MTS 视频怎
  • 非 IDR 图片 NAL 单元 - 0x21 和 0x61 含义

    有谁知道是什么0x21 and 0x61是指在 h 264 编码的视频流中吗 我知道0x01意味着它是一个b frame and 0x41意味着它是一个p frame 我的编码视频给了我两个0x21帧后跟一帧b frame I 21 21
  • 将 H264 视频转换为原始 YUV 格式

    是否可以使用 ffmpeg 从 H264 编码视频创建原始 YUV 视频 我想用 matlab 打开视频并逐帧访问 Luma Cb 和 Cr 分量 是的 您可以 您只需指定像素格式即可 要获取格式的完整列表 ffmpeg pix fmts
  • OpenCV IP 相机应用程序崩溃 [h264 @ 0xxxxx] 访问单元中缺少图片

    我在 cpp 中有一个 opencv 应用程序 它使用 opencv 的简单结构捕获视频流并将其保存到视频文件中 它与我的网络摄像头完美配合 但是 当我运行它从 IP 摄像机捕获流时 它可能会在大约十秒后崩溃 我的编译命令是 g O3 IP
  • 在 MediaFoundation 硬件 MFT 中设置更大的 GOP 大小

    我正在尝试直播通过桌面复制 API 捕获的桌面 H264 编码工作正常 除了桌面复制 API 仅在屏幕发生变化时才传送帧 但视频编码器希望以恒定的帧速率传送帧 因此 当没有触发屏幕更改时 我被迫保存之前的样本 以恒定的速率向编码器提供数据

随机推荐