Projects
Multimedia
bento4
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 2
View file
bento4.changes
Changed
@@ -1,4 +1,9 @@ ------------------------------------------------------------------- +Wed Jun 7 07:03:05 UTC 2017 - aloisio@gmx.com + +- Update to 1.5.0-615 + +------------------------------------------------------------------- Tue Apr 11 11:00:01 UTC 2017 - aloisio@gmx.com - Initial package (v1.5.0-614)
View file
bento4.spec
Changed
@@ -16,10 +16,10 @@ # -%define _over 1.5.0-614 -%define _libver 1_5_0r614 +%define _over 1.5.0-615 +%define _libver 1_5_0r615 Name: bento4 -Version: 1.5.0r614 +Version: 1.5.0r615 Release: 0 Summary: C++ toolkit for all your MP4 and MPEG DASH media format needs License: GPL-2.0
View file
bento4-1.5.0r614.tar.gz/Documents/Websites/www.bok.net/dash/players/html5/presets.js -> bento4-1.5.0r615.tar.gz/Documents/Websites/www.bok.net/dash/players/html5/presets.js
Changed
@@ -17,59 +17,59 @@ emeConfig: 'manual' }, { - title: 'Guido Bunny WV', - url: 'https://s3.amazonaws.com/exp.tutorial/output_bunny/stream.mpd', - licenseUrl: 'https://wv.test.expressplay.com/hms/wv/rights/?ExpressPlayToken=AQAAAw3paOwAAABQTIL_9kQ0ovZm4rsIOjZosklIDNdmy4olq4L9ivYyzS5RiMqVyPhTQT4Z2lWqQskU4Kn9Lno4H-pQSbJ8NxQiyB3Sb-w0OGBLhYlz29DiPoP8wTJginn-6qHfMsbxv5_03U5FMg', - emeConfig: 'license-url' - }, - { - title: 'Local Bunny ClearKey', - url: 'http://192.168.1.199:8081/bunny_wv/stream.mpd', - kid: '12341234123412341234123412341234', - key: '43215678123412341234123412341234', + title: 'Local Test, CENC, ClearKey', + url: 'http://localhost:8081/clearkey_cenc/stream.mpd', + kid: '000102030405060708090a0b0c0d0e0f', + key: '00112233445566778899aabbccddeeff', emeConfig: 'manual' }, { - title: 'Local Bunny WV', - url: 'http://192.168.1.199:8081/bunny_wv/stream.mpd', - licenseUrl: 'https://wv.test.expressplay.com/hms/wv/rights/?ExpressPlayToken=AQAAAw3paOwAAABQTIL_9kQ0ovZm4rsIOjZosklIDNdmy4olq4L9ivYyzS5RiMqVyPhTQT4Z2lWqQskU4Kn9Lno4H-pQSbJ8NxQiyB3Sb-w0OGBLhYlz29DiPoP8wTJginn-6qHfMsbxv5_03U5FMg', - emeConfig: 'license-url' + title: 'Local Test, CBC1, ClearKey', + url: 'http://localhost:8081/clearkey__cbc1/stream.mpd', + kid: '000102030405060708090a0b0c0d0e0f', + key: '00112233445566778899aabbccddeeff', + emeConfig: 'manual' }, { - title: 'Local Bunny WV - Video Only', - url: 'http://192.168.1.199:8081/bunny_video_wv/stream.mpd', - licenseUrl: 'https://wv.test.expressplay.com/hms/wv/rights/?ExpressPlayToken=AQAAAw3paOwAAABQTIL_9kQ0ovZm4rsIOjZosklIDNdmy4olq4L9ivYyzS5RiMqVyPhTQT4Z2lWqQskU4Kn9Lno4H-pQSbJ8NxQiyB3Sb-w0OGBLhYlz29DiPoP8wTJginn-6qHfMsbxv5_03U5FMg', - emeConfig: 'license-url' + title: 'Local Test, CENS, ClearKey', + url: 'http://localhost:8081/clearkey__cens/stream.mpd', + kid: '000102030405060708090a0b0c0d0e0f', + key: '00112233445566778899aabbccddeeff', + emeConfig: 'manual' }, { - title: 'Local Bunny WV - FFMPEG', - url: 'http://192.168.1.199:8081/bunny_ff_wv/stream.mpd', - licenseUrl: 'https://wv.test.expressplay.com/hms/wv/rights/?ExpressPlayToken=AQAAAw3paOwAAABQTIL_9kQ0ovZm4rsIOjZosklIDNdmy4olq4L9ivYyzS5RiMqVyPhTQT4Z2lWqQskU4Kn9Lno4H-pQSbJ8NxQiyB3Sb-w0OGBLhYlz29DiPoP8wTJginn-6qHfMsbxv5_03U5FMg', - emeConfig: 'license-url' + title: 'Local Test, CBCS, ClearKey', + url: 'http://localhost:8081/clearkey__cbcs/stream.mpd', + kid: '000102030405060708090a0b0c0d0e0f', + key: '00112233445566778899aabbccddeeff', + emeConfig: 'manual' }, { - title: 'Local Sintel ClearKey', - url: 'http://192.168.1.199:8081/sintel_wv/stream.mpd', - kid: '12341234123412341234123412341234', - key: '43215678123412341234123412341234', + title: 'Local Test, CENC, Widevine', + url: 'http://localhost:8081/widevine_cenc/stream.mpd', + kid: '90351951686b5e1ba222439ecec1f12a', + key: '0a237b0752cbf1a827e2fecfb87479a2', emeConfig: 'manual' }, { - title: 'Local Sintel WV', - url: 'http://192.168.1.199:8081/sintel_wv/stream.mpd', - licenseUrl: 'https://wv.test.expressplay.com/hms/wv/rights/?ExpressPlayToken=AQAAAw3paOwAAABQTIL_9kQ0ovZm4rsIOjZosklIDNdmy4olq4L9ivYyzS5RiMqVyPhTQT4Z2lWqQskU4Kn9Lno4H-pQSbJ8NxQiyB3Sb-w0OGBLhYlz29DiPoP8wTJginn-6qHfMsbxv5_03U5FMg', - emeConfig: 'license-url' + title: 'Local Test, CBC1, Widevine', + url: 'http://localhost:8081/widevine_cbc1/stream.mpd', + kid: '90351951686b5e1ba222439ecec1f12a', + key: '0a237b0752cbf1a827e2fecfb87479a2', + emeConfig: 'manual' }, { - title: 'Local Mango WV', - url: 'http://192.168.1.199:8081/tears_wv/stream.mpd', - licenseUrl: 'https://wv.test.expressplay.com/hms/wv/rights/?ExpressPlayToken=AQAAAw3paOwAAABQTIL_9kQ0ovZm4rsIOjZosklIDNdmy4olq4L9ivYyzS5RiMqVyPhTQT4Z2lWqQskU4Kn9Lno4H-pQSbJ8NxQiyB3Sb-w0OGBLhYlz29DiPoP8wTJginn-6qHfMsbxv5_03U5FMg', - emeConfig: 'license-url' + title: 'Local Test, CENS, Widevine', + url: 'http://localhost:8081/widevine_cens/stream.mpd', + kid: '90351951686b5e1ba222439ecec1f12a', + key: '0a237b0752cbf1a827e2fecfb87479a2', + emeConfig: 'manual' }, { - title: 'Local Bunny PR', - url: 'http://192.168.1.199:8081/bunny_pr/stream.mpd', - licenseUrl: 'http://pr.test.expressplay.com/playready/RightsManager.asmx?ExpressPlayToken=AQAAAw3pWq4AAABg6n4MVsv33YnWphWSMTHOCPWrKJmUxfMbfQ6Q8OaxvdWo5cuBvYZADKNNUG9gO45Y9IBO2VZk1PU7YQBr-_jE4hBswX6U0iHTZO2lw7dkcprR2eaP-X0dv7hcfkWhshL51vKV-ibDwSPJx5Or-5F-eZqAyWc', - emeConfig: 'license-url' + title: 'Local Test, CBCS, Widevine', + url: 'http://localhost:8081/widevine_cbcs/stream.mpd', + kid: '90351951686b5e1ba222439ecec1f12a', + key: '0a237b0752cbf1a827e2fecfb87479a2', + emeConfig: 'manual' } ];
View file
bento4-1.5.0r614.tar.gz/Documents/Websites/www.bok.net/dash/players/html5/shaka-player/app.js -> bento4-1.5.0r615.tar.gz/Documents/Websites/www.bok.net/dash/players/html5/shaka-player/app.js
Changed
@@ -120,7 +120,7 @@ var mediaUrl = document.getElementById('manifestUrlInput').value; // (re)configure the player - drmConfig = { + var drmConfig = { drm: { servers: { 'com.widevine.alpha': 'https://widevine-proxy.appspot.com/proxy'
View file
bento4-1.5.0r614.tar.gz/Documents/Websites/www.bok.net/dash/players/html5/shaka-player/index.html -> bento4-1.5.0r615.tar.gz/Documents/Websites/www.bok.net/dash/players/html5/shaka-player/index.html
Changed
@@ -1,11 +1,10 @@ <html> <head> - <title>Sample DASH Player using dash.js</title> + <title>Sample DASH Player using Shaka Player</title> <!-- <script src="shaka-player.compiled.debug.js"></script> --> - - <script src="third_party/closure/goog/base.js"></script> - <script src="dist/deps.js"></script> - <script src="shaka-player.uncompiled.js"></script> + <!-- <script src="third_party/closure/goog/base.js"></script> --> + <!-- <script src="dist/deps.js"></script> --> + <script src="//cdnjs.cloudflare.com/ajax/libs/shaka-player/2.0.5/shaka-player.compiled.debug.js"></script> <script src="app.js"></script> <script src="../presets.js"></script>
View file
bento4-1.5.0r614.tar.gz/Source/C++/Apps/Mp42Hls/Mp42Hls.cpp -> bento4-1.5.0r615.tar.gz/Source/C++/Apps/Mp42Hls/Mp42Hls.cpp
Changed
@@ -1080,7 +1080,10 @@ last_ts = audio_ts; } if (segment_output) { - // compute the segment size (not including padding) + // flush the output stream + segment_output->Flush(); + + // compute the segment size (including padding) AP4_Position segment_end = 0; segment_output->Tell(segment_end); AP4_UI32 segment_size = 0; @@ -1090,9 +1093,6 @@ segment_size = (AP4_UI32)(segment_end-segment_position); } - // flush the output stream - segment_output->Flush(); - // update counters segment_sizes.Append(segment_size); segment_positions.Append(segment_position);
View file
bento4-1.5.0r614.tar.gz/Source/C++/Apps/Mp4Fragment/Mp4Fragment.cpp -> bento4-1.5.0r615.tar.gz/Source/C++/Apps/Mp4Fragment/Mp4Fragment.cpp
Changed
@@ -202,6 +202,7 @@ AP4_Ordinal m_FragmentIndex; AP4_Sample m_Sample; AP4_UI64 m_Timestamp; + AP4_UI64 m_UnscaledTimestamp; bool m_Eos; AP4_TfraAtom* m_Tfra; }; @@ -215,6 +216,7 @@ m_SampleIndex(0), m_FragmentIndex(0), m_Timestamp(0), + m_UnscaledTimestamp(0), m_Eos(false), m_Tfra(new AP4_TfraAtom(0)) { @@ -571,7 +573,7 @@ // emit a fragment for the selected track if (Options.verbosity > 1) { - printf("fragment: track ID %d ", cursor->m_Track->GetId()); + printf("fragment: track ID %d\n", cursor->m_Track->GetId()); } // decide which sample description index to use @@ -608,8 +610,7 @@ AP4_TfdtAtom* tfdt = new AP4_TfdtAtom(1, cursor->m_Timestamp + (AP4_UI64)(Options.tfdt_start * (double)cursor->m_Track->GetMediaTimeScale())); traf->AddChild(tfdt); } - AP4_UI32 trun_flags = AP4_TRUN_FLAG_DATA_OFFSET_PRESENT | - AP4_TRUN_FLAG_SAMPLE_DURATION_PRESENT | + AP4_UI32 trun_flags = AP4_TRUN_FLAG_DATA_OFFSET_PRESENT | AP4_TRUN_FLAG_SAMPLE_SIZE_PRESENT; AP4_UI32 first_sample_flags = 0; if (cursor->m_Track->GetType() == AP4_Track::TYPE_VIDEO) { @@ -626,9 +627,11 @@ fragments.Add(fragment); // add samples to the fragment - unsigned int sample_count = 0; + unsigned int sample_count = 0; AP4_Array<AP4_TrunAtom::Entry> trun_entries; fragment->m_MdatSize = AP4_ATOM_HEADER_SIZE; + AP4_UI32 constant_sample_duration = 0; + bool all_segment_durations_equal = true; for (;;) { // if we have one non-zero CTS delta, we'll need to express it if (cursor->m_Sample.GetCtsDelta()) { @@ -638,11 +641,13 @@ // add one sample trun_entries.SetItemCount(sample_count+1); AP4_TrunAtom::Entry& trun_entry = trun_entries[sample_count]; - trun_entry.sample_duration = timescale? - (AP4_UI32)AP4_ConvertTime(cursor->m_Sample.GetDuration(), - cursor->m_Track->GetMediaTimeScale(), - timescale): - cursor->m_Sample.GetDuration(); + AP4_UI64 next_unscaled_timestamp = cursor->m_UnscaledTimestamp+cursor->m_Sample.GetDuration(); + AP4_UI64 next_scaled_timestamp = timescale? + AP4_ConvertTime(next_unscaled_timestamp, + cursor->m_Track->GetMediaTimeScale(), + timescale): + next_unscaled_timestamp; + trun_entry.sample_duration = (AP4_UI32)(next_scaled_timestamp-cursor->m_Timestamp); trun_entry.sample_size = cursor->m_Sample.GetSize(); trun_entry.sample_composition_time_offset = timescale? (AP4_UI32)AP4_ConvertTime(cursor->m_Sample.GetCtsDelta(), @@ -655,8 +660,20 @@ fragment->m_MdatSize += trun_entry.sample_size; fragment->m_Duration += trun_entry.sample_duration; + // check if the durations are all the same + if (all_segment_durations_equal) { + if (constant_sample_duration == 0) { + constant_sample_duration = trun_entry.sample_duration; + } else { + if (constant_sample_duration != trun_entry.sample_duration) { + all_segment_durations_equal = false; + } + } + } + // next sample - cursor->m_Timestamp += trun_entry.sample_duration; + cursor->m_UnscaledTimestamp = next_unscaled_timestamp; + cursor->m_Timestamp = next_scaled_timestamp; result = cursor->SetSampleIndex(cursor->m_SampleIndex+1); if (AP4_FAILED(result)) { fprintf(stderr, "ERROR: failed to get sample %d (%d)\n", cursor->m_SampleIndex+1, result); @@ -673,10 +690,19 @@ break; // done with this fragment } } - if (Options.verbosity > 1) { + if (Options.verbosity > 2) { printf(" %d samples\n", sample_count); + printf(" constant sample duration: %s\n", all_segment_durations_equal?"yes":"no"); } - + + // update the 'trun' flags if needed + if (all_segment_durations_equal) { + tfhd->SetDefaultSampleDuration(constant_sample_duration); + tfhd->UpdateFlags(tfhd->GetFlags() | AP4_TFHD_FLAG_DEFAULT_SAMPLE_DURATION_PRESENT); + } else { + trun->SetFlags(trun->GetFlags() | AP4_TRUN_FLAG_SAMPLE_DURATION_PRESENT); + } + // update moof and children trun->SetEntries(trun_entries); trun->SetDataOffset((AP4_UI32)moof->GetSize()+AP4_ATOM_HEADER_SIZE);
View file
bento4-1.5.0r614.tar.gz/Source/C++/Apps/Mp4Info/Mp4Info.cpp -> bento4-1.5.0r615.tar.gz/Source/C++/Apps/Mp4Info/Mp4Info.cpp
Changed
@@ -40,13 +40,19 @@ /*---------------------------------------------------------------------- | constants +---------------------------------------------------------------------*/ -#define BANNER "MP4 File Info - Version 1.3.3\n"\ +#define BANNER "MP4 File Info - Version 1.3.4\n"\ "(Bento4 Version " AP4_VERSION_STRING ")\n"\ - "(c) 2002-2015 Axiomatic Systems, LLC" + "(c) 2002-2017 Axiomatic Systems, LLC" /*---------------------------------------------------------------------- | globals +---------------------------------------------------------------------*/ +typedef struct { + AP4_UI64 sample_count; + AP4_UI64 duration; + double bitrate; +} MediaInfo; + typedef enum { TEXT_FORMAT, JSON_FORMAT @@ -964,12 +970,11 @@ } /*---------------------------------------------------------------------- -| ComputeBitrate +| ScanMedia +---------------------------------------------------------------------*/ -static double -ComputeBitrate(AP4_Movie& movie, AP4_Track& track, AP4_ByteStream& stream) +static void +ScanMedia(AP4_Movie& movie, AP4_Track& track, AP4_ByteStream& stream, MediaInfo& info) { - double bitrate = 0.0; AP4_UI64 total_size = 0; AP4_UI64 total_duration = 0; @@ -979,6 +984,8 @@ AP4_LinearReader reader(movie, &stream); reader.EnableTrack(track.GetId()); + info.sample_count = 0; + AP4_Sample sample; if (movie.HasFragments()) { AP4_DataBuffer sample_data; @@ -988,11 +995,13 @@ if (AP4_SUCCEEDED(result)) { total_size += sample.GetSize(); total_duration += sample.GetDuration(); + ++info.sample_count; } else { break; } } } else { + info.sample_count = track.GetSampleCount(); for (unsigned int i=0; i<track.GetSampleCount(); i++) { if (AP4_SUCCEEDED(track.GetSample(i, sample))) { total_size += sample.GetSize(); @@ -1000,13 +1009,14 @@ } total_duration = track.GetMediaDuration(); } + info.duration = total_duration; double duration_ms = (double)AP4_ConvertTime(total_duration, track.GetMediaTimeScale(), 1000); if (duration_ms) { - bitrate = 8.0*1000.0*(double)total_size/duration_ms; + info.bitrate = 8.0*1000.0*(double)total_size/duration_ms; + } else { + info.bitrate = 0.0; } - - return bitrate; } /*---------------------------------------------------------------------- @@ -1053,7 +1063,14 @@ printf(" duration: %lld (media timescale units)\n", track.GetMediaDuration()); printf(" duration: %d (ms)\n", (AP4_UI32)AP4_ConvertTime(track.GetMediaDuration(), track.GetMediaTimeScale(), 1000)); if (!fast) { - printf(" bitrate (computed): %.3f Kbps\n", (float)ComputeBitrate(movie, track, stream)/1000.0); + MediaInfo media_info; + ScanMedia(movie, track, stream, media_info); + printf(" bitrate (computed): %.3f Kbps\n", media_info.bitrate/1000.0); + if (movie.HasFragments()) { + printf(" sample count with fragments: %lld\n", media_info.sample_count); + printf(" duration with fragments: %lld\n", media_info.duration); + printf(" duration with fragments: %d (ms)\n", (AP4_UI32)AP4_ConvertTime(media_info.duration, track.GetMediaTimeScale(), 1000)); + } } if (track.GetWidth() || track.GetHeight()) { printf(" display width: %f\n", (float)track.GetWidth()/65536.0); @@ -1141,8 +1158,17 @@ printf(" \"duration\":%lld,\n", track.GetMediaDuration()); printf(" \"duration_ms\":%d", (AP4_UI32)AP4_ConvertTime(track.GetMediaDuration(), track.GetMediaTimeScale(), 1000)); if (!fast) { + MediaInfo media_info; + ScanMedia(movie, track, stream, media_info); printf(",\n"); - printf(" \"bitrate\":%.3f\n", (float)ComputeBitrate(movie, track, stream)/1000.0); + printf(" \"bitrate\":%.3f", media_info.bitrate/1000.0); + if (movie.HasFragments()) { + printf(",\n"); + printf(" \"sample_count_with_fragments\":%lld,\n", media_info.sample_count); + printf(" \"duration_with_fragments\":%lld,\n", media_info.duration); + printf(" \"duration_with_fragments_ms\":%d", (AP4_UI32)AP4_ConvertTime(media_info.duration, track.GetMediaTimeScale(), 1000)); + } + printf("\n"); } else { printf("\n"); } @@ -1259,13 +1285,19 @@ break; } } + + if (Options.format == JSON_FORMAT) { + printf("],\n"); + } + + // fast-start switch (Options.format) { case TEXT_FORMAT: - printf("\n"); + printf(" fast start: %s\n\n", file.IsMoovBeforeMdat() ? "yes" : "no"); break; case JSON_FORMAT: - printf("]\n},\n"); + printf(" \"fast_start\":%s\n},\n", file.IsMoovBeforeMdat() ? "true" : "false"); break; } } @@ -1535,7 +1567,6 @@ if (Options.format == JSON_FORMAT) printf("{\n"); AP4_File* file = new AP4_File(*input, true); - input->Release(); ShowFileInfo(*file); AP4_Movie* movie = file->GetMovie(); @@ -1576,6 +1607,7 @@ if (Options.format == JSON_FORMAT) printf("}\n"); + input->Release(); delete file; return 0;
View file
bento4-1.5.0r614.tar.gz/Source/C++/Codecs/Ap4AvcParser.cpp -> bento4-1.5.0r615.tar.gz/Source/C++/Codecs/Ap4AvcParser.cpp
Changed
@@ -263,7 +263,9 @@ | AP4_AvcFrameParser::ParseSPS +---------------------------------------------------------------------*/ AP4_Result -AP4_AvcFrameParser::ParseSPS(const unsigned char* data, unsigned int data_size, AP4_AvcSequenceParameterSet& sps) +AP4_AvcFrameParser::ParseSPS(const unsigned char* data, + unsigned int data_size, + AP4_AvcSequenceParameterSet& sps) { sps.raw_bytes.SetData(data, data_size); AP4_DataBuffer unescaped(data, data_size); @@ -404,7 +406,9 @@ | AP4_AvcFrameParser::ParsePPS +---------------------------------------------------------------------*/ AP4_Result -AP4_AvcFrameParser::ParsePPS(const unsigned char* data, unsigned int data_size, AP4_AvcPictureParameterSet& pps) +AP4_AvcFrameParser::ParsePPS(const unsigned char* data, + unsigned int data_size, + AP4_AvcPictureParameterSet& pps) { pps.raw_bytes.SetData(data, data_size); AP4_DataBuffer unescaped(data, data_size); @@ -497,10 +501,10 @@ | AP4_AvcFrameParser::ParseSliceHeader +---------------------------------------------------------------------*/ AP4_Result -AP4_AvcFrameParser::ParseSliceHeader(const AP4_UI08* data, - unsigned int data_size, - unsigned int nal_unit_type, - AP4_AvcSliceHeader& slice_header) +AP4_AvcFrameParser::ParseSliceHeader(const AP4_UI08* data, + unsigned int data_size, + unsigned int nal_unit_type, + AP4_AvcSliceHeader& slice_header) { AP4_DataBuffer unescaped(data, data_size); AP4_NalParser::Unescape(unescaped);
View file
bento4-1.5.0r614.tar.gz/Source/C++/Core/Ap4CommonEncryption.cpp -> bento4-1.5.0r615.tar.gz/Source/C++/Core/Ap4CommonEncryption.cpp
Changed
@@ -64,60 +64,64 @@ const unsigned int AP4_CENC_NAL_UNIT_ENCRYPTION_MIN_SIZE = 112; /*---------------------------------------------------------------------- -| AP4_CencSampleEncrypter::~AP4_CencSampleEncrypter -+---------------------------------------------------------------------*/ -AP4_CencSampleEncrypter::~AP4_CencSampleEncrypter() -{ - delete m_Cipher; -} - -/*---------------------------------------------------------------------- -| AP4_CencCtrSampleEncrypter::EncryptSampleData +| AP4_CencBasicSubSampleMapper::GetSubSampleMap +---------------------------------------------------------------------*/ AP4_Result -AP4_CencCtrSampleEncrypter::EncryptSampleData(AP4_DataBuffer& data_in, - AP4_DataBuffer& data_out, - AP4_DataBuffer& /* sample_infos */) +AP4_CencBasicSubSampleMapper::GetSubSampleMap(AP4_DataBuffer& sample_data, + AP4_Array<AP4_UI16>& bytes_of_cleartext_data, + AP4_Array<AP4_UI32>& bytes_of_encrypted_data) { - // the output has the same size as the input - data_out.SetDataSize(data_in.GetDataSize()); - // setup direct pointers to the buffers - const AP4_UI08* in = data_in.GetData(); - AP4_UI08* out = data_out.UseData(); + const AP4_UI08* in = sample_data.GetData(); - // setup the IV - m_Cipher->SetIV(m_Iv); + // process the sample data, one NALU at a time + const AP4_UI08* in_end = sample_data.GetData()+sample_data.GetDataSize(); + while ((AP4_Size)(in_end-in) > 1+m_NaluLengthSize) { + unsigned int nalu_length; + switch (m_NaluLengthSize) { + case 1: + nalu_length = *in; + break; + + case 2: + nalu_length = AP4_BytesToUInt16BE(in); + break; + + case 4: + nalu_length = AP4_BytesToUInt32BE(in); + break; + + default: + return AP4_ERROR_INVALID_FORMAT; + } - // process the sample data - if (data_in.GetDataSize()) { - AP4_Size out_size = data_out.GetDataSize(); - AP4_Result result = m_Cipher->ProcessBuffer(in, data_in.GetDataSize(), out, &out_size, false); - if (AP4_FAILED(result)) return result; - } - - // update the IV - if (m_IvSize == 16) { - unsigned int block_count = (data_in.GetDataSize()+15)/16; - AP4_UI64 counter = AP4_BytesToUInt64BE(&m_Iv[8]); - AP4_BytesFromUInt64BE(&m_Iv[8], counter+block_count); - } else if (m_IvSize == 8){ - AP4_UI64 counter = AP4_BytesToUInt64BE(&m_Iv[0]); - AP4_BytesFromUInt64BE(&m_Iv[0], counter+1); - } else { - return AP4_ERROR_INTERNAL; + unsigned int chunk_size = m_NaluLengthSize+nalu_length; + unsigned int cleartext_size = chunk_size%16; + unsigned int block_count = chunk_size/16; + if (cleartext_size < m_NaluLengthSize+1) { + AP4_ASSERT(block_count); + --block_count; + cleartext_size += 16; + } + + // move the pointers + in += chunk_size; + + // store the info + bytes_of_cleartext_data.Append((AP4_UI16)cleartext_size); + bytes_of_encrypted_data.Append((AP4_UI32)(block_count*16)); } return AP4_SUCCESS; } /*---------------------------------------------------------------------- -| AP4_CencCtrSubSampleEncrypter::GetSubSampleMap +| AP4_CencAdvancedSubSampleEncrypter::GetSubSampleMap +---------------------------------------------------------------------*/ AP4_Result -AP4_CencCtrSubSampleEncrypter::GetSubSampleMap(AP4_DataBuffer& sample_data, - AP4_Array<AP4_UI16>& bytes_of_cleartext_data, - AP4_Array<AP4_UI32>& bytes_of_encrypted_data) +AP4_CencAdvancedSubSampleMapper::GetSubSampleMap(AP4_DataBuffer& sample_data, + AP4_Array<AP4_UI16>& bytes_of_cleartext_data, + AP4_Array<AP4_UI32>& bytes_of_encrypted_data) { // setup direct pointers to the buffers const AP4_UI08* in = sample_data.GetData(); @@ -209,6 +213,54 @@ } /*---------------------------------------------------------------------- +| AP4_CencSampleEncrypter::~AP4_CencSampleEncrypter ++---------------------------------------------------------------------*/ +AP4_CencSampleEncrypter::~AP4_CencSampleEncrypter() +{ + delete m_Cipher; +} + +/*---------------------------------------------------------------------- +| AP4_CencCtrSampleEncrypter::EncryptSampleData ++---------------------------------------------------------------------*/ +AP4_Result +AP4_CencCtrSampleEncrypter::EncryptSampleData(AP4_DataBuffer& data_in, + AP4_DataBuffer& data_out, + AP4_DataBuffer& /* sample_infos */) +{ + // the output has the same size as the input + data_out.SetDataSize(data_in.GetDataSize()); + + // setup direct pointers to the buffers + const AP4_UI08* in = data_in.GetData(); + AP4_UI08* out = data_out.UseData(); + + // setup the IV + m_Cipher->SetIV(m_Iv); + + // process the sample data + if (data_in.GetDataSize()) { + AP4_Size out_size = data_out.GetDataSize(); + AP4_Result result = m_Cipher->ProcessBuffer(in, data_in.GetDataSize(), out, &out_size, false); + if (AP4_FAILED(result)) return result; + } + + // update the IV + if (m_IvSize == 16) { + unsigned int block_count = (data_in.GetDataSize()+15)/16; + AP4_UI64 counter = AP4_BytesToUInt64BE(&m_Iv[8]); + AP4_BytesFromUInt64BE(&m_Iv[8], counter+block_count); + } else if (m_IvSize == 8){ + AP4_UI64 counter = AP4_BytesToUInt64BE(&m_Iv[0]); + AP4_BytesFromUInt64BE(&m_Iv[0], counter+1); + } else { + return AP4_ERROR_INTERNAL; + } + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- | AP4_CencCtrSubSampleEncrypter::EncryptSampleData +---------------------------------------------------------------------*/ AP4_Result @@ -233,7 +285,7 @@ // get the subsample map AP4_Array<AP4_UI16> bytes_of_cleartext_data; AP4_Array<AP4_UI32> bytes_of_encrypted_data; - AP4_Result result = GetSubSampleMap(data_in, bytes_of_cleartext_data, bytes_of_encrypted_data); + AP4_Result result = m_SubSampleMapper->GetSubSampleMap(data_in, bytes_of_cleartext_data, bytes_of_encrypted_data); if (AP4_FAILED(result)) return result; // process the data @@ -279,58 +331,6 @@ } /*---------------------------------------------------------------------- -| AP4_CencCbcSubSampleEncrypter::GetSubSampleMap -+---------------------------------------------------------------------*/ -AP4_Result -AP4_CencCbcSubSampleEncrypter::GetSubSampleMap(AP4_DataBuffer& sample_data, - AP4_Array<AP4_UI16>& bytes_of_cleartext_data, - AP4_Array<AP4_UI32>& bytes_of_encrypted_data) -{ - // setup direct pointers to the buffers - const AP4_UI08* in = sample_data.GetData(); - - // process the sample data, one NALU at a time - const AP4_UI08* in_end = sample_data.GetData()+sample_data.GetDataSize(); - while ((AP4_Size)(in_end-in) > 1+m_NaluLengthSize) { - unsigned int nalu_length; - switch (m_NaluLengthSize) { - case 1: - nalu_length = *in; - break; - - case 2: - nalu_length = AP4_BytesToUInt16BE(in); - break; - - case 4: - nalu_length = AP4_BytesToUInt32BE(in); - break; - - default: - return AP4_ERROR_INVALID_FORMAT; - } - - unsigned int chunk_size = m_NaluLengthSize+nalu_length; - unsigned int cleartext_size = chunk_size%16; - unsigned int block_count = chunk_size/16; - if (cleartext_size < m_NaluLengthSize+1) { - AP4_ASSERT(block_count); - --block_count; - cleartext_size += 16; - } - - // move the pointers - in += chunk_size; - - // store the info - bytes_of_cleartext_data.Append((AP4_UI16)cleartext_size); - bytes_of_encrypted_data.Append((AP4_UI32)(block_count*16)); - } - - return AP4_SUCCESS; -} - -/*---------------------------------------------------------------------- | AP4_CencCbcSampleEncrypter::EncryptSampleData +---------------------------------------------------------------------*/ AP4_Result @@ -357,8 +357,10 @@ in += block_count*16; out += block_count*16; - // update the IV (last cipherblock emitted) - AP4_CopyMemory(m_Iv, out-16, 16); + if (!m_ConstantIv) { + // update the IV (last cipherblock emitted) + AP4_CopyMemory(m_Iv, out-16, 16); + } } // any partial block at the end remains in the clear @@ -394,7 +396,7 @@ // get the subsample map AP4_Array<AP4_UI16> bytes_of_cleartext_data; AP4_Array<AP4_UI32> bytes_of_encrypted_data; - AP4_Result result = GetSubSampleMap(data_in, bytes_of_cleartext_data, bytes_of_encrypted_data); + AP4_Result result = m_SubSampleMapper->GetSubSampleMap(data_in, bytes_of_cleartext_data, bytes_of_encrypted_data); if (AP4_FAILED(result)) return result; for (unsigned int i=0; i<bytes_of_cleartext_data.ItemCount(); i++) { @@ -402,15 +404,21 @@ AP4_CopyMemory(out, in, bytes_of_cleartext_data[i]); // encrypt the rest + if (m_ResetIvForEachSubsample) { + m_Cipher->SetIV(m_Iv); + } if (bytes_of_encrypted_data[i]) { AP4_Size out_size = bytes_of_encrypted_data[i]; - m_Cipher->ProcessBuffer(in+bytes_of_cleartext_data[i], - bytes_of_encrypted_data[i], - out+bytes_of_cleartext_data[i], - &out_size, false); + result = m_Cipher->ProcessBuffer(in+bytes_of_cleartext_data[i], + bytes_of_encrypted_data[i], + out+bytes_of_cleartext_data[i], + &out_size, false); + if (AP4_FAILED(result)) return result; - // update the IV (last cipherblock emitted) - AP4_CopyMemory(m_Iv, out+bytes_of_cleartext_data[i]+bytes_of_encrypted_data[i]-16, 16); + if (!m_ConstantIv) { + // update the IV (last cipherblock emitted) + AP4_CopyMemory(m_Iv, out+bytes_of_cleartext_data[i]+bytes_of_encrypted_data[i]-16, 16); + } } // move the pointers @@ -439,8 +447,12 @@ // constructor AP4_CencTrackEncrypter(AP4_CencVariant variant, AP4_UI32 default_is_protected, - AP4_UI08 default_iv_size, + AP4_UI08 default_per_sample_iv_size, const AP4_UI08* default_kid, + AP4_UI08 default_constant_iv_size, + const AP4_UI08* default_constant_iv, + AP4_UI08 default_crypt_byte_block, + AP4_UI08 default_skip_byte_block, AP4_Array<AP4_SampleEntry*>& sample_entries, AP4_UI32 format); @@ -455,8 +467,12 @@ AP4_Array<AP4_SampleEntry*> m_SampleEntries; AP4_UI32 m_Format; AP4_UI32 m_DefaultIsProtected; - AP4_UI08 m_DefaultIvSize; + AP4_UI08 m_DefaultPerSampleIvSize; AP4_UI08 m_DefaultKid[16]; + AP4_UI08 m_DefaultConstantIvSize; + AP4_UI08 m_DefaultConstantIv[16]; + AP4_UI08 m_DefaultCryptByteBlock; + AP4_UI08 m_DefaultSkipByteBlock; }; /*---------------------------------------------------------------------- @@ -465,17 +481,27 @@ AP4_CencTrackEncrypter::AP4_CencTrackEncrypter( AP4_CencVariant variant, AP4_UI32 default_is_protected, - AP4_UI08 default_iv_size, + AP4_UI08 default_per_sample_iv_size, const AP4_UI08* default_kid, + AP4_UI08 default_constant_iv_size, + const AP4_UI08* default_constant_iv, + AP4_UI08 default_crypt_byte_block, + AP4_UI08 default_skip_byte_block, AP4_Array<AP4_SampleEntry*>& sample_entries, AP4_UI32 format) : m_Variant(variant), m_Format(format), m_DefaultIsProtected(default_is_protected), - m_DefaultIvSize(default_iv_size) + m_DefaultPerSampleIvSize(default_per_sample_iv_size), + m_DefaultConstantIvSize(default_constant_iv_size), + m_DefaultCryptByteBlock(default_crypt_byte_block), + m_DefaultSkipByteBlock(default_skip_byte_block) { - // copy the KID + // copy the KID and IV AP4_CopyMemory(m_DefaultKid, default_kid, 16); + if (default_constant_iv) { + AP4_CopyMemory(m_DefaultConstantIv, default_constant_iv, 16); + } // copy the sample entry list for (unsigned int i=0; i<sample_entries.ItemCount(); i++) { @@ -502,7 +528,7 @@ schm = new AP4_SchmAtom(AP4_PROTECTION_SCHEME_TYPE_PIFF, AP4_PROTECTION_SCHEME_VERSION_PIFF_11); tenc = new AP4_PiffTrackEncryptionAtom(m_DefaultIsProtected, - m_DefaultIvSize, + m_DefaultPerSampleIvSize, m_DefaultKid); break; @@ -510,7 +536,7 @@ schm = new AP4_SchmAtom(AP4_PROTECTION_SCHEME_TYPE_CENC, AP4_PROTECTION_SCHEME_VERSION_CENC_10); tenc = new AP4_TencAtom(m_DefaultIsProtected, - m_DefaultIvSize, + m_DefaultPerSampleIvSize, m_DefaultKid); break; @@ -518,7 +544,7 @@ schm = new AP4_SchmAtom(AP4_PROTECTION_SCHEME_TYPE_CBC1, AP4_PROTECTION_SCHEME_VERSION_CENC_10); tenc = new AP4_TencAtom(m_DefaultIsProtected, - m_DefaultIvSize, + m_DefaultPerSampleIvSize, m_DefaultKid); break; @@ -526,16 +552,24 @@ schm = new AP4_SchmAtom(AP4_PROTECTION_SCHEME_TYPE_CENS, AP4_PROTECTION_SCHEME_VERSION_CENC_10); tenc = new AP4_TencAtom(m_DefaultIsProtected, - m_DefaultIvSize, - m_DefaultKid); + m_DefaultPerSampleIvSize, + m_DefaultKid, + m_DefaultConstantIvSize, + m_DefaultConstantIv, + m_DefaultCryptByteBlock, + m_DefaultSkipByteBlock); break; case AP4_CENC_VARIANT_MPEG_CBCS: schm = new AP4_SchmAtom(AP4_PROTECTION_SCHEME_TYPE_CBCS, AP4_PROTECTION_SCHEME_VERSION_CENC_10); tenc = new AP4_TencAtom(m_DefaultIsProtected, - m_DefaultIvSize, - m_DefaultKid); + m_DefaultPerSampleIvSize, + m_DefaultKid, + m_DefaultConstantIvSize, + m_DefaultConstantIv, + m_DefaultCryptByteBlock, + m_DefaultSkipByteBlock); break; } @@ -677,13 +711,23 @@ break; case AP4_CENC_VARIANT_MPEG_CBC1: - case AP4_CENC_VARIANT_MPEG_CENS: - case AP4_CENC_VARIANT_MPEG_CBCS: m_SampleEncryptionAtom = new AP4_SencAtom(16); m_Saiz = new AP4_SaizAtom(); m_Saio = new AP4_SaioAtom(); break; + case AP4_CENC_VARIANT_MPEG_CENS: + m_SampleEncryptionAtom = new AP4_SencAtom(16, 0, NULL, 0, 0); + m_Saiz = new AP4_SaizAtom(); + m_Saio = new AP4_SaioAtom(); + break; + + case AP4_CENC_VARIANT_MPEG_CBCS: + m_SampleEncryptionAtom = new AP4_SencAtom(0, 16, NULL, 0, 0); + m_Saiz = new AP4_SaizAtom(); + m_Saio = new AP4_SaioAtom(); + break; + default: return AP4_ERROR_INTERNAL; } @@ -738,8 +782,13 @@ m_SampleEncryptionAtomShadow->SetSampleInfosSize(sample_count*m_SampleEncryptionAtomShadow->GetPerSampleIvSize()); } if (m_Saiz) { - m_Saiz->SetDefaultSampleInfoSize(m_SampleEncryptionAtom->GetPerSampleIvSize()); - m_Saiz->SetSampleCount(sample_count); + if (m_SampleEncryptionAtom->GetPerSampleIvSize()) { + m_Saiz->SetDefaultSampleInfoSize(m_SampleEncryptionAtom->GetPerSampleIvSize()); + m_Saiz->SetSampleCount(sample_count); + } else { + m_Saiz->SetDefaultSampleInfoSize(0); + m_Saiz->SetSampleCount(0); + } } return AP4_SUCCESS; } @@ -1155,18 +1204,29 @@ AP4_BlockCipher::CipherMode cipher_mode; AP4_BlockCipher::CtrParams cipher_ctr_params; const void* cipher_mode_params = NULL; - AP4_UI32 is_protected = 0; + AP4_UI08 crypt_byte_block = 0; + AP4_UI08 skip_byte_block = 0; + bool constant_iv = false; + bool reset_iv_at_each_subsample = false; switch (m_Variant) { case AP4_CENC_VARIANT_PIFF_CTR: - is_protected = 1; cipher_mode = AP4_BlockCipher::CTR; cipher_ctr_params.counter_size = 8; cipher_mode_params = &cipher_ctr_params; + + track_encrypter = new AP4_CencTrackEncrypter(m_Variant, + 1, + cipher_iv_size, + kid, + 0, + NULL, + 0, + 0, + entries, + enc_format); break; case AP4_CENC_VARIANT_MPEG_CENC: - case AP4_CENC_VARIANT_MPEG_CENS: - is_protected = 1; cipher_mode = AP4_BlockCipher::CTR; cipher_ctr_params.counter_size = 8; cipher_mode_params = &cipher_ctr_params; @@ -1175,29 +1235,94 @@ !AP4_GlobalOptions::GetBool("mpeg-cenc.iv-size-16")) { cipher_iv_size = 8; } + + track_encrypter = new AP4_CencTrackEncrypter(m_Variant, + 1, + cipher_iv_size, + kid, + 0, + NULL, + 0, + 0, + entries, + enc_format); break; + case AP4_CENC_VARIANT_MPEG_CENS: + cipher_mode = AP4_BlockCipher::CTR; + cipher_ctr_params.counter_size = 8; + cipher_mode_params = &cipher_ctr_params; + if (AP4_GlobalOptions::GetBool("mpeg-cenc.iv-size-8") && !AP4_GlobalOptions::GetBool("mpeg-cenc.iv-size-16")) { + cipher_iv_size = 8; + } + if (enc_format == AP4_ATOM_TYPE_ENCV) { + crypt_byte_block = 1; + skip_byte_block = 9; + } + track_encrypter = new AP4_CencTrackEncrypter(m_Variant, + 1, + cipher_iv_size, + kid, + 0, + NULL, + crypt_byte_block, + skip_byte_block, + entries, + enc_format); + break; + case AP4_CENC_VARIANT_PIFF_CBC: - is_protected = 2; cipher_mode = AP4_BlockCipher::CBC; + track_encrypter = new AP4_CencTrackEncrypter(m_Variant, + 2, + cipher_iv_size, + kid, + 0, + NULL, + 0, + 0, + entries, + enc_format); break; case AP4_CENC_VARIANT_MPEG_CBC1: + cipher_mode = AP4_BlockCipher::CBC; + track_encrypter = new AP4_CencTrackEncrypter(m_Variant, + 1, + cipher_iv_size, + kid, + 0, + NULL, + 0, + 0, + entries, + enc_format); + break; + case AP4_CENC_VARIANT_MPEG_CBCS: - is_protected = 1; cipher_mode = AP4_BlockCipher::CBC; + if (enc_format == AP4_ATOM_TYPE_ENCV) { + crypt_byte_block = 1; + skip_byte_block = 9; + } + constant_iv = true; + reset_iv_at_each_subsample = true; + track_encrypter = new AP4_CencTrackEncrypter(m_Variant, + 1, + 0, + kid, + cipher_iv_size, + iv->GetData(), + crypt_byte_block, + skip_byte_block, + entries, + enc_format); break; default: return NULL; } - track_encrypter = new AP4_CencTrackEncrypter(m_Variant, - is_protected, - cipher_iv_size, - kid, - entries, - enc_format); - + // create a block cipher AP4_BlockCipher* block_cipher = NULL; AP4_Result result = m_BlockCipherFactory->CreateCipher(AP4_BlockCipher::AES_128, @@ -1207,50 +1332,79 @@ key->GetData(), key->GetDataSize(), block_cipher); - if (AP4_FAILED(result)) return NULL; + if (AP4_FAILED(result)) { + delete track_encrypter; + return NULL; + } + // compute the size of NAL units + unsigned int nalu_length_size = 0; + if (format == AP4_ATOM_TYPE_AVC1 || + format == AP4_ATOM_TYPE_AVC2 || + format == AP4_ATOM_TYPE_AVC3 || + format == AP4_ATOM_TYPE_AVC4) { + AP4_AvccAtom* avcc = AP4_DYNAMIC_CAST(AP4_AvccAtom, entries[0]->GetChild(AP4_ATOM_TYPE_AVCC)); + if (avcc) { + nalu_length_size = avcc->GetNaluLengthSize(); + } + } else if (format == AP4_ATOM_TYPE_HEV1 || + format == AP4_ATOM_TYPE_HVC1) { + AP4_HvccAtom* hvcc = AP4_DYNAMIC_CAST(AP4_HvccAtom, entries[0]->GetChild(AP4_ATOM_TYPE_HVCC)); + if (hvcc) { + nalu_length_size = hvcc->GetNaluLengthSize(); + } + } + // add a new cipher state for this track AP4_CencSampleEncrypter* sample_encrypter = NULL; - AP4_StreamCipher* stream_cipher = NULL; + AP4_StreamCipher* stream_cipher = NULL; switch (cipher_mode) { case AP4_BlockCipher::CBC: stream_cipher = new AP4_CbcStreamCipher(block_cipher); - if (format == AP4_ATOM_TYPE_AVC1 || - format == AP4_ATOM_TYPE_AVC2 || - format == AP4_ATOM_TYPE_AVC3 || - format == AP4_ATOM_TYPE_AVC4) { - AP4_AvccAtom* avcc = AP4_DYNAMIC_CAST(AP4_AvccAtom, entries[0]->GetChild(AP4_ATOM_TYPE_AVCC)); - if (avcc == NULL) return NULL; - sample_encrypter = new AP4_CencCbcSubSampleEncrypter(stream_cipher, avcc->GetNaluLengthSize(), format); - } else if (format == AP4_ATOM_TYPE_HEV1 || - format == AP4_ATOM_TYPE_HVC1) { - AP4_HvccAtom* hvcc = AP4_DYNAMIC_CAST(AP4_HvccAtom, entries[0]->GetChild(AP4_ATOM_TYPE_HVCC)); - if (hvcc == NULL) return NULL; - sample_encrypter = new AP4_CencCbcSubSampleEncrypter(stream_cipher, hvcc->GetNaluLengthSize(), format); + if (crypt_byte_block && skip_byte_block) { + stream_cipher = new AP4_PatternStreamCipher(stream_cipher, crypt_byte_block, skip_byte_block); + } + + if (nalu_length_size) { + AP4_CencSubSampleMapper* subsample_mapper = NULL; + if (m_Variant == AP4_CENC_VARIANT_MPEG_CBCS) { + subsample_mapper = new AP4_CencAdvancedSubSampleMapper /* AP4_CencCbcsSubSampleMapper */(nalu_length_size, format); + } else { + subsample_mapper = new AP4_CencBasicSubSampleMapper(nalu_length_size, format); + } + sample_encrypter = new AP4_CencCbcSubSampleEncrypter(stream_cipher, + constant_iv, + reset_iv_at_each_subsample, + subsample_mapper); } else { - sample_encrypter = new AP4_CencCbcSampleEncrypter(stream_cipher); + sample_encrypter = new AP4_CencCbcSampleEncrypter(stream_cipher, constant_iv); } + break; case AP4_BlockCipher::CTR: stream_cipher = new AP4_CtrStreamCipher(block_cipher, 16); - if (format == AP4_ATOM_TYPE_AVC1 || - format == AP4_ATOM_TYPE_AVC2 || - format == AP4_ATOM_TYPE_AVC3 || - format == AP4_ATOM_TYPE_AVC4) { - AP4_AvccAtom* avcc = AP4_DYNAMIC_CAST(AP4_AvccAtom, entries[0]->GetChild(AP4_ATOM_TYPE_AVCC)); - if (avcc == NULL) return NULL; - sample_encrypter = new AP4_CencCtrSubSampleEncrypter(stream_cipher, avcc->GetNaluLengthSize(), cipher_iv_size, format); - } else if (format == AP4_ATOM_TYPE_HEV1 || - format == AP4_ATOM_TYPE_HVC1) { - AP4_HvccAtom* hvcc = AP4_DYNAMIC_CAST(AP4_HvccAtom, entries[0]->GetChild(AP4_ATOM_TYPE_HVCC)); - if (hvcc == NULL) return NULL; - sample_encrypter = new AP4_CencCtrSubSampleEncrypter(stream_cipher, hvcc->GetNaluLengthSize(), cipher_iv_size, format); + if (crypt_byte_block && skip_byte_block) { + stream_cipher = new AP4_PatternStreamCipher(stream_cipher, crypt_byte_block, skip_byte_block); + } + if (nalu_length_size) { + AP4_CencSubSampleMapper* subsample_mapper = new AP4_CencAdvancedSubSampleMapper(nalu_length_size, format); + sample_encrypter = new AP4_CencCtrSubSampleEncrypter(stream_cipher, + constant_iv, + reset_iv_at_each_subsample, + cipher_iv_size, + subsample_mapper); } else { - sample_encrypter = new AP4_CencCtrSampleEncrypter(stream_cipher, cipher_iv_size); + sample_encrypter = new AP4_CencCtrSampleEncrypter(stream_cipher, constant_iv, cipher_iv_size); } break; } + if (sample_encrypter == NULL) { + delete stream_cipher; + delete block_cipher; + delete track_encrypter; + return NULL; + } sample_encrypter->SetIv(iv->GetData()); // if we need to leave some samples unencrypted, create clones of the sample descriptions @@ -1324,9 +1478,10 @@ AP4_CencSingleSampleDecrypter::Create(AP4_UI32 cipher_type, const AP4_UI08* key, AP4_Size key_size, - unsigned int crypt_byte_block, - unsigned int skip_byte_block, + AP4_UI08 crypt_byte_block, + AP4_UI08 skip_byte_block, AP4_BlockCipherFactory* block_cipher_factory, + bool reset_iv_at_each_subsample, AP4_CencSingleSampleDecrypter*& decrypter) { // check the parameters @@ -1338,7 +1493,7 @@ } // create the cipher - AP4_StreamCipher* stream_cipher = NULL; + AP4_StreamCipher* stream_cipher = NULL; bool full_blocks_only = false; switch (cipher_type) { case AP4_CENC_CIPHER_NONE: @@ -1387,8 +1542,13 @@ return AP4_ERROR_NOT_SUPPORTED; } + // wrap with a pattern processor if needed + if (crypt_byte_block && skip_byte_block) { + stream_cipher = new AP4_PatternStreamCipher(stream_cipher, crypt_byte_block, skip_byte_block); + } + // create the decrypter - decrypter = new AP4_CencSingleSampleDecrypter(stream_cipher, full_blocks_only, crypt_byte_block, skip_byte_block); + decrypter = new AP4_CencSingleSampleDecrypter(stream_cipher, full_blocks_only, reset_iv_at_each_subsample); return AP4_SUCCESS; } @@ -1438,7 +1598,6 @@ if (subsample_count) { // process the sample data, one sub-sample at a time const AP4_UI08* in_end = data_in.GetData()+data_in.GetDataSize(); - unsigned int encrypted_total = 0; for (unsigned int i=0; i<subsample_count; i++) { AP4_UI16 cleartext_size = bytes_of_cleartext_data[i]; AP4_UI32 encrypted_size = bytes_of_encrypted_data[i]; @@ -1455,21 +1614,26 @@ // decrypt the rest if (encrypted_size) { - AP4_Result result = DecryptRange(encrypted_total, in+cleartext_size, out+cleartext_size, encrypted_size); + if (m_ResetIvAtEachSubsample) { + m_Cipher->SetIV(iv); + } + + AP4_Result result = m_Cipher->ProcessBuffer(in+cleartext_size, encrypted_size, out+cleartext_size, &encrypted_size, false); if (AP4_FAILED(result)) return result; } // move the pointers and udate counters - in += cleartext_size+encrypted_size; - out += cleartext_size+encrypted_size; - encrypted_total += encrypted_size; + in += cleartext_size+encrypted_size; + out += cleartext_size+encrypted_size; } } else { if (m_FullBlocksOnly) { unsigned int block_count = data_in.GetDataSize()/16; if (block_count) { - AP4_Result result = DecryptRange(0, in, out, block_count*16); + AP4_Size out_size = data_out.GetDataSize(); + AP4_Result result = m_Cipher->ProcessBuffer(in, block_count*16, out, &out_size, false); if (AP4_FAILED(result)) return result; + AP4_ASSERT(out_size == block_count*16); in += block_count*16; out += block_count*16; } @@ -1482,7 +1646,7 @@ } else { // process the entire sample data at once AP4_Size encrypted_size = data_in.GetDataSize(); - AP4_Result result = DecryptRange(0, in, out, encrypted_size); + AP4_Result result = m_Cipher->ProcessBuffer(in, encrypted_size, out, &encrypted_size, false); if (AP4_FAILED(result)) return result; } } @@ -1491,88 +1655,6 @@ } /*---------------------------------------------------------------------- -| AP4_CencSingleSampleDecrypter::DecryptRange -+---------------------------------------------------------------------*/ -AP4_Result -AP4_CencSingleSampleDecrypter::DecryptRange(unsigned int range_position, const AP4_UI08* in, AP4_UI08* out, AP4_Size size) -{ - if (m_CryptByteBlock && m_SkipByteBlock) { - // pattern encryption - unsigned int pattern_span = m_CryptByteBlock+m_SkipByteBlock; - - // check that the range is block-aligned (required by the spec for pattern encryption) - if (range_position % 16) return AP4_ERROR_INVALID_FORMAT; - - // compute where we are in the pattern - unsigned int block_position = range_position/16; - unsigned int pattern_position = block_position % pattern_span; - - // process the range - AP4_Size processed = 0; - while (processed < size) { - unsigned int crypt_size = 0; - unsigned int skip_size = m_SkipByteBlock*16; - if (pattern_position < m_CryptByteBlock) { - // in the encrypted part - crypt_size = (m_CryptByteBlock-pattern_position)*16; - } else { - // in the skipped part - skip_size = pattern_span-pattern_position; - } - - // clip - AP4_Size remain = size-processed; - if (crypt_size > remain) { - crypt_size = 16*(remain/16); - skip_size = remain-crypt_size; - } - if (crypt_size+skip_size > remain) { - skip_size = remain-crypt_size; - } - - // encrypted part - if (crypt_size) { - AP4_Size in_size = crypt_size; - AP4_Size out_size = crypt_size; - - AP4_Result result = m_Cipher->ProcessBuffer(in, in_size, out, &out_size); - if (AP4_FAILED(result)) return result; - // check that we got back what we expectected - if (out_size != in_size) { - return AP4_ERROR_INTERNAL; - } - in += crypt_size; - out += crypt_size; - processed += crypt_size; - } - - // skipped part - if (skip_size) { - AP4_CopyMemory(out, in, skip_size); - } - in += skip_size; - out += skip_size; - processed += skip_size; - - // we're now at the start of a new pattern - pattern_position = 0; - } - } else { - AP4_Size in_size = size; - AP4_Size out_size = size; - AP4_Result result = m_Cipher->ProcessBuffer(in, in_size, out, &out_size, false); - if (AP4_FAILED(result)) return result; - - // check that we got back what we expectected - if (out_size != in_size) { - return AP4_ERROR_INTERNAL; - } - } - - return AP4_SUCCESS; -} - -/*---------------------------------------------------------------------- | AP4_CencSampleDecrypter::Create +---------------------------------------------------------------------*/ AP4_Result @@ -1626,12 +1708,14 @@ // create the sample info table AP4_CencSampleInfoTable* sample_info_table = NULL; AP4_UI32 protection_sheme = 0; + bool reset_iv_at_each_subsample = false; AP4_Result result = AP4_CencSampleInfoTable::Create(sample_description, traf, saio, saiz, sample_encryption_atom, protection_sheme, + reset_iv_at_each_subsample, aux_info_data, aux_info_data_offset, sample_info_table); @@ -1640,7 +1724,13 @@ } // we now have all the info we need to create the decrypter - return Create(sample_info_table, protection_sheme, key, key_size, block_cipher_factory, decrypter); + return Create(sample_info_table, + protection_sheme, + key, + key_size, + block_cipher_factory, + reset_iv_at_each_subsample, + decrypter); } /*---------------------------------------------------------------------- @@ -1652,6 +1742,7 @@ const AP4_UI08* key, AP4_Size key_size, AP4_BlockCipherFactory* block_cipher_factory, + bool reset_iv_at_each_subsample, AP4_CencSampleDecrypter*& decrypter) { // default return value @@ -1687,6 +1778,7 @@ sample_info_table->GetCryptByteBlock(), sample_info_table->GetSkipByteBlock(), block_cipher_factory, + reset_iv_at_each_subsample, single_sample_decrypter); if (AP4_FAILED(result)) return result; @@ -2072,7 +2164,7 @@ | AP4_CencTrackEncryption::AP4_CencTrackEncryption +---------------------------------------------------------------------*/ AP4_CencTrackEncryption::AP4_CencTrackEncryption(AP4_UI08 version) : - m_FormatVersion(version), + m_Version_(version), m_DefaultIsProtected(0), m_DefaultPerSampleIvSize(0), m_DefaultConstantIvSize(0), @@ -2086,14 +2178,15 @@ /*---------------------------------------------------------------------- | AP4_CencTrackEncryption::AP4_CencTrackEncryption +---------------------------------------------------------------------*/ -AP4_CencTrackEncryption::AP4_CencTrackEncryption(AP4_UI08 default_is_protected, +AP4_CencTrackEncryption::AP4_CencTrackEncryption(AP4_UI08 version, + AP4_UI08 default_is_protected, AP4_UI08 default_per_sample_iv_size, const AP4_UI08* default_kid, AP4_UI08 default_constant_iv_size, const AP4_UI08* default_constant_iv, AP4_UI08 default_crypt_byte_block, AP4_UI08 default_skip_byte_block) : - m_FormatVersion(0), + m_Version_(version), m_DefaultIsProtected(default_is_protected), m_DefaultPerSampleIvSize(default_per_sample_iv_size), m_DefaultConstantIvSize(default_constant_iv_size), @@ -2120,7 +2213,7 @@ AP4_UI08 reserved; AP4_Result result = stream.ReadUI08(reserved); if (AP4_FAILED(result)) return result; - if (m_FormatVersion == 0) { + if (m_Version_ == 0) { result = stream.ReadUI08(reserved); if (AP4_FAILED(result)) return result; } else { @@ -2162,7 +2255,7 @@ inspector.AddField("default_isProtected", m_DefaultIsProtected); inspector.AddField("default_Per_Sample_IV_Size", m_DefaultPerSampleIvSize); inspector.AddField("default_KID", m_DefaultKid, 16); - if (m_FormatVersion >= 1) { + if (m_Version_ >= 1) { inspector.AddField("default_crypt_byte_block", m_DefaultCryptByteBlock); inspector.AddField("default_skip_byte_block", m_DefaultSkipByteBlock); } @@ -2186,7 +2279,7 @@ // write the fields result = stream.WriteUI08(0); // reserved if (AP4_FAILED(result)) return result; - if (m_FormatVersion == 0) { + if (m_Version_ == 0) { result = stream.WriteUI08(0); // reserved if (AP4_FAILED(result)) return result; } else { @@ -2221,6 +2314,7 @@ AP4_CencSampleInfoTable::Create(AP4_ProtectedSampleDescription* sample_description, AP4_ContainerAtom* traf, AP4_UI32& cipher_type, + bool& reset_iv_at_each_subsample, AP4_ByteStream& aux_info_data, AP4_Position aux_info_data_offset, AP4_CencSampleInfoTable*& sample_info_table) @@ -2234,6 +2328,7 @@ saiz, sample_encryption_atom, cipher_type, + reset_iv_at_each_subsample, aux_info_data, aux_info_data_offset, sample_info_table); @@ -2249,16 +2344,18 @@ AP4_SaizAtom*& saiz, AP4_CencSampleEncryption*& sample_encryption_atom, AP4_UI32& cipher_type, + bool& reset_iv_at_each_subsample, AP4_ByteStream& aux_info_data, AP4_Position aux_info_data_offset, AP4_CencSampleInfoTable*& sample_info_table) { // default return values - saio = NULL; - saiz = NULL; - sample_encryption_atom = NULL; - sample_info_table = NULL; - cipher_type = AP4_CENC_CIPHER_NONE; + saio = NULL; + saiz = NULL; + sample_encryption_atom = NULL; + sample_info_table = NULL; + cipher_type = AP4_CENC_CIPHER_NONE; + reset_iv_at_each_subsample = false; // get the scheme info atom AP4_ContainerAtom* schi = sample_description->GetSchemeInfo()->GetSchiAtom(); @@ -2308,8 +2405,12 @@ break; case AP4_PROTECTION_SCHEME_TYPE_CBC1: + cipher_type = AP4_CENC_CIPHER_AES_128_CBC; + break; + case AP4_PROTECTION_SCHEME_TYPE_CBCS: cipher_type = AP4_CENC_CIPHER_AES_128_CBC; + reset_iv_at_each_subsample = true; break; default: @@ -2355,7 +2456,8 @@ // try to create a sample info table from senc if (sample_info_table == NULL && sample_encryption_atom) { - AP4_Result result = sample_encryption_atom->CreateSampleInfoTable(crypt_byte_block, + AP4_Result result = sample_encryption_atom->CreateSampleInfoTable(0, + crypt_byte_block, skip_byte_block, per_sample_iv_size, constant_iv_size, @@ -2382,7 +2484,8 @@ } } if (sample_info_table == NULL && saio && saiz) { - AP4_Result result = Create(crypt_byte_block, + AP4_Result result = Create(0, + crypt_byte_block, skip_byte_block, per_sample_iv_size, constant_iv_size, @@ -2408,7 +2511,8 @@ | AP4_CencSampleInfoTable::Create +---------------------------------------------------------------------*/ AP4_Result -AP4_CencSampleInfoTable::Create(AP4_UI08 crypt_byte_block, +AP4_CencSampleInfoTable::Create(AP4_UI08 flags, + AP4_UI08 crypt_byte_block, AP4_UI08 skip_byte_block, AP4_UI08 per_sample_iv_size, AP4_UI08 constant_iv_size, @@ -2447,7 +2551,8 @@ return AP4_ERROR_INVALID_PARAMETERS; } } - AP4_CencSampleInfoTable* table = new AP4_CencSampleInfoTable(crypt_byte_block, + AP4_CencSampleInfoTable* table = new AP4_CencSampleInfoTable(flags, + crypt_byte_block, skip_byte_block, sample_info_count, iv_size); @@ -2532,7 +2637,7 @@ } AP4_UI32 sample_count = AP4_BytesToUInt32BE(serialized); serialized += 4; serialized_size -= 4; - serialized += 1; serialized_size -= 1; + AP4_UI08 flags = serialized[0]; serialized += 1; serialized_size -= 1; AP4_UI08 crypt_byte_block = serialized[0]; serialized += 1; serialized_size -= 1; AP4_UI08 skip_byte_block = serialized[0]; serialized += 1; serialized_size -= 1; AP4_UI08 iv_size = serialized[0]; serialized += 1; serialized_size -= 1; @@ -2540,7 +2645,7 @@ if (serialized_size < sample_count*iv_size) { return AP4_ERROR_INVALID_FORMAT; } - AP4_CencSampleInfoTable* table = new AP4_CencSampleInfoTable(crypt_byte_block, skip_byte_block, sample_count, (AP4_UI08)iv_size); + AP4_CencSampleInfoTable* table = new AP4_CencSampleInfoTable(flags, crypt_byte_block, skip_byte_block, sample_count, (AP4_UI08)iv_size); table->m_IvData.SetData(serialized, sample_count*iv_size); serialized += sample_count*iv_size; serialized_size -= sample_count*iv_size; @@ -2601,13 +2706,15 @@ /*---------------------------------------------------------------------- | AP4_CencSampleInfoTable::AP4_CencSampleInfoTable +---------------------------------------------------------------------*/ -AP4_CencSampleInfoTable::AP4_CencSampleInfoTable(AP4_UI08 crypt_byte_block, +AP4_CencSampleInfoTable::AP4_CencSampleInfoTable(AP4_UI08 flags, + AP4_UI08 crypt_byte_block, AP4_UI08 skip_byte_block, AP4_UI32 sample_count, AP4_UI08 iv_size) : + m_SampleCount(sample_count), + m_Flags(flags), m_CryptByteBlock(crypt_byte_block), m_SkipByteBlock(skip_byte_block), - m_SampleCount(sample_count), m_IvSize(iv_size) { m_IvData.SetDataSize(m_IvSize*sample_count); @@ -2645,8 +2752,11 @@ buffer.SetDataSize(size); AP4_UI08* data = buffer.UseData(); - AP4_BytesFromUInt32BE(data, m_SampleCount); data += 4; - AP4_BytesFromUInt32BE(data, m_IvSize); data += 4; + AP4_BytesFromUInt32BE(data, m_SampleCount); data += 4; + *data++ = m_Flags; + *data++ = m_CryptByteBlock; + *data++ = m_SkipByteBlock; + *data++ = m_IvSize; AP4_CopyMemory(data, m_IvData.GetData(), m_SampleCount*m_IvSize); data += m_SampleCount*m_IvSize; AP4_BytesFromUInt32BE(data, m_BytesOfCleartextData.ItemCount()); data += 4; for (unsigned int i=0; i<m_BytesOfCleartextData.ItemCount(); i++) { @@ -2817,7 +2927,7 @@ m_SampleInfoCursor(0) { AP4_SetMemory(m_ConstantIv, 0, 16); - if (constant_iv_size <= 16) { + if (constant_iv_size <= 16 && constant_iv) { AP4_CopyMemory(m_ConstantIv, constant_iv, m_ConstantIvSize); } AP4_SetMemory(m_Kid, 0, 16); @@ -2896,7 +3006,8 @@ | AP4_CencSampleEncryption::CreateSampleInfoTable +---------------------------------------------------------------------*/ AP4_Result -AP4_CencSampleEncryption::CreateSampleInfoTable(AP4_UI08 default_crypt_byte_block, +AP4_CencSampleEncryption::CreateSampleInfoTable(AP4_UI08 flags, + AP4_UI08 default_crypt_byte_block, AP4_UI08 default_skip_byte_block, AP4_UI08 default_per_sample_iv_size, AP4_UI08 default_constant_iv_size, @@ -2925,7 +3036,8 @@ // create the table AP4_Result result = AP4_ERROR_INVALID_FORMAT; - table = new AP4_CencSampleInfoTable(default_crypt_byte_block, + table = new AP4_CencSampleInfoTable(flags, + default_crypt_byte_block, default_skip_byte_block, m_SampleInfoCount, per_sample_iv_size?per_sample_iv_size:default_constant_iv_size);
View file
bento4-1.5.0r614.tar.gz/Source/C++/Core/Ap4CommonEncryption.h -> bento4-1.5.0r615.tar.gz/Source/C++/Core/Ap4CommonEncryption.h
Changed
@@ -2,7 +2,7 @@ | | AP4 - Common Encryption support | -| Copyright 2002-2011 Axiomatic Systems, LLC +| Copyright 2002-2017 Axiomatic Systems, LLC | | | This file is part of Bento4/AP4 (MP4 Atom Processing Library). @@ -98,7 +98,8 @@ protected: // constructors AP4_CencTrackEncryption(AP4_UI08 version); - AP4_CencTrackEncryption(AP4_UI08 default_is_protected, + AP4_CencTrackEncryption(AP4_UI08 version, + AP4_UI08 default_is_protected, AP4_UI08 default_per_sample_iv_size, const AP4_UI08* default_kid, AP4_UI08 default_constant_iv_size = 0, @@ -108,7 +109,7 @@ private: // members - AP4_UI08 m_FormatVersion; // cannot be called m_Version because it would conflict with AP4_Atom::m_Version + AP4_UI08 m_Version_; // cannot be called m_Version because it would conflict with AP4_Atom::m_Version AP4_UI08 m_DefaultIsProtected; AP4_UI08 m_DefaultPerSampleIvSize; AP4_UI08 m_DefaultConstantIvSize; @@ -145,7 +146,8 @@ AP4_Cardinal GetSampleInfoCount() { return m_SampleInfoCount; } AP4_Result AddSampleInfo(const AP4_UI08* iv, AP4_DataBuffer& subsample_info); AP4_Result SetSampleInfosSize(AP4_Size size); - AP4_Result CreateSampleInfoTable(AP4_UI08 default_crypt_byte_block, + AP4_Result CreateSampleInfoTable(AP4_UI08 flags, + AP4_UI08 default_crypt_byte_block, AP4_UI08 default_skip_byte_block, AP4_UI08 default_per_sample_iv_size, AP4_UI08 default_constant_iv_size, @@ -190,6 +192,7 @@ static AP4_Result Create(AP4_ProtectedSampleDescription* sample_description, AP4_ContainerAtom* traf, AP4_UI32& cipher_type, + bool& reset_iv_at_each_subsample, AP4_ByteStream& aux_info_data, AP4_Position aux_info_data_offset, AP4_CencSampleInfoTable*& sample_info_table); @@ -200,11 +203,13 @@ AP4_SaizAtom*& saiz, AP4_CencSampleEncryption*& sample_encryption_atom, AP4_UI32& cipher_type, + bool& reset_iv_at_each_subsample, AP4_ByteStream& aux_info_data, AP4_Position aux_info_data_offset, AP4_CencSampleInfoTable*& sample_info_table); - static AP4_Result Create(AP4_UI08 crypt_byte_block, + static AP4_Result Create(AP4_UI08 flags, + AP4_UI08 crypt_byte_block, AP4_UI08 skip_byte_block, AP4_UI08 per_sample_iv_size, AP4_UI08 constant_iv_size, @@ -223,12 +228,14 @@ AP4_CencSampleInfoTable*& sample_info_table); // constructor - AP4_CencSampleInfoTable(AP4_UI08 crypt_byte_block, + AP4_CencSampleInfoTable(AP4_UI08 flags, + AP4_UI08 crypt_byte_block, AP4_UI08 skip_byte_block, AP4_UI32 sample_count, AP4_UI08 iv_size); // methods + AP4_UI08 GetFlags() { return m_Flags; } AP4_UI08 GetCryptByteBlock() { return m_CryptByteBlock; } AP4_UI08 GetSkipByteBlock() { return m_SkipByteBlock; } AP4_UI32 GetSampleCount() { return m_SampleCount; } @@ -261,9 +268,10 @@ AP4_Result Serialize(AP4_DataBuffer& buffer); private: + AP4_UI32 m_SampleCount; + AP4_UI08 m_Flags; AP4_UI08 m_CryptByteBlock; AP4_UI08 m_SkipByteBlock; - AP4_UI32 m_SampleCount; AP4_UI08 m_IvSize; AP4_DataBuffer m_IvData; AP4_Array<AP4_UI16> m_BytesOfCleartextData; @@ -284,7 +292,7 @@ | +---------------+----------------+------------------------------------+ | | 4 bytes | 32-bit integer | sample_count | | +---------------+----------------+------------------------------------+ -| | 1 byte | 8-bit integer | reserved (0) | +| | 1 byte | 8-bit integer | flags | | +---------------+----------------+------------------------------------+ | | 1 byte | 8-bit integer | crypt_byte_block | | +---------------+----------------+------------------------------------+ @@ -349,8 +357,11 @@ { public: // constructor and destructor - AP4_CencSampleEncrypter(AP4_StreamCipher* cipher) : m_Cipher(cipher) { - AP4_SetMemory(m_Iv, 0, 16); + AP4_CencSampleEncrypter(AP4_StreamCipher* cipher, + bool constant_iv) : + m_Cipher(cipher), + m_ConstantIv(constant_iv) { + AP4_SetMemory(m_Iv, 0, 16); }; virtual ~AP4_CencSampleEncrypter(); @@ -371,6 +382,7 @@ protected: AP4_UI08 m_Iv[16]; AP4_StreamCipher* m_Cipher; + bool m_ConstantIv; }; /*---------------------------------------------------------------------- @@ -380,8 +392,10 @@ { public: // constructor and destructor - AP4_CencCtrSampleEncrypter(AP4_StreamCipher* cipher, unsigned int iv_size) : - AP4_CencSampleEncrypter(cipher), + AP4_CencCtrSampleEncrypter(AP4_StreamCipher* cipher, + bool constant_iv, + unsigned int iv_size) : + AP4_CencSampleEncrypter(cipher, constant_iv), m_IvSize(iv_size) {} // methods @@ -400,8 +414,9 @@ { public: // constructor and destructor - AP4_CencCbcSampleEncrypter(AP4_StreamCipher* cipher) : - AP4_CencSampleEncrypter(cipher) {} + AP4_CencCbcSampleEncrypter(AP4_StreamCipher* cipher, + bool constant_iv) : + AP4_CencSampleEncrypter(cipher, constant_iv) {} // methods virtual AP4_Result EncryptSampleData(AP4_DataBuffer& data_in, @@ -410,45 +425,126 @@ }; /*---------------------------------------------------------------------- -| AP4_CencSubSampleEncrypter +| AP4_CencSubSampleMapper +---------------------------------------------------------------------*/ -class AP4_CencSubSampleEncrypter : public AP4_CencSampleEncrypter +class AP4_CencSubSampleMapper { public: // constructor and destructor - AP4_CencSubSampleEncrypter(AP4_StreamCipher* cipher, - AP4_Size nalu_length_size, - AP4_UI32 format) : - AP4_CencSampleEncrypter(cipher), + AP4_CencSubSampleMapper(AP4_Size nalu_length_size, AP4_UI32 format) : m_NaluLengthSize(nalu_length_size), m_Format(format) {} - + virtual ~AP4_CencSubSampleMapper() {} + // methods - virtual bool UseSubSamples() { return true; } - + virtual AP4_Result GetSubSampleMap(AP4_DataBuffer& sample_data, + AP4_Array<AP4_UI16>& bytes_of_cleartext_data, + AP4_Array<AP4_UI32>& bytes_of_encrypted_data) = 0; + +protected: // members AP4_Size m_NaluLengthSize; AP4_UI32 m_Format; }; /*---------------------------------------------------------------------- +| AP4_CencBasicSubSampleMapper ++---------------------------------------------------------------------*/ +class AP4_CencBasicSubSampleMapper : public AP4_CencSubSampleMapper +{ +public: + // constructor and destructor + AP4_CencBasicSubSampleMapper(AP4_Size nalu_length_size, AP4_UI32 format) : + AP4_CencSubSampleMapper(nalu_length_size, format) {} + + // methods + virtual AP4_Result GetSubSampleMap(AP4_DataBuffer& sample_data, + AP4_Array<AP4_UI16>& bytes_of_cleartext_data, + AP4_Array<AP4_UI32>& bytes_of_encrypted_data); +}; + +/*---------------------------------------------------------------------- +| AP4_CencAdvancedSubSampleMapper ++---------------------------------------------------------------------*/ +class AP4_CencAdvancedSubSampleMapper : public AP4_CencSubSampleMapper +{ +public: + // constructor and destructor + AP4_CencAdvancedSubSampleMapper(AP4_Size nalu_length_size, AP4_UI32 format) : + AP4_CencSubSampleMapper(nalu_length_size, format) {} + + // methods + virtual AP4_Result GetSubSampleMap(AP4_DataBuffer& sample_data, + AP4_Array<AP4_UI16>& bytes_of_cleartext_data, + AP4_Array<AP4_UI32>& bytes_of_encrypted_data); +}; + +/*---------------------------------------------------------------------- +| AP4_CencCbcsSubSampleMapper ++---------------------------------------------------------------------*/ +class AP4_CencCbcsSubSampleMapper : public AP4_CencSubSampleMapper +{ +public: + // constructor and destructor + AP4_CencCbcsSubSampleMapper(AP4_Size nalu_length_size, AP4_UI32 format) : + AP4_CencSubSampleMapper(nalu_length_size, format) {} + + // methods + virtual AP4_Result GetSubSampleMap(AP4_DataBuffer& sample_data, + AP4_Array<AP4_UI16>& bytes_of_cleartext_data, + AP4_Array<AP4_UI32>& bytes_of_encrypted_data); +}; + +/*---------------------------------------------------------------------- +| AP4_CencSubSampleEncrypter ++---------------------------------------------------------------------*/ +class AP4_CencSubSampleEncrypter : public AP4_CencSampleEncrypter +{ +public: + // constructor and destructor + AP4_CencSubSampleEncrypter(AP4_StreamCipher* cipher, + bool constant_iv, + bool reset_iv_at_each_subsample, + AP4_CencSubSampleMapper* subsample_mapper) : + AP4_CencSampleEncrypter(cipher, constant_iv), + m_ResetIvForEachSubsample(reset_iv_at_each_subsample), + m_SubSampleMapper(subsample_mapper) {} + virtual ~AP4_CencSubSampleEncrypter() { + delete m_SubSampleMapper; + } + + // methods + virtual bool UseSubSamples() { return true; } + virtual AP4_Result GetSubSampleMap(AP4_DataBuffer& sample_data, + AP4_Array<AP4_UI16>& bytes_of_cleartext_data, + AP4_Array<AP4_UI32>& bytes_of_encrypted_data) { + return m_SubSampleMapper->GetSubSampleMap(sample_data, bytes_of_cleartext_data, bytes_of_encrypted_data); + } + + // members + bool m_ResetIvForEachSubsample; + AP4_CencSubSampleMapper* m_SubSampleMapper; +}; + +/*---------------------------------------------------------------------- | AP4_CencCtrSubSampleEncrypter +---------------------------------------------------------------------*/ class AP4_CencCtrSubSampleEncrypter : public AP4_CencSubSampleEncrypter { public: // constructor and destructor - AP4_CencCtrSubSampleEncrypter(AP4_StreamCipher* cipher, - AP4_Size nalu_length_size, - unsigned int iv_size, - AP4_UI32 format) : - AP4_CencSubSampleEncrypter(cipher, nalu_length_size, format), + AP4_CencCtrSubSampleEncrypter(AP4_StreamCipher* cipher, + bool constant_iv, + bool reset_iv_at_each_subsample, + unsigned int iv_size, + AP4_CencSubSampleMapper* subsample_mapper) : + AP4_CencSubSampleEncrypter(cipher, + constant_iv, + reset_iv_at_each_subsample, + subsample_mapper), m_IvSize(iv_size) {} // methods - virtual AP4_Result GetSubSampleMap(AP4_DataBuffer& sample_data, - AP4_Array<AP4_UI16>& bytes_of_cleartext_data, - AP4_Array<AP4_UI32>& bytes_of_encrypted_data); virtual AP4_Result EncryptSampleData(AP4_DataBuffer& data_in, AP4_DataBuffer& data_out, AP4_DataBuffer& sample_infos); @@ -464,15 +560,16 @@ { public: // constructor and destructor - AP4_CencCbcSubSampleEncrypter(AP4_StreamCipher* cipher, - AP4_Size nalu_length_size, - AP4_UI32 format) : - AP4_CencSubSampleEncrypter(cipher, nalu_length_size, format) {} + AP4_CencCbcSubSampleEncrypter(AP4_StreamCipher* cipher, + bool constant_iv, + bool reset_iv_at_each_subsample, + AP4_CencSubSampleMapper* subsample_mapper) : + AP4_CencSubSampleEncrypter(cipher, + constant_iv, + reset_iv_at_each_subsample, + subsample_mapper) {} // methods - virtual AP4_Result GetSubSampleMap(AP4_DataBuffer& sample_data, - AP4_Array<AP4_UI16>& bytes_of_cleartext_data, - AP4_Array<AP4_UI32>& bytes_of_encrypted_data); virtual AP4_Result EncryptSampleData(AP4_DataBuffer& data_in, AP4_DataBuffer& data_out, AP4_DataBuffer& sample_infos); @@ -562,17 +659,16 @@ static AP4_Result Create(AP4_UI32 cipher_type, const AP4_UI08* key, AP4_Size key_size, - unsigned int crypt_byte_block, - unsigned int skip_byte_block, + AP4_UI08 crypt_byte_block, + AP4_UI08 skip_byte_block, AP4_BlockCipherFactory* block_cipher_factory, + bool reset_iv_at_each_subsample, AP4_CencSingleSampleDecrypter*& decrypter); // methods AP4_CencSingleSampleDecrypter(AP4_StreamCipher* cipher) : m_Cipher(cipher), - m_FullBlocksOnly(false), - m_CryptByteBlock(0), - m_SkipByteBlock(0) {} + m_FullBlocksOnly(false) {} virtual ~AP4_CencSingleSampleDecrypter(); virtual AP4_Result DecryptSampleData(AP4_DataBuffer& data_in, AP4_DataBuffer& data_out, @@ -593,21 +689,15 @@ // constructor AP4_CencSingleSampleDecrypter(AP4_StreamCipher* cipher, bool full_blocks_only, - unsigned int crypt_byte_block, - unsigned int skip_byte_block) : + bool reset_iv_at_each_subsample) : m_Cipher(cipher), m_FullBlocksOnly(full_blocks_only), - m_CryptByteBlock(crypt_byte_block), - m_SkipByteBlock(skip_byte_block) {} - - // methods - AP4_Result DecryptRange(unsigned int range_position, const AP4_UI08* in, AP4_UI08* out, AP4_Size size); + m_ResetIvAtEachSubsample(reset_iv_at_each_subsample) {} // members AP4_StreamCipher* m_Cipher; bool m_FullBlocksOnly; - unsigned int m_CryptByteBlock; - unsigned int m_SkipByteBlock; + bool m_ResetIvAtEachSubsample; }; /*---------------------------------------------------------------------- @@ -642,6 +732,7 @@ const AP4_UI08* key, AP4_Size key_size, AP4_BlockCipherFactory* block_cipher_factory, + bool reset_iv_at_each_subsample, AP4_CencSampleDecrypter*& decrypter); // methods
View file
bento4-1.5.0r614.tar.gz/Source/C++/Core/Ap4ElstAtom.cpp -> bento4-1.5.0r615.tar.gz/Source/C++/Core/Ap4ElstAtom.cpp
Changed
@@ -80,7 +80,7 @@ stream.ReadUI32(media_time); stream.ReadUI16(media_rate); stream.ReadUI16(zero); - m_Entries.Append(AP4_ElstEntry(segment_duration, media_time, media_rate)); + m_Entries.Append(AP4_ElstEntry(segment_duration, (AP4_SI32)media_time, media_rate)); } else { AP4_UI64 segment_duration; AP4_UI64 media_time; @@ -88,7 +88,7 @@ stream.ReadUI64(media_time); stream.ReadUI16(media_rate); stream.ReadUI16(zero); - m_Entries.Append(AP4_ElstEntry(segment_duration, media_time, media_rate)); + m_Entries.Append(AP4_ElstEntry(segment_duration, (AP4_SI64)media_time, media_rate)); } } }
View file
bento4-1.5.0r614.tar.gz/Source/C++/Core/Ap4FragmentSampleTable.cpp -> bento4-1.5.0r615.tar.gz/Source/C++/Core/Ap4FragmentSampleTable.cpp
Changed
@@ -47,7 +47,8 @@ AP4_ByteStream* sample_stream, AP4_Position moof_offset, AP4_Position mdat_payload_offset, - AP4_UI64 dts_origin) + AP4_UI64 dts_origin) : + m_Duration(0) { AP4_TfhdAtom* tfhd = AP4_DYNAMIC_CAST(AP4_TfhdAtom, traf->GetChild(AP4_ATOM_TYPE_TFHD)); if (tfhd == NULL) return;
View file
bento4-1.5.0r614.tar.gz/Source/C++/Core/Ap4Piff.cpp -> bento4-1.5.0r615.tar.gz/Source/C++/Core/Ap4Piff.cpp
Changed
@@ -88,7 +88,8 @@ AP4_UI08 default_iv_size, const AP4_UI08* default_kid) : AP4_UuidAtom(AP4_FULL_UUID_ATOM_HEADER_SIZE+20, AP4_UUID_PIFF_TRACK_ENCRYPTION_ATOM, 0, 0), - AP4_CencTrackEncryption(default_algorithm_id, + AP4_CencTrackEncryption(0, + default_algorithm_id, default_iv_size, default_kid) {
View file
bento4-1.5.0r614.tar.gz/Source/C++/Core/Ap4SampleTable.cpp -> bento4-1.5.0r615.tar.gz/Source/C++/Core/Ap4SampleTable.cpp
Changed
@@ -58,14 +58,14 @@ // create the stsd atom AP4_StsdAtom* stsd = new AP4_StsdAtom(this); - // create the stsz atom - AP4_StszAtom* stsz = new AP4_StszAtom(); + // create the stts atom + AP4_SttsAtom* stts = new AP4_SttsAtom(); // create the stsc atom AP4_StscAtom* stsc = new AP4_StscAtom(); - // create the stts atom - AP4_SttsAtom* stts = new AP4_SttsAtom(); + // create the stsz atom + AP4_StszAtom* stsz = new AP4_StszAtom(); // create the stss atom AP4_StssAtom* stss = new AP4_StssAtom(); @@ -180,10 +180,10 @@ // attach the children of stbl stbl->AddChild(stsd); - stbl->AddChild(stsz); - stbl->AddChild(stsc); stbl->AddChild(stts); if (ctts) stbl->AddChild(ctts); + stbl->AddChild(stsc); + stbl->AddChild(stsz); if (!all_samples_are_sync && stss->GetEntries().ItemCount() != 0) { stbl->AddChild(stss); } else {
View file
bento4-1.5.0r614.tar.gz/Source/C++/Core/Ap4SencAtom.cpp -> bento4-1.5.0r615.tar.gz/Source/C++/Core/Ap4SencAtom.cpp
Changed
@@ -85,6 +85,24 @@ } /*---------------------------------------------------------------------- +| AP4_SencAtom::AP4_SencAtom ++---------------------------------------------------------------------*/ +AP4_SencAtom::AP4_SencAtom(AP4_UI08 per_sample_iv_size, + AP4_UI08 constant_iv_size, + const AP4_UI08* constant_iv, + AP4_UI08 crypt_byte_block, + AP4_UI08 skip_byte_block): + AP4_Atom(AP4_ATOM_TYPE_SENC, AP4_FULL_ATOM_HEADER_SIZE+4, 0, 0), + AP4_CencSampleEncryption(*this, + per_sample_iv_size, + constant_iv_size, + constant_iv, + crypt_byte_block, + skip_byte_block) +{ +} + +/*---------------------------------------------------------------------- | AP4_SencAtom::WriteFields +---------------------------------------------------------------------*/ AP4_Result
View file
bento4-1.5.0r614.tar.gz/Source/C++/Core/Ap4SencAtom.h -> bento4-1.5.0r615.tar.gz/Source/C++/Core/Ap4SencAtom.h
Changed
@@ -49,9 +49,14 @@ // constructors AP4_SencAtom(AP4_UI08 iv_size = 16); AP4_SencAtom(AP4_UI32 algorithm_id, - AP4_UI08 iv_size, + AP4_UI08 per_sample_iv_size, const AP4_UI08* kid); - + AP4_SencAtom(AP4_UI08 per_sample_iv_size, + AP4_UI08 constant_iv_size, + const AP4_UI08* constant_iv, + AP4_UI08 crypt_byte_block, + AP4_UI08 skip_byte_block); + // methods virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); virtual AP4_Result WriteFields(AP4_ByteStream& stream);
View file
bento4-1.5.0r614.tar.gz/Source/C++/Core/Ap4TencAtom.cpp -> bento4-1.5.0r615.tar.gz/Source/C++/Core/Ap4TencAtom.cpp
Changed
@@ -65,7 +65,8 @@ AP4_UI08 default_per_sample_iv_size, const AP4_UI08* default_kid) : AP4_Atom(AP4_ATOM_TYPE_TENC, AP4_FULL_ATOM_HEADER_SIZE+20, 0, 0), - AP4_CencTrackEncryption(default_is_protected, + AP4_CencTrackEncryption(0, + default_is_protected, default_per_sample_iv_size, default_kid) { @@ -82,7 +83,8 @@ AP4_UI08 default_crypt_byte_block, AP4_UI08 default_skip_byte_block) : AP4_Atom(AP4_ATOM_TYPE_TENC, AP4_FULL_ATOM_HEADER_SIZE+20+(default_per_sample_iv_size?0:1+default_constant_iv_size), 1, 0), - AP4_CencTrackEncryption(default_is_protected, + AP4_CencTrackEncryption(1, + default_is_protected, default_per_sample_iv_size, default_kid, default_constant_iv_size,
View file
bento4-1.5.0r614.tar.gz/Source/C++/Core/Ap4TfhdAtom.cpp -> bento4-1.5.0r615.tar.gz/Source/C++/Core/Ap4TfhdAtom.cpp
Changed
@@ -124,6 +124,16 @@ } /*---------------------------------------------------------------------- +| AP4_TfhdAtom::UpdateFlags ++---------------------------------------------------------------------*/ +void +AP4_TfhdAtom::UpdateFlags(AP4_UI32 flags) +{ + m_Flags = flags; + m_Size32 = ComputeSize(flags); +} + +/*---------------------------------------------------------------------- | AP4_TfhdAtom::WriteFields +---------------------------------------------------------------------*/ AP4_Result
View file
bento4-1.5.0r614.tar.gz/Source/C++/Core/Ap4TfhdAtom.h -> bento4-1.5.0r615.tar.gz/Source/C++/Core/Ap4TfhdAtom.h
Changed
@@ -81,6 +81,8 @@ AP4_UI32 GetDefaultSampleFlags() { return m_DefaultSampleFlags; } void SetDefaultSampleFlags(AP4_UI32 flags) { m_DefaultSampleFlags = flags; } + void UpdateFlags(AP4_UI32 flags); + private: // methods AP4_TfhdAtom(AP4_UI32 size,
View file
bento4-1.5.0r614.tar.gz/Source/C++/Crypto/Ap4StreamCipher.cpp -> bento4-1.5.0r615.tar.gz/Source/C++/Crypto/Ap4StreamCipher.cpp
Changed
@@ -519,3 +519,129 @@ return DecryptBuffer(in, in_size, out, out_size, is_last_buffer); } } + +/*---------------------------------------------------------------------- +| AP4_PatternStreamCipher ++---------------------------------------------------------------------*/ +AP4_PatternStreamCipher::AP4_PatternStreamCipher(AP4_StreamCipher* cipher, + AP4_UI08 crypt_byte_block, + AP4_UI08 skip_byte_block) : + m_Cipher(cipher), + m_CryptByteBlock(crypt_byte_block), + m_SkipByteBlock(skip_byte_block), + m_StreamOffset(0) +{ +} + +/*---------------------------------------------------------------------- +| AP4_PatternStreamCipher::~AP4_PatternStreamCipher ++---------------------------------------------------------------------*/ +AP4_PatternStreamCipher::~AP4_PatternStreamCipher() +{ + delete m_Cipher; +} + +/*---------------------------------------------------------------------- +| AP4_PatternStreamCipher::SetStreamOffset ++---------------------------------------------------------------------*/ +AP4_Result +AP4_PatternStreamCipher::SetStreamOffset(AP4_UI64 /*offset*/, + AP4_Cardinal* /*preroll*/) +{ + return AP4_ERROR_NOT_SUPPORTED; +} + +/*---------------------------------------------------------------------- +| AP4_PatternStreamCipher ++---------------------------------------------------------------------*/ +AP4_Result +AP4_PatternStreamCipher::ProcessBuffer(const AP4_UI08* in, + AP4_Size in_size, + AP4_UI08* out, + AP4_Size* out_size, + bool /* is_last_buffer */) +{ + // set default return values + *out_size = 0; + + // check that the range is block-aligned (required by the spec for pattern encryption) + if (m_StreamOffset % 16) return AP4_ERROR_INVALID_FORMAT; + + // compute where we are in the pattern + unsigned int pattern_span = m_CryptByteBlock+m_SkipByteBlock; + unsigned int block_position = (unsigned int)(m_StreamOffset/16); + unsigned int pattern_position = block_position % pattern_span; + + // process the range + while (*out_size < in_size) { + unsigned int crypt_size = 0; + unsigned int skip_size = m_SkipByteBlock*16; + if (pattern_position < m_CryptByteBlock) { + // in the encrypted part + crypt_size = (m_CryptByteBlock-pattern_position)*16; + } else { + // in the skipped part + skip_size = pattern_span-pattern_position; + } + + // clip + AP4_Size remain = in_size-*out_size; + if (crypt_size > remain) { + crypt_size = 16*(remain/16); + skip_size = remain-crypt_size; + } + if (crypt_size+skip_size > remain) { + skip_size = remain-crypt_size; + } + + // encrypted part + if (crypt_size) { + AP4_Size in_chunk_size = crypt_size; + AP4_Size out_chunk_size = crypt_size; + + AP4_Result result = m_Cipher->ProcessBuffer(in, in_chunk_size, out, &out_chunk_size); + if (AP4_FAILED(result)) return result; + // check that we got back what we expectected + if (out_chunk_size != in_chunk_size) { + return AP4_ERROR_INTERNAL; + } + in += crypt_size; + out += crypt_size; + *out_size += crypt_size; + m_StreamOffset += crypt_size; + } + + // skipped part + if (skip_size) { + AP4_CopyMemory(out, in, skip_size); + in += skip_size; + out += skip_size; + *out_size += skip_size; + m_StreamOffset += skip_size; + } + + // we're now at the start of a new pattern + pattern_position = 0; + } + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_PatternStreamCipher ++---------------------------------------------------------------------*/ +AP4_Result +AP4_PatternStreamCipher::SetIV(const AP4_UI08* iv) +{ + m_StreamOffset = 0; + return m_Cipher->SetIV(iv); +} + +/*---------------------------------------------------------------------- +| AP4_PatternStreamCipher ++---------------------------------------------------------------------*/ +const AP4_UI08* +AP4_PatternStreamCipher::GetIV() +{ + return m_Cipher->GetIV(); +}
View file
bento4-1.5.0r614.tar.gz/Source/C++/Crypto/Ap4StreamCipher.h -> bento4-1.5.0r615.tar.gz/Source/C++/Crypto/Ap4StreamCipher.h
Changed
@@ -165,4 +165,39 @@ bool is_last_buffer); }; +/*---------------------------------------------------------------------- +| AP4_PatternStreamCipher ++---------------------------------------------------------------------*/ +class AP4_PatternStreamCipher : public AP4_StreamCipher +{ +public: + // methods + + /** + * The stream cipher is passed with transfer of ownership (it will + * be destroyed when this object is destroyed). + */ + AP4_PatternStreamCipher(AP4_StreamCipher* cipher, AP4_UI08 crypt_byte_block, AP4_UI08 skip_byte_block); + ~AP4_PatternStreamCipher(); + + // AP4_StreamCipher implementation + virtual AP4_Result SetStreamOffset(AP4_UI64 offset, + AP4_Cardinal* preroll); + virtual AP4_UI64 GetStreamOffset() { return m_StreamOffset; } + virtual AP4_Result ProcessBuffer(const AP4_UI08* in, + AP4_Size in_size, + AP4_UI08* out, + AP4_Size* out_size, + bool is_last_buffer = false); + virtual AP4_Result SetIV(const AP4_UI08* iv); + virtual const AP4_UI08* GetIV(); + +private: + // members + AP4_StreamCipher* m_Cipher; + AP4_UI08 m_CryptByteBlock; + AP4_UI08 m_SkipByteBlock; + AP4_UI64 m_StreamOffset; +}; + #endif // _AP4_STREAM_CIPHER_H_
View file
bento4-1.5.0r614.tar.gz/Source/Python/utils/mp4-dash.py -> bento4-1.5.0r615.tar.gz/Source/Python/utils/mp4-dash.py
Changed
@@ -22,12 +22,13 @@ import re import platform import sys +import math from mp4utils import * from subtitles import * # setup main options -VERSION = "1.7.0" -SDK_REVISION = '614' +VERSION = "1.8.0" +SDK_REVISION = '615' SCRIPT_PATH = path.abspath(path.dirname(__file__)) sys.path += [SCRIPT_PATH] @@ -106,6 +107,13 @@ TempFiles = [] +MpegCencSchemeMap = { + 'cenc': 'MPEG-CENC', + 'cbc1': 'MPEG-CBC1', + 'cens': 'MPEG-CENS', + 'cbcs': 'MPEG-CBCS' +} + ############################################# def AddSegmentList(options, container, subdir, track, use_byte_range=False): if subdir: @@ -206,7 +214,7 @@ kids = [] for track in tracks: kid = track.kid - if kid is None: + if kid is None and not options.no_media: PrintErrorAndExit('ERROR: no encryption info found in track '+str(track)) if kid not in kids: kids.append(kid) @@ -227,7 +235,7 @@ if options.eme_signaling in ['pssh-v0', 'pssh-v1']: container.append(xml.Comment(' EME Common Encryption ')) xml.register_namespace('cenc', CENC_2013_NAMESPACE) - cp = xml.SubElement(container, 'ContentProtection', schemeIdUri=EME_COMMON_ENCRYPTION_SCHEME_ID_URI, value='cenc') + cp = xml.SubElement(container, 'ContentProtection', schemeIdUri=EME_COMMON_ENCRYPTION_SCHEME_ID_URI, value=options.encryption_cenc_scheme) if options.eme_signaling == 'pssh-v1': pssh_box = MakePsshBoxV1(EME_COMMON_ENCRYPTION_PSSH_SYSTEM_ID.decode('hex'), [default_kid], '') else: @@ -239,7 +247,7 @@ # MPEG Common Encryption container.append(xml.Comment(' MPEG Common Encryption ')) xml.register_namespace('cenc', CENC_2013_NAMESPACE) - cp = xml.SubElement(container, 'ContentProtection', schemeIdUri=MPEG_COMMON_ENCRYPTION_SCHEME_ID_URI, value='cenc') + cp = xml.SubElement(container, 'ContentProtection', schemeIdUri=MPEG_COMMON_ENCRYPTION_SCHEME_ID_URI, value=options.encryption_cenc_scheme) default_kid_with_dashes = (default_kid[0:8]+'-'+default_kid[8:12]+'-'+default_kid[12:16]+'-'+default_kid[16:20]+'-'+default_kid[20:32]).lower() cp.set('{'+CENC_2013_NAMESPACE+'}default_KID', default_kid_with_dashes) @@ -564,7 +572,7 @@ ############################################# def OutputHlsTrack(options, track, media_subdir, media_playlist_name, media_file_name): - hls_target_duration = 10 + hls_target_duration = math.ceil(max(track.segment_durations)) media_playlist_file = open(path.join(options.output_dir, media_subdir, media_playlist_name), 'w+') media_playlist_file.write('#EXTM3U\r\n') @@ -582,6 +590,10 @@ media_playlist_file.write('#EXT-X-MAP:URI="%s"\r\n' % (SPLIT_INIT_SEGMENT_NAME)) segment_pattern = SEGMENT_PATTERN.replace('ll','') + if options.encryption_key: + key_info = options.track_key_infos.get(track.id) + media_playlist_file.write('#EXT-X-KEY:METHOD=SAMPLE-AES,URI="'+options.hls_key_url+'",IV=0x'+key_info['iv']+'\r\n') + for i in range(len(track.segment_durations)): media_playlist_file.write('#EXTINF:%f,\r\n' % (track.segment_durations[i])) if options.on_demand: @@ -618,8 +630,25 @@ language_name = LanguageNames.get(language, language).decode('utf-8') audio_group_name = adaptation_set_name[0]+'/'+adaptation_set_name[2] - audio_groups[audio_group_name] = adaptation_set_name[2] + audio_groups[audio_group_name] = { + 'codec': '', + 'average_segment_bitrate': 0, + 'max_segment_bitrate': 0 + } for audio_track in audio_tracks: + # update the avergage and max bitrates + if audio_track.average_segment_bitrate > audio_groups[audio_group_name]['average_segment_bitrate']: + audio_groups[audio_group_name]['average_segment_bitrate'] = audio_track.average_segment_bitrate + if audio_track.max_segment_bitrate > audio_groups[audio_group_name]['max_segment_bitrate']: + audio_groups[audio_group_name]['max_segment_bitrate'] = audio_track.max_segment_bitrate + + # update/check the codec + if audio_groups[audio_group_name]['codec'] == '': + audio_groups[audio_group_name]['codec'] = audio_track.codec + else: + if audio_groups[audio_group_name]['codec'] != audio_track.codec: + print 'WARNING: audio codecs not all the same:', audio_groups[audio_group_name]['codec'], audio_track.codec + if options.on_demand: media_subdir = '' media_file_name = audio_track.parent.media_name @@ -662,16 +691,28 @@ raise Exception('mode not yet supported with HLS') - for audio_group_name in audio_groups: - audio_codec = audio_groups[audio_group_name] - master_playlist_file.write('#EXT-X-STREAM-INF:AUDIO="%s",AVERAGE-BANDWIDTH=%d,BANDWIDTH=%d,CODECS="%s",RESOLUTION=%dx%d\r\n' % ( - audio_group_name, + if len(audio_groups): + # one entry per audio group + for audio_group_name in audio_groups: + audio_codec = audio_groups[audio_group_name]['codec'] + master_playlist_file.write('#EXT-X-STREAM-INF:AUDIO="%s",AVERAGE-BANDWIDTH=%d,BANDWIDTH=%d,CODECS="%s",RESOLUTION=%dx%d\r\n' % ( + audio_group_name, + video_track.average_segment_bitrate + audio_groups[audio_group_name]['average_segment_bitrate'], + video_track.max_segment_bitrate + audio_groups[audio_group_name]['max_segment_bitrate'], + video_track.codec+','+audio_codec, + video_track.width, + video_track.height)) + master_playlist_file.write(media_playlist_path+'\r\n') + else: + # no audio + master_playlist_file.write('#EXT-X-STREAM-INF:AVERAGE-BANDWIDTH=%d,BANDWIDTH=%d,CODECS="%s",RESOLUTION=%dx%d\r\n' % ( video_track.average_segment_bitrate, video_track.max_segment_bitrate, - video_track.codec+','+audio_codec, + video_track.codec, video_track.width, video_track.height)) master_playlist_file.write(media_playlist_path+'\r\n') + OutputHlsTrack(options, video_track, media_subdir, media_playlist_name, media_file_name) ############################################# @@ -1056,6 +1097,15 @@ key_info['key'] = key_hex key_info['kid'] = kid_hex + if options.hls: + # for HLS, we need to know the IV + import random + sys_random = random.SystemRandom() + random_iv = sys_random.getrandbits(128) + key_info['iv'] = '%016x' % random_iv + else: + key_info['iv'] = 'random' + options.key_infos.append(key_info) ############################################# @@ -1141,6 +1191,8 @@ help="Smooth Streaming FourCC value for H.264 video (default=H264) [some older players use AVC1]", metavar="<fourcc>", default='H264') parser.add_option('', '--hls', dest="hls", default=False, action="store_true", help="Output HLS playlists in addition to MPEG DASH") + parser.add_option('', '--hls-key-url', dest="hls_key_url", + help="HLS key URL (default: key.bin)", metavar="<url>", default='key.bin') parser.add_option('', '--hls-master-playlist-name', dest="hls_master_playlist_name", help="HLS master playlist name (default: master.m3u8)", metavar="<filename>", default='master.m3u8') parser.add_option('', '--hls-media-playlist-name', dest="hls_media_playlist_name", @@ -1157,6 +1209,8 @@ help="Encrypt some or all tracks with MPEG CENC (AES-128), where <key-spec> specifies the KID(s) and Key(s) to use, using one of the following forms: " + "(1) <KID>:<key> with <KID> as a 32-character hex string and <key> either a 32-character hex string or the character '#' followed by a base64-encoded key seed; or " + "(2) @<key-locator> where <key-locator> is an expression of one of the supported key locator schemes. Each entry may be prefixed with an optional track filter, and multiple <key-spec> entries can be used, separated by ','. (see online docs for details)") + parser.add_option('', "--encryption-cenc-scheme", dest="encryption_cenc_scheme", metavar='<cenc-scheme>', default='cenc', choices=('cenc', 'cbc1', 'cens', 'cbcs'), + help="MPEG Common Encryption scheme (cenc, cbc1, cens or cbcs). (default: cenc)") parser.add_option('', "--encryption-args", dest="encryption_args", metavar='<cmdline-arguments>', default=None, help="Pass additional command line arguments to mp4encrypt (separated by spaces)") parser.add_option('', "--eme-signaling", dest="eme_signaling", metavar='<eme-signaling-type>', choices=['pssh-v0', 'pssh-v1'], @@ -1288,6 +1342,10 @@ if options.primetime_metadata: options.primetime = True + if options.hls: + if options.encryption_key and options.encryption_cenc_scheme != 'cbcs': + raise Exception('--hls requires --encryption-cenc-scheme=cbcs') + # compute the KID(s) and encryption key(s) if needed if options.encryption_key: ResolveEncryptionKeys(options) @@ -1351,7 +1409,7 @@ media_sources.append(media_source) # encrypt the input files if needed - if not options.no_media and options.encryption_key: + if options.encryption_key: encrypted_files = {} for media_source in media_sources: if media_source.format != 'mp4': continue @@ -1382,6 +1440,11 @@ if track['type'].lower() in key_info['filter']: options.track_key_infos[track['id']] = key_info + # skip now if we're only outputing the MPD + if options.no_media: + continue + + # don't process any further if we won't have key material for this track if len(options.track_key_infos) == 0: continue @@ -1391,7 +1454,7 @@ TempFiles.append(encrypted_file.name) encrypted_file.close() # necessary on Windows MapFileName(encrypted_file.name, path.basename(encrypted_file.name) + ' = Encrypted[' + GetMappedFileName(media_file) + ']') - args = ['--method', 'MPEG-CENC'] + args = ['--method', MpegCencSchemeMap[options.encryption_cenc_scheme]] if options.encryption_args: args += options.encryption_args.split() @@ -1401,7 +1464,7 @@ for track_id in sorted(options.track_key_infos.keys()): key_info = options.track_key_infos[track_id] - args += ['--key', str(track_id)+':'+key_info['key']+':random', '--property', str(track_id)+':KID:'+key_info['kid']] + args += ['--key', str(track_id)+':'+key_info['key']+':'+key_info['iv'], '--property', str(track_id)+':KID:'+key_info['kid']] # EME Common Encryption / Clearkey if options.eme_signaling == 'pssh-v0':
View file
bento4-1.5.0r614.tar.gz/Source/Python/utils/mp4-hls.py -> bento4-1.5.0r615.tar.gz/Source/Python/utils/mp4-hls.py
Changed
@@ -27,7 +27,7 @@ # setup main options VERSION = "1.1.0" -SDK_REVISION = '614' +SDK_REVISION = '615' SCRIPT_PATH = path.abspath(path.dirname(__file__)) sys.path += [SCRIPT_PATH]
View file
bento4-1.5.0r614.tar.gz/Test/Bento4CryptoTester.py -> bento4-1.5.0r615.tar.gz/Test/Bento4CryptoTester.py
Changed
@@ -119,16 +119,22 @@ BIN_ROOT=sys.argv[1] files = sys.argv[2:] +if len(sys.argv) >= 4: + methods = sys.argv[3].split(',') +else: + methods = None + counter = 0 for file in files: json_info = Mp4Info(file, format='json', fast=True) info = json.loads(json_info, strict=False) - if info['movie']['fragments']: - methods = METHODS_FOR_FRAGMENTED_MP4 - else: - methods = METHODS_FOR_LINEAR_MP4 + if methods is None: + if info['movie']['fragments']: + methods = METHODS_FOR_FRAGMENTED_MP4 + else: + methods = METHODS_FOR_LINEAR_MP4 for method in methods: for key in KEYS:
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.