Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DASH: Support convert RTMP/WebRTC to MPEG-DASH #299

Closed
winlinvip opened this issue May 15, 2015 · 27 comments · Fixed by #3240
Closed

DASH: Support convert RTMP/WebRTC to MPEG-DASH #299

winlinvip opened this issue May 15, 2015 · 27 comments · Fixed by #3240
Assignees
Labels
Feature It's a new feature. TransByAI Translated by AI/GPT.
Milestone

Comments

@winlinvip
Copy link
Member

winlinvip commented May 15, 2015

Usage

Make sure your SRS version is SRS 5.0.96+.

Build SRS and run:

./configure && make && ./objs/srs -c conf/dash.conf 

Publish by FFmpeg:

ffmpeg -re -i doc/source.flv -c copy -f flv rtmp://localhost/live/livestream

Play by

@winlinvip winlinvip added the Feature It's a new feature. label May 15, 2015
@winlinvip winlinvip added this to the srs 3.0 release milestone May 15, 2015
@winlinvip
Copy link
Member Author

@winlinvip winlinvip changed the title Delivery MPEG-DASH Migrate from NGINX-RTMP, Delivery MPEG-DASH Aug 23, 2015
@winlinvip winlinvip modified the milestones: srs 3.0 release, srs 4.0 release Aug 23, 2015
@winlinvip winlinvip modified the milestones: srs 4.0 release, srs 3.0 release Sep 11, 2015
@winlinvip
Copy link
Member Author

winlinvip commented Jan 11, 2017

DASH is becoming more and more popular in some countries.

@winlinvip
Copy link
Member Author

winlinvip commented Jan 24, 2017

SRS will support MPEG-DASH in this Chinese New Year holiday.

@winlinvip
Copy link
Member Author

winlinvip commented Jan 24, 2017

DASH in wikipedia. The segment of DASH can use MP4 or TS file. The DASH players include ExoPlayer for Android, MSE for H5(js), THEOPlayer, VIDEOJS, dash.js and dashif or dash industry forum. The Helix(RealNetwork), NGINX-RTMP and WOWZA servers already support transmux RTMP to DASH.

Remark: The VLC can't play DASH.

The dashif show us a example: http://dash.edgesuite.net/dash264/TestCases/1a/netflix/exMPD_BIP_TC1.mpd
Or mirror on ossrs.net: http://ossrs.net/dash264/TestCases/1a/netflix/exMPD_BIP_TC1.mpd
The dash.js mirror on ossrs.net: http://ossrs.net/dash.js/samples/dash-if-reference-player/

DASH HelloWorld, Use dash.js player to play:

  1. Elephent Dream: http://ossrs.net/dash264/TestCases/1a/netflix/exMPD_BIP_TC1.mpd
  2. 4K test: http://ossrs.net/akamai/streamroot/050714/Spring_4Ktest.mpd

Most of these demos use mp4 format, not ts.

ISOM(ISO base media file): doc/ISO_IEC_14496-12-base-format-2012.pdf
DASH: doc/ISO_IEC_23009-1-DASH-2012.pdf
MP42(MP4 file format): doc/ISO_IEC_14496-14-MP4-2003.pdf
ESDS/ES_Descriptor: doc/ISO_IEC_14496-1-System-2010.pdf
M4V by Apple: qt

Remark: The mp4 14496-14-2003 is brand mp42, while FFMPEG use isom which compatible with mp41.

Part 1: Systems
Part 2: Visual
Part 3: Audio
Part 4: Conformance testing
Part 5: Reference software
Part 6: Delivery Multimedia Integration Framework (DMIF)
Part 7: Optimized reference software for coding of audio-visual objects 
Part 8: Carriage of ISO/IEC 14496 contents over IP networks
Part 9: Reference hardware description
Part 10: Advanced Video Coding (AVC)
Part 11: Scene description and application engine
Part 12: ISO base media file format
Part 13: Intellectual Property Management and Protection (IPMP) extensions 
Part 14: MP4 file format
Part 15: Advanced Video Coding (AVC) file format
Part 16: Animation Framework eXtension (AFX)

@mbeacom
Copy link

mbeacom commented Jan 24, 2017

https://github.com/Bilibili/ijkplayer also supports dash and runs on iOS and Android, but offers a host of other functionality like RTMP seek.

winlinvip added a commit that referenced this issue Jan 26, 2017
winlinvip added a commit that referenced this issue Jan 26, 2017
@winlinvip
Copy link
Member Author

winlinvip commented Jan 27, 2017

We must fix #738 to support mp4 muxer first.

@winlinvip
Copy link
Member Author

winlinvip commented Jan 28, 2017

