FFMPEG/DASH-LL 以不同的速率创建音频和视频块;玩家很困惑(404错误)

Posted

技术标签:

【中文标题】FFMPEG/DASH-LL 以不同的速率创建音频和视频块;玩家很困惑(404错误)【英文标题】:FFMPEG/DASH-LL creates audio and video chunks at different rates; player is confused (404 errors) 【发布时间】:2021-05-24 15:28:03 【问题描述】:

我正在尝试从静态文件创建 MPEG-DASH“实时”流,以测试各种低延迟模式。 FFmpeg 中的 DASH muxer 创建了两个 AdaptationSet,一个用于视频块,一个用于音频块。

但是,音频和视频块文件的创建速度不同(应该是这样吗?)。即,这里stream0 是视频块,stream1 是音频块。运行几秒后,webroot目录包含:

chunk-stream0-00001.m4s  chunk-stream1-00001.m4s  
chunk-stream0-00002.m4s  chunk-stream1-00002.m4s  
chunk-stream0-00003.m4s  chunk-stream1-00003.m4s  
chunk-stream0-00004.m4s  chunk-stream1-00004.m4s  
                         chunk-stream1-00005.m4s  
                         chunk-stream1-00006.m4s  
                         chunk-stream1-00007.m4s  
                         chunk-stream1-00008.m4s  
                         chunk-stream1-00009.m4s  
master.mpd  
init-stream0.m4s  
init-stream1.m4s  

流不会在 dash.js 或 shaka-player 上加载(或播放),并且视频块有很多 404 (Not Found) 错误。播放器依次向stream0和stream1请求块,即stream0-001 + stream1-001,然后是stream0-002 + stream1-002,以此类推。

但由于 stream0 仅从 001 到 004,因此在尝试加载 stream0-005 到 009 时会出现很多 404 错误。

让FFmpeg运行一段时间后差距变大。例如,stream0 是 62 到 75,但 stream1 是 174 到 187。此时重新加载播放器页面失败并显示 dash.all.debug.js:15615 [2055][FragmentController] No video bytes to push or stream is inactive. 并显示 404 错误 stream0 chunk 188(尚不存在!)

FFmpeg 命令取自DASH streaming from the top-down:

ffmpeg -re -i /mnt/swdevel/TestStreams/H264/ThreeHourMovie.mp4 \
-c:v libx264 -x264-params keyint=120:scenecut=0 -b:v 1M -c:a copy \
-f dash -dash_segment_type mp4 \
 -seg_duration 2 \
 -target_latency 3 \
 -frag_type duration \
 -frag_duration 0.2 \
 -window_size 10 \
 -extra_window_size 3 \
 -streaming 1 \
 -ldash 1 \
 -use_template 1 \
 -use_timeline 0 \
 -write_prft 1 \
 -fflags +nobuffer+flush_packets \
 -format_options "movflags=+cmaf" \
 -utc_timing_url "/pelican/testPlayers/time.php" \
 master.mpd

dash.js播放器代码非常简单:

const srcUrl = "../ottWebRoot/playerTest/master.mpd"; 

var player = dashjs.MediaPlayer().create();

let autoPlay = false;
player.initialize(document.querySelector("#videoTagId"), srcUrl, autoPlay);

player.updateSettings(

    streaming :
    
        lowLatencyEnabled : true,
        liveDelay : 2,
        jumpGaps : true,
        jumpLargeGaps : true,
        smallGapLimit : 1.5,
    
);

为了在清单中提供UTCTiming 元素,小的time.php URL 从网络服务器返回一个UTC 时间:

<?php
    print gmdate("Y-m-d\TH:i:s\Z");
?>

(它还显示最新 stream1/audio 块的 404 错误,这可能是不同的问题)

我不确定接下来要尝试什么。任何和建议都非常感谢。

编辑我

@Anonymous Coward 更改键间隔的建议改善了很多。 stream0 和 stream1 的块是同步的,并且具有相同的序列号。

但是,在初始页面加载(不按播放)和播放过程中仍然存在许多 404 错误。

我运行watch -n 1 ls -lt &lt;webRootFolder 并与浏览器控制台中的错误并排比较。很难比较,但 看起来 浏览器正在尝试“在播放边缘”获取尚未由 FFmpeg 创建的文件。见下图。

如何指示浏览器在获取边缘块之前稍等片刻?

编辑二

使用shaka-player 代替dash.js 可以正常播放,不会出现404 错误。配置为:

    player.configure(
    
        streaming: 
        
            lowLatencyMode: true,
            inaccurateManifestTolerance: 0,
            rebufferingGoal: 0.1,
        
        
    );

客户

MacOS 10.12 dash.js 最新 3.2.2 Chrome 79、Safari 12、FireFox v?

服务器

Apache 2.4.37 PHP 7.2.4(仅限时间函数) Centos 8

(供参考,这里是FFmpeg生成的mpd文件)

