HarmonyOS鸿蒙Next中MJPEG网络视频流如何进行实时处理

HarmonyOS鸿蒙Next中MJPEG网络视频流如何进行实时处理 文档显示自API22开始,视频解码器已经可以支持解码MJPEG格式的码流,那么具体如何处理接收到的网络MJPEG视频流进行播放呢,需要对接收到的数据进行手动分帧处理吗?考虑实时性的话是不是需要直接在Native层进行,而且希望加上录制功能,所以解码出的图像数据还需要复制一份送入编码器,请指点一下可以怎么完成。

6 回复

开发者您好,需要对接收到的数据进行手动分帧处理,解码可以使用buffer模式,将解码器的输出结果重新编码,开发者麻烦请详细描述下你们的使用场景,为什么需要解码后再编码?按照伙伴描述这种情况应该算转码,不算录屏。

更多关于HarmonyOS鸿蒙Next中MJPEG网络视频流如何进行实时处理的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


开发者您好,图像渲染的话,开发者可以参考这个文档:https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/graphics/native-window-guidelines.md;还有就是关于视频流的接收,在ArkTS层接收数据,传递到Native层,性能方面不会有太大差异,如果担心,也可以就把接收数据也放到native侧。

很喜欢HarmonyOS的卡片式设计,信息一目了然,操作也更便捷。

是这样的,因为我最主要的目的就是把接收到的视频流录制几十秒下来,需要播放功能主要是为了掌握录制的时机,可以实时预览到画面。buffer模式的话我需要自己处理图像的渲染,我能得到surfuceId,但是不知道如何渲染,我应该怎么得到XComponent的渲染缓冲区提交渲染任务呢?

还有就是关于视频流的接收,我目前是在ArkTS层接收数据,传递到Native层,这样实时性能满足吗,您有什么建议?

下面是我分帧的处理方式,请问这个帧格式有没有什么问题?

void MjpegProcessor::ParseFromBuffer(std::vector<uint8_t>& buffer) {
    const std::vector<uint8_t> SOI = {0xFF, 0xD8};
    const std::vector<uint8_t> EOI = {0xFF, 0xD9};

    size_t offset = 0;
    while (true) {
        // 查找 SOI
        size_t start = FindPattern(buffer, offset, SOI);
        if (start == std::string::npos) {
            // 没有 SOI,丢弃整个缓冲区
            buffer.clear();
            return;
        }

        // 查找 EOI
        size_t end = FindPattern(buffer, start + 2, EOI);
        if (end == std::string::npos) {
            // 只有 SOI 没有 EOI,保留从 SOI 开始的数据,丢弃之前的部分
            if (start > 0) {
                buffer.erase(buffer.begin(), buffer.begin() + start);
            }
            // 等待更多数据
            return;
        }

        // 找到完整帧
        size_t frameLen = (end - start) + 2; // 包含 EOI
        auto frameData = std::make_shared<std::vector<uint8_t>>(
            buffer.begin() + start,
            buffer.begin() + start + frameLen
        );

        int64_t pts = GetCurrentTimestamp();

        // 放入帧队列
        {
            std::lock_guard<std::mutex> lock(frameQueueMutex_);
            frameQueue_.push({std::move(frameData), pts});
        }
        frameQueueCV_.notify_one();

        // 更新偏移,继续下一帧
        offset = start + frameLen;
    }

    // 移除已处理的数据(从开头到 offset)
    if (offset > 0) {
        buffer.erase(buffer.begin(), buffer.begin() + offset);
    }
}

在HarmonyOS Next中,可使用@ohos.multimedia.media的AVDecoder解码MJPEG帧数据,通过createAVDecoder创建MJPEG解码器,逐帧送入bufQueue。解码后输出到OH_NativeBufferPixelMap,再通过ImageComponentXComponent进行渲染。利用@ohos.net.http拉流,解析边界标记后提交帧。推荐使用XComponent+NativeWindow实现低延迟实时显示。

在HarmonyOS Next中处理MJPEG网络视频流

核心流程可分三步走。首先,需要从网络流中手动解析JPEG帧边界,因为MJPEG本质是连续的JPEG图像,通常依靠0xFF 0xD80xFF 0xD9字节标记来分帧。然后,将每一帧完整的JPEG数据直接喂给视频解码器。

考虑到实时录制需求,推荐在Native层(C/C++)使用NDK接口完成全流程,以避免多次数据拷贝的开销。

处理流程如下:

  1. 接收与分帧:在Native层通过网络接收数据,按JPEG帧头尾标记分离出单帧数据。
  2. 解码:创建MJPEG解码器,将已分帧数据通过OH_VideoDecoder_PushInputBuffer送入。从OH_VideoDecoder_FreeOutputBuffer的回调中获取解码后的OH_NativeWindowBuffer
  3. 录制与渲染:实现关键在于数据复用而非拷贝。先利用解码输出的OH_NativeWindowBuffer进行画面渲染。然后,为编码器创建一个编码输入surface,通过OH_VideoEncoder_GetSurface获取,将之前同一块OH_NativeWindowBuffer直接送入编码器surface进行录制编码。这样解码和编码共享同一内存,无需二次拷贝图像数据,能有效保障低延迟。
回到顶部