http://ossrs.net/dash264/TestCases/1a/netflix/exMPD_BIP_TC1.mpd
* 150kbps: ElephantsDream_H264BPL30_0100.264.dash
* 250kbps: ElephantsDream_H264BPL30_0175.264.dash
* 350kbps: ElephantsDream_H264BPL30_0250.264.dash
* 750kbps: ElephantsDream_H264BPL30_0500.264.dash
Use fmp4(fragmented mp4) for each stream is a big mp4 file.
http://ossrs.net/akamai/streamroot/050714/Spring_4Ktest.mpd
* 2.8mbps: Spring_3000k_track1_dashinit.mp4
* 4.8mbps: Spring_5000k_track1_dashinit.mp4
* 7.3mbps: Spring_7500k_track1_dashinit.mp4
* 9.6mbps: Spring_10000k_track1_dashinit.mp4
* 14.6mbps: Spring_15000k_track1_dashinit.mp4
* 19.6mbps: Spring_20000k_track1_dashinit.mp4
Each mp4 is big file using fmp4 format.
http://ossrs.net/dash/streams/gpac/mp4-main-multi-mpd-AV-NBS.mpd
mp4-main-multi-h264bl_low-.mp4 plus mp4-main-multi-h264bl_low-{1-60}.m4s
mp4-main-multi-h264bl_hd-.mp4 plus mp4-main-multi-h264bl_hd-{1-60}.m4s
mp4-main-multi-h264bl_full-.mp4 plus mp4-main-multi-h264bl_full-{1-60}.m4s
Each stream has a mp4 header file, and m4s stream files.

I found DASH use brand iso2 compatible with isom and dash, and use fmp4(fragmented mp4):
dash

While FFMPEG use brand isom compatible with iso2:
ffmpeg

The 'isom' requirements are a subset of the 'iso2' requirements.

I must support isom for general mp4 format, then support dvr to mp4 file, then support fmp4, finally support dash over fmp4.

TRANS_BY_GPT3

@winlinvip
Copy link
Member Author

winlinvip commented Feb 10, 2017