<?xml version="1.0" encoding="utf-8"?>
<MPD xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="urn:mpeg:dash:schema:mpd:2011"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd"
    profiles="urn:mpeg:dash:profile:isoff-live:2011"
    type="dynamic"
    minimumUpdatePeriod="PT500S"
    availabilityStartTime="2021-05-24T14:50:00.263Z"
    publishTime="2021-05-24T15:22:45.335Z"
    timeShiftBufferDepth="PT50.0S"
    maxSegmentDuration="PT2.0S"
    minBufferTime="PT5.0S">
    <ProgramInformation>
    </ProgramInformation>
    <ServiceDescription id="0">
        <Latency target="3000" referenceId="0"/>
    </ServiceDescription>
    <Period id="0" start="PT0.0S">
        <AdaptationSet id="0" contentType="video" startWithSAP="1" segmentAlignment="true" bitstreamSwitching="true" frameRate="24/1" maxWidth="1280" maxHeight="682" par="15:8" lang="und">
            <Resync dT="200000" type="0"/>
            <Representation id="0" mimeType="video/mp4" codecs="avc1.64081f" band   sar="1023:1024">
                <ProducerReferenceTime id="0" inband="true" type="captured" wallClockTime="2021-05-24T14:50:00.263Z" presentationTime="0">
                    <UTCTiming schemeIdUri="urn:mpeg:dash:utc:http-xsdate:2014" value="/pelican/testPlayers/time.php"/>
                </ProducerReferenceTime>
                <Resync dT="5000000" type="1"/>
                <SegmentTemplate timescale="1000000" duration="2000000" availabilityTimeOffset="1.800" availabilityTimeComplete="false" initialization="init-stream$RepresentationID$.m4s" media="chunk-stream$RepresentationID$-$Number%05d$.m4s" startNumber="1">
                </SegmentTemplate>
            </Representation>
        </AdaptationSet>
        <AdaptationSet id="1" contentType="audio" startWithSAP="1" segmentAlignment="true" bitstreamSwitching="true" lang="und">
            <Resync dT="200000" type="0"/>
            <Representation id="1" mimeType="audio/mp4" codecs="mp4a.40.2" band audiosamplingRate="48000">
                <AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2" />
                <ProducerReferenceTime id="1" inband="true" type="captured" wallClockTime="2021-05-24T14:50:00.306Z" presentationTime="0">
                    <UTCTiming schemeIdUri="urn:mpeg:dash:utc:http-xsdate:2014" value="/pelican/testPlayers/time.php"/>
                </ProducerReferenceTime>
                <Resync dT="21333" type="1"/>
                <SegmentTemplate timescale="1000000" duration="2000000" availabilityTimeOffset="1.800" availabilityTimeComplete="false" initialization="init-stream$RepresentationID$.m4s" media="chunk-stream$RepresentationID$-$Number%05d$.m4s" startNumber="1">
                </SegmentTemplate>
            </Representation>
        </AdaptationSet>
    </Period>
    <UTCTiming schemeIdUri="urn:mpeg:dash:utc:http-xsdate:2014" value="/pelican/testPlayers/time.php"/>
</MPD>

【问题讨论】:

如果它在 Shaka 而不是 dash.js 中播放,最好向 dash.js 团队提出一个错误,因为我知道他们在 LL-DASH 上努力工作:github.com/Dash-Industry-Forum/dash.js/issues/new/choose跨度> 【参考方案1】:

输入 ThreeHourMovie.mp4 的帧速率为 24Hz(请参阅 AdaptationSet@frameRate),因此将 keyint 设置为 120 将在 x264 的输出端每 5 秒给出一个 IDR。

您正在指示 DASH 多路复用器(通过 seg_duration)输出和发送信号 2s 段,但这是不可能的,因为段必须以 IDR 开头(如您链接的指南中所述)。所以复用器输出 5s 段,但在 manifest 中发出 2s 信号,这显然是不正确的。

keyint 更改为seg_duration 的正确倍数(即在本例中为keyint=48),它可能会开始工作。

【讨论】:

谢谢!这改善了很多。但是,在获取“边缘”文件时仍然存在 404 错误问题。请参阅主要问题中的 EDIT I。有什么建议吗? 我在播放器中更改了liveDelay,但还是一样...【参考方案2】:

我在 Exoplayer 上观察到了同样的情况。但是,如果我设置值 "-use_timeline 1"问题不存在了。但是,将 use_timeline 设置为 1 时,模板上不会有部分片段。我不确定这是 ffmpeg 的错误。

【讨论】:

以上是关于FFMPEG/DASH-LL 以不同的速率创建音频和视频块;玩家很困惑(404错误)的主要内容,如果未能解决你的问题,请参考以下文章

如何以不同的速度播放音频?

音频编码-G.711

音频兼容方案

MP3/wav 音频文件的持续时间

SoundTouch实现音频变速变调

在连接到网络音频 api 的音频元素上设置播放速率