FFmpeg生成的YUV转HLS流无法被VideoJS播放,求技术排查
解决VideoJS无法播放FFmpeg生成的HLS流问题
看起来你遇到的问题主要集中在本地文件协议的MIME类型识别和FFmpeg HLS参数/时间戳处理这两个核心点,咱们一步步拆解解决:
一、先搞定XML解析错误(最紧急的阻碍)
你看到的XML Parsing Error完全是因为用file://协议打开本地HTML文件导致的——浏览器在本地文件模式下,无法正确识别.m3u8的application/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