Besides general mp4 format is fine(see #738), we can focus to fmp4 now.

About the DASH MPD:

  1. Multiple CDN fault-tolenrance backup:
G.2 Example for ISO Base media file format Live profile
ISO_IEC_23009-1-DASH-2012.pdf, page 126
<BaseURL>http://cdn1.example.com/</BaseURL>
<BaseURL>http://cdn2.example.com/</BaseURL>

Table 3 - Semantics of MPD element.
BaseURL 0...N specifies a Base URL that can be used for reference resolution and 
alternative URL selection. For more details refer to the description in 5.6.

5.6.5 Alternative base URLs
If alternative base URLs are provided through the BaseURL element at any level, identical 
Segments shall be accessible at multiple locations. In the absence of other criteria, the 
DASH Client may use the first BaseURL element as the "base URI". The DASH Client may use base URLs provided in the BaseURL element as the "base URI" and may implement any suitable action.
algorithm to determine which URLs it uses for requests.
  1. Timeshift:
G.2 Example for ISO Base media file format Live profile
ISO_IEC_23009-1-DASH-2012.pdf, page 126
timeShiftBufferDepth="PT30M"

Table 3 - Meaning of MPD element.
@timeShiftBufferDepth specifies the duration of the time shifting buffer that is guaranteed 
to be available for a Media Presentation with type 'dynamic'. When not present, the value is 
Infinite. This attribute value is not applicable if the type attribute is equal to 'static'.

To setup the playhead when startup:

G.2 Example for ISO Base media file format Live profile
ISO_IEC_23009-1-DASH-2012.pdf, page 126
availabilityStartTime="2011-12-25T12:30:00"

At the time this MPD was fetched, 432 Segments of the dynamic presentation were available 
so the wall clock time must have been approximately 2011-12-25T12:44:24 UTC.

<SegmentTimeline> <S t="0" d="180180" r="432"/>

dash-live

TRANS_BY_GPT3

@winlinvip
Copy link
Member Author

winlinvip commented Jun 4, 2017

Use SRS3+, config is:

listen              1935;
max_connections     1000;
daemon              off;
srs_log_tank        console;
http_server {
    enabled         on;
    listen          8080;
}
vhost __defaultVhost__ {
    ingest livestream {
        enabled      on;
        input {
            type    file;
            url     ./doc/source.200kbps.768x320.flv;
        }
        ffmpeg      ./objs/ffmpeg/bin/ffmpeg;
        engine {
            enabled          off;
            output          rtmp://127.0.0.1:[port]/live?vhost=[vhost]/livestream;
        }
    }
    dash  {
        enabled             on;
        dash_fragment       30;
        dash_update_period  150;
        dash_timeshift      300;
    }
}

Use player: http://ossrs.net/dash.js/samples/dash-if-reference-player/
Play url: http://localhost:8080/live/livestream.mpd

Or open the player: http://ossrs.net/dash.js/samples/dash-if-reference-player/?url=http://localhost:8080/live/livestream.mpd

The player reports the error, but it's very hard to trace it:

Seeking to: 1496576739 
Top qualityaudio index has changed from undefined to 0 
AbrController (audio) stay on 0/0 (buffer: 0) 
Getting the request for audio time : 1496576739 
Index for audio time 1496576739 is 498858912 
SegmentTemplate: 1496576736 / Infinity 
Video Element Error: MEDIA_ERR_DECODE 
[object MediaError] 
Schedule controller stopping for video 
Schedule controller stopping for audio 

winlinvip added a commit that referenced this issue Jun 4, 2017
@winlinvip
Copy link
Member Author

I release this feature as Experimental, util anyone who can fix the issue of player(or indicates what happened and how to fix the fmp4 encoder)

@winlinvip
Copy link
Member Author

winlinvip commented Dec 27, 2019

Live example from FFMPEG#7382:

https://livesim.dashif.org/livesim/periods_60/continuous_1/testpic_2s/Manifest.mpd

https://livesim.dashif.org/livesim/sts_1577417238/sid_4a6eb645/periods_60/continuous_1/testpic_2s/Manifest.mpd

<?xml version="1.0" encoding="utf-8"?>
<MPD availabilityStartTime="1970-01-01T00:00:00Z" id="Config part of url maybe?" maxSegmentDuration="PT2S" minBufferTime="PT2S" minimumUpdatePeriod="PT25S" profiles="urn:mpeg:dash:profile:isoff-live:2011,http://dashif.org/guidelines/dash-if-simple" publishTime="2019-12-27T03:27:37Z" timeShiftBufferDepth="PT5M" type="dynamic" ns1:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:ns1="http://www.w3.org/2001/XMLSchema-instance">
   <ProgramInformation>
      <Title>Media Presentation Description from DASH-IF live simulator</Title>
   </ProgramInformation>
   <BaseURL>https://livesim.dashif.org/livesim/sts_1577417238/sid_4a6eb645/periods_60/continuous_1/testpic_2s/</BaseURL>
<Period id="p26290282" start="PT1577416920S">
      <AdaptationSet contentType="audio" lang="eng" mimeType="audio/mp4" segmentAlignment="true" startWithSAP="1">
         <Role schemeIdUri="urn:mpeg:dash:role:2011" value="main" />
         <SegmentTemplate duration="2" initialization="$RepresentationID$/init.mp4" media="$RepresentationID$/$Number$.m4s" presentationTimeOffset="1577416920" startNumber="788708460" />
         <Representation audioSamplingRate="48000" bandwidth="48000" codecs="mp4a.40.2" id="A48">
            <AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2" />
         </Representation>
      </AdaptationSet>
      <AdaptationSet contentType="video" maxFrameRate="60/2" maxHeight="360" maxWidth="640" mimeType="video/mp4" minHeight="360" minWidth="640" par="16:9" segmentAlignment="true" startWithSAP="1">
         <Role schemeIdUri="urn:mpeg:dash:role:2011" value="main" />
         <SegmentTemplate duration="2" initialization="$RepresentationID$/init.mp4" media="$RepresentationID$/$Number$.m4s" presentationTimeOffset="1577416920" startNumber="788708460" />
         <Representation bandwidth="300000" codecs="avc1.64001e" frameRate="60/2" height="360" id="V300" sar="1:1" width="640" />
      </AdaptationSet>
   </Period>
<Period id="p26290283" start="PT1577416980S">
      <AdaptationSet contentType="audio" lang="eng" mimeType="audio/mp4" segmentAlignment="true" startWithSAP="1">
         <SupplementalProperty schemeIdUri="urn:mpeg:dash:period_continuity:2014" value="p26290282" />
<Role schemeIdUri="urn:mpeg:dash:role:2011" value="main" />
         <SegmentTemplate duration="2" initialization="$RepresentationID$/init.mp4" media="$RepresentationID$/$Number$.m4s" presentationTimeOffset="1577416980" startNumber="788708490" />
         <Representation audioSamplingRate="48000" bandwidth="48000" codecs="mp4a.40.2" id="A48">
            <AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2" />
         </Representation>
      </AdaptationSet>
      <AdaptationSet contentType="video" maxFrameRate="60/2" maxHeight="360" maxWidth="640" mimeType="video/mp4" minHeight="360" minWidth="640" par="16:9" segmentAlignment="true" startWithSAP="1">
         <SupplementalProperty schemeIdUri="urn:mpeg:dash:period_continuity:2014" value="p26290282" />
<Role schemeIdUri="urn:mpeg:dash:role:2011" value="main" />
         <SegmentTemplate duration="2" initialization="$RepresentationID$/init.mp4" media="$RepresentationID$/$Number$.m4s" presentationTimeOffset="1577416980" startNumber="788708490" />
         <Representation bandwidth="300000" codecs="avc1.64001e" frameRate="60/2" height="360" id="V300" sar="1:1" width="640" />
      </AdaptationSet>
   </Period>
<Period id="p26290284" start="PT1577417040S">
      <AdaptationSet contentType="audio" lang="eng" mimeType="audio/mp4" segmentAlignment="true" startWithSAP="1">
         <SupplementalProperty schemeIdUri="urn:mpeg:dash:period_continuity:2014" value="p26290283" />
<Role schemeIdUri="urn:mpeg:dash:role:2011" value="main" />
         <SegmentTemplate duration="2" initialization="$RepresentationID$/init.mp4" media="$RepresentationID$/$Number$.m4s" presentationTimeOffset="1577417040" startNumber="788708520" />
         <Representation audioSamplingRate="48000" bandwidth="48000" codecs="mp4a.40.2" id="A48">
            <AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2" />
         </Representation>
      </AdaptationSet>
      <AdaptationSet contentType="video" maxFrameRate="60/2" maxHeight="360" maxWidth="640" mimeType="video/mp4" minHeight="360" minWidth="640" par="16:9" segmentAlignment="true" startWithSAP="1">
         <SupplementalProperty schemeIdUri="urn:mpeg:dash:period_continuity:2014" value="p26290283" />
<Role schemeIdUri="urn:mpeg:dash:role:2011" value="main" />
         <SegmentTemplate duration="2" initialization="$RepresentationID$/init.mp4" media="$RepresentationID$/$Number$.m4s" presentationTimeOffset="1577417040" startNumber="788708520" />
         <Representation bandwidth="300000" codecs="avc1.64001e" frameRate="60/2" height="360" id="V300" sar="1:1" width="640" />
      </AdaptationSet>
   </Period>
<Period id="p26290285" start="PT1577417100S">
      <AdaptationSet contentType="audio" lang="eng" mimeType="audio/mp4" segmentAlignment="true" startWithSAP="1">
         <SupplementalProperty schemeIdUri="urn:mpeg:dash:period_continuity:2014" value="p26290284" />
<Role schemeIdUri="urn:mpeg:dash:role:2011" value="main" />
         <SegmentTemplate duration="2" initialization="$RepresentationID$/init.mp4" media="$RepresentationID$/$Number$.m4s" presentationTimeOffset="1577417100" startNumber="788708550" />
         <Representation audioSamplingRate="48000" bandwidth="48000" codecs="mp4a.40.2" id="A48">
            <AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2" />
         </Representation>
      </AdaptationSet>
      <AdaptationSet contentType="video" maxFrameRate="60/2" maxHeight="360" maxWidth="640" mimeType="video/mp4" minHeight="360" minWidth="640" par="16:9" segmentAlignment="true" startWithSAP="1">
         <SupplementalProperty schemeIdUri="urn:mpeg:dash:period_continuity:2014" value="p26290284" />
<Role schemeIdUri="urn:mpeg:dash:role:2011" value="main" />
         <SegmentTemplate duration="2" initialization="$RepresentationID$/init.mp4" media="$RepresentationID$/$Number$.m4s" presentationTimeOffset="1577417100" startNumber="788708550" />
         <Representation bandwidth="300000" codecs="avc1.64001e" frameRate="60/2" height="360" id="V300" sar="1:1" width="640" />
      </AdaptationSet>
   </Period>
<Period id="p26290286" start="PT1577417160S">
      <AdaptationSet contentType="audio" lang="eng" mimeType="audio/mp4" segmentAlignment="true" startWithSAP="1">
         <SupplementalProperty schemeIdUri="urn:mpeg:dash:period_continuity:2014" value="p26290285" />
<Role schemeIdUri="urn:mpeg:dash:role:2011" value="main" />
         <SegmentTemplate duration="2" initialization="$RepresentationID$/init.mp4" media="$RepresentationID$/$Number$.m4s" presentationTimeOffset="1577417160" startNumber="788708580" />
         <Representation audioSamplingRate="48000" bandwidth="48000" codecs="mp4a.40.2" id="A48">
            <AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2" />
         </Representation>
      </AdaptationSet>
      <AdaptationSet contentType="video" maxFrameRate="60/2" maxHeight="360" maxWidth="640" mimeType="video/mp4" minHeight="360" minWidth="640" par="16:9" segmentAlignment="true" startWithSAP="1">
         <SupplementalProperty schemeIdUri="urn:mpeg:dash:period_continuity:2014" value="p26290285" />
<Role schemeIdUri="urn:mpeg:dash:role:2011" value="main" />
         <SegmentTemplate duration="2" initialization="$RepresentationID$/init.mp4" media="$RepresentationID$/$Number$.m4s" presentationTimeOffset="1577417160" startNumber="788708580" />
         <Representation bandwidth="300000" codecs="avc1.64001e" frameRate="60/2" height="360" id="V300" sar="1:1" width="640" />
      </AdaptationSet>
   </Period>
<Period id="p26290287" start="PT1577417220S">
      <AdaptationSet contentType="audio" lang="eng" mimeType="audio/mp4" segmentAlignment="true" startWithSAP="1">
         <SupplementalProperty schemeIdUri="urn:mpeg:dash:period_continuity:2014" value="p26290286" />
<Role schemeIdUri="urn:mpeg:dash:role:2011" value="main" />
         <SegmentTemplate duration="2" initialization="$RepresentationID$/init.mp4" media="$RepresentationID$/$Number$.m4s" presentationTimeOffset="1577417220" startNumber="788708610" />
         <Representation audioSamplingRate="48000" bandwidth="48000" codecs="mp4a.40.2" id="A48">
            <AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2" />
         </Representation>
      </AdaptationSet>
      <AdaptationSet contentType="video" maxFrameRate="60/2" maxHeight="360" maxWidth="640" mimeType="video/mp4" minHeight="360" minWidth="640" par="16:9" segmentAlignment="true" startWithSAP="1">
         <SupplementalProperty schemeIdUri="urn:mpeg:dash:period_continuity:2014" value="p26290286" />
<Role schemeIdUri="urn:mpeg:dash:role:2011" value="main" />
         <SegmentTemplate duration="2" initialization="$RepresentationID$/init.mp4" media="$RepresentationID$/$Number$.m4s" presentationTimeOffset="1577417220" startNumber="788708610" />
         <Representation bandwidth="300000" codecs="avc1.64001e" frameRate="60/2" height="360" id="V300" sar="1:1" width="640" />
      </AdaptationSet>
   </Period>
<Period id="p26290288" start="PT1577417280S">
      <AdaptationSet contentType="audio" lang="eng" mimeType="audio/mp4" segmentAlignment="true" startWithSAP="1">
         <SupplementalProperty schemeIdUri="urn:mpeg:dash:period_continuity:2014" value="p26290287" />
<Role schemeIdUri="urn:mpeg:dash:role:2011" value="main" />
         <SegmentTemplate duration="2" initialization="$RepresentationID$/init.mp4" media="$RepresentationID$/$Number$.m4s" presentationTimeOffset="1577417280" startNumber="788708640" />
         <Representation audioSamplingRate="48000" bandwidth="48000" codecs="mp4a.40.2" id="A48">
            <AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2" />
         </Representation>
      </AdaptationSet>
      <AdaptationSet contentType="video" maxFrameRate="60/2" maxHeight="360" maxWidth="640" mimeType="video/mp4" minHeight="360" minWidth="640" par="16:9" segmentAlignment="true" startWithSAP="1">
         <SupplementalProperty schemeIdUri="urn:mpeg:dash:period_continuity:2014" value="p26290287" />
<Role schemeIdUri="urn:mpeg:dash:role:2011" value="main" />
         <SegmentTemplate duration="2" initialization="$RepresentationID$/init.mp4" media="$RepresentationID$/$Number$.m4s" presentationTimeOffset="1577417280" startNumber="788708640" />
         <Representation bandwidth="300000" codecs="avc1.64001e" frameRate="60/2" height="360" id="V300" sar="1:1" width="640" />
      </AdaptationSet>
   </Period>
</MPD>

@winlinvip
Copy link
Member Author

Live stream:

https://livesim.dashif.org/livesim/testpic_2s/Manifest.mpd

https://livesim.dashif.org/livesim/sts_1577417658/sid_6953a24f/testpic_2s/Manifest.mpd

<?xml version="1.0" encoding="utf-8"?>
<MPD availabilityStartTime="1970-01-01T00:00:00Z" id="Config part of url maybe?" maxSegmentDuration="PT2S" minBufferTime="PT2S" minimumUpdatePeriod="P100Y" profiles="urn:mpeg:dash:profile:isoff-live:2011,http://dashif.org/guidelines/dash-if-simple" publishTime="2019-12-27T03:34:28Z" timeShiftBufferDepth="PT5M" type="dynamic" ns1:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:ns1="http://www.w3.org/2001/XMLSchema-instance">
   <ProgramInformation>
      <Title>Media Presentation Description from DASH-IF live simulator</Title>
   </ProgramInformation>
   <BaseURL>https://livesim.dashif.org/livesim/sts_1577417658/sid_6953a24f/testpic_2s/</BaseURL>
<Period id="p0" start="PT0S">
      <AdaptationSet contentType="audio" lang="eng" mimeType="audio/mp4" segmentAlignment="true" startWithSAP="1">
         <Role schemeIdUri="urn:mpeg:dash:role:2011" value="main" />
         <SegmentTemplate duration="2" initialization="$RepresentationID$/init.mp4" media="$RepresentationID$/$Number$.m4s" startNumber="0" />
         <Representation audioSamplingRate="48000" bandwidth="48000" codecs="mp4a.40.2" id="A48">
            <AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2" />
         </Representation>
      </AdaptationSet>
      <AdaptationSet contentType="video" maxFrameRate="60/2" maxHeight="360" maxWidth="640" mimeType="video/mp4" minHeight="360" minWidth="640" par="16:9" segmentAlignment="true" startWithSAP="1">
         <Role schemeIdUri="urn:mpeg:dash:role:2011" value="main" />
         <SegmentTemplate duration="2" initialization="$RepresentationID$/init.mp4" media="$RepresentationID$/$Number$.m4s" startNumber="0" />
         <Representation bandwidth="300000" codecs="avc1.64001e" frameRate="60/2" height="360" id="V300" sar="1:1" width="640" />
      </AdaptationSet>
   </Period>
</MPD>

@winlinvip
Copy link
Member Author

winlinvip commented Dec 27, 2019

Use online mp4box to parse fmp4/m4s: http://download.tsi.telecom-paristech.fr/gpac/mp4box.js/filereader.html

image

image

@winlinvip
Copy link
Member Author

https://livesim.dashif.org/livesim/mup_30/testpic_2s/Manifest.mpd

https://livesim.dashif.org/livesim/sts_1577438849/sid_24086ba5/mup_30/testpic_2s/Manifest.mpd

<?xml version="1.0" encoding="utf-8"?>
<MPD availabilityStartTime="1970-01-01T00:00:00Z" id="Config part of url maybe?" maxSegmentDuration="PT2S" minBufferTime="PT2S" minimumUpdatePeriod="PT30S" profiles="urn:mpeg:dash:profile:isoff-live:2011,http://dashif.org/guidelines/dash-if-simple" publishTime="2019-12-27T09:27:48Z" timeShiftBufferDepth="PT5M" type="dynamic" ns1:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:ns1="http://www.w3.org/2001/XMLSchema-instance">
   <ProgramInformation>
      <Title>Media Presentation Description from DASH-IF live simulator</Title>
   </ProgramInformation>
   <BaseURL>https://livesim.dashif.org/livesim/sts_1577438849/sid_24086ba5/mup_30/testpic_2s/</BaseURL>
<Period id="p0" start="PT0S">
      <AdaptationSet contentType="audio" lang="eng" mimeType="audio/mp4" segmentAlignment="true" startWithSAP="1">
         <Role schemeIdUri="urn:mpeg:dash:role:2011" value="main" />
         <SegmentTemplate duration="2" initialization="$RepresentationID$/init.mp4" media="$RepresentationID$/$Number$.m4s" startNumber="0" />
         <Representation audioSamplingRate="48000" bandwidth="48000" codecs="mp4a.40.2" id="A48">
            <AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2" />
         </Representation>
      </AdaptationSet>
      <AdaptationSet contentType="video" maxFrameRate="60/2" maxHeight="360" maxWidth="640" mimeType="video/mp4" minHeight="360" minWidth="640" par="16:9" segmentAlignment="true" startWithSAP="1">
         <Role schemeIdUri="urn:mpeg:dash:role:2011" value="main" />
         <SegmentTemplate duration="2" initialization="$RepresentationID$/init.mp4" media="$RepresentationID$/$Number$.m4s" startNumber="0" />
         <Representation bandwidth="300000" codecs="avc1.64001e" frameRate="60/2" height="360" id="V300" sar="1:1" width="640" />
      </AdaptationSet>
   </Period>
</MPD>

@winlinvip
Copy link
Member Author

winlinvip commented Dec 27, 2019

The main reason for the DASH failure before discovery in SRS is the data offset of the turn box, which actually only includes the length of the moof and mdat headers.

Thanks to Master Brother's FFMPEG, for example, the segments generated by ffmpeg:

09d8d5e3210 ffmpeg]# /tmp/srs/trunk/objs/srs_mp4_parser chunk-stream0-00002.m4s 
    styp, 24B, brands:msdh,0(msdh,msix)
    sidx, 52B, v1, flags=0, refs#1, TBN=12800, ePTS=189517
        #0, ref=0/301000, duration=149504, SAP=1/0/0
    moof, 3604B, 2 boxes
        mfhd, 16B, FB(4B), sequence=2
        traf, 3580B, 3 boxes
            tfhd, 28B, FB(4B,V0,0x20038), track=1, dsu=512, dss=3685, dsf=16842752, moof-base
            tfdt, 20B, FB(4B,V1,0x00), bmdt=188928
            trun, 3524B, FB(4B,V0,0xe01), samples=292, data-offset=3612
                , size=3685, flags=33554432, cts=1024
                , size=1768, flags=16842752, cts=1024
                , size=1928, flags=16842752, cts=1024
                , size=1678, flags=16842752, cts=1024
                , size=113, flags=16842752, cts=1024
                , size=1227, flags=16842752, cts=1024
                , size=1808, flags=16842752, cts=1024
                , size=1170, flags=16842752, cts=1024
    mdat, 297396B, total 297388 bytes

