You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

FFmpeg生成的YUV转HLS流无法被VideoJS播放,求技术排查

解决VideoJS无法播放FFmpeg生成的HLS流问题

看起来你遇到的问题主要集中在本地文件协议的MIME类型识别FFmpeg HLS参数/时间戳处理这两个核心点,咱们一步步拆解解决:

一、先搞定XML解析错误(最紧急的阻碍)

你看到的XML Parsing Error完全是因为用file://协议打开本地HTML文件导致的——浏览器在本地文件模式下,无法正确识别.m3u8application/x-mpegURL类型,默认把它当成XML去解析了。

解决方法:

用本地HTTP服务器托管你的文件,比如:

  • 用Python启动简易服务器:python -m http.server 8000(Python3)或python -m SimpleHTTPServer 8000(Python2)
  • 然后通过http://localhost:8000/vstream.html访问页面,不要直接双击HTML文件。

这一步应该能直接消除XML解析错误,让浏览器正确识别HLS流的类型。

二、修正FFmpeg的HLS参数与时间戳逻辑

从你的代码看,部分参数和时间戳处理存在兼容性问题,调整后能让生成的流更符合VideoJS(VHS插件)的要求:

1. 完善HLS基础参数

你当前的hls_flags只设置了delete_segments,直播场景下需要追加append_list来让播放列表自动更新;同时建议显式指定HLS版本和分段文件名:

AVDictionary* options = 0;
if (fragmented) {
    if (codecID == AV_CODEC_ID_H264)
        av_dict_set(&options, "hls_segment_type", "fmp4", 0);
    else
        av_dict_set(&options, "hls_segment_type", "mpegts", 0);
    
    av_dict_set(&options, "hls_time", "2.0", 0);
    av_dict_set_int(&options, "hls_list_size", 5, 0);
    // 追加append_list确保播放列表自动更新,添加discont_start处理直播断点
    av_dict_set(&options, "hls_flags", "delete_segments+append_list+discont_start", 0);
    av_dict_set(&options, "hls_version", "7", 0); // 用更高版本支持更多特性
    av_dict_set(&options, "hls_segment_filename", "test%d.ts", 0); // 确保分段命名规则明确
}
int ret = avformat_write_header(formatContext, &options);

2. 修正时间戳赋值逻辑

你手动设置dts = pts的方式不适合带P帧的流(你的GOP是2,存在P帧),应该基于帧的原始时间戳做时间基转换:

// 假设frame已正确设置pts/dts
int ret = avcodec_send_frame(videoStream->codecContext, frame);
if (ret < 0) { /* 错误处理 */ }

AVPacket avPacket;
av_init_packet(&avPacket);
avPacket.stream_index = videoStream->index;

ret = avcodec_receive_packet(videoStream->codecContext, &avPacket);
if (ret == 0) {
    // 把编码器时间基转换为流的时间基
    avPacket.pts = av_rescale_q(avPacket.pts, videoStream->codecContext->time_base, videoStream->time_base);
    avPacket.dts = av_rescale_q(avPacket.dts, videoStream->codecContext->time_base, videoStream->time_base);
    avPacket.duration = av_rescale_q(avPacket.duration, videoStream->codecContext->time_base, videoStream->time_base);
    
    ret = av_interleaved_write_frame(formatContext, &avPacket);
    av_packet_unref(&avPacket);
}

避免手动累加pts,依赖FFmpeg的时间戳自动处理会更可靠。

三、优化VideoJS配置

你的HTML代码可以做小调整,强制使用VHS插件处理HLS,同时适配直播场景:

<script>
var player = videojs('my_video_1', {
  html5: {
    vhs: {
      overrideNative: true, // 强制用VHS处理,不依赖浏览器原生HLS
      enableLowInitialPlaylist: true // 直播场景加快首帧加载
    }
  },
  preload: 'metadata' // 直播场景无需预加载全部内容
});
</script>

另外,那个reloadSourceOnError的警告是插件重复注册导致的,不影响播放,可以忽略。

四、验证生成的流是否标准

用FFmpeg工具验证TS文件和m3u8的合法性:

  • 检查TS文件:ffmpeg -i test190.ts -v error -f null -,无报错则说明TS文件正常
  • 查看m3u8信息:ffprobe test.m3u8,确认流的时间基、编码格式等参数符合预期

按照上面的步骤逐一排查,应该能解决你的播放问题。

内容的提问来源于stack exchange,提问作者charlie

火山引擎 最新活动