OrangePi3588Media/docs/bugfix/bugfix_hls_keyframe_detection.md

3.0 KiB
Raw Permalink Blame History

HLS 输出文件无法生成问题修复

问题描述

在测试 5 路并发处理时,发现 RTSP 输出正常,但 HLS 输出目录始终为空,没有生成 .ts 分片文件和 .m3u8 播放列表。

现象

  • FFmpeg muxer 初始化成功(日志显示 muxer server ready
  • 编码器正常工作(日志显示 encoded frames=xxx
  • av_interleaved_write_frame 调用成功无错误
  • 但 HLS 目录中始终没有任何文件生成

根本原因分析

1. 关键帧检测错误

src/hw_codec.cppMppEncoder 类中,关键帧检测存在两处问题:

// 错误代码(修复前)
RK_U32 flag = mpp_packet_get_flag(packet);
out.keyframe = (flag & 0x08) != 0;  // 错误的标志位

问题 1标志位错误

  • 代码使用 0x08 检测关键帧
  • MPP_PACKET_FLAG_INTRA 实际值为 0x10 (0x00000010)

问题 2MPP 标志不可靠

  • 实际测试发现 MPP 返回的 flag 值始终为 0
  • 即使对于 IDR 帧MPP 也没有设置关键帧标志

2. HLS 需要关键帧才能写入

FFmpeg 的 HLS muxer 需要接收到关键帧IDR 帧才能开始写入分片。由于所有帧都被标记为非关键帧HLS muxer 无法开始分片,导致没有文件生成。

修复方案

通过解析 H264 NAL 单元类型来检测关键帧:

// 修复后的代码
out.keyframe = (flag & 0x10) != 0;  // MPP_PACKET_FLAG_INTRA = 0x00000010

// Fallback: 通过 NAL 类型检测关键帧
if (!out.keyframe && len >= 5) {
    const uint8_t* d = out.data.data();
    for (size_t i = 0; i + 4 < len && i < 1000; ++i) {
        // 查找 NAL 起始码 00 00 00 01
        if (d[i]==0 && d[i+1]==0 && d[i+2]==0 && d[i+3]==1) {
            uint8_t nal_type = d[i+4] & 0x1F;
            // NAL type 5 = IDR slice (关键帧)
            // NAL type 7 = SPS (序列参数集,通常伴随关键帧)
            if (nal_type == 5 || nal_type == 7) {
                out.keyframe = true;
                break;
            }
        }
    }
}

NAL 类型参考

NAL Type 含义 是否关键帧
1 非 IDR 切片
5 IDR 切片
6 SEI 补充增强信息
7 SPS 序列参数集 (伴随关键帧)
8 PPS 图像参数集

验证结果

修复后验证 5 路并发 HLS 输出:

$ ls -la web/hls/cam1/
-rw-rw-r-- 1 477708 index0.ts
-rw-rw-r-- 1 473384 index1.ts
-rw-rw-r-- 1 522828 index2.ts
-rw-rw-r-- 1 510420 index3.ts
-rw-rw-r-- 1    227 index.m3u8
$ cat web/hls/cam1/index.m3u8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-DISCONTINUITY
#EXTINF:5.933000,
index0.ts
#EXTINF:5.467000,
index1.ts
...
  • 5 路并发 HLS 输出正常
  • 每路生成 .ts 分片文件和 .m3u8 播放列表
  • 分片时长约 5-6 秒,符合配置
  • RTSP 输出同时正常

相关文件

  • src/hw_codec.cpp: MPP 编码器关键帧检测逻辑

修复日期

2026-02-26