Its data_offset is 3612 = moof (3604B) + mdat-header (8B).

image

It can be played after modification.

image

Additionally, another issue has been fixed. Slices need to be continuous, previously there were occasional timestamp alignment issues with slice numbers, resulting in jumps and causing failures for dash.js to locate the slice. However, it can easily lead to AV (audio-visual) synchronization issues, so this problem still needs to be further addressed and fixed in detail.

Of course, several DASH bugs have also been fixed, including a crash. Currently, after these changes (sidx box synchronization still needs to be added), DASH has basically met the requirements for Experimental features. d11a7b2

TRANS_BY_GPT3

@winlinvip

This comment was marked as outdated.

@winlinvip winlinvip self-assigned this Aug 26, 2021
@winlinvip

This comment was marked as outdated.

@winlinvip

This comment was marked as outdated.

@winlinvip winlinvip reopened this Oct 29, 2021
@winlinvip winlinvip modified the milestones: 3.0, 5.0 Dec 13, 2021
@winlinvip winlinvip linked a pull request Nov 23, 2022 that will close this issue
@winlinvip winlinvip changed the title PROTOCOL: Migrate from NGINX-RTMP, Delivery MPEG-DASH PROTOCOL: Support convert RTMP to MPEG-DASH Nov 24, 2022
@winlinvip winlinvip changed the title PROTOCOL: Support convert RTMP to MPEG-DASH PROTOCOL: Support convert RTMP/WebRTC to MPEG-DASH Nov 24, 2022
@winlinvip winlinvip changed the title PROTOCOL: Support convert RTMP/WebRTC to MPEG-DASH DASH: Support convert RTMP/WebRTC to MPEG-DASH Nov 24, 2022
@xiaozhihong
Copy link
Collaborator

