Calculate presentationTimeOffset and Period@duration from segments
Prefer timestamps from Video AdaptationSets if available - this avoids possible video playback jitters due to gaps. presentationTimeOffset is not applied to the first period as it may in negative dts which Chrome does not like: https://crbug.com/398141. It is safe to apply to subsequent periods as the actual offset applied takes Period@start into consideration: offset = Period@start - presentationTimeOffset The result timestamp with offset applied is close to Period@start, so it is unlikely to result in a negative dts value. Closes b/73899306. Change-Id: If8361f5469610093b3aac6675754536ad7e83c4c
This commit is contained in:
parent
1d6a2de5ab
commit
f8a1cb66ad
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>-->
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.741S">
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.736S">
|
||||
<Period id="0">
|
||||
<AdaptationSet id="0" contentType="audio" subsegmentAlignment="true">
|
||||
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>-->
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.741S">
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.736S">
|
||||
<Period id="0">
|
||||
<AdaptationSet id="0" contentType="audio" subsegmentAlignment="true">
|
||||
<Representation id="0" bandwidth="75444" codecs="opus" mimeType="audio/webm" audioSamplingRate="48000">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>-->
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.76317S">
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.73607S">
|
||||
<Period id="0">
|
||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
||||
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>-->
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.76317S">
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.73607S">
|
||||
<Period id="0">
|
||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
||||
<ContentProtection value="cbc1" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>-->
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.76317S">
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.73607S">
|
||||
<Period id="0">
|
||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
||||
<ContentProtection value="cbcs" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>-->
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.76317S">
|
||||
<Period id="0" duration="PT2.06873S">
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.73607S">
|
||||
<Period id="0" duration="PT2.002S">
|
||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
||||
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
||||
<ContentProtection schemeIdUri="urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b">
|
||||
|
@ -28,7 +28,7 @@
|
|||
</Representation>
|
||||
</AdaptationSet>
|
||||
</Period>
|
||||
<Period id="1" duration="PT0.694441S">
|
||||
<Period id="1" duration="PT0.734067S">
|
||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
||||
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
||||
<ContentProtection schemeIdUri="urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>-->
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.76317S">
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.73607S">
|
||||
<Period id="0">
|
||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
||||
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>-->
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.76317S">
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.73607S">
|
||||
<Period id="0">
|
||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
||||
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>-->
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.76317S">
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.73607S">
|
||||
<Period id="0">
|
||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
||||
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>-->
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.76317S">
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.73607S">
|
||||
<Period id="0">
|
||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
||||
<Representation id="0" bandwidth="885590" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>-->
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.76317S">
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.73607S">
|
||||
<Period id="0">
|
||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
||||
<ContentProtection value="cens" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>-->
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.76317S">
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.73607S">
|
||||
<Period id="0">
|
||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
||||
<Representation id="0" bandwidth="882064" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1">
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>-->
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-live:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.76317S">
|
||||
<Period id="0" duration="PT2.06873S">
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-live:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.73607S">
|
||||
<Period id="0" duration="PT2.002S">
|
||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" segmentAlignment="true" par="16:9">
|
||||
<Representation id="0" bandwidth="875099" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1">
|
||||
<SegmentTemplate timescale="30000" initialization="output_video-init.mp4" media="output_video-$Number$.m4s" startNumber="1">
|
||||
|
@ -22,7 +22,7 @@
|
|||
</Representation>
|
||||
</AdaptationSet>
|
||||
</Period>
|
||||
<Period id="1" duration="PT0.694444S">
|
||||
<Period id="1" duration="PT0.734067S">
|
||||
<AdaptationSet id="1" contentType="audio" segmentAlignment="true">
|
||||
<Representation id="1" bandwidth="108486" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
|
||||
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
|
||||
|
@ -35,7 +35,7 @@
|
|||
</AdaptationSet>
|
||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" segmentAlignment="true" par="16:9">
|
||||
<Representation id="0" bandwidth="869044" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1">
|
||||
<SegmentTemplate timescale="30000" presentationTimeOffset="62060" initialization="output_video-init.mp4" media="output_video-$Number$.m4s" startNumber="3">
|
||||
<SegmentTemplate timescale="30000" presentationTimeOffset="62061" initialization="output_video-init.mp4" media="output_video-$Number$.m4s" startNumber="3">
|
||||
<SegmentTimeline>
|
||||
<S t="62062" d="22022"/>
|
||||
</SegmentTimeline>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>-->
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-live:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.76317S">
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-live:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.73607S">
|
||||
<Period id="0">
|
||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" segmentAlignment="true" par="16:9">
|
||||
<Representation id="0" bandwidth="873071" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>-->
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.76317S">
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.73607S">
|
||||
<Period id="0">
|
||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
||||
<Representation id="0" bandwidth="882064" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>-->
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.76317S">
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.73607S">
|
||||
<Period id="0">
|
||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
||||
<Representation id="0" bandwidth="882064" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>-->
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.76317S">
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.73607S">
|
||||
<Period id="0">
|
||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
||||
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>-->
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.76317S">
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.73607S">
|
||||
<Period id="0">
|
||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
||||
<Representation id="0" bandwidth="882064" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>-->
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.76317S">
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.73607S">
|
||||
<Period id="0">
|
||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
||||
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>-->
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.76317S">
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.73607S">
|
||||
<Period id="0">
|
||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
||||
<Representation id="0" bandwidth="882064" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>-->
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.76317S">
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.73607S">
|
||||
<Period id="0">
|
||||
<AdaptationSet id="0" contentType="text" subsegmentAlignment="true">
|
||||
<Representation id="0" bandwidth="256" mimeType="text/vtt">
|
||||
|
|
|
@ -201,15 +201,14 @@ Representation* AdaptationSet::AddRepresentation(const MediaInfo& media_info) {
|
|||
return representation_ptr;
|
||||
}
|
||||
|
||||
Representation* AdaptationSet::CopyRepresentationWithTimeOffset(
|
||||
const Representation& representation,
|
||||
uint64_t presentation_time_offset) {
|
||||
Representation* AdaptationSet::CopyRepresentation(
|
||||
const Representation& representation) {
|
||||
// Note that AdaptationSet outlive Representation, so this object
|
||||
// will die before AdaptationSet.
|
||||
std::unique_ptr<RepresentationStateChangeListener> listener(
|
||||
new RepresentationStateChangeListenerImpl(representation.id(), this));
|
||||
std::unique_ptr<Representation> new_representation(new Representation(
|
||||
representation, presentation_time_offset, std::move(listener)));
|
||||
std::unique_ptr<Representation> new_representation(
|
||||
new Representation(representation, std::move(listener)));
|
||||
|
||||
UpdateFromMediaInfo(new_representation->GetMediaInfo());
|
||||
Representation* representation_ptr = new_representation.get();
|
||||
|
@ -384,6 +383,10 @@ const std::list<Representation*> AdaptationSet::GetRepresentations() const {
|
|||
return representations;
|
||||
}
|
||||
|
||||
bool AdaptationSet::IsVideo() const {
|
||||
return content_type_ == "video";
|
||||
}
|
||||
|
||||
void AdaptationSet::UpdateFromMediaInfo(const MediaInfo& media_info) {
|
||||
// For videos, record the width, height, and the frame rate to calculate the
|
||||
// max {width,height,framerate} required for DASH IOP.
|
||||
|
|
|
@ -63,13 +63,10 @@ class AdaptationSet {
|
|||
/// AdaptationSet. One use case is to duplicate Representation in different
|
||||
/// periods.
|
||||
/// @param representation is an existing Representation to be cloned from.
|
||||
/// @param presentation_time_offset is the presentation time offset for the
|
||||
/// new Representation instance.
|
||||
/// @return On success, returns a pointer to Representation. Otherwise returns
|
||||
/// NULL. The returned pointer is owned by the AdaptationSet instance.
|
||||
virtual Representation* CopyRepresentationWithTimeOffset(
|
||||
const Representation& representation,
|
||||
uint64_t presentation_time_offset);
|
||||
virtual Representation* CopyRepresentation(
|
||||
const Representation& representation);
|
||||
|
||||
/// Add a ContenProtection element to the adaptation set.
|
||||
/// AdaptationSet does not add <ContentProtection> elements
|
||||
|
@ -166,6 +163,9 @@ class AdaptationSet {
|
|||
// Return the list of Representations in this AdaptationSet.
|
||||
const std::list<Representation*> GetRepresentations() const;
|
||||
|
||||
/// @return true if it is a video AdaptationSet.
|
||||
bool IsVideo() const;
|
||||
|
||||
protected:
|
||||
/// @param adaptation_set_id is an ID number for this AdaptationSet.
|
||||
/// @param lang is the language of this AdaptationSet. Mainly relevant for
|
||||
|
|
|
@ -120,7 +120,7 @@ TEST_F(AdaptationSetTest, CheckAdaptationSetTextContentType) {
|
|||
AttributeEqual("contentType", "text"));
|
||||
}
|
||||
|
||||
TEST_F(AdaptationSetTest, CopyRepresentationWithTimeOffset) {
|
||||
TEST_F(AdaptationSetTest, CopyRepresentation) {
|
||||
const char kVideoMediaInfo[] =
|
||||
"video_info {\n"
|
||||
" codec: 'avc1'\n"
|
||||
|
@ -137,12 +137,9 @@ TEST_F(AdaptationSetTest, CopyRepresentationWithTimeOffset) {
|
|||
Representation* representation =
|
||||
adaptation_set->AddRepresentation(ConvertToMediaInfo(kVideoMediaInfo));
|
||||
|
||||
const uint64_t kPresentationTimeOffset = 80;
|
||||
Representation* new_representation =
|
||||
adaptation_set->CopyRepresentationWithTimeOffset(*representation,
|
||||
kPresentationTimeOffset);
|
||||
EXPECT_EQ(kPresentationTimeOffset,
|
||||
new_representation->GetMediaInfo().presentation_time_offset());
|
||||
adaptation_set->CopyRepresentation(*representation);
|
||||
ASSERT_TRUE(new_representation);
|
||||
}
|
||||
|
||||
// Verify that language passed to the constructor sets the @lang field is set.
|
||||
|
@ -627,13 +624,10 @@ TEST_F(AdaptationSetTest, GetRepresentations) {
|
|||
|
||||
auto new_adaptation_set =
|
||||
CreateAdaptationSet(kAnyAdaptationSetId, kNoLanguage);
|
||||
const uint64_t kPresentationTimeOffset = 80;
|
||||
Representation* new_representation2 =
|
||||
new_adaptation_set->CopyRepresentationWithTimeOffset(
|
||||
*representation2, kPresentationTimeOffset);
|
||||
new_adaptation_set->CopyRepresentation(*representation2);
|
||||
Representation* new_representation1 =
|
||||
new_adaptation_set->CopyRepresentationWithTimeOffset(
|
||||
*representation1, kPresentationTimeOffset);
|
||||
new_adaptation_set->CopyRepresentation(*representation1);
|
||||
|
||||
EXPECT_THAT(new_adaptation_set->GetRepresentations(),
|
||||
// Elements are ordered by id().
|
||||
|
|
|
@ -48,9 +48,8 @@ class MockAdaptationSet : public AdaptationSet {
|
|||
~MockAdaptationSet() override;
|
||||
|
||||
MOCK_METHOD1(AddRepresentation, Representation*(const MediaInfo& media_info));
|
||||
MOCK_METHOD2(CopyRepresentationWithTimeOffset,
|
||||
Representation*(const Representation& representation,
|
||||
uint64_t presentation_time_offset));
|
||||
MOCK_METHOD1(CopyRepresentation,
|
||||
Representation*(const Representation& representation));
|
||||
MOCK_METHOD1(AddContentProtectionElement,
|
||||
void(const ContentProtectionElement& element));
|
||||
MOCK_METHOD2(UpdateContentProtectionPssh,
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "packager/base/files/file_path.h"
|
||||
#include "packager/base/logging.h"
|
||||
#include "packager/base/optional.h"
|
||||
#include "packager/base/strings/string_number_conversions.h"
|
||||
#include "packager/base/strings/stringprintf.h"
|
||||
#include "packager/base/synchronization/lock.h"
|
||||
|
@ -172,23 +173,18 @@ xmlDocPtr MpdBuilder::GenerateMpd() {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// Prefer Period@duration to Period@start for static MPD with more than one
|
||||
// periods.
|
||||
if (mpd_options_.mpd_type == MpdType::kStatic && periods_.size() > 1) {
|
||||
// The duration of every period is determined by its start_time and next
|
||||
// period start_time. The code below traverses |periods_| backwards.
|
||||
double next_period_start_time = GetStaticMpdDuration();
|
||||
std::for_each(
|
||||
periods_.rbegin(), periods_.rend(),
|
||||
[&next_period_start_time](const std::unique_ptr<Period>& period) {
|
||||
period->set_duration_seconds(next_period_start_time -
|
||||
period->start_time_in_seconds());
|
||||
next_period_start_time = period->start_time_in_seconds();
|
||||
});
|
||||
bool output_period_duration = false;
|
||||
if (mpd_options_.mpd_type == MpdType::kStatic) {
|
||||
UpdatePeriodDurationAndPresentationTimestamp();
|
||||
// Only output period duration if there are more than one period. In the
|
||||
// case of only one period, Period@duration is redundant as it is identical
|
||||
// to Mpd Duration so the convention is not to output Period@duration.
|
||||
output_period_duration = periods_.size() > 1;
|
||||
}
|
||||
|
||||
for (const auto& period : periods_) {
|
||||
xml::scoped_xml_ptr<xmlNode> period_node(period->GetXml());
|
||||
xml::scoped_xml_ptr<xmlNode> period_node(
|
||||
period->GetXml(output_period_duration));
|
||||
if (!period_node || !mpd.AddChild(std::move(period_node)))
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -309,26 +305,11 @@ void MpdBuilder::AddDynamicMpdInfo(XmlNode* mpd_node) {
|
|||
float MpdBuilder::GetStaticMpdDuration() {
|
||||
DCHECK_EQ(MpdType::kStatic, mpd_options_.mpd_type);
|
||||
|
||||
if (periods_.empty()) {
|
||||
LOG(WARNING) << "No Period found. Set MPD duration to 0.";
|
||||
return 0.0f;
|
||||
float total_duration = 0.0f;
|
||||
for (const auto& period : periods_) {
|
||||
total_duration += period->duration_seconds();
|
||||
}
|
||||
|
||||
// Attribute mediaPresentationDuration must be present for 'static' MPD. So
|
||||
// setting "PT0S" is required even if none of the representaions have duration
|
||||
// attribute.
|
||||
float max_duration = 0.0f;
|
||||
|
||||
// TODO(kqyang): Right now all periods contain the duration for the whole MPD.
|
||||
// Simply get the duration from the first period. Ideally the period duration
|
||||
// should only count the (sub)segments in that period.
|
||||
for (const auto* adaptation_set : periods_.front()->GetAdaptationSets()) {
|
||||
for (const auto* representation : adaptation_set->GetRepresentations()) {
|
||||
max_duration =
|
||||
std::max(representation->GetDurationSeconds(), max_duration);
|
||||
}
|
||||
}
|
||||
return max_duration;
|
||||
return total_duration;
|
||||
}
|
||||
|
||||
bool MpdBuilder::GetEarliestTimestamp(double* timestamp_seconds) {
|
||||
|
@ -336,10 +317,13 @@ bool MpdBuilder::GetEarliestTimestamp(double* timestamp_seconds) {
|
|||
DCHECK(!periods_.empty());
|
||||
double timestamp = 0;
|
||||
double earliest_timestamp = -1;
|
||||
// TODO(kqyang): This is used to set availabilityStartTime. We may consider
|
||||
// set presentationTimeOffset in the Representations then we can set
|
||||
// availabilityStartTime to the time when MPD is first generated.
|
||||
// The first period should have the earliest timestamp.
|
||||
for (const auto* adaptation_set : periods_.front()->GetAdaptationSets()) {
|
||||
for (const auto* representation : adaptation_set->GetRepresentations()) {
|
||||
if (representation->GetEarliestTimestamp(×tamp) &&
|
||||
if (representation->GetStartAndEndTimestamps(×tamp, nullptr) &&
|
||||
(earliest_timestamp < 0 || timestamp < earliest_timestamp)) {
|
||||
earliest_timestamp = timestamp;
|
||||
}
|
||||
|
@ -351,6 +335,72 @@ bool MpdBuilder::GetEarliestTimestamp(double* timestamp_seconds) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void MpdBuilder::UpdatePeriodDurationAndPresentationTimestamp() {
|
||||
DCHECK_EQ(MpdType::kStatic, mpd_options_.mpd_type);
|
||||
|
||||
bool first_period = true;
|
||||
for (const auto& period : periods_) {
|
||||
std::list<Representation*> video_representations;
|
||||
std::list<Representation*> non_video_representations;
|
||||
for (const auto& adaptation_set : period->GetAdaptationSets()) {
|
||||
const auto& representations = adaptation_set->GetRepresentations();
|
||||
if (adaptation_set->IsVideo()) {
|
||||
video_representations.insert(video_representations.end(),
|
||||
representations.begin(),
|
||||
representations.end());
|
||||
} else {
|
||||
non_video_representations.insert(non_video_representations.end(),
|
||||
representations.begin(),
|
||||
representations.end());
|
||||
}
|
||||
}
|
||||
|
||||
base::Optional<double> earliest_start_time;
|
||||
base::Optional<double> latest_end_time;
|
||||
// The timestamps are based on Video Representations if exist.
|
||||
const auto& representations = video_representations.size() > 0
|
||||
? video_representations
|
||||
: non_video_representations;
|
||||
for (const auto& representation : representations) {
|
||||
double start_time = 0;
|
||||
double end_time = 0;
|
||||
if (representation->GetStartAndEndTimestamps(&start_time, &end_time)) {
|
||||
earliest_start_time =
|
||||
std::min(earliest_start_time.value_or(start_time), start_time);
|
||||
latest_end_time =
|
||||
std::max(latest_end_time.value_or(end_time), end_time);
|
||||
}
|
||||
}
|
||||
|
||||
if (!earliest_start_time)
|
||||
return;
|
||||
|
||||
period->set_duration_seconds(*latest_end_time - *earliest_start_time);
|
||||
|
||||
double presentation_time_offset = *earliest_start_time;
|
||||
if (first_period) {
|
||||
first_period = false;
|
||||
// Chrome does not like negative dts (https://crbug.com/398141).
|
||||
// Always set presentationTimeOffset (pto) to 0 for the first period as it
|
||||
// may result in an error on Chrome v63.0.3239.132 if it sets to a non
|
||||
// zero value.
|
||||
// It is fine with subsequent periods as the actual offset applied takes
|
||||
// Period@start into consideration:
|
||||
// offset = Period@start - presentationTimeOffset
|
||||
// The result timestamp with offset applied is close to Period@start, so
|
||||
// it is unlikely to result in a negative dts value.
|
||||
// TODO(kqyang): Set the pto to |dts| instead of always setting it to 0 to
|
||||
// workaround Chrome negative DTS bug.
|
||||
presentation_time_offset = 0;
|
||||
}
|
||||
for (const auto& adaptation_set : period->GetAdaptationSets()) {
|
||||
for (const auto& representation : adaptation_set->GetRepresentations()) {
|
||||
representation->SetPresentationTimeOffset(presentation_time_offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MpdBuilder::MakePathsRelativeToMpd(const std::string& mpd_path,
|
||||
MediaInfo* media_info) {
|
||||
DCHECK(media_info);
|
||||
|
|
|
@ -110,6 +110,9 @@ class MpdBuilder {
|
|||
// successful, false otherwise.
|
||||
bool GetEarliestTimestamp(double* timestamp_seconds);
|
||||
|
||||
// Update Period durations and presentation timestamps.
|
||||
void UpdatePeriodDurationAndPresentationTimestamp();
|
||||
|
||||
MpdOptions mpd_options_;
|
||||
std::list<std::unique_ptr<Period>> periods_;
|
||||
|
||||
|
|
|
@ -4,15 +4,19 @@
|
|||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
#include <gflags/gflags.h>
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "packager/mpd/base/adaptation_set.h"
|
||||
#include "packager/mpd/base/mpd_builder.h"
|
||||
#include "packager/mpd/base/period.h"
|
||||
#include "packager/mpd/base/representation.h"
|
||||
#include "packager/mpd/test/mpd_builder_test_helper.h"
|
||||
#include "packager/version/version.h"
|
||||
|
||||
DECLARE_int32(pto_adjustment);
|
||||
|
||||
using ::testing::HasSubstr;
|
||||
|
||||
namespace shaka {
|
||||
|
@ -56,6 +60,23 @@ class MpdBuilderTest : public ::testing::Test {
|
|||
ExpectMpdToEqualExpectedOutputFile(mpd_doc, expected_output_file));
|
||||
}
|
||||
|
||||
void AddSegmentToPeriod(double segment_start_time_seconds,
|
||||
double segment_duration_seconds,
|
||||
Period* period) {
|
||||
MediaInfo media_info = GetTestMediaInfo(kFileNameVideoMediaInfo1);
|
||||
// Not relevant in this test.
|
||||
const bool kContentProtectionFlag = true;
|
||||
const size_t kBytes = 1000;
|
||||
|
||||
AdaptationSet* adaptation_set =
|
||||
period->GetOrCreateAdaptationSet(media_info, kContentProtectionFlag);
|
||||
Representation* representation =
|
||||
adaptation_set->AddRepresentation(media_info);
|
||||
representation->AddNewSegment(
|
||||
segment_start_time_seconds * media_info.reference_time_scale(),
|
||||
segment_duration_seconds * media_info.reference_time_scale(), kBytes);
|
||||
}
|
||||
|
||||
protected:
|
||||
// Creates a new AdaptationSet and adds a Representation element using
|
||||
// |media_info|.
|
||||
|
@ -174,31 +195,57 @@ TEST_F(OnDemandMpdBuilderTest, MultiplePeriodTest) {
|
|||
}
|
||||
|
||||
TEST_F(OnDemandMpdBuilderTest, MultiplePeriodCheckXmlTest) {
|
||||
const double kPeriodStartTimeSeconds = 0.0;
|
||||
const double kPeriodStartTimeSeconds2 = 3.1;
|
||||
const double kPeriodStartTimeSeconds3 = 8.0;
|
||||
mpd_.GetOrCreatePeriod(kPeriodStartTimeSeconds);
|
||||
mpd_.GetOrCreatePeriod(kPeriodStartTimeSeconds2);
|
||||
mpd_.GetOrCreatePeriod(kPeriodStartTimeSeconds3);
|
||||
// Disable pto adjustment.
|
||||
FLAGS_pto_adjustment = 0;
|
||||
|
||||
const double kPeriod1StartTimeSeconds = 0.0;
|
||||
const double kPeriod2StartTimeSeconds = 3.1;
|
||||
const double kPeriod3StartTimeSeconds = 8.0;
|
||||
|
||||
// Actual period duration is determined by the segments not by the period
|
||||
// start time above, which only provides an anchor point.
|
||||
const double kPeriod1SegmentStartSeconds = 0.2;
|
||||
const double kPeriod1SegmentDurationSeconds = 3.0;
|
||||
const double kPeriod2SegmentStartSeconds = 5.5;
|
||||
const double kPeriod2SegmentDurationSeconds = 10.5;
|
||||
const double kPeriod3SegmentStartSeconds = 1.5;
|
||||
const double kPeriod3SegmentDurationSeconds = 10.0;
|
||||
|
||||
Period* period = mpd_.GetOrCreatePeriod(kPeriod1StartTimeSeconds);
|
||||
AddSegmentToPeriod(kPeriod1SegmentStartSeconds,
|
||||
kPeriod1SegmentDurationSeconds, period);
|
||||
|
||||
period = mpd_.GetOrCreatePeriod(kPeriod2StartTimeSeconds);
|
||||
AddSegmentToPeriod(kPeriod2SegmentStartSeconds,
|
||||
kPeriod2SegmentDurationSeconds, period);
|
||||
|
||||
period = mpd_.GetOrCreatePeriod(kPeriod3StartTimeSeconds);
|
||||
AddSegmentToPeriod(kPeriod3SegmentStartSeconds,
|
||||
kPeriod3SegmentDurationSeconds, period);
|
||||
|
||||
std::string mpd_doc;
|
||||
ASSERT_TRUE(mpd_.ToString(&mpd_doc));
|
||||
EXPECT_THAT(mpd_doc, HasSubstr("<Period id=\"0\" duration=\"PT3S\">\n"));
|
||||
EXPECT_THAT(
|
||||
mpd_doc,
|
||||
HasSubstr("<SegmentBase indexRange=\"121-221\" timescale=\"1000\">"));
|
||||
EXPECT_THAT(mpd_doc, HasSubstr("<Period id=\"1\" duration=\"PT10.5S\">\n"));
|
||||
EXPECT_THAT(mpd_doc,
|
||||
HasSubstr(" <Period id=\"0\" duration=\"PT3.1S\"/>\n"
|
||||
" <Period id=\"1\" duration=\"PT4.9S\"/>\n"
|
||||
// There are no Representations so MPD duration is 0,
|
||||
// which results in a negative duration for the last
|
||||
// period. This would not happen in practice.
|
||||
" <Period id=\"2\" duration=\"PT-8S\"/>\n"));
|
||||
HasSubstr("<SegmentBase indexRange=\"121-221\" "
|
||||
"timescale=\"1000\" presentationTimeOffset=\"5500\">"));
|
||||
EXPECT_THAT(mpd_doc, HasSubstr("<Period id=\"2\" duration=\"PT10S\">\n"));
|
||||
EXPECT_THAT(mpd_doc,
|
||||
HasSubstr("<SegmentBase indexRange=\"121-221\" "
|
||||
"timescale=\"1000\" presentationTimeOffset=\"1500\">"));
|
||||
}
|
||||
|
||||
TEST_F(LiveMpdBuilderTest, MultiplePeriodCheckXmlTest) {
|
||||
const double kPeriodStartTimeSeconds = 0.0;
|
||||
const double kPeriodStartTimeSeconds2 = 3.1;
|
||||
const double kPeriodStartTimeSeconds3 = 8.0;
|
||||
mpd_.GetOrCreatePeriod(kPeriodStartTimeSeconds);
|
||||
mpd_.GetOrCreatePeriod(kPeriodStartTimeSeconds2);
|
||||
mpd_.GetOrCreatePeriod(kPeriodStartTimeSeconds3);
|
||||
const double kPeriod1StartTimeSeconds = 0.0;
|
||||
const double kPeriod2StartTimeSeconds = 3.1;
|
||||
const double kPeriod3StartTimeSeconds = 8.0;
|
||||
mpd_.GetOrCreatePeriod(kPeriod1StartTimeSeconds);
|
||||
mpd_.GetOrCreatePeriod(kPeriod2StartTimeSeconds);
|
||||
mpd_.GetOrCreatePeriod(kPeriod3StartTimeSeconds);
|
||||
|
||||
std::string mpd_doc;
|
||||
ASSERT_TRUE(mpd_.ToString(&mpd_doc));
|
||||
|
|
|
@ -94,7 +94,7 @@ AdaptationSet* Period::GetOrCreateAdaptationSet(
|
|||
return adaptation_set_ptr;
|
||||
}
|
||||
|
||||
xml::scoped_xml_ptr<xmlNode> Period::GetXml() const {
|
||||
xml::scoped_xml_ptr<xmlNode> Period::GetXml(bool output_period_duration) const {
|
||||
xml::XmlNode period("Period");
|
||||
|
||||
// Required for 'dynamic' MPDs.
|
||||
|
@ -106,11 +106,10 @@ xml::scoped_xml_ptr<xmlNode> Period::GetXml() const {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if (duration_seconds_ != 0) {
|
||||
if (output_period_duration) {
|
||||
period.SetStringAttribute("duration",
|
||||
SecondsToXmlDuration(duration_seconds_));
|
||||
} else if (mpd_options_.mpd_type == MpdType::kDynamic ||
|
||||
start_time_in_seconds_ != 0) {
|
||||
} else if (mpd_options_.mpd_type == MpdType::kDynamic) {
|
||||
period.SetStringAttribute("start",
|
||||
SecondsToXmlDuration(start_time_in_seconds_));
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ class Period {
|
|||
/// Generates <Period> xml element with its child AdaptationSet elements.
|
||||
/// @return On success returns a non-NULL scoped_xml_ptr. Otherwise returns a
|
||||
/// NULL scoped_xml_ptr.
|
||||
xml::scoped_xml_ptr<xmlNode> GetXml() const;
|
||||
xml::scoped_xml_ptr<xmlNode> GetXml(bool output_period_duration) const;
|
||||
|
||||
/// @return The list of AdaptationSets in this Period.
|
||||
const std::list<AdaptationSet*> GetAdaptationSets() const;
|
||||
|
@ -56,6 +56,9 @@ class Period {
|
|||
/// @return The start time of this Period.
|
||||
double start_time_in_seconds() const { return start_time_in_seconds_; }
|
||||
|
||||
/// @return period duration in seconds.
|
||||
double duration_seconds() const { return duration_seconds_; }
|
||||
|
||||
/// Set period duration.
|
||||
void set_duration_seconds(double duration_seconds) {
|
||||
duration_seconds_ = duration_seconds;
|
||||
|
|
|
@ -28,6 +28,7 @@ const uint32_t kDefaultPeriodId = 9u;
|
|||
const double kDefaultPeriodStartTime = 5.6;
|
||||
const uint32_t kDefaultAdaptationSetId = 0u;
|
||||
const uint32_t kTrickPlayAdaptationSetId = 1u;
|
||||
const bool kOutputPeriodDuration = true;
|
||||
|
||||
bool ElementEqual(const Element& lhs, const Element& rhs) {
|
||||
const bool all_equal_except_sublement_check =
|
||||
|
@ -138,12 +139,13 @@ TEST_P(PeriodTest, GetXml) {
|
|||
content_protection_in_adaptation_set_));
|
||||
|
||||
const char kExpectedXml[] =
|
||||
"<Period id=\"9\" start=\"PT5.6S\">"
|
||||
"<Period id=\"9\">"
|
||||
// ContentType and Representation elements are populated after
|
||||
// Representation::Init() is called.
|
||||
" <AdaptationSet id=\"0\" contentType=\"\"/>"
|
||||
"</Period>";
|
||||
EXPECT_THAT(testable_period_.GetXml().get(), XmlNodeEqual(kExpectedXml));
|
||||
EXPECT_THAT(testable_period_.GetXml(!kOutputPeriodDuration).get(),
|
||||
XmlNodeEqual(kExpectedXml));
|
||||
}
|
||||
|
||||
TEST_P(PeriodTest, DynamicMpdGetXml) {
|
||||
|
@ -174,7 +176,8 @@ TEST_P(PeriodTest, DynamicMpdGetXml) {
|
|||
// Representation::Init() is called.
|
||||
" <AdaptationSet id=\"0\" contentType=\"\"/>"
|
||||
"</Period>";
|
||||
EXPECT_THAT(testable_period_.GetXml().get(), XmlNodeEqual(kExpectedXml));
|
||||
EXPECT_THAT(testable_period_.GetXml(!kOutputPeriodDuration).get(),
|
||||
XmlNodeEqual(kExpectedXml));
|
||||
}
|
||||
|
||||
TEST_P(PeriodTest, SetDurationAndGetXml) {
|
||||
|
@ -206,7 +209,16 @@ TEST_P(PeriodTest, SetDurationAndGetXml) {
|
|||
// Representation::Init() is called.
|
||||
" <AdaptationSet id=\"0\" contentType=\"\"/>"
|
||||
"</Period>";
|
||||
EXPECT_THAT(testable_period_.GetXml().get(), XmlNodeEqual(kExpectedXml));
|
||||
EXPECT_THAT(testable_period_.GetXml(kOutputPeriodDuration).get(),
|
||||
XmlNodeEqual(kExpectedXml));
|
||||
const char kExpectedXmlSuppressDuration[] =
|
||||
"<Period id=\"9\">"
|
||||
// ContentType and Representation elements are populated after
|
||||
// Representation::Init() is called.
|
||||
" <AdaptationSet id=\"0\" contentType=\"\"/>"
|
||||
"</Period>";
|
||||
EXPECT_THAT(testable_period_.GetXml(!kOutputPeriodDuration).get(),
|
||||
XmlNodeEqual(kExpectedXmlSuppressDuration));
|
||||
}
|
||||
|
||||
// Verify ForceSetSegmentAlignment is called.
|
||||
|
|
|
@ -6,11 +6,24 @@
|
|||
|
||||
#include "packager/mpd/base/representation.h"
|
||||
|
||||
#include <gflags/gflags.h>
|
||||
|
||||
#include "packager/base/logging.h"
|
||||
#include "packager/mpd/base/mpd_options.h"
|
||||
#include "packager/mpd/base/mpd_utils.h"
|
||||
#include "packager/mpd/base/xml/xml_node.h"
|
||||
|
||||
DEFINE_int32(
|
||||
pto_adjustment,
|
||||
-1,
|
||||
"There could be rounding errors in MSE which could cut the first key frame "
|
||||
"of the representation and thus cut all the frames until the next key "
|
||||
"frame, which then leads to a big gap in presentation timeline which "
|
||||
"stalls playback. A small back off may be necessary to compensate for the "
|
||||
"possible rounding error. It should not cause any playback issues if it is "
|
||||
"small enough. The workaround can be removed once the problem is handled "
|
||||
"in all players.");
|
||||
|
||||
namespace shaka {
|
||||
namespace {
|
||||
|
||||
|
@ -117,7 +130,6 @@ Representation::Representation(
|
|||
|
||||
Representation::Representation(
|
||||
const Representation& representation,
|
||||
uint64_t presentation_time_offset,
|
||||
std::unique_ptr<RepresentationStateChangeListener> state_change_listener)
|
||||
: Representation(representation.media_info_,
|
||||
representation.mpd_options_,
|
||||
|
@ -129,8 +141,6 @@ Representation::Representation(
|
|||
start_number_ = representation.start_number_;
|
||||
for (const SegmentInfo& segment_info : representation.segment_infos_)
|
||||
start_number_ += segment_info.repeat + 1;
|
||||
|
||||
media_info_.set_presentation_time_offset(presentation_time_offset);
|
||||
}
|
||||
|
||||
Representation::~Representation() {}
|
||||
|
@ -300,19 +310,34 @@ void Representation::SuppressOnce(SuppressFlag flag) {
|
|||
output_suppression_flags_ |= flag;
|
||||
}
|
||||
|
||||
bool Representation::GetEarliestTimestamp(double* timestamp_seconds) const {
|
||||
DCHECK(timestamp_seconds);
|
||||
void Representation::SetPresentationTimeOffset(
|
||||
double presentation_time_offset) {
|
||||
uint64_t pto = presentation_time_offset * media_info_.reference_time_scale();
|
||||
if (pto <= 0)
|
||||
return;
|
||||
pto += FLAGS_pto_adjustment;
|
||||
media_info_.set_presentation_time_offset(pto);
|
||||
}
|
||||
|
||||
bool Representation::GetStartAndEndTimestamps(
|
||||
double* start_timestamp_seconds,
|
||||
double* end_timestamp_seconds) const {
|
||||
if (segment_infos_.empty())
|
||||
return false;
|
||||
|
||||
*timestamp_seconds = static_cast<double>(segment_infos_.begin()->start_time) /
|
||||
if (start_timestamp_seconds) {
|
||||
*start_timestamp_seconds =
|
||||
static_cast<double>(segment_infos_.begin()->start_time) /
|
||||
GetTimeScale(media_info_);
|
||||
return true;
|
||||
}
|
||||
|
||||
float Representation::GetDurationSeconds() const {
|
||||
return media_info_.media_duration_seconds();
|
||||
if (end_timestamp_seconds) {
|
||||
*end_timestamp_seconds =
|
||||
static_cast<double>(segment_infos_.rbegin()->start_time +
|
||||
segment_infos_.rbegin()->duration *
|
||||
(segment_infos_.rbegin()->repeat + 1)) /
|
||||
GetTimeScale(media_info_);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Representation::HasRequiredMediaInfoFields() const {
|
||||
|
|
|
@ -128,12 +128,19 @@ class Representation {
|
|||
/// This may be called multiple times to set different (or the same) flags.
|
||||
void SuppressOnce(SuppressFlag flag);
|
||||
|
||||
/// Gets the earliest, normalized segment timestamp.
|
||||
/// @return true if successful, false otherwise.
|
||||
bool GetEarliestTimestamp(double* timestamp_seconds) const;
|
||||
/// Set @presentationTimeOffset in SegmentBase / SegmentTemplate.
|
||||
void SetPresentationTimeOffset(double presentation_time_offset);
|
||||
|
||||
/// @return The duration of the Representation in seconds.
|
||||
float GetDurationSeconds() const;
|
||||
/// Gets the start and end timestamps in seconds.
|
||||
/// @param start_timestamp_seconds contains the returned start timestamp in
|
||||
/// seconds on success. It can be nullptr, which means that start
|
||||
/// timestamp does not need to be returned.
|
||||
/// @param end_timestamp_seconds contains the returned end timestamp in
|
||||
/// seconds on success. It can be nullptr, which means that end
|
||||
/// timestamp does not need to be returned.
|
||||
/// @return true if successful, false otherwise.
|
||||
bool GetStartAndEndTimestamps(double* start_timestamp_seconds,
|
||||
double* end_timestamp_seconds) const;
|
||||
|
||||
/// @return ID number for <Representation>.
|
||||
uint32_t id() const { return id_; }
|
||||
|
@ -154,13 +161,10 @@ class Representation {
|
|||
std::unique_ptr<RepresentationStateChangeListener> state_change_listener);
|
||||
|
||||
/// @param representation points to the original Representation to be cloned.
|
||||
/// @param presentation_time_offset is the presentation time offset for the
|
||||
/// new Representation.
|
||||
/// @param state_change_listener is an event handler for state changes to
|
||||
/// the representation. If null, no event handler registered.
|
||||
Representation(
|
||||
const Representation& representation,
|
||||
uint64_t presentation_time_offset,
|
||||
std::unique_ptr<RepresentationStateChangeListener> state_change_listener);
|
||||
|
||||
private:
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "packager/mpd/base/representation.h"
|
||||
|
||||
#include <gflags/gflags.h>
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <inttypes.h>
|
||||
|
@ -15,6 +16,8 @@
|
|||
#include "packager/mpd/test/mpd_builder_test_helper.h"
|
||||
#include "packager/mpd/test/xml_compare.h"
|
||||
|
||||
DECLARE_int32(pto_adjustment);
|
||||
|
||||
using ::testing::Not;
|
||||
|
||||
namespace shaka {
|
||||
|
@ -54,12 +57,10 @@ class RepresentationTest : public ::testing::Test {
|
|||
|
||||
std::unique_ptr<Representation> CopyRepresentation(
|
||||
const Representation& representation,
|
||||
uint64_t presentation_time_offset,
|
||||
std::unique_ptr<RepresentationStateChangeListener>
|
||||
state_change_listener) {
|
||||
return std::unique_ptr<Representation>(
|
||||
new Representation(representation, presentation_time_offset,
|
||||
std::move(state_change_listener)));
|
||||
new Representation(representation, std::move(state_change_listener)));
|
||||
}
|
||||
|
||||
std::unique_ptr<RepresentationStateChangeListener> NoListener() {
|
||||
|
@ -506,16 +507,14 @@ TEST_F(SegmentTemplateTest, RepresentationClone) {
|
|||
const uint64_t kSize = 128;
|
||||
AddSegments(kStartTime, kDuration, kSize, 0);
|
||||
|
||||
const uint64_t kPresentationTimeOffset = 100;
|
||||
auto cloned_representation = CopyRepresentation(
|
||||
*representation_, kPresentationTimeOffset, NoListener());
|
||||
auto cloned_representation =
|
||||
CopyRepresentation(*representation_, NoListener());
|
||||
const char kExpectedXml[] =
|
||||
"<Representation id=\"1\" bandwidth=\"0\" "
|
||||
" codecs=\"avc1.010101\" mimeType=\"video/mp4\" sar=\"1:1\" "
|
||||
" width=\"720\" height=\"480\" frameRate=\"10/5\">\n"
|
||||
" <SegmentTemplate presentationTimeOffset=\"100\" timescale=\"1000\" "
|
||||
" initialization=\"init.mp4\" media=\"$Number$.mp4\" "
|
||||
" startNumber=\"2\">\n"
|
||||
" <SegmentTemplate timescale=\"1000\" initialization=\"init.mp4\" "
|
||||
" media=\"$Number$.mp4\" startNumber=\"2\">\n"
|
||||
" <SegmentTimeline/>\n"
|
||||
" </SegmentTemplate>\n"
|
||||
"</Representation>\n";
|
||||
|
@ -523,30 +522,50 @@ TEST_F(SegmentTemplateTest, RepresentationClone) {
|
|||
XmlNodeEqual(kExpectedXml));
|
||||
}
|
||||
|
||||
TEST_F(SegmentTemplateTest, GetEarliestTimestamp) {
|
||||
double earliest_timestamp;
|
||||
TEST_F(SegmentTemplateTest, PresentationTimeOffset) {
|
||||
FLAGS_pto_adjustment = -1;
|
||||
|
||||
const uint64_t kStartTime = 0;
|
||||
const uint64_t kDuration = 10;
|
||||
const uint64_t kSize = 128;
|
||||
AddSegments(kStartTime, kDuration, kSize, 0);
|
||||
|
||||
const double kPresentationTimeOffsetSeconds = 2.3;
|
||||
representation_->SetPresentationTimeOffset(kPresentationTimeOffsetSeconds);
|
||||
|
||||
const char kExpectedXml[] =
|
||||
"<Representation id=\"1\" bandwidth=\"102400\" "
|
||||
" codecs=\"avc1.010101\" mimeType=\"video/mp4\" sar=\"1:1\" "
|
||||
" width=\"720\" height=\"480\" frameRate=\"10/5\">\n"
|
||||
// pto = kPresentationTimeOffsetSeconds * timescale + FLAGS_pto_adjustment
|
||||
" <SegmentTemplate timescale=\"1000\" presentationTimeOffset=\"2299\""
|
||||
" initialization=\"init.mp4\" media=\"$Time$.mp4\">\n"
|
||||
" <SegmentTimeline>\n"
|
||||
" <S t=\"0\" d=\"10\"/>\n"
|
||||
" </SegmentTimeline>\n"
|
||||
" </SegmentTemplate>\n"
|
||||
"</Representation>\n";
|
||||
EXPECT_THAT(representation_->GetXml().get(), XmlNodeEqual(kExpectedXml));
|
||||
}
|
||||
|
||||
TEST_F(SegmentTemplateTest, GetStartAndEndTimestamps) {
|
||||
double start_timestamp;
|
||||
double end_timestamp;
|
||||
// No segments.
|
||||
EXPECT_FALSE(representation_->GetEarliestTimestamp(&earliest_timestamp));
|
||||
EXPECT_FALSE(representation_->GetStartAndEndTimestamps(&start_timestamp,
|
||||
&end_timestamp));
|
||||
|
||||
const uint64_t kStartTime = 88;
|
||||
const uint64_t kDuration = 10;
|
||||
const uint64_t kSize = 128;
|
||||
AddSegments(kStartTime, kDuration, kSize, 0);
|
||||
AddSegments(kStartTime + kDuration, kDuration, kSize, 0);
|
||||
ASSERT_TRUE(representation_->GetEarliestTimestamp(&earliest_timestamp));
|
||||
AddSegments(kStartTime + kDuration, kDuration, kSize, 2);
|
||||
ASSERT_TRUE(representation_->GetStartAndEndTimestamps(&start_timestamp,
|
||||
&end_timestamp));
|
||||
EXPECT_EQ(static_cast<double>(kStartTime) / kDefaultTimeScale,
|
||||
earliest_timestamp);
|
||||
}
|
||||
|
||||
TEST_F(SegmentTemplateTest, GetDuration) {
|
||||
const float kMediaDurationSeconds = 88.8f;
|
||||
MediaInfo media_info = ConvertToMediaInfo(GetDefaultMediaInfo());
|
||||
media_info.set_media_duration_seconds(kMediaDurationSeconds);
|
||||
representation_ =
|
||||
CreateRepresentation(media_info, kAnyRepresentationId, NoListener());
|
||||
ASSERT_TRUE(representation_->Init());
|
||||
|
||||
EXPECT_EQ(kMediaDurationSeconds, representation_->GetDurationSeconds());
|
||||
start_timestamp);
|
||||
EXPECT_EQ(static_cast<double>(kStartTime + kDuration * 4) / kDefaultTimeScale,
|
||||
end_timestamp);
|
||||
}
|
||||
|
||||
TEST_F(SegmentTemplateTest, NormalRepeatedSegmentDuration) {
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
|
||||
#include "packager/mpd/base/simple_mpd_notifier.h"
|
||||
|
||||
#include <gflags/gflags.h>
|
||||
|
||||
#include "packager/base/logging.h"
|
||||
#include "packager/base/stl_util.h"
|
||||
#include "packager/mpd/base/adaptation_set.h"
|
||||
|
@ -17,17 +15,6 @@
|
|||
#include "packager/mpd/base/period.h"
|
||||
#include "packager/mpd/base/representation.h"
|
||||
|
||||
DEFINE_int32(
|
||||
pto_adjustment,
|
||||
-1,
|
||||
"There could be rounding errors in MSE which could cut the first key frame "
|
||||
"of the representation and thus cut all the frames until the next key "
|
||||
"frame, which then leads to a big gap in presentation timeline which "
|
||||
"stalls playback. A small back off may be necessary to compensate for the "
|
||||
"possible rounding error. It should not cause any playback issues if it is "
|
||||
"small enough. The workaround can be removed once the problem is handled "
|
||||
"in all players.");
|
||||
|
||||
namespace shaka {
|
||||
|
||||
SimpleMpdNotifier::SimpleMpdNotifier(const MpdOptions& mpd_options)
|
||||
|
@ -164,13 +151,8 @@ Representation* SimpleMpdNotifier::AddRepresentationToPeriod(
|
|||
|
||||
Representation* representation = nullptr;
|
||||
if (original_representation) {
|
||||
uint64_t presentation_time_offset =
|
||||
period->start_time_in_seconds() * media_info.reference_time_scale();
|
||||
if (presentation_time_offset > 0) {
|
||||
presentation_time_offset += FLAGS_pto_adjustment;
|
||||
}
|
||||
representation = adaptation_set->CopyRepresentationWithTimeOffset(
|
||||
*original_representation, presentation_time_offset);
|
||||
representation =
|
||||
adaptation_set->CopyRepresentation(*original_representation);
|
||||
} else {
|
||||
representation = adaptation_set->AddRepresentation(media_info);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
#include <gflags/gflags.h>
|
||||
#include <gmock/gmock.h>
|
||||
#include <google/protobuf/util/message_differencer.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
@ -17,8 +16,6 @@
|
|||
#include "packager/mpd/base/simple_mpd_notifier.h"
|
||||
#include "packager/mpd/test/mpd_builder_test_helper.h"
|
||||
|
||||
DECLARE_int32(pto_adjustment);
|
||||
|
||||
namespace shaka {
|
||||
|
||||
using ::testing::_;
|
||||
|
@ -245,10 +242,8 @@ TEST_F(SimpleMpdNotifierTest, NotifyCueEvent) {
|
|||
EXPECT_CALL(*mock_period2,
|
||||
GetOrCreateAdaptationSet(EqualsProto(valid_media_info1_), _))
|
||||
.WillOnce(Return(mock_adaptation_set2.get()));
|
||||
EXPECT_CALL(
|
||||
*mock_adaptation_set2,
|
||||
CopyRepresentationWithTimeOffset(
|
||||
Ref(*mock_representation), kCueEventTimestamp + FLAGS_pto_adjustment))
|
||||
EXPECT_CALL(*mock_adaptation_set2,
|
||||
CopyRepresentation(Ref(*mock_representation)))
|
||||
.WillOnce(Return(mock_representation2.get()));
|
||||
EXPECT_TRUE(notifier.NotifyCueEvent(container_id, kCueEventTimestamp));
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT10.5S">
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT0S">
|
||||
<Period>
|
||||
<AdaptationSet id="0" contentType="audio">
|
||||
<Representation id="0" bandwidth="400" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT10.5S">
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT0S">
|
||||
<Period id="0">
|
||||
<AdaptationSet id="0" width="720" height="480" frameRate="10/1" contentType="video" par="3:2">
|
||||
<Representation id="0" bandwidth="7620" codecs="avc1.010101" mimeType="video/mp4" sar="1:1">
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT10.5S">
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT0S">
|
||||
<Period id="0">
|
||||
<AdaptationSet id="0" width="720" height="480" frameRate="10/1" contentType="video" par="3:2">
|
||||
<Representation id="0" bandwidth="7620" codecs="avc1.010101" mimeType="video/mp4" sar="1:1">
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT10.5S">
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT0S">
|
||||
<Period id="0">
|
||||
<AdaptationSet id="0" maxWidth="720" maxHeight="480" maxFrameRate="10/1" contentType="video">
|
||||
<Representation id="0" bandwidth="7620" codecs="avc1.010101" mimeType="video/mp4" width="720" height="480" frameRate="10/1" sar="1:1">
|
||||
|
|
Loading…
Reference in New Issue