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:
KongQun Yang 2018-01-29 10:37:50 -08:00
parent 30b5fdf19f
commit ee9b7f6392
40 changed files with 322 additions and 187 deletions

View File

@ -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">

View File

@ -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">

View File

@ -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">

View File

@ -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">

View File

@ -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">

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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">

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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">

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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>

View File

@ -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">

View File

@ -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">

View File

@ -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">

View File

@ -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.

View File

@ -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

View File

@ -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().

View File

@ -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,

View File

@ -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(&timestamp) &&
if (representation->GetStartAndEndTimestamps(&timestamp, 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);

View File

@ -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_;

View File

@ -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));

View File

@ -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_));
}

View File

@ -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;

View File

@ -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.

View File

@ -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 {

View File

@ -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:

View File

@ -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) {

View File

@ -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);
}

View File

@ -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));
}

View File

@ -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">

View File

@ -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">

View File

@ -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">

View File

@ -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">