xiaozhihong commented Nov 24, 2022

Give a simple explanation of some key points about DASH, mainly the daunting mpd file with numerous fields and combinations.

One major feature of the DASH protocol is mapping the time slices of audio and video to UTC time, allowing for real-time streaming and the selection of appropriate segments for playback.

The commonly used descriptions for segmentation in DASH mpd are as follows (excluding irrelevant fields):

1. Using SegmentTemplate and without SegmentTimeline

<?xml version="1.0" encoding="utf-8"?>
<MPD ...>
    <Period start="PT0S">
        <AdaptationSet mimeType="audio/mp4" segmentAlignment="true" startWithSAP="1">
            <Representation id="audio" bandwidth="48000" codecs="mp4a.40.2">
                <SegmentTemplate initialization="$RepresentationID$-init.mp4" media="$RepresentationID$-$Number$.m4s" duration="5000" timescale="1000">
                </SegmentTemplate>
            </Representation>
        </AdaptationSet>
        <AdaptationSet mimeType="video/mp4" segmentAlignment="true" startWithSAP="1">
            <Representation id="video" bandwidth="800000" codecs="avc1.64001e" width="1280" height="720">
                <SegmentTemplate initialization="$RepresentationID$-init.mp4" media="$RepresentationID$-$Number$.m4s" duration="5000" timescale="1000">
                </SegmentTemplate>
            </Representation>
        </AdaptationSet>
    </Period>
