Implement SampleEncryption box parsing and generation
Issue #41 Change-Id: Ic57436b6e6c8b58fc264037fd81c98627c525932
This commit is contained in:
parent
c0df6b3239
commit
098e087459
Binary file not shown.
|
@ -1,4 +1,4 @@
|
||||||
bandwidth: 128635
|
bandwidth: 128728
|
||||||
audio_info {
|
audio_info {
|
||||||
codec: "mp4a.40.2"
|
codec: "mp4a.40.2"
|
||||||
sampling_frequency: 44100
|
sampling_frequency: 44100
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -2,7 +2,7 @@
|
||||||
<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" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT2.763174533843994S">
|
<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" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT2.763174533843994S">
|
||||||
<Period>
|
<Period>
|
||||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subSegmentAlignment="true" par="16:9">
|
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subSegmentAlignment="true" par="16:9">
|
||||||
<Representation id="0" bandwidth="885058" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1" width="640" height="360" frameRate="30000/1001">
|
<Representation id="0" bandwidth="885151" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1" width="640" height="360" frameRate="30000/1001">
|
||||||
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
||||||
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
||||||
<cenc:pssh>AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2</cenc:pssh>
|
<cenc:pssh>AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2</cenc:pssh>
|
||||||
|
@ -14,7 +14,7 @@
|
||||||
</Representation>
|
</Representation>
|
||||||
</AdaptationSet>
|
</AdaptationSet>
|
||||||
<AdaptationSet id="1" contentType="audio" subSegmentAlignment="true">
|
<AdaptationSet id="1" contentType="audio" subSegmentAlignment="true">
|
||||||
<Representation id="1" bandwidth="128635" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
|
<Representation id="1" bandwidth="128728" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
|
||||||
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
|
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
|
||||||
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
||||||
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
||||||
<cenc:pssh>AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2</cenc:pssh>
|
<cenc:pssh>AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2</cenc:pssh>
|
||||||
</ContentProtection>
|
</ContentProtection>
|
||||||
<Representation id="0" bandwidth="885058" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1" width="640" height="360" frameRate="30000/1001">
|
<Representation id="0" bandwidth="885151" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1" width="640" height="360" frameRate="30000/1001">
|
||||||
<BaseURL>output_video.mp4</BaseURL>
|
<BaseURL>output_video.mp4</BaseURL>
|
||||||
<SegmentBase indexRange="941-1008" timescale="30000">
|
<SegmentBase indexRange="941-1008" timescale="30000">
|
||||||
<Initialization range="0-940"/>
|
<Initialization range="0-940"/>
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
||||||
<cenc:pssh>AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2</cenc:pssh>
|
<cenc:pssh>AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2</cenc:pssh>
|
||||||
</ContentProtection>
|
</ContentProtection>
|
||||||
<Representation id="1" bandwidth="128635" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
|
<Representation id="1" bandwidth="128728" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
|
||||||
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
|
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
|
||||||
<BaseURL>output_audio.mp4</BaseURL>
|
<BaseURL>output_audio.mp4</BaseURL>
|
||||||
<SegmentBase indexRange="817-884" timescale="44100">
|
<SegmentBase indexRange="817-884" timescale="44100">
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<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" minBufferTime="PT2S" type="dynamic" profiles="urn:mpeg:dash:profile:isoff-live:2011" availabilityStartTime="place_holder" minimumUpdatePeriod="PT5S" timeShiftBufferDepth="PT1800S">
|
<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" minBufferTime="PT2S" type="dynamic" profiles="urn:mpeg:dash:profile:isoff-live:2011" availabilityStartTime="place_holder" minimumUpdatePeriod="PT5S" timeShiftBufferDepth="PT1800S">
|
||||||
<Period start="PT0S">
|
<Period start="PT0S">
|
||||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" segmentAlignment="true" par="16:9">
|
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" segmentAlignment="true" par="16:9">
|
||||||
<Representation id="0" bandwidth="875528" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1" width="640" height="360" frameRate="30000/1001">
|
<Representation id="0" bandwidth="875620" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1" width="640" height="360" frameRate="30000/1001">
|
||||||
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
||||||
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
||||||
<cenc:pssh>AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2</cenc:pssh>
|
<cenc:pssh>AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2</cenc:pssh>
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
</Representation>
|
</Representation>
|
||||||
</AdaptationSet>
|
</AdaptationSet>
|
||||||
<AdaptationSet id="1" contentType="audio" segmentAlignment="true">
|
<AdaptationSet id="1" contentType="audio" segmentAlignment="true">
|
||||||
<Representation id="1" bandwidth="124085" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
|
<Representation id="1" bandwidth="124195" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
|
||||||
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
|
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
|
||||||
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
||||||
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
||||||
<cenc:pssh>AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2</cenc:pssh>
|
<cenc:pssh>AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2</cenc:pssh>
|
||||||
</ContentProtection>
|
</ContentProtection>
|
||||||
<Representation id="0" bandwidth="875528" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1" width="640" height="360" frameRate="30000/1001">
|
<Representation id="0" bandwidth="875620" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1" width="640" height="360" frameRate="30000/1001">
|
||||||
<SegmentTemplate timescale="30000" initialization="output_video-init.mp4" media="output_video-$Number$.m4s" startNumber="1">
|
<SegmentTemplate timescale="30000" initialization="output_video-init.mp4" media="output_video-$Number$.m4s" startNumber="1">
|
||||||
<SegmentTimeline>
|
<SegmentTimeline>
|
||||||
<S t="2002" d="30030" r="1"/>
|
<S t="2002" d="30030" r="1"/>
|
||||||
|
@ -20,7 +20,7 @@
|
||||||
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
||||||
<cenc:pssh>AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2</cenc:pssh>
|
<cenc:pssh>AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2</cenc:pssh>
|
||||||
</ContentProtection>
|
</ContentProtection>
|
||||||
<Representation id="1" bandwidth="124085" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
|
<Representation id="1" bandwidth="124195" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
|
||||||
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
|
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
|
||||||
<SegmentTemplate timescale="44100" initialization="output_audio-init.mp4" media="output_audio-$Number$.m4s" startNumber="1">
|
<SegmentTemplate timescale="44100" initialization="output_audio-init.mp4" media="output_audio-$Number$.m4s" startNumber="1">
|
||||||
<SegmentTimeline>
|
<SegmentTimeline>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<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" minBufferTime="PT2S" type="dynamic" profiles="urn:mpeg:dash:profile:isoff-live:2011" availabilityStartTime="place_holder" minimumUpdatePeriod="PT5S" timeShiftBufferDepth="PT1800S">
|
<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" minBufferTime="PT2S" type="dynamic" profiles="urn:mpeg:dash:profile:isoff-live:2011" availabilityStartTime="place_holder" minimumUpdatePeriod="PT5S" timeShiftBufferDepth="PT1800S">
|
||||||
<Period start="PT0S">
|
<Period start="PT0S">
|
||||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" segmentAlignment="true" par="16:9">
|
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" segmentAlignment="true" par="16:9">
|
||||||
<Representation id="0" bandwidth="876377" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1" width="640" height="360" frameRate="30000/1001">
|
<Representation id="0" bandwidth="876470" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1" width="640" height="360" frameRate="30000/1001">
|
||||||
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="00000000-0000-0000-0000-000000000000"/>
|
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="00000000-0000-0000-0000-000000000000"/>
|
||||||
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed"/>
|
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed"/>
|
||||||
<SegmentTemplate timescale="30000" initialization="output_video-init.mp4" media="output_video-$Number$.m4s" startNumber="1">
|
<SegmentTemplate timescale="30000" initialization="output_video-init.mp4" media="output_video-$Number$.m4s" startNumber="1">
|
||||||
|
@ -14,7 +14,7 @@
|
||||||
</Representation>
|
</Representation>
|
||||||
</AdaptationSet>
|
</AdaptationSet>
|
||||||
<AdaptationSet id="1" contentType="audio" segmentAlignment="true">
|
<AdaptationSet id="1" contentType="audio" segmentAlignment="true">
|
||||||
<Representation id="1" bandwidth="125028" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
|
<Representation id="1" bandwidth="125138" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
|
||||||
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
|
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
|
||||||
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="00000000-0000-0000-0000-000000000000"/>
|
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="00000000-0000-0000-0000-000000000000"/>
|
||||||
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed"/>
|
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed"/>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" segmentAlignment="true" par="16:9">
|
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" segmentAlignment="true" par="16:9">
|
||||||
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="00000000-0000-0000-0000-000000000000"/>
|
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="00000000-0000-0000-0000-000000000000"/>
|
||||||
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed"/>
|
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed"/>
|
||||||
<Representation id="0" bandwidth="876377" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1" width="640" height="360" frameRate="30000/1001">
|
<Representation id="0" bandwidth="876470" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1" width="640" height="360" frameRate="30000/1001">
|
||||||
<SegmentTemplate timescale="30000" initialization="output_video-init.mp4" media="output_video-$Number$.m4s" startNumber="1">
|
<SegmentTemplate timescale="30000" initialization="output_video-init.mp4" media="output_video-$Number$.m4s" startNumber="1">
|
||||||
<SegmentTimeline>
|
<SegmentTimeline>
|
||||||
<S t="2002" d="30030" r="1"/>
|
<S t="2002" d="30030" r="1"/>
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
<AdaptationSet id="1" contentType="audio" segmentAlignment="true">
|
<AdaptationSet id="1" contentType="audio" segmentAlignment="true">
|
||||||
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="00000000-0000-0000-0000-000000000000"/>
|
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="00000000-0000-0000-0000-000000000000"/>
|
||||||
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed"/>
|
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed"/>
|
||||||
<Representation id="1" bandwidth="125028" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
|
<Representation id="1" bandwidth="125138" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
|
||||||
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
|
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
|
||||||
<SegmentTemplate timescale="44100" initialization="output_audio-init.mp4" media="output_audio-$Number$.m4s" startNumber="1">
|
<SegmentTemplate timescale="44100" initialization="output_audio-init.mp4" media="output_audio-$Number$.m4s" startNumber="1">
|
||||||
<SegmentTimeline>
|
<SegmentTimeline>
|
||||||
|
|
Binary file not shown.
|
@ -1,4 +1,4 @@
|
||||||
bandwidth: 885058
|
bandwidth: 885151
|
||||||
video_info {
|
video_info {
|
||||||
codec: "avc1.64001e"
|
codec: "avc1.64001e"
|
||||||
width: 640
|
width: 640
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,93 +0,0 @@
|
||||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
#include "packager/media/formats/mp4/cenc.h"
|
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
#include "packager/media/base/buffer_reader.h"
|
|
||||||
#include "packager/media/base/buffer_writer.h"
|
|
||||||
#include "packager/media/formats/mp4/rcheck.h"
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
// According to ISO/IEC FDIS 23001-7: CENC spec, IV should be either
|
|
||||||
// 64-bit (8-byte) or 128-bit (16-byte).
|
|
||||||
bool IsIvSizeValid(size_t iv_size) { return iv_size == 8 || iv_size == 16; }
|
|
||||||
|
|
||||||
// 16-bit |clear_bytes| and 32-bit |cipher_bytes|.
|
|
||||||
const size_t kSubsampleEntrySize = sizeof(uint16_t) + sizeof(uint32_t);
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace edash_packager {
|
|
||||||
namespace media {
|
|
||||||
namespace mp4 {
|
|
||||||
|
|
||||||
FrameCENCInfo::FrameCENCInfo() {}
|
|
||||||
FrameCENCInfo::FrameCENCInfo(const std::vector<uint8_t>& iv) : iv_(iv) {
|
|
||||||
}
|
|
||||||
FrameCENCInfo::~FrameCENCInfo() {}
|
|
||||||
|
|
||||||
bool FrameCENCInfo::Parse(uint8_t iv_size, BufferReader* reader) {
|
|
||||||
DCHECK(reader);
|
|
||||||
// Mandated by CENC spec.
|
|
||||||
RCHECK(IsIvSizeValid(iv_size));
|
|
||||||
|
|
||||||
iv_.resize(iv_size);
|
|
||||||
RCHECK(reader->ReadToVector(&iv_, iv_size));
|
|
||||||
|
|
||||||
if (!reader->HasBytes(1))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
uint16_t subsample_count;
|
|
||||||
RCHECK(reader->Read2(&subsample_count) &&
|
|
||||||
reader->HasBytes(subsample_count * kSubsampleEntrySize));
|
|
||||||
|
|
||||||
subsamples_.resize(subsample_count);
|
|
||||||
for (uint16_t i = 0; i < subsample_count; ++i) {
|
|
||||||
uint16_t clear_bytes;
|
|
||||||
uint32_t cipher_bytes;
|
|
||||||
RCHECK(reader->Read2(&clear_bytes) &&
|
|
||||||
reader->Read4(&cipher_bytes));
|
|
||||||
subsamples_[i].clear_bytes = clear_bytes;
|
|
||||||
subsamples_[i].cipher_bytes = cipher_bytes;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FrameCENCInfo::Write(BufferWriter* writer) const {
|
|
||||||
DCHECK(writer);
|
|
||||||
DCHECK(IsIvSizeValid(iv_.size()));
|
|
||||||
writer->AppendVector(iv_);
|
|
||||||
|
|
||||||
uint16_t subsample_count = subsamples_.size();
|
|
||||||
if (subsample_count == 0)
|
|
||||||
return;
|
|
||||||
writer->AppendInt(subsample_count);
|
|
||||||
|
|
||||||
for (uint16_t i = 0; i < subsample_count; ++i) {
|
|
||||||
writer->AppendInt(subsamples_[i].clear_bytes);
|
|
||||||
writer->AppendInt(subsamples_[i].cipher_bytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t FrameCENCInfo::ComputeSize() const {
|
|
||||||
uint16_t subsample_count = subsamples_.size();
|
|
||||||
if (subsample_count == 0)
|
|
||||||
return iv_.size();
|
|
||||||
|
|
||||||
return iv_.size() + sizeof(subsample_count) +
|
|
||||||
subsample_count * kSubsampleEntrySize;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t FrameCENCInfo::GetTotalSizeOfSubsamples() const {
|
|
||||||
size_t size = 0;
|
|
||||||
for (size_t i = 0; i < subsamples_.size(); ++i) {
|
|
||||||
size += subsamples_[i].clear_bytes + subsamples_[i].cipher_bytes;
|
|
||||||
}
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace mp4
|
|
||||||
} // namespace media
|
|
||||||
} // namespace edash_packager
|
|
|
@ -1,52 +0,0 @@
|
||||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
#ifndef MEDIA_FORMATS_MP4_CENC_H_
|
|
||||||
#define MEDIA_FORMATS_MP4_CENC_H_
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "packager/media/base/decrypt_config.h"
|
|
||||||
|
|
||||||
namespace edash_packager {
|
|
||||||
namespace media {
|
|
||||||
|
|
||||||
class BufferReader;
|
|
||||||
class BufferWriter;
|
|
||||||
|
|
||||||
namespace mp4 {
|
|
||||||
|
|
||||||
class FrameCENCInfo {
|
|
||||||
public:
|
|
||||||
FrameCENCInfo();
|
|
||||||
explicit FrameCENCInfo(const std::vector<uint8_t>& iv);
|
|
||||||
~FrameCENCInfo();
|
|
||||||
|
|
||||||
bool Parse(uint8_t iv_size, BufferReader* reader);
|
|
||||||
void Write(BufferWriter* writer) const;
|
|
||||||
size_t ComputeSize() const;
|
|
||||||
size_t GetTotalSizeOfSubsamples() const;
|
|
||||||
|
|
||||||
void AddSubsample(const SubsampleEntry& subsample) {
|
|
||||||
subsamples_.push_back(subsample);
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<uint8_t>& iv() const { return iv_; }
|
|
||||||
const std::vector<SubsampleEntry>& subsamples() const { return subsamples_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<uint8_t> iv_;
|
|
||||||
std::vector<SubsampleEntry> subsamples_;
|
|
||||||
|
|
||||||
// Not using DISALLOW_COPY_AND_ASSIGN here intentionally to allow the compiler
|
|
||||||
// generated copy constructor and assignment operator.
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace mp4
|
|
||||||
} // namespace media
|
|
||||||
} // namespace edash_packager
|
|
||||||
|
|
||||||
#endif // MEDIA_FORMATS_MP4_CENC_H_
|
|
|
@ -13,7 +13,6 @@
|
||||||
#include "packager/media/filters/vp8_parser.h"
|
#include "packager/media/filters/vp8_parser.h"
|
||||||
#include "packager/media/filters/vp9_parser.h"
|
#include "packager/media/filters/vp9_parser.h"
|
||||||
#include "packager/media/formats/mp4/box_definitions.h"
|
#include "packager/media/formats/mp4/box_definitions.h"
|
||||||
#include "packager/media/formats/mp4/cenc.h"
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// Generate 64bit IV by default.
|
// Generate 64bit IV by default.
|
||||||
|
@ -67,6 +66,11 @@ Status EncryptingFragmenter::InitializeFragment(int64_t first_sample_dts) {
|
||||||
|
|
||||||
traf()->auxiliary_size.sample_info_sizes.clear();
|
traf()->auxiliary_size.sample_info_sizes.clear();
|
||||||
traf()->auxiliary_offset.offsets.clear();
|
traf()->auxiliary_offset.offsets.clear();
|
||||||
|
if (IsSubsampleEncryptionRequired()) {
|
||||||
|
traf()->sample_encryption.flags |=
|
||||||
|
SampleEncryption::kUseSubsampleEncryption;
|
||||||
|
}
|
||||||
|
traf()->sample_encryption.sample_encryption_entries.clear();
|
||||||
|
|
||||||
const bool enable_encryption = clear_time_ <= 0;
|
const bool enable_encryption = clear_time_ <= 0;
|
||||||
if (!enable_encryption) {
|
if (!enable_encryption) {
|
||||||
|
@ -116,6 +120,7 @@ void EncryptingFragmenter::FinalizeFragmentForEncryption() {
|
||||||
DCHECK(!IsSubsampleEncryptionRequired());
|
DCHECK(!IsSubsampleEncryptionRequired());
|
||||||
saiz.default_sample_info_size = encryptor_->iv().size();
|
saiz.default_sample_info_size = encryptor_->iv().size();
|
||||||
}
|
}
|
||||||
|
traf()->sample_encryption.iv_size = encryptor_->iv().size();
|
||||||
}
|
}
|
||||||
|
|
||||||
Status EncryptingFragmenter::CreateEncryptor() {
|
Status EncryptingFragmenter::CreateEncryptor() {
|
||||||
|
@ -141,7 +146,8 @@ void EncryptingFragmenter::EncryptBytes(uint8_t* data, uint32_t size) {
|
||||||
Status EncryptingFragmenter::EncryptSample(scoped_refptr<MediaSample> sample) {
|
Status EncryptingFragmenter::EncryptSample(scoped_refptr<MediaSample> sample) {
|
||||||
DCHECK(encryptor_);
|
DCHECK(encryptor_);
|
||||||
|
|
||||||
FrameCENCInfo cenc_info(encryptor_->iv());
|
SampleEncryptionEntry sample_encryption_entry;
|
||||||
|
sample_encryption_entry.initialization_vector = encryptor_->iv();
|
||||||
uint8_t* data = sample->writable_data();
|
uint8_t* data = sample->writable_data();
|
||||||
if (IsSubsampleEncryptionRequired()) {
|
if (IsSubsampleEncryptionRequired()) {
|
||||||
if (vpx_parser_) {
|
if (vpx_parser_) {
|
||||||
|
@ -155,7 +161,7 @@ Status EncryptingFragmenter::EncryptSample(scoped_refptr<MediaSample> sample) {
|
||||||
subsample.clear_bytes = frame.uncompressed_header_size;
|
subsample.clear_bytes = frame.uncompressed_header_size;
|
||||||
subsample.cipher_bytes =
|
subsample.cipher_bytes =
|
||||||
frame.frame_size - frame.uncompressed_header_size;
|
frame.frame_size - frame.uncompressed_header_size;
|
||||||
cenc_info.AddSubsample(subsample);
|
sample_encryption_entry.subsamples.push_back(subsample);
|
||||||
if (subsample.cipher_bytes > 0)
|
if (subsample.cipher_bytes > 0)
|
||||||
EncryptBytes(data + subsample.clear_bytes, subsample.cipher_bytes);
|
EncryptBytes(data + subsample.clear_bytes, subsample.cipher_bytes);
|
||||||
data += frame.frame_size;
|
data += frame.frame_size;
|
||||||
|
@ -167,27 +173,30 @@ Status EncryptingFragmenter::EncryptSample(scoped_refptr<MediaSample> sample) {
|
||||||
if (!reader.ReadNBytesInto8(&nalu_length, nalu_length_size_))
|
if (!reader.ReadNBytesInto8(&nalu_length, nalu_length_size_))
|
||||||
return Status(error::MUXER_FAILURE, "Fail to read nalu_length.");
|
return Status(error::MUXER_FAILURE, "Fail to read nalu_length.");
|
||||||
|
|
||||||
SubsampleEntry subsample;
|
|
||||||
subsample.clear_bytes = nalu_length_size_ + 1;
|
|
||||||
subsample.cipher_bytes = nalu_length - 1;
|
|
||||||
if (!reader.SkipBytes(nalu_length)) {
|
if (!reader.SkipBytes(nalu_length)) {
|
||||||
return Status(error::MUXER_FAILURE,
|
return Status(error::MUXER_FAILURE,
|
||||||
"Sample size does not match nalu_length.");
|
"Sample size does not match nalu_length.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SubsampleEntry subsample;
|
||||||
|
subsample.clear_bytes = nalu_length_size_ + 1;
|
||||||
|
subsample.cipher_bytes = nalu_length - 1;
|
||||||
|
sample_encryption_entry.subsamples.push_back(subsample);
|
||||||
|
|
||||||
EncryptBytes(data + subsample.clear_bytes, subsample.cipher_bytes);
|
EncryptBytes(data + subsample.clear_bytes, subsample.cipher_bytes);
|
||||||
cenc_info.AddSubsample(subsample);
|
|
||||||
data += nalu_length_size_ + nalu_length;
|
data += nalu_length_size_ + nalu_length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The length of per-sample auxiliary datum, defined in CENC ch. 7.
|
// The length of per-sample auxiliary datum, defined in CENC ch. 7.
|
||||||
traf()->auxiliary_size.sample_info_sizes.push_back(cenc_info.ComputeSize());
|
traf()->auxiliary_size.sample_info_sizes.push_back(
|
||||||
|
sample_encryption_entry.ComputeSize());
|
||||||
} else {
|
} else {
|
||||||
EncryptBytes(data, sample->data_size());
|
EncryptBytes(data, sample->data_size());
|
||||||
}
|
}
|
||||||
|
|
||||||
cenc_info.Write(aux_data());
|
traf()->sample_encryption.sample_encryption_entries.push_back(
|
||||||
|
sample_encryption_entry);
|
||||||
encryptor_->UpdateIv();
|
encryptor_->UpdateIv();
|
||||||
return Status::OK;
|
return Status::OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,7 +84,6 @@ Status Fragmenter::InitializeFragment(int64_t first_sample_dts) {
|
||||||
earliest_presentation_time_ = kInvalidTime;
|
earliest_presentation_time_ = kInvalidTime;
|
||||||
first_sap_time_ = kInvalidTime;
|
first_sap_time_ = kInvalidTime;
|
||||||
data_.reset(new BufferWriter());
|
data_.reset(new BufferWriter());
|
||||||
aux_data_.reset(new BufferWriter());
|
|
||||||
return Status::OK;
|
return Status::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,6 @@ class Fragmenter {
|
||||||
bool fragment_initialized() const { return fragment_initialized_; }
|
bool fragment_initialized() const { return fragment_initialized_; }
|
||||||
bool fragment_finalized() const { return fragment_finalized_; }
|
bool fragment_finalized() const { return fragment_finalized_; }
|
||||||
BufferWriter* data() { return data_.get(); }
|
BufferWriter* data() { return data_.get(); }
|
||||||
BufferWriter* aux_data() { return aux_data_.get(); }
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
TrackFragment* traf() { return traf_; }
|
TrackFragment* traf() { return traf_; }
|
||||||
|
@ -82,7 +81,6 @@ class Fragmenter {
|
||||||
int64_t earliest_presentation_time_;
|
int64_t earliest_presentation_time_;
|
||||||
int64_t first_sap_time_;
|
int64_t first_sap_time_;
|
||||||
scoped_ptr<BufferWriter> data_;
|
scoped_ptr<BufferWriter> data_;
|
||||||
scoped_ptr<BufferWriter> aux_data_;
|
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(Fragmenter);
|
DISALLOW_COPY_AND_ASSIGN(Fragmenter);
|
||||||
};
|
};
|
||||||
|
|
|
@ -22,8 +22,6 @@
|
||||||
'box_definitions.h',
|
'box_definitions.h',
|
||||||
'box_reader.cc',
|
'box_reader.cc',
|
||||||
'box_reader.h',
|
'box_reader.h',
|
||||||
'cenc.cc',
|
|
||||||
'cenc.h',
|
|
||||||
'chunk_info_iterator.cc',
|
'chunk_info_iterator.cc',
|
||||||
'chunk_info_iterator.h',
|
'chunk_info_iterator.h',
|
||||||
'composition_offset_iterator.cc',
|
'composition_offset_iterator.cc',
|
||||||
|
|
|
@ -25,6 +25,10 @@ namespace edash_packager {
|
||||||
namespace media {
|
namespace media {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
const char kKey[] =
|
||||||
|
"\xeb\xdd\x62\xf1\x68\x14\xd2\x7b\x68\xef\x12\x2a\xfc\xe4\xae\x3c";
|
||||||
|
const char kKeyId[] = "0123456789012345";
|
||||||
|
|
||||||
class MockKeySource : public KeySource {
|
class MockKeySource : public KeySource {
|
||||||
public:
|
public:
|
||||||
MOCK_METHOD1(FetchKeys, Status(const std::vector<uint8_t>& pssh_data));
|
MOCK_METHOD1(FetchKeys, Status(const std::vector<uint8_t>& pssh_data));
|
||||||
|
@ -225,7 +229,7 @@ TEST_F(MP4MediaParserTest, NON_FRAGMENTED_MP4) {
|
||||||
|
|
||||||
TEST_F(MP4MediaParserTest, CencWithoutDecryptionSource) {
|
TEST_F(MP4MediaParserTest, CencWithoutDecryptionSource) {
|
||||||
// Parsing should fail but it will get the streams successfully.
|
// Parsing should fail but it will get the streams successfully.
|
||||||
EXPECT_FALSE(ParseMP4File("bear-640x360-v_frag-cenc.mp4", 512));
|
EXPECT_FALSE(ParseMP4File("bear-640x360-v_frag-cenc-aux.mp4", 512));
|
||||||
EXPECT_EQ(1u, num_streams_);
|
EXPECT_EQ(1u, num_streams_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,20 +237,16 @@ TEST_F(MP4MediaParserTest, CencInitWithoutDecryptionSource) {
|
||||||
InitializeParser(NULL);
|
InitializeParser(NULL);
|
||||||
|
|
||||||
std::vector<uint8_t> buffer =
|
std::vector<uint8_t> buffer =
|
||||||
ReadTestDataFile("bear-640x360-v_frag-cenc.mp4");
|
ReadTestDataFile("bear-640x360-v_frag-cenc-aux.mp4");
|
||||||
const int kFirstMoofOffset = 1646;
|
const int kFirstMoofOffset = 1646;
|
||||||
EXPECT_TRUE(AppendDataInPieces(buffer.data(), kFirstMoofOffset, 512));
|
EXPECT_TRUE(AppendDataInPieces(buffer.data(), kFirstMoofOffset, 512));
|
||||||
EXPECT_EQ(1u, num_streams_);
|
EXPECT_EQ(1u, num_streams_);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MP4MediaParserTest, CencWithDecryptionSource) {
|
TEST_F(MP4MediaParserTest, CencWithDecryptionSourceAndAuxInMdat) {
|
||||||
MockKeySource mock_key_source;
|
MockKeySource mock_key_source;
|
||||||
EXPECT_CALL(mock_key_source, FetchKeys(_)).WillOnce(Return(Status::OK));
|
EXPECT_CALL(mock_key_source, FetchKeys(_)).WillOnce(Return(Status::OK));
|
||||||
|
|
||||||
const char kKey[] =
|
|
||||||
"\xeb\xdd\x62\xf1\x68\x14\xd2\x7b\x68\xef\x12\x2a\xfc\xe4\xae\x3c";
|
|
||||||
const char kKeyId[] = "0123456789012345";
|
|
||||||
|
|
||||||
EncryptionKey encryption_key;
|
EncryptionKey encryption_key;
|
||||||
encryption_key.key.assign(kKey, kKey + strlen(kKey));
|
encryption_key.key.assign(kKey, kKey + strlen(kKey));
|
||||||
EXPECT_CALL(mock_key_source,
|
EXPECT_CALL(mock_key_source,
|
||||||
|
@ -256,7 +256,26 @@ TEST_F(MP4MediaParserTest, CencWithDecryptionSource) {
|
||||||
InitializeParser(&mock_key_source);
|
InitializeParser(&mock_key_source);
|
||||||
|
|
||||||
std::vector<uint8_t> buffer =
|
std::vector<uint8_t> buffer =
|
||||||
ReadTestDataFile("bear-640x360-v_frag-cenc.mp4");
|
ReadTestDataFile("bear-640x360-v_frag-cenc-aux.mp4");
|
||||||
|
EXPECT_TRUE(AppendDataInPieces(buffer.data(), buffer.size(), 512));
|
||||||
|
EXPECT_EQ(1u, num_streams_);
|
||||||
|
EXPECT_EQ(82u, num_samples_);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(MP4MediaParserTest, CencWithDecryptionSourceAndSenc) {
|
||||||
|
MockKeySource mock_key_source;
|
||||||
|
EXPECT_CALL(mock_key_source, FetchKeys(_)).WillOnce(Return(Status::OK));
|
||||||
|
|
||||||
|
EncryptionKey encryption_key;
|
||||||
|
encryption_key.key.assign(kKey, kKey + strlen(kKey));
|
||||||
|
EXPECT_CALL(mock_key_source,
|
||||||
|
GetKey(std::vector<uint8_t>(kKeyId, kKeyId + strlen(kKeyId)), _))
|
||||||
|
.WillOnce(DoAll(SetArgPointee<1>(encryption_key), Return(Status::OK)));
|
||||||
|
|
||||||
|
InitializeParser(&mock_key_source);
|
||||||
|
|
||||||
|
std::vector<uint8_t> buffer =
|
||||||
|
ReadTestDataFile("bear-640x360-v_frag-cenc-senc.mp4");
|
||||||
EXPECT_TRUE(AppendDataInPieces(buffer.data(), buffer.size(), 512));
|
EXPECT_TRUE(AppendDataInPieces(buffer.data(), buffer.size(), 512));
|
||||||
EXPECT_EQ(1u, num_streams_);
|
EXPECT_EQ(1u, num_streams_);
|
||||||
EXPECT_EQ(82u, num_samples_);
|
EXPECT_EQ(82u, num_samples_);
|
||||||
|
|
|
@ -385,39 +385,41 @@ Status Segmenter::FinalizeFragment(bool finalize_segment,
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaData mdat;
|
MediaData mdat;
|
||||||
// Fill in data offsets. Data offset base is moof size + mdat box size.
|
// Data offset relative to 'moof': moof size + mdat header size.
|
||||||
// (mdat is still empty, mdat size is the same as mdat box size).
|
// The code will also update box sizes for moof_ and its child boxes.
|
||||||
uint64_t base = moof_->ComputeSize() + mdat.ComputeSize();
|
uint64_t data_offset = moof_->ComputeSize() + mdat.HeaderSize();
|
||||||
|
// 'traf' should follow 'mfhd' moof header box.
|
||||||
|
uint64_t next_traf_position = moof_->HeaderSize() + moof_->header.box_size();
|
||||||
for (size_t i = 0; i < moof_->tracks.size(); ++i) {
|
for (size_t i = 0; i < moof_->tracks.size(); ++i) {
|
||||||
TrackFragment& traf = moof_->tracks[i];
|
TrackFragment& traf = moof_->tracks[i];
|
||||||
Fragmenter* fragmenter = fragmenters_[i];
|
if (traf.auxiliary_offset.offsets.size() > 0) {
|
||||||
if (fragmenter->aux_data()->Size() > 0) {
|
DCHECK_EQ(traf.auxiliary_offset.offsets.size(), 1u);
|
||||||
traf.auxiliary_offset.offsets[0] += base;
|
DCHECK(!traf.sample_encryption.sample_encryption_entries.empty());
|
||||||
base += fragmenter->aux_data()->Size();
|
|
||||||
|
next_traf_position += traf.box_size();
|
||||||
|
// SampleEncryption 'senc' box should be the last box in 'traf'.
|
||||||
|
// |auxiliary_offset| should point to the data of SampleEncryption.
|
||||||
|
traf.auxiliary_offset.offsets[0] =
|
||||||
|
next_traf_position - traf.sample_encryption.box_size() +
|
||||||
|
traf.sample_encryption.HeaderSize() +
|
||||||
|
sizeof(uint32_t); // for sample count field in 'senc'
|
||||||
}
|
}
|
||||||
traf.runs[0].data_offset += base;
|
traf.runs[0].data_offset = data_offset + mdat.data_size;
|
||||||
base += fragmenter->data()->Size();
|
mdat.data_size += fragmenters_[i]->data()->Size();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate segment reference.
|
// Generate segment reference.
|
||||||
sidx_->references.resize(sidx_->references.size() + 1);
|
sidx_->references.resize(sidx_->references.size() + 1);
|
||||||
fragmenters_[GetReferenceStreamId()]->GenerateSegmentReference(
|
fragmenters_[GetReferenceStreamId()]->GenerateSegmentReference(
|
||||||
&sidx_->references[sidx_->references.size() - 1]);
|
&sidx_->references[sidx_->references.size() - 1]);
|
||||||
sidx_->references[sidx_->references.size() - 1].referenced_size = base;
|
sidx_->references[sidx_->references.size() - 1].referenced_size =
|
||||||
|
data_offset + mdat.data_size;
|
||||||
|
|
||||||
// Write the fragment to buffer.
|
// Write the fragment to buffer.
|
||||||
moof_->Write(fragment_buffer_.get());
|
moof_->Write(fragment_buffer_.get());
|
||||||
|
|
||||||
for (size_t i = 0; i < moof_->tracks.size(); ++i) {
|
|
||||||
Fragmenter* fragmenter = fragmenters_[i];
|
|
||||||
mdat.data_size =
|
|
||||||
fragmenter->aux_data()->Size() + fragmenter->data()->Size();
|
|
||||||
mdat.WriteHeader(fragment_buffer_.get());
|
mdat.WriteHeader(fragment_buffer_.get());
|
||||||
if (fragmenter->aux_data()->Size()) {
|
for (Fragmenter* fragmenter : fragmenters_)
|
||||||
fragment_buffer_->AppendBuffer(*fragmenter->aux_data());
|
|
||||||
}
|
|
||||||
fragment_buffer_->AppendBuffer(*fragmenter->data());
|
fragment_buffer_->AppendBuffer(*fragmenter->data());
|
||||||
}
|
|
||||||
|
|
||||||
// Increase sequence_number for next fragment.
|
// Increase sequence_number for next fragment.
|
||||||
++moof_->header.sequence_number;
|
++moof_->header.sequence_number;
|
||||||
|
|
|
@ -40,6 +40,12 @@ struct TrackRunInfo {
|
||||||
const AudioSampleEntry* audio_description;
|
const AudioSampleEntry* audio_description;
|
||||||
const VideoSampleEntry* video_description;
|
const VideoSampleEntry* video_description;
|
||||||
|
|
||||||
|
// Stores sample encryption entries, which is populated from 'senc' box if it
|
||||||
|
// is available, otherwise will try to load from cenc auxiliary information.
|
||||||
|
std::vector<SampleEncryptionEntry> sample_encryption_entries;
|
||||||
|
|
||||||
|
// These variables are useful to load |sample_encryption_entries| from cenc
|
||||||
|
// auxiliary information when 'senc' box is not available.
|
||||||
int64_t aux_info_start_offset; // Only valid if aux_info_total_size > 0.
|
int64_t aux_info_start_offset; // Only valid if aux_info_total_size > 0.
|
||||||
int aux_info_default_size;
|
int aux_info_default_size;
|
||||||
std::vector<uint8_t> aux_info_sizes; // Populated if default_size == 0.
|
std::vector<uint8_t> aux_info_sizes; // Populated if default_size == 0.
|
||||||
|
@ -300,6 +306,40 @@ bool TrackRunIterator::Init(const MovieFragment& moof) {
|
||||||
RCHECK(desc_idx > 0); // Descriptions are one-indexed in the file
|
RCHECK(desc_idx > 0); // Descriptions are one-indexed in the file
|
||||||
desc_idx -= 1;
|
desc_idx -= 1;
|
||||||
|
|
||||||
|
const AudioSampleEntry* audio_sample_entry = NULL;
|
||||||
|
const VideoSampleEntry* video_sample_entry = NULL;
|
||||||
|
switch (stsd.type) {
|
||||||
|
case kAudio:
|
||||||
|
RCHECK(!stsd.audio_entries.empty());
|
||||||
|
if (desc_idx > stsd.audio_entries.size())
|
||||||
|
desc_idx = 0;
|
||||||
|
audio_sample_entry = &stsd.audio_entries[desc_idx];
|
||||||
|
break;
|
||||||
|
case kVideo:
|
||||||
|
RCHECK(!stsd.video_entries.empty());
|
||||||
|
if (desc_idx > stsd.video_entries.size())
|
||||||
|
desc_idx = 0;
|
||||||
|
video_sample_entry = &stsd.video_entries[desc_idx];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
NOTREACHED();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SampleEncryptionEntries should not have been parsed, without having
|
||||||
|
// iv_size. Parse the box now.
|
||||||
|
DCHECK(traf.sample_encryption.sample_encryption_entries.empty());
|
||||||
|
std::vector<SampleEncryptionEntry> sample_encryption_entries;
|
||||||
|
if (!traf.sample_encryption.sample_encryption_data.empty()) {
|
||||||
|
RCHECK(audio_sample_entry || video_sample_entry);
|
||||||
|
const uint8_t default_iv_size =
|
||||||
|
audio_sample_entry
|
||||||
|
? audio_sample_entry->sinf.info.track_encryption.default_iv_size
|
||||||
|
: video_sample_entry->sinf.info.track_encryption.default_iv_size;
|
||||||
|
RCHECK(traf.sample_encryption.ParseFromSampleEncryptionData(
|
||||||
|
default_iv_size, &sample_encryption_entries));
|
||||||
|
}
|
||||||
|
|
||||||
int64_t run_start_dts = traf.decode_time_absent
|
int64_t run_start_dts = traf.decode_time_absent
|
||||||
? next_fragment_start_dts_[i]
|
? next_fragment_start_dts_[i]
|
||||||
: traf.decode_time.decode_time;
|
: traf.decode_time.decode_time;
|
||||||
|
@ -314,27 +354,30 @@ bool TrackRunIterator::Init(const MovieFragment& moof) {
|
||||||
tri.sample_start_offset = trun.data_offset;
|
tri.sample_start_offset = trun.data_offset;
|
||||||
|
|
||||||
tri.track_type = stsd.type;
|
tri.track_type = stsd.type;
|
||||||
if (tri.track_type == kAudio) {
|
tri.audio_description = audio_sample_entry;
|
||||||
RCHECK(!stsd.audio_entries.empty());
|
tri.video_description = video_sample_entry;
|
||||||
if (desc_idx > stsd.audio_entries.size())
|
|
||||||
desc_idx = 0;
|
|
||||||
tri.audio_description = &stsd.audio_entries[desc_idx];
|
|
||||||
} else if (tri.track_type == kVideo) {
|
|
||||||
RCHECK(!stsd.video_entries.empty());
|
|
||||||
if (desc_idx > stsd.video_entries.size())
|
|
||||||
desc_idx = 0;
|
|
||||||
tri.video_description = &stsd.video_entries[desc_idx];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collect information from the auxiliary_offset entry with the same index
|
tri.aux_info_start_offset = -1;
|
||||||
// in the 'saiz' container as the current run's index in the 'trun'
|
tri.aux_info_total_size = 0;
|
||||||
// container, if it is present.
|
// Populate sample encryption entries from SampleEncryption 'senc' box if
|
||||||
if (traf.auxiliary_offset.offsets.size() > j) {
|
// it is available; otherwise initialize aux_info variables, which will
|
||||||
|
// be used to populate sample encryption entries later in CacheAuxInfo.
|
||||||
|
if (!sample_encryption_entries.empty()) {
|
||||||
|
RCHECK(sample_encryption_entries.size() >=
|
||||||
|
sample_count_sum + trun.sample_count);
|
||||||
|
for (size_t k = 0; k < trun.sample_count; ++k) {
|
||||||
|
tri.sample_encryption_entries.push_back(
|
||||||
|
sample_encryption_entries[sample_count_sum + k]);
|
||||||
|
}
|
||||||
|
} else if (traf.auxiliary_offset.offsets.size() > j) {
|
||||||
|
// Collect information from the auxiliary_offset entry with the same
|
||||||
|
// index in the 'saiz' container as the current run's index in the
|
||||||
|
// 'trun' container, if it is present.
|
||||||
|
tri.aux_info_start_offset = traf.auxiliary_offset.offsets[j];
|
||||||
// There should be an auxiliary info entry corresponding to each sample
|
// There should be an auxiliary info entry corresponding to each sample
|
||||||
// in the auxiliary offset entry's corresponding track run.
|
// in the auxiliary offset entry's corresponding track run.
|
||||||
RCHECK(traf.auxiliary_size.sample_count >=
|
RCHECK(traf.auxiliary_size.sample_count >=
|
||||||
sample_count_sum + trun.sample_count);
|
sample_count_sum + trun.sample_count);
|
||||||
tri.aux_info_start_offset = traf.auxiliary_offset.offsets[j];
|
|
||||||
tri.aux_info_default_size =
|
tri.aux_info_default_size =
|
||||||
traf.auxiliary_size.default_sample_info_size;
|
traf.auxiliary_size.default_sample_info_size;
|
||||||
if (tri.aux_info_default_size == 0) {
|
if (tri.aux_info_default_size == 0) {
|
||||||
|
@ -358,9 +401,6 @@ bool TrackRunIterator::Init(const MovieFragment& moof) {
|
||||||
tri.aux_info_total_size += tri.aux_info_sizes[k];
|
tri.aux_info_total_size += tri.aux_info_sizes[k];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
tri.aux_info_start_offset = -1;
|
|
||||||
tri.aux_info_total_size = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tri.samples.resize(trun.sample_count);
|
tri.samples.resize(trun.sample_count);
|
||||||
|
@ -391,7 +431,6 @@ void TrackRunIterator::ResetRun() {
|
||||||
sample_dts_ = run_itr_->start_dts;
|
sample_dts_ = run_itr_->start_dts;
|
||||||
sample_offset_ = run_itr_->sample_start_offset;
|
sample_offset_ = run_itr_->sample_start_offset;
|
||||||
sample_itr_ = run_itr_->samples.begin();
|
sample_itr_ = run_itr_->samples.begin();
|
||||||
cenc_info_.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrackRunIterator::AdvanceSample() {
|
void TrackRunIterator::AdvanceSample() {
|
||||||
|
@ -405,14 +444,17 @@ void TrackRunIterator::AdvanceSample() {
|
||||||
// info is available in the stream.
|
// info is available in the stream.
|
||||||
bool TrackRunIterator::AuxInfoNeedsToBeCached() {
|
bool TrackRunIterator::AuxInfoNeedsToBeCached() {
|
||||||
DCHECK(IsRunValid());
|
DCHECK(IsRunValid());
|
||||||
return is_encrypted() && aux_info_size() > 0 && cenc_info_.size() == 0;
|
return is_encrypted() && aux_info_size() > 0 &&
|
||||||
|
run_itr_->sample_encryption_entries.size() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This implementation currently only caches CENC auxiliary info.
|
// This implementation currently only caches CENC auxiliary info.
|
||||||
bool TrackRunIterator::CacheAuxInfo(const uint8_t* buf, int buf_size) {
|
bool TrackRunIterator::CacheAuxInfo(const uint8_t* buf, int buf_size) {
|
||||||
RCHECK(AuxInfoNeedsToBeCached() && buf_size >= aux_info_size());
|
RCHECK(AuxInfoNeedsToBeCached() && buf_size >= aux_info_size());
|
||||||
|
|
||||||
cenc_info_.resize(run_itr_->samples.size());
|
std::vector<SampleEncryptionEntry>& sample_encryption_entries =
|
||||||
|
runs_[run_itr_ - runs_.begin()].sample_encryption_entries;
|
||||||
|
sample_encryption_entries.resize(run_itr_->samples.size());
|
||||||
int64_t pos = 0;
|
int64_t pos = 0;
|
||||||
for (size_t i = 0; i < run_itr_->samples.size(); i++) {
|
for (size_t i = 0; i < run_itr_->samples.size(); i++) {
|
||||||
int info_size = run_itr_->aux_info_default_size;
|
int info_size = run_itr_->aux_info_default_size;
|
||||||
|
@ -420,7 +462,9 @@ bool TrackRunIterator::CacheAuxInfo(const uint8_t* buf, int buf_size) {
|
||||||
info_size = run_itr_->aux_info_sizes[i];
|
info_size = run_itr_->aux_info_sizes[i];
|
||||||
|
|
||||||
BufferReader reader(buf + pos, info_size);
|
BufferReader reader(buf + pos, info_size);
|
||||||
RCHECK(cenc_info_[i].Parse(track_encryption().default_iv_size, &reader));
|
const bool has_subsamples = info_size > track_encryption().default_iv_size;
|
||||||
|
RCHECK(sample_encryption_entries[i].ParseFromBuffer(
|
||||||
|
track_encryption().default_iv_size, has_subsamples, &reader));
|
||||||
pos += info_size;
|
pos += info_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -539,12 +583,14 @@ const TrackEncryption& TrackRunIterator::track_encryption() const {
|
||||||
|
|
||||||
scoped_ptr<DecryptConfig> TrackRunIterator::GetDecryptConfig() {
|
scoped_ptr<DecryptConfig> TrackRunIterator::GetDecryptConfig() {
|
||||||
size_t sample_idx = sample_itr_ - run_itr_->samples.begin();
|
size_t sample_idx = sample_itr_ - run_itr_->samples.begin();
|
||||||
DCHECK_LT(sample_idx, cenc_info_.size());
|
DCHECK_LT(sample_idx, run_itr_->sample_encryption_entries.size());
|
||||||
const FrameCENCInfo& cenc_info = cenc_info_[sample_idx];
|
const SampleEncryptionEntry& sample_encryption_entry =
|
||||||
|
run_itr_->sample_encryption_entries[sample_idx];
|
||||||
DCHECK(is_encrypted());
|
DCHECK(is_encrypted());
|
||||||
DCHECK(!AuxInfoNeedsToBeCached());
|
DCHECK(!AuxInfoNeedsToBeCached());
|
||||||
|
|
||||||
const size_t total_size_of_subsamples = cenc_info.GetTotalSizeOfSubsamples();
|
const size_t total_size_of_subsamples =
|
||||||
|
sample_encryption_entry.GetTotalSizeOfSubsamples();
|
||||||
if (total_size_of_subsamples != 0 &&
|
if (total_size_of_subsamples != 0 &&
|
||||||
total_size_of_subsamples != static_cast<size_t>(sample_size())) {
|
total_size_of_subsamples != static_cast<size_t>(sample_size())) {
|
||||||
LOG(ERROR) << "Incorrect CENC subsample size.";
|
LOG(ERROR) << "Incorrect CENC subsample size.";
|
||||||
|
@ -553,9 +599,9 @@ scoped_ptr<DecryptConfig> TrackRunIterator::GetDecryptConfig() {
|
||||||
|
|
||||||
return scoped_ptr<DecryptConfig>(new DecryptConfig(
|
return scoped_ptr<DecryptConfig>(new DecryptConfig(
|
||||||
track_encryption().default_kid,
|
track_encryption().default_kid,
|
||||||
cenc_info.iv(),
|
sample_encryption_entry.initialization_vector,
|
||||||
0, // No offset to start of media data in MP4 using CENC.
|
0, // No offset to start of media data in MP4 using CENC.
|
||||||
cenc_info.subsamples()));
|
sample_encryption_entry.subsamples));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace mp4
|
} // namespace mp4
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
|
|
||||||
#include "packager/base/memory/scoped_ptr.h"
|
#include "packager/base/memory/scoped_ptr.h"
|
||||||
#include "packager/media/formats/mp4/box_definitions.h"
|
#include "packager/media/formats/mp4/box_definitions.h"
|
||||||
#include "packager/media/formats/mp4/cenc.h"
|
|
||||||
|
|
||||||
namespace edash_packager {
|
namespace edash_packager {
|
||||||
namespace media {
|
namespace media {
|
||||||
|
@ -111,7 +110,6 @@ class TrackRunIterator {
|
||||||
std::vector<TrackRunInfo>::const_iterator run_itr_;
|
std::vector<TrackRunInfo>::const_iterator run_itr_;
|
||||||
std::vector<SampleInfo>::const_iterator sample_itr_;
|
std::vector<SampleInfo>::const_iterator sample_itr_;
|
||||||
|
|
||||||
std::vector<FrameCENCInfo> cenc_info_;
|
|
||||||
// Track the start dts of the next segment, only useful if decode_time box is
|
// Track the start dts of the next segment, only useful if decode_time box is
|
||||||
// absent.
|
// absent.
|
||||||
std::vector<int64_t> next_fragment_start_dts_;
|
std::vector<int64_t> next_fragment_start_dts_;
|
||||||
|
|
|
@ -11,14 +11,16 @@
|
||||||
#include "packager/media/formats/mp4/rcheck.h"
|
#include "packager/media/formats/mp4/rcheck.h"
|
||||||
#include "packager/media/formats/mp4/track_run_iterator.h"
|
#include "packager/media/formats/mp4/track_run_iterator.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
// The sum of the elements in a vector initialized with SumAscending,
|
// The sum of the elements in a vector initialized with SumAscending,
|
||||||
// less the value of the last element.
|
// less the value of the last element.
|
||||||
static const int kSumAscending1 = 45;
|
const int kSumAscending1 = 45;
|
||||||
|
|
||||||
static const int kAudioScale = 48000;
|
const int kAudioScale = 48000;
|
||||||
static const int kVideoScale = 25;
|
const int kVideoScale = 25;
|
||||||
|
|
||||||
static const uint8_t kAuxInfo[] = {
|
const uint8_t kAuxInfo[] = {
|
||||||
// Sample 1: IV (no subsumples).
|
// Sample 1: IV (no subsumples).
|
||||||
0x41, 0x54, 0x65, 0x73, 0x74, 0x49, 0x76, 0x31,
|
0x41, 0x54, 0x65, 0x73, 0x74, 0x49, 0x76, 0x31,
|
||||||
// Sample 2: IV.
|
// Sample 2: IV.
|
||||||
|
@ -30,11 +32,39 @@ static const uint8_t kAuxInfo[] = {
|
||||||
// Sample 2: Subsample 2.
|
// Sample 2: Subsample 2.
|
||||||
0x00, 0x03, 0x00, 0x00, 0x00, 0x04};
|
0x00, 0x03, 0x00, 0x00, 0x00, 0x04};
|
||||||
|
|
||||||
static const char kIv1[] = {0x41, 0x54, 0x65, 0x73, 0x74, 0x49, 0x76, 0x31, };
|
const uint8_t kSampleEncryptionDataWithSubsamples[] = {
|
||||||
|
// Sample count.
|
||||||
|
0x00, 0x00, 0x00, 0x02,
|
||||||
|
// Sample 1: IV.
|
||||||
|
0x41, 0x54, 0x65, 0x73, 0x74, 0x49, 0x76, 0x31,
|
||||||
|
// Sample 1: Subsample count.
|
||||||
|
0x00, 0x01,
|
||||||
|
// Sample 1: Subsample 1.
|
||||||
|
0x00, 0x01, 0x00, 0x00, 0x00, 0x02,
|
||||||
|
// Sample 2: IV.
|
||||||
|
0x41, 0x54, 0x65, 0x73, 0x74, 0x49, 0x76, 0x32,
|
||||||
|
// Sample 2: Subsample count.
|
||||||
|
0x00, 0x02,
|
||||||
|
// Sample 2: Subsample 1.
|
||||||
|
0x00, 0x01, 0x00, 0x00, 0x00, 0x02,
|
||||||
|
// Sample 2: Subsample 2.
|
||||||
|
0x00, 0x03, 0x00, 0x00, 0x00, 0x04};
|
||||||
|
|
||||||
static const uint8_t kKeyId[] = {0x41, 0x47, 0x6f, 0x6f, 0x67, 0x6c,
|
const uint8_t kSampleEncryptionDataWithoutSubsamples[] = {
|
||||||
0x65, 0x54, 0x65, 0x73, 0x74, 0x4b,
|
// Sample count.
|
||||||
0x65, 0x79, 0x49, 0x44};
|
0x00, 0x00, 0x00, 0x02,
|
||||||
|
// Sample 1: IV.
|
||||||
|
0x41, 0x54, 0x65, 0x73, 0x74, 0x49, 0x76, 0x31,
|
||||||
|
// Sample 2: IV.
|
||||||
|
0x41, 0x54, 0x65, 0x73, 0x74, 0x49, 0x76, 0x32};
|
||||||
|
|
||||||
|
const char kIv1[] = {0x41, 0x54, 0x65, 0x73, 0x74, 0x49, 0x76, 0x31};
|
||||||
|
const char kIv2[] = {0x41, 0x54, 0x65, 0x73, 0x74, 0x49, 0x76, 0x32};
|
||||||
|
|
||||||
|
const uint8_t kKeyId[] = {0x41, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x54,
|
||||||
|
0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x49, 0x44};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
namespace edash_packager {
|
namespace edash_packager {
|
||||||
namespace media {
|
namespace media {
|
||||||
|
@ -143,6 +173,38 @@ class TrackRunIteratorTest : public testing::Test {
|
||||||
frag->runs[0].sample_sizes[1] = 10;
|
frag->runs[0].sample_sizes[1] = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AddSampleEncryption(uint8_t use_subsample_flag, TrackFragment* frag) {
|
||||||
|
frag->sample_encryption.iv_size = 8;
|
||||||
|
frag->sample_encryption.flags = use_subsample_flag;
|
||||||
|
if (use_subsample_flag) {
|
||||||
|
frag->sample_encryption.sample_encryption_data.assign(
|
||||||
|
kSampleEncryptionDataWithSubsamples,
|
||||||
|
kSampleEncryptionDataWithSubsamples +
|
||||||
|
arraysize(kSampleEncryptionDataWithSubsamples));
|
||||||
|
} else {
|
||||||
|
frag->sample_encryption.sample_encryption_data.assign(
|
||||||
|
kSampleEncryptionDataWithoutSubsamples,
|
||||||
|
kSampleEncryptionDataWithoutSubsamples +
|
||||||
|
arraysize(kSampleEncryptionDataWithoutSubsamples));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update sample sizes and aux info header.
|
||||||
|
frag->runs.resize(1);
|
||||||
|
frag->runs[0].sample_count = 2;
|
||||||
|
frag->auxiliary_offset.offsets.push_back(0);
|
||||||
|
frag->auxiliary_size.sample_count = 2;
|
||||||
|
if (use_subsample_flag) {
|
||||||
|
// Update sample sizes to match with subsample entries above.
|
||||||
|
frag->runs[0].sample_sizes[0] = 3;
|
||||||
|
frag->runs[0].sample_sizes[1] = 10;
|
||||||
|
// Set aux info header.
|
||||||
|
frag->auxiliary_size.sample_info_sizes.push_back(16);
|
||||||
|
frag->auxiliary_size.sample_info_sizes.push_back(22);
|
||||||
|
} else {
|
||||||
|
frag->auxiliary_size.default_sample_info_size = 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SetAscending(std::vector<uint32_t>* vec) {
|
void SetAscending(std::vector<uint32_t>* vec) {
|
||||||
vec->resize(10);
|
vec->resize(10);
|
||||||
for (size_t i = 0; i < vec->size(); i++)
|
for (size_t i = 0; i < vec->size(); i++)
|
||||||
|
@ -303,7 +365,77 @@ TEST_F(TrackRunIteratorTest, IgnoreUnknownAuxInfoTest) {
|
||||||
EXPECT_FALSE(iter_->AuxInfoNeedsToBeCached());
|
EXPECT_FALSE(iter_->AuxInfoNeedsToBeCached());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TrackRunIteratorTest, DecryptConfigTest) {
|
TEST_F(TrackRunIteratorTest,
|
||||||
|
DecryptConfigTestWithSampleEncryptionAndSubsample) {
|
||||||
|
AddEncryption(&moov_.tracks[1]);
|
||||||
|
iter_.reset(new TrackRunIterator(&moov_));
|
||||||
|
|
||||||
|
MovieFragment moof = CreateFragment();
|
||||||
|
AddSampleEncryption(SampleEncryption::kUseSubsampleEncryption,
|
||||||
|
&moof.tracks[1]);
|
||||||
|
|
||||||
|
ASSERT_TRUE(iter_->Init(moof));
|
||||||
|
// The run for track 2 will be the second, which is parsed according to
|
||||||
|
// data_offset.
|
||||||
|
iter_->AdvanceRun();
|
||||||
|
EXPECT_EQ(iter_->track_id(), 2u);
|
||||||
|
|
||||||
|
EXPECT_TRUE(iter_->is_encrypted());
|
||||||
|
// No need to cache aux info as it is already available in SampleEncryption.
|
||||||
|
EXPECT_FALSE(iter_->AuxInfoNeedsToBeCached());
|
||||||
|
EXPECT_EQ(iter_->aux_info_size(), 0);
|
||||||
|
EXPECT_EQ(iter_->sample_offset(), 200);
|
||||||
|
EXPECT_EQ(iter_->GetMaxClearOffset(), moof.tracks[1].runs[0].data_offset);
|
||||||
|
scoped_ptr<DecryptConfig> config = iter_->GetDecryptConfig();
|
||||||
|
EXPECT_EQ(std::vector<uint8_t>(kKeyId, kKeyId + arraysize(kKeyId)),
|
||||||
|
config->key_id());
|
||||||
|
EXPECT_EQ(std::vector<uint8_t>(kIv1, kIv1 + arraysize(kIv1)), config->iv());
|
||||||
|
EXPECT_EQ(config->subsamples().size(), 1u);
|
||||||
|
EXPECT_EQ(config->subsamples()[0].clear_bytes, 1u);
|
||||||
|
EXPECT_EQ(config->subsamples()[0].cipher_bytes, 2u);
|
||||||
|
iter_->AdvanceSample();
|
||||||
|
config = iter_->GetDecryptConfig();
|
||||||
|
EXPECT_EQ(std::vector<uint8_t>(kIv2, kIv2 + arraysize(kIv2)), config->iv());
|
||||||
|
EXPECT_EQ(config->subsamples().size(), 2u);
|
||||||
|
EXPECT_EQ(config->subsamples()[0].clear_bytes, 1u);
|
||||||
|
EXPECT_EQ(config->subsamples()[0].cipher_bytes, 2u);
|
||||||
|
EXPECT_EQ(config->subsamples()[1].clear_bytes, 3u);
|
||||||
|
EXPECT_EQ(config->subsamples()[1].cipher_bytes, 4u);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TrackRunIteratorTest,
|
||||||
|
DecryptConfigTestWithSampleEncryptionAndNoSubsample) {
|
||||||
|
AddEncryption(&moov_.tracks[1]);
|
||||||
|
iter_.reset(new TrackRunIterator(&moov_));
|
||||||
|
|
||||||
|
MovieFragment moof = CreateFragment();
|
||||||
|
AddSampleEncryption(!SampleEncryption::kUseSubsampleEncryption,
|
||||||
|
&moof.tracks[1]);
|
||||||
|
|
||||||
|
ASSERT_TRUE(iter_->Init(moof));
|
||||||
|
// The run for track 2 will be the second, which is parsed according to
|
||||||
|
// data_offset.
|
||||||
|
iter_->AdvanceRun();
|
||||||
|
EXPECT_EQ(iter_->track_id(), 2u);
|
||||||
|
|
||||||
|
EXPECT_TRUE(iter_->is_encrypted());
|
||||||
|
// No need to cache aux info as it is already available in SampleEncryption.
|
||||||
|
EXPECT_FALSE(iter_->AuxInfoNeedsToBeCached());
|
||||||
|
EXPECT_EQ(iter_->aux_info_size(), 0);
|
||||||
|
EXPECT_EQ(iter_->sample_offset(), 200);
|
||||||
|
EXPECT_EQ(iter_->GetMaxClearOffset(), moof.tracks[1].runs[0].data_offset);
|
||||||
|
scoped_ptr<DecryptConfig> config = iter_->GetDecryptConfig();
|
||||||
|
EXPECT_EQ(std::vector<uint8_t>(kKeyId, kKeyId + arraysize(kKeyId)),
|
||||||
|
config->key_id());
|
||||||
|
EXPECT_EQ(std::vector<uint8_t>(kIv1, kIv1 + arraysize(kIv1)), config->iv());
|
||||||
|
EXPECT_EQ(config->subsamples().size(), 0u);
|
||||||
|
iter_->AdvanceSample();
|
||||||
|
config = iter_->GetDecryptConfig();
|
||||||
|
EXPECT_EQ(std::vector<uint8_t>(kIv2, kIv2 + arraysize(kIv2)), config->iv());
|
||||||
|
EXPECT_EQ(config->subsamples().size(), 0u);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TrackRunIteratorTest, DecryptConfigTestWithAuxInfo) {
|
||||||
AddEncryption(&moov_.tracks[1]);
|
AddEncryption(&moov_.tracks[1]);
|
||||||
iter_.reset(new TrackRunIterator(&moov_));
|
iter_.reset(new TrackRunIterator(&moov_));
|
||||||
|
|
||||||
|
@ -316,7 +448,7 @@ TEST_F(TrackRunIteratorTest, DecryptConfigTest) {
|
||||||
// element in the file.
|
// element in the file.
|
||||||
EXPECT_EQ(iter_->track_id(), 2u);
|
EXPECT_EQ(iter_->track_id(), 2u);
|
||||||
EXPECT_TRUE(iter_->is_encrypted());
|
EXPECT_TRUE(iter_->is_encrypted());
|
||||||
EXPECT_TRUE(iter_->AuxInfoNeedsToBeCached());
|
ASSERT_TRUE(iter_->AuxInfoNeedsToBeCached());
|
||||||
EXPECT_EQ(static_cast<uint32_t>(iter_->aux_info_size()), arraysize(kAuxInfo));
|
EXPECT_EQ(static_cast<uint32_t>(iter_->aux_info_size()), arraysize(kAuxInfo));
|
||||||
EXPECT_EQ(iter_->aux_info_offset(), 50);
|
EXPECT_EQ(iter_->aux_info_offset(), 50);
|
||||||
EXPECT_EQ(iter_->GetMaxClearOffset(), 50);
|
EXPECT_EQ(iter_->GetMaxClearOffset(), 50);
|
||||||
|
@ -328,11 +460,9 @@ TEST_F(TrackRunIteratorTest, DecryptConfigTest) {
|
||||||
EXPECT_EQ(iter_->sample_offset(), 200);
|
EXPECT_EQ(iter_->sample_offset(), 200);
|
||||||
EXPECT_EQ(iter_->GetMaxClearOffset(), moof.tracks[0].runs[0].data_offset);
|
EXPECT_EQ(iter_->GetMaxClearOffset(), moof.tracks[0].runs[0].data_offset);
|
||||||
scoped_ptr<DecryptConfig> config = iter_->GetDecryptConfig();
|
scoped_ptr<DecryptConfig> config = iter_->GetDecryptConfig();
|
||||||
ASSERT_EQ(arraysize(kKeyId), config->key_id().size());
|
EXPECT_EQ(std::vector<uint8_t>(kKeyId, kKeyId + arraysize(kKeyId)),
|
||||||
EXPECT_TRUE(
|
config->key_id());
|
||||||
!memcmp(kKeyId, config->key_id().data(), config->key_id().size()));
|
EXPECT_EQ(std::vector<uint8_t>(kIv1, kIv1 + arraysize(kIv1)), config->iv());
|
||||||
ASSERT_EQ(arraysize(kIv1), config->iv().size());
|
|
||||||
EXPECT_TRUE(!memcmp(kIv1, config->iv().data(), config->iv().size()));
|
|
||||||
EXPECT_TRUE(config->subsamples().empty());
|
EXPECT_TRUE(config->subsamples().empty());
|
||||||
iter_->AdvanceSample();
|
iter_->AdvanceSample();
|
||||||
config = iter_->GetDecryptConfig();
|
config = iter_->GetDecryptConfig();
|
||||||
|
|
|
@ -41,7 +41,11 @@ bear-640x360-non_square_pixel-with_pasp.mp4 - A non-square pixel version of the
|
||||||
bear-640x360-non_square_pixel-without_pasp.mp4 - A non-square pixel version of the video track of bear-640x360.mp4 without PixelAspectRatio box.
|
bear-640x360-non_square_pixel-without_pasp.mp4 - A non-square pixel version of the video track of bear-640x360.mp4 without PixelAspectRatio box.
|
||||||
|
|
||||||
// Encrypted Files.
|
// Encrypted Files.
|
||||||
bear-640x360-v_frag-cenc.mp4 - A fragmented MP4 version of the video track of bear-640x360.mp4 encrypted (ISO CENC) using key ID [1] and key [2].
|
bear-640x360-v_frag-cenc-aux.mp4 - A fragmented MP4 version of the video track of bear-640x360.mp4
|
||||||
|
encrypted (ISO CENC) using key ID [1] and key [2] and with sample
|
||||||
|
encryption auxiliary information in the beginning of mdat box.
|
||||||
|
bear-640x360-v_frag-cenc-senc.mp4 - Same as above, but with sample encryption information stored in
|
||||||
|
senc box.
|
||||||
|
|
||||||
[1] 30313233343536373839303132333435
|
[1] 30313233343536373839303132333435
|
||||||
[2] ebdd62f16814d27b68ef122afce4ae3c
|
[2] ebdd62f16814d27b68ef122afce4ae3c
|
||||||
|
|
Binary file not shown.
Loading…
Reference in New Issue