</MPD>

In this kind of MPD, since there is no explicit indication of segment information, the player needs to calculate the current segment number.
$Number$ = (currentUTCTime - availabilityStartTime) * timesacle / duration + startNumber
Due to inaccuracies in the clock or deviations caused by differences between the declared and actual segment durations, long-term streaming may result in audio-video desynchronization or incorrect calculation of segment numbers.

2. SegmentTemplate also has a SegmentTimeline.

2.1 "$Number$"

<?xml version="1.0" encoding="utf-8"?>
<MPD ...>
    <Period start="PT0S">
        <AdaptationSet mimeType="audio/mp4" segmentAlignment="true" startWithSAP="1">
            <Representation id="audio" bandwidth="48000" codecs="mp4a.40.2">
                <SegmentTemplate initialization="$RepresentationID$-init.mp4" media="$RepresentationID$-$Number$.m4s" startNumber="2898" timescale="1000">
                    <SegmentTimeline>
                        <S t="100" d="4907" />
                        <S t="5007" d="5013" />
                        <S t="10020" d="4992" />
                    </SegmentTimeline>
                </SegmentTemplate>
            </Representation>
        </AdaptationSet>
        <AdaptationSet mimeType="video/mp4" segmentAlignment="true" startWithSAP="1">
            <Representation id="video" bandwidth="800000" codecs="avc1.64001e" width="1280" height="720">
                <SegmentTemplate initialization="$RepresentationID$-init.mp4" media="$RepresentationID$-$Number$.m4s" startNumber="2898" timescale="1000">
                    <SegmentTimeline>
                        <S t="0" d="5000" />
                        <S t="5000" d="5000" />
                        <S t="10000" d="5000" />
                    </SegmentTimeline>
                </SegmentTemplate>
            </Representation>
        </AdaptationSet>
    </Period>
</MPD>

This MPD is similar to the previous one, with the difference that it includes a SegmentTimeline. According to the standard, in this case, the SegmentTemplate should not include a duration. Each segment's duration and start time are represented by the line <S t="0", d="5000" />, which means the segment starts playing at availabilityStartTime + t and has a duration of 5000/timescale seconds. With this precise indication, the player selects segments from the SegmentTimeline list that fall within the current playback window [availabilityStartTime + t ~ availabilityStartTime + t + duration]. The placeholder $Number$ is replaced with the line number + startNumber of the segment being played.

2.2 "$Time$"

<?xml version="1.0" encoding="utf-8"?>
<MPD ...>
    <Period start="PT0S">
        <AdaptationSet mimeType="audio/mp4" segmentAlignment="true" startWithSAP="1">
            <Representation id="audio" bandwidth="48000" codecs="mp4a.40.2">
                <SegmentTemplate initialization="$RepresentationID$-init.mp4" media="$RepresentationID$-$Time$.m4s" timescale="1000">
                    <SegmentTimeline>
                        <S t="100" d="4907" />
                        <S t="5007" d="5013" />
                        <S t="10020" d="4992" />
                    </SegmentTimeline>
                </SegmentTemplate>
            </Representation>
        </AdaptationSet>
        <AdaptationSet mimeType="video/mp4" segmentAlignment="true" startWithSAP="1">
            <Representation id="video" bandwidth="800000" codecs="avc1.64001e" width="1280" height="720">
                <SegmentTemplate initialization="$RepresentationID$-init.mp4" media="$RepresentationID$-$Time$.m4s" timescale="1000">
                    <SegmentTimeline>
                        <S t="0" d="5000" />
                        <S t="5000" d="5000" />
                        <S t="10000" d="5000" />
                    </SegmentTimeline>
                </SegmentTemplate>
            </Representation>
        </AdaptationSet>
    </Period>
</MPD>

Similar to the segment selection logic above, just replace $Time$ with the t value of the selected segment.

3. Use SegmentList

<?xml version="1.0" encoding="utf-8"?>
<MPD ...>
    <Period start="PT0S">
        <AdaptationSet mimeType="audio/mp4" segmentAlignment="true" startWithSAP="1">
            <Representation id="audio" bandwidth="48000" codecs="mp4a.40.2">
                <SegmentList duration="5">
                    <SegmentURL media="video-1.m4s"/>
                    <SegmentURL media="video-2.m4s"/>
                    <SegmentURL media="video-3.m4s"/>
                </SegmentList>
            </Representation>
        </AdaptationSet>
        <AdaptationSet mimeType="video/mp4" segmentAlignment="true" startWithSAP="1">
            <Representation id="video" bandwidth="800000" codecs="avc1.64001e" width="1280" height="720">
                <SegmentList duration="5">
                    <SegmentURL media="audio-1.m4s"/>
                    <SegmentURL media="audio-2.m4s"/>
                    <SegmentURL media="audio-3.m4s"/>
                </SegmentList>
            </Representation>
        </AdaptationSet>
    </Period>
</MPD>

This type of MPD is relatively rare in live streaming, so we won't discuss it in detail for now.

Other important fields in MPD

availabilityStartTime

This field indicates the earliest UTC time to start playing all slices.

Since DASH plays strictly according to UTC time, it is necessary to map media time to UTC time. Generally, mapping is done according to the following logic.
availabilityStartTime = firstFrameRecvTime - firstFrameTimestamp
This way, all subsequent segments can calculate the corresponding UTC time for playback.

timeShiftBufferDepth

This field is relatively easy to understand, it represents the window time of the player, which can play segments up to the length of timeShiftBufferDepth in the past.

minimumUpdatePeriod

This field is also easily understood. It represents the minimum update frequency of the MPD. For MPDs that use SegmentTimeline, the update frequency is typically set to the duration of the latest segment to ensure that the player can refresh the MPD in a timely manner and obtain the latest segment for playback.

minBufferTime

Minimum buffer time: The player must ensure that it has data exceeding this buffer length in order to start the playback.

publishTime

The generation time of MPD at the source station needs to be rewritten every time the MPD is refreshed, and CDN can be used to refresh the cache.

Known Issues

Failure of VLC Play $Time$ Mode

When using SegmentTimeline and replacing with $Time$, there is an issue with VLC 3.0.17 playback, while VLC 4.0 works normally.
With the help of Zhili, the VLC bug has been located. The PR is here

Stream Re-Pushing

When reconnecting and re-pushing the stream, HLS can use the EXT-X-DISCONTINUITY tag to concatenate the new segments at the end of the m3u8 file. Mainstream players such as hls.js, VLC, and ffplay can play it seamlessly.

However, DASH does not have a similar tag. According to the standard documentation, using a new Period can be attempted to solve this issue, but currently, it still cannot be played successfully.

The solution used by SRS is to regenerate a new MPD file after re-pushing while discarding the old MPD. In terms of player behavior, dash.js can restart the player and continue playing, while VLC will freeze abnormally and stop.

Summary

DASH is a fancy protocol that considers many aspects. It needs to support both video-on-demand and live streaming, while also compressing the MPD file to reduce its size. This makes DASH very complex in design and use. It is undeniable that it is a great design but it can be challenging for developers. Compared to HLS, it has a higher level of complexity, which is why there are currently fewer vendors using DASH. The standard documentation for DASH is also very cumbersome, lacking clear explanations and rich examples. Due to these various reasons, DASH has become a protocol that is excellent but not user-friendly.

TRANS_BY_GPT3

@xiaozhihong
Copy link
Collaborator

xiaozhihong commented Nov 24, 2022

SRS selects SegmentTemplate with SegmentTimeline and uses $Number as the URL substitution symbol, mainly considering the compatibility issues of current mainstream players.

TRANS_BY_GPT3

@winlinvip
Copy link
Member Author

Fixed in v5.0.96

@winlinvip winlinvip added the TransByAI Translated by AI/GPT. label Jul 25, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature It's a new feature. TransByAI Translated by AI/GPT.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants