Projects
Multimedia
bento4
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 16
View file
bento4.changes
Changed
@@ -1,4 +1,10 @@ ------------------------------------------------------------------- +Sun Jun 7 12:35:09 UTC 2020 - aloisio@gmx.com + +- Update to version 1.6.0-636 +- Refreshed bento4-shared_library.patch + +------------------------------------------------------------------- Mon May 18 08:00:12 UTC 2020 - aloisio@gmx.com - Update to version 1.6.0-634
View file
bento4.spec
Changed
@@ -16,10 +16,10 @@ # -%define _over 1.6.0-634 -%define _libver 1_6_0r634 +%define _over 1.6.0-636 +%define _libver 1_6_0r636 Name: bento4 -Version: 1.6.0r634 +Version: 1.6.0r636 Release: 0 Summary: C++ toolkit for all your MP4 and MPEG DASH media format needs License: GPL-2.0-or-later @@ -60,9 +60,7 @@ write most Quicktime files as well. %prep -%setup -q -n Bento4-%{_over} -%patch0 -p1 -%patch1 -p1 +%autosetup -p1 -n Bento4-%{_over} sed -e 's/__VERSION__/%{version}/g' -i CMakeLists.txt sed -e '6s/.*/AP4_BUILD_CONFIG = Release/' -i Build/Makefiles/Bootstrap.mak
View file
bento4-shared_library.patch
Changed
@@ -1,8 +1,8 @@ -Index: Bento4-1.5.1-628/CMakeLists.txt +Index: Bento4-1.6.0-636/CMakeLists.txt =================================================================== ---- Bento4-1.5.1-628.orig/CMakeLists.txt -+++ Bento4-1.5.1-628/CMakeLists.txt -@@ -27,13 +27,21 @@ file(GLOB AP4_SOURCES +--- Bento4-1.6.0-636.orig/CMakeLists.txt ++++ Bento4-1.6.0-636/CMakeLists.txt +@@ -42,6 +42,14 @@ file(GLOB AP4_SOURCES ${SOURCE_SYSTEM}/StdC/*.cpp ) @@ -14,18 +14,21 @@ + ${SOURCE_ROOT}Codecs/*.h +) + + # Platform specifics if(WIN32) set(AP4_SOURCES ${AP4_SOURCES} ${SOURCE_SYSTEM}/Win32/Ap4Win32Random.cpp) - else() - set(AP4_SOURCES ${AP4_SOURCES} ${SOURCE_SYSTEM}/Posix/Ap4PosixRandom.cpp) - endif() +@@ -57,8 +65,8 @@ set(AP4_INCLUDE_DIRS + ${SOURCE_METADATA} + ) -add_library(ap4 STATIC ${AP4_SOURCES}) +-target_include_directories(ap4 PUBLIC ${AP4_INCLUDE_DIRS}) +add_library(ap4-__VERSION__ SHARED ${AP4_SOURCES}) ++target_include_directories(ap4-__VERSION__ PUBLIC ${AP4_INCLUDE_DIRS}) - # Includes - include_directories( -@@ -47,6 +55,11 @@ include_directories( + # Use the statically linked C runtime library + if(MSVC) +@@ -72,12 +80,16 @@ if(BUILD_APPS) file(GLOB BENTO4_APPS RELATIVE ${SOURCE_ROOT}/Apps ${SOURCE_ROOT}/Apps/*) foreach(app ${BENTO4_APPS}) string(TOLOWER ${app} binary_name) @@ -34,7 +37,12 @@ - target_link_libraries(${binary_name} ap4) + target_link_libraries(${binary_name} ap4-__VERSION__) + INSTALL(TARGETS ${binary_name} DESTINATION bin) + + if(MSVC) + set_property(TARGET ${binary_name} PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>") + target_compile_definitions(${binary_name} PRIVATE -D_CONSOLE) + endif() endforeach() -+ +INSTALL (TARGETS ap4-__VERSION__ DESTINATION lib${LIB_SUFFIX}) +INSTALL(FILES ${SDK_INCLUDES} DESTINATION include/ap4) + endif(BUILD_APPS)
View file
bento4-1.6.0r634.tar.gz/.github/workflows/ci.yml -> bento4-1.6.0r636.tar.gz/.github/workflows/ci.yml
Changed
@@ -10,7 +10,7 @@ branches: [ master ] jobs: - build-linux-macos: + build: name: Bento4 Build ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: @@ -19,13 +19,19 @@ include: - os: ubuntu-latest CMAKE_OPTIONS: -DCMAKE_BUILD_TYPE=Release + CMAKE_OUTPUT_SUBDIR: x86_64-unknown-linux + PYTHON3_COMMAND: python3 - os: macos-latest CMAKE_OPTIONS: -G Xcode + CMAKE_OUTPUT_SUBDIR: universal-apple-macosx + PYTHON3_COMMAND: python3 - os: windows-latest CMAKE_OPTIONS: -DCMAKE_BUILD_TYPE=Release + CMAKE_OUTPUT_SUBDIR: x86_64-microsoft-win32 + PYTHON3_COMMAND: py steps: - # Checks-out the repository under $GITHUB_WORKSPACE, so that the jobs can access it + # Check out the repository under $GITHUB_WORKSPACE, so that the jobs can access it - uses: actions/checkout@v2 # CMake Build @@ -33,5 +39,19 @@ run: | mkdir cmakebuild cd cmakebuild - cmake ${{matrix.CMAKE_OPTIONS}} .. + mkdir ${{matrix.CMAKE_OUTPUT_SUBDIR}} + cd ${{matrix.CMAKE_OUTPUT_SUBDIR}} + cmake ${{matrix.CMAKE_OPTIONS}} ../.. cmake --build . --config Release + + # Create SDK + - name: Create SDK + if: github.event_name == 'push' + run: ${{matrix.PYTHON3_COMMAND}} Scripts/SdkPackager.py + + # Upload the SDK + - name: Upload SDK + if: github.event_name == 'push' + uses: actions/upload-artifact@v2 + with: + path: SDK/*.zip
View file
bento4-1.6.0r634.tar.gz/.gitignore -> bento4-1.6.0r636.tar.gz/.gitignore
Changed
@@ -53,3 +53,4 @@ .coverage coverage_html Test/Output +Build/Targets/x86_64-microsoft-win32-vs2019/.vs
View file
bento4-1.6.0r634.tar.gz/Build/Docker/Dockerfile -> bento4-1.6.0r636.tar.gz/Build/Docker/Dockerfile
Changed
@@ -1,7 +1,7 @@ FROM alpine:latest # Setup environment variables -ENV BENTO4_VERSION 1.5.1-629 +ENV BENTO4_VERSION 1.6.0-636 # Install Dependencies RUN apk update && apk add --no-cache ca-certificates bash python3 make cmake gcc g++ git
View file
bento4-1.6.0r634.tar.gz/CMakeLists.txt -> bento4-1.6.0r636.tar.gz/CMakeLists.txt
Changed
@@ -1,6 +1,12 @@ # cmake -DCMAKE_BUILD_TYPE=Debug .. # cmake -DCMAKE_BUILD_TYPE=Release .. -cmake_minimum_required(VERSION 2.8) +if(MSVC) + cmake_policy(SET CMP0091 NEW) + cmake_minimum_required(VERSION 3.15) +else() + cmake_minimum_required(VERSION 3.10) +endif() + project(bento4) # Variables @@ -20,6 +26,13 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-warn-absolute-paths") endif() +set(CMAKE_OSX_DEPLOYMENT_TARGET 10.12) + +if(MSVC) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /GF /Gy /GR") +endif() + # AP4 Library file(GLOB AP4_SOURCES ${SOURCE_CODECS}/*.cpp @@ -29,26 +42,42 @@ ${SOURCE_SYSTEM}/StdC/*.cpp ) +# Platform specifics if(WIN32) set(AP4_SOURCES ${AP4_SOURCES} ${SOURCE_SYSTEM}/Win32/Ap4Win32Random.cpp) else() set(AP4_SOURCES ${AP4_SOURCES} ${SOURCE_SYSTEM}/Posix/Ap4PosixRandom.cpp) endif() -add_library(ap4 STATIC ${AP4_SOURCES}) - # Includes -include_directories( +set(AP4_INCLUDE_DIRS ${SOURCE_CORE} ${SOURCE_CODECS} ${SOURCE_CRYPTO} ${SOURCE_METADATA} ) +add_library(ap4 STATIC ${AP4_SOURCES}) +target_include_directories(ap4 PUBLIC ${AP4_INCLUDE_DIRS}) + +# Use the statically linked C runtime library +if(MSVC) + set_property(TARGET ap4 PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>") + target_compile_definitions(ap4 PRIVATE -D_LIB) +endif() + # Apps +option(BUILD_APPS "Build example applications" ON) +if(BUILD_APPS) file(GLOB BENTO4_APPS RELATIVE ${SOURCE_ROOT}/Apps ${SOURCE_ROOT}/Apps/*) foreach(app ${BENTO4_APPS}) string(TOLOWER ${app} binary_name) add_executable(${binary_name} ${SOURCE_ROOT}/Apps/${app}/${app}.cpp) target_link_libraries(${binary_name} ap4) + + if(MSVC) + set_property(TARGET ${binary_name} PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>") + target_compile_definitions(${binary_name} PRIVATE -D_CONSOLE) + endif() endforeach() +endif(BUILD_APPS)
View file
bento4-1.6.0r634.tar.gz/Documents/MkDocs/mkdocs.yml -> bento4-1.6.0r636.tar.gz/Documents/MkDocs/mkdocs.yml
Changed
@@ -14,6 +14,10 @@ docs_dir: 'src' +# Repo info +repo_name: axiomatic-systems/Bento4 +repo_url: https://github.com/axiomatic-systems/Bento4 + # Extensions markdown_extensions: - admonition
View file
bento4-1.6.0r634.tar.gz/README.md -> bento4-1.6.0r636.tar.gz/README.md
Changed
@@ -138,3 +138,12 @@ For Release builds: ```make AP4_BUILD_CONFIG=Release``` + +Release Notes +------------- + +### 1.6.0-636 +Dolby Vision encryption now properly encrypts in a NAL-unit-aware mode + +### Previous releases +(no seaparate notes, please refer to commit logs) \ No newline at end of file
View file
bento4-1.6.0r634.tar.gz/Scripts/SdkPackager.py -> bento4-1.6.0r636.tar.gz/Scripts/SdkPackager.py
Changed
@@ -38,16 +38,20 @@ cmd = 'git status --porcelain -b' lines = os.popen(cmd).readlines() branch = '' + suffix = '' if not lines[0].startswith('## master'): print('WARNING: not on master branch') branch = '+' + lines[0][3:].strip() if len(lines) > 1: - print('ERROR: git status not empty') + print('WARNING: git status not empty') print(''.join(lines)) - return None + suffix = '*' cmd = 'git tag --contains HEAD' tags = os.popen(cmd).readlines() + if not tags: + # no tags, use the commit hash + return os.popen('git rev-parse --short HEAD').readlines()[0].strip() + suffix if len(tags) != 1: print('ERROR: expected exactly one tag for HEAD, found', len(tags), ':', tags) return None @@ -55,7 +59,7 @@ sep = version.find('-') if sep < 0: print('ERROR: unrecognized version string format:', version) - return version[sep+1:] + branch + return version[sep+1:] + branch + suffix ############################################################# # File Copy
View file
bento4-1.6.0r634.tar.gz/Scripts/SdkPrepForRelease.py -> bento4-1.6.0r636.tar.gz/Scripts/SdkPrepForRelease.py
Changed
@@ -40,17 +40,26 @@ filename = os.path.join(BENTO4_HOME, "Source", "Python", "utils", "mp4-dash.py") print("Patching", filename) file_lines = open(filename).readlines() -file_out = open(filename, "wb") +file_out = open(filename, "w") for line in file_lines: if line.startswith("SDK_REVISION = "): line = "SDK_REVISION = '"+SDK_REVISION+"'\n" - file_out.write(line.encode('ascii')) + file_out.write(line) filename = os.path.join(BENTO4_HOME, "Source", "Python", "utils", "mp4-hls.py") print("Patching", filename) file_lines = open(filename).readlines() -file_out = open(filename, "wb") +file_out = open(filename, "w") for line in file_lines: if line.startswith("SDK_REVISION = "): line = "SDK_REVISION = '"+SDK_REVISION+"'\n" - file_out.write(line.encode('ascii')) + file_out.write(line) + +filename = os.path.join(BENTO4_HOME, "Build", "Docker", "Dockerfile") +print("Patching", filename) +file_lines = open(filename).readlines() +file_out = open(filename, "w") +for line in file_lines: + if line.startswith("ENV BENTO4_VERSION 1.6.0-"): + line = "ENV BENTO4_VERSION 1.6.0-"+SDK_REVISION+"\n" + file_out.write(line)
View file
bento4-1.6.0r634.tar.gz/Source/C++/Apps/Mp4Mux/Mp4Mux.cpp -> bento4-1.6.0r636.tar.gz/Source/C++/Apps/Mp4Mux/Mp4Mux.cpp
Changed
@@ -99,6 +99,9 @@ " optional params:\n" " track: audio, video, or integer track ID (default=all tracks)\n" "\n" + "Common optional parameters for all types:\n" + " language: language code (3-character ISO 639-2 Alpha-3 code)\n" + "\n" "If no type is specified for an input, the type will be inferred from the file extension\n" "\n" "Options:\n" @@ -220,12 +223,36 @@ } /*---------------------------------------------------------------------- +| GetLanguageFromParameters ++---------------------------------------------------------------------*/ +static const char* +GetLanguageFromParameters(AP4_Array<Parameter>& parameters, const char* defaut_value) +{ + // check if we have a language parameter + for (unsigned int i=0; i<parameters.ItemCount(); i++) { + if (parameters[i].m_Name == "language") { + const char* language = parameters[i].m_Value.GetChars(); + + // the language must be a 3-character ISO 639-2 Alpha-3 code + if (strlen(language) != 3) { + fprintf(stderr, "ERROR: language codes must be 3-character ISO 639-2 Alpha-3 codes\n"); + return NULL; + } + + return language; + } + } + + return defaut_value; +} + +/*---------------------------------------------------------------------- | AddAacTrack +---------------------------------------------------------------------*/ static void AddAacTrack(AP4_Movie& movie, const char* input_name, - AP4_Array<Parameter>& /*parameters*/, + AP4_Array<Parameter>& parameters, SampleFileStorage& sample_storage) { AP4_ByteStream* input; @@ -235,6 +262,10 @@ return; } + // check if we have a language parameter + const char* language = GetLanguageFromParameters(parameters, "und"); + if (!language) return; + // create a sample table AP4_SyntheticSampleTable* sample_table = new AP4_SyntheticSampleTable(); @@ -332,7 +363,7 @@ sample_count*1024, // track duration sample_rate, // media time scale sample_count*1024, // media duration - "und", // language + language, // language 0, 0); // width, height // cleanup @@ -358,6 +389,10 @@ return; } + // check if we have a language parameter + const char* language = GetLanguageFromParameters(parameters, "und"); + if (!language) return; + // see if the frame rate is specified unsigned int video_frame_rate = AP4_MUX_DEFAULT_VIDEO_FRAME_RATE*1000; for (unsigned int i=0; i<parameters.ItemCount(); i++) { @@ -538,7 +573,7 @@ video_track_duration, // track duration video_frame_rate, // media time scale video_media_duration, // media duration - "und", // language + language, // language video_width<<16, // width video_height<<16 // height ); @@ -573,6 +608,10 @@ return; } + // check if we have a language parameter + const char* language = GetLanguageFromParameters(parameters, "und"); + if (!language) return; + // see if the frame rate is specified unsigned int video_frame_rate = AP4_MUX_DEFAULT_VIDEO_FRAME_RATE*1000; for (unsigned int i=0; i<parameters.ItemCount(); i++) { @@ -796,7 +835,7 @@ video_track_duration, // track duration video_frame_rate, // media time scale video_media_duration, // media duration - "und", // language + language, // language video_width<<16, // width video_height<<16 // height ); @@ -835,7 +874,10 @@ if (input_movie == NULL) { return; } - + + // check if we have a language parameter + const char* language = GetLanguageFromParameters(parameters, NULL); + // check the parameters to decide which track(s) to import unsigned int track_id = 0; for (unsigned int i=0; i<parameters.ItemCount(); i++) { @@ -879,8 +921,15 @@ AP4_Track* track = track_item->GetData(); if (track_id == 0 || track->GetId() == track_id) { track = track->Clone(); + // reset the track ID so that it can be re-assigned track->SetId(0); + + // override the language if specified in the parameters + if (language) { + track->SetTrackLanguage(language); + } + movie.AddTrack(track); } track_item = track_item->GetNext();
View file
bento4-1.6.0r634.tar.gz/Source/C++/Core/Ap4Atom.cpp -> bento4-1.6.0r636.tar.gz/Source/C++/Core/Ap4Atom.cpp
Changed
@@ -1,6 +1,6 @@ /***************************************************************** | -| AP4 - Atoms +| AP4 - Atoms | | Copyright 2002-2008 Axiomatic Systems, LLC | @@ -57,7 +57,7 @@ AP4_Atom::TypeFromString(const char* s) { // convert the name into an atom type - return ((AP4_UI32)s[0])<<24 | + return ((AP4_UI32)s[0])<<24 | ((AP4_UI32)s[1])<<16 | ((AP4_UI32)s[2])<< 8 | ((AP4_UI32)s[3]); @@ -66,7 +66,7 @@ /*---------------------------------------------------------------------- | AP4_Atom::AP4_Atom +---------------------------------------------------------------------*/ -AP4_Atom::AP4_Atom(Type type, AP4_UI32 size /* = AP4_ATOM_HEADER_SIZE */) : +AP4_Atom::AP4_Atom(Type type, AP4_UI32 size /* = AP4_ATOM_HEADER_SIZE */) : m_Type(type), m_Size32(size), m_Size64(0), @@ -80,7 +80,7 @@ /*---------------------------------------------------------------------- | AP4_Atom::AP4_Atom +---------------------------------------------------------------------*/ -AP4_Atom::AP4_Atom(Type type, AP4_UI64 size, bool force_64) : +AP4_Atom::AP4_Atom(Type type, AP4_UI64 size, bool force_64) : m_Type(type), m_Size32(0), m_Size64(0), @@ -95,9 +95,9 @@ /*---------------------------------------------------------------------- | AP4_Atom::AP4_Atom +---------------------------------------------------------------------*/ -AP4_Atom::AP4_Atom(Type type, - AP4_UI32 size, - AP4_UI08 version, +AP4_Atom::AP4_Atom(Type type, + AP4_UI32 size, + AP4_UI08 version, AP4_UI32 flags) : m_Type(type), m_Size32(size), @@ -112,10 +112,10 @@ /*---------------------------------------------------------------------- | AP4_Atom::AP4_Atom +---------------------------------------------------------------------*/ -AP4_Atom::AP4_Atom(Type type, +AP4_Atom::AP4_Atom(Type type, AP4_UI64 size, bool force_64, - AP4_UI08 version, + AP4_UI08 version, AP4_UI32 flags) : m_Type(type), m_Size32(0), @@ -132,8 +132,8 @@ | AP4_Atom::ReadFullHeader +---------------------------------------------------------------------*/ AP4_Result -AP4_Atom::ReadFullHeader(AP4_ByteStream& stream, - AP4_UI08& version, +AP4_Atom::ReadFullHeader(AP4_ByteStream& stream, + AP4_UI08& version, AP4_UI32& flags) { AP4_UI32 header; @@ -275,7 +275,7 @@ char name[5]; AP4_FormatFourCharsPrintable(name, m_Type); name[4] = '\0'; - inspector.StartAtom(name, + inspector.StartAtom(name, m_Version, m_Flags, GetHeaderSize(), @@ -288,7 +288,7 @@ | AP4_Atom::Detach +---------------------------------------------------------------------*/ AP4_Result -AP4_Atom::Detach() +AP4_Atom::Detach() { if (m_Parent) { return m_Parent->RemoveChild(this); @@ -304,25 +304,25 @@ AP4_Atom::Clone() { AP4_Atom* clone = NULL; - + // check the size (refuse to clone atoms that are too large) AP4_LargeSize size = GetSize(); if (size > AP4_ATOM_MAX_CLONE_SIZE) return NULL; // create a memory byte stream to which we can serialize AP4_MemoryByteStream* mbs = new AP4_MemoryByteStream((AP4_Size)GetSize()); - + // serialize to memory if (AP4_FAILED(Write(*mbs))) { mbs->Release(); return NULL; } - + // create the clone from the serialized form mbs->Seek(0); AP4_DefaultAtomFactory atom_factory; atom_factory.CreateAtomFromStream(*mbs, clone); - + // release the memory stream mbs->Release(); @@ -332,9 +332,9 @@ /*---------------------------------------------------------------------- | AP4_UnknownAtom::AP4_UnknownAtom +---------------------------------------------------------------------*/ -AP4_UnknownAtom::AP4_UnknownAtom(Type type, +AP4_UnknownAtom::AP4_UnknownAtom(Type type, AP4_UI64 size, - AP4_ByteStream& stream) : + AP4_ByteStream& stream) : AP4_Atom(type, size), m_SourceStream(&stream) { @@ -347,7 +347,7 @@ stream.Read(m_Payload.UseData(), payload_size); return; } - + // store source stream position stream.Tell(m_SourcePosition); @@ -372,7 +372,7 @@ /*---------------------------------------------------------------------- | AP4_UnknownAtom::AP4_UnknownAtom +---------------------------------------------------------------------*/ -AP4_UnknownAtom::AP4_UnknownAtom(Type type, +AP4_UnknownAtom::AP4_UnknownAtom(Type type, const AP4_UI08* payload, AP4_Size payload_size) : AP4_Atom(type, AP4_ATOM_HEADER_SIZE+payload_size, false), @@ -421,7 +421,7 @@ if (m_SourceStream == NULL) { return stream.Write(m_Payload.GetData(), m_Payload.GetDataSize()); } - + // remember the source position AP4_Position position; m_SourceStream->Tell(position); @@ -444,7 +444,7 @@ /*---------------------------------------------------------------------- | AP4_UnknownAtom::Clone +---------------------------------------------------------------------*/ -AP4_Atom* +AP4_Atom* AP4_UnknownAtom::Clone() { return new AP4_UnknownAtom(*this); @@ -463,16 +463,20 @@ /*---------------------------------------------------------------------- | AP4_NullTerminatedStringAtom::AP4_NullTerminatedStringAtom +---------------------------------------------------------------------*/ -AP4_NullTerminatedStringAtom::AP4_NullTerminatedStringAtom(AP4_Atom::Type type, - AP4_UI64 size, +AP4_NullTerminatedStringAtom::AP4_NullTerminatedStringAtom(AP4_Atom::Type type, + AP4_UI64 size, AP4_ByteStream& stream) : AP4_Atom(type, size) { - AP4_Size str_size = (AP4_Size)size-AP4_ATOM_HEADER_SIZE; - char* str = new char[str_size]; - stream.Read(str, str_size); - str[str_size-1] = '\0'; // force null-termination - m_Value = str; + AP4_Size str_size = (AP4_Size)size - AP4_ATOM_HEADER_SIZE; + + if (str_size) { + char* str = new char[str_size]; + stream.Read(str, str_size); + str[str_size - 1] = '\0'; // force null-termination + m_Value = str; + delete[] str; + } } /*---------------------------------------------------------------------- @@ -605,7 +609,7 @@ AP4_Result result = m_Children.Find(AP4_AtomFinder(type, index), atom); if (AP4_SUCCEEDED(result)) { return atom; - } else { + } else { return NULL; } } @@ -635,7 +639,7 @@ | AP4_AtomParent::FindChild +---------------------------------------------------------------------*/ AP4_Atom* -AP4_AtomParent::FindChild(const char* path, +AP4_AtomParent::FindChild(const char* path, bool auto_create, bool auto_create_full) { @@ -646,12 +650,12 @@ while (path[0] && path[1] && path[2] && path[3]) { // we have 4 valid chars const char* end = &path[4]; - + // look for the end or a separator while (*end != '\0' && *end != '/' && *end != '[') { ++end; } - + // decide if this is a 4-character code or a UUID AP4_UI08 uuid[16]; AP4_Atom::Type type = 0; @@ -681,7 +685,7 @@ } end = x+1; } - + // check what's at the end now if (*end == '/') { ++end; @@ -689,7 +693,7 @@ // malformed path return NULL; } - + // look for this atom in the current list AP4_Atom* atom = NULL; if (is_uuid) { @@ -735,7 +739,7 @@ AP4_Atom* child_clone = child->GetData()->Clone(); destination.AddChild(child_clone); } - + return AP4_SUCCESS; } @@ -784,7 +788,7 @@ for (unsigned int i=0; i<indent; i++) { prefix[i] = ' '; } - prefix[indent] = '\0'; + prefix[indent] = '\0'; } /*---------------------------------------------------------------------- @@ -820,24 +824,24 @@ char extra[32] = ""; if (header_size == 28 || header_size == 12 || header_size == 20) { if (version && flags) { - AP4_FormatString(extra, sizeof(extra), + AP4_FormatString(extra, sizeof(extra), ", version=%d, flags=%x", version, flags); } else if (version) { - AP4_FormatString(extra, sizeof(extra), + AP4_FormatString(extra, sizeof(extra), ", version=%d", version); } else if (flags) { - AP4_FormatString(extra, sizeof(extra), + AP4_FormatString(extra, sizeof(extra), ", flags=%x", flags); } } - AP4_FormatString(info, sizeof(info), - "size=%d+%lld%s", - header_size, - size-header_size, + AP4_FormatString(info, sizeof(info), + "size=%d+%lld%s", + header_size, + size-header_size, extra); char prefix[256]; @@ -871,9 +875,9 @@ { // write atom name char info[128]; - AP4_FormatString(info, sizeof(info), - "size=%d+%lld", - header_size, + AP4_FormatString(info, sizeof(info), + "size=%d+%lld", + header_size, size-header_size); char prefix[256]; @@ -906,7 +910,7 @@ char prefix[256]; AP4_MakePrefixString(m_Indent, prefix, sizeof(prefix)); m_Stream->WriteString(prefix); - + m_Stream->WriteString(name); m_Stream->WriteString(" = "); m_Stream->WriteString(value); @@ -924,8 +928,8 @@ m_Stream->WriteString(prefix); char str[32]; - AP4_FormatString(str, sizeof(str), - hint == HINT_HEX ? "%llx":"%lld", + AP4_FormatString(str, sizeof(str), + hint == HINT_HEX ? "%llx":"%lld", value); m_Stream->WriteString(name); m_Stream->WriteString(" = "); @@ -944,8 +948,8 @@ m_Stream->WriteString(prefix); char str[32]; - AP4_FormatString(str, sizeof(str), - "%f", + AP4_FormatString(str, sizeof(str), + "%f", value); m_Stream->WriteString(name); m_Stream->WriteString(" = "); @@ -957,8 +961,8 @@ | AP4_PrintInspector::AddField +---------------------------------------------------------------------*/ void -AP4_PrintInspector::AddField(const char* name, - const unsigned char* bytes, +AP4_PrintInspector::AddField(const char* name, + const unsigned char* bytes, AP4_Size byte_count, FormatHint /* hint */) { @@ -1001,6 +1005,148 @@ } /*---------------------------------------------------------------------- +| Read one code point from a UTF-8 string ++---------------------------------------------------------------------*/ +static AP4_Result +ReadUTF8(const AP4_UI08* utf, AP4_Size* length, AP4_UI32* code_point) { + if (*length < 1) { + return AP4_ERROR_NOT_ENOUGH_DATA; + } + + AP4_UI32 c = utf[0]; + if ((c & 0x80) == 0) { + *length = 1; + *code_point = c; + return AP4_SUCCESS; + } + if (*length < 2) { + return AP4_ERROR_NOT_ENOUGH_DATA; + } + *code_point = 0; + if ((utf[1] & 0xc0) != 0x80) { + return AP4_ERROR_INVALID_FORMAT; + } + if ((c & 0xe0) == 0xe0) { + if (*length < 3) { + return AP4_ERROR_NOT_ENOUGH_DATA; + } + if ((utf[2] & 0xc0) != 0x80) { + return AP4_ERROR_INVALID_FORMAT; + } + if ((c & 0xf0) == 0xf0) { + if (*length < 4) { + return AP4_ERROR_NOT_ENOUGH_DATA; + } + if ((c & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80) { + return AP4_ERROR_INVALID_FORMAT; + } + *length = 4; + c = (utf[0] & 0x07) << 18; + c |= (utf[1] & 0x3f) << 12; + c |= (utf[2] & 0x3f) << 6; + c |= (utf[3] & 0x3f); + } else { + *length = 3; + c = (utf[0] & 0x0f) << 12; + c |= (utf[1] & 0x3f) << 6; + c |= (utf[2] & 0x3f); + } + } else { + /* 2-byte code */ + *length = 2; + c = (utf[0] & 0x1f) << 6; + c |= (utf[1] & 0x3f); + } + + *code_point = c; + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_JsonInspector::EscapeString +| +| Not very efficient but simple function to escape characters in a +| JSON string ++---------------------------------------------------------------------*/ +AP4_String +AP4_JsonInspector::EscapeString(const char* string) +{ + AP4_String result(string); + + // Shortcut + if (result.GetLength() == 0) { + return result; + } + + // Compute the output size + AP4_Size string_length = (AP4_Size)strlen(string); + const AP4_UI08* input = (const AP4_UI08*)string; + AP4_Size input_length = string_length; + AP4_Size output_size = 0; + while (input_length) { + AP4_Size chars_available = input_length; + AP4_UI32 code_point = 0; + AP4_Result r = ReadUTF8(input, &chars_available, &code_point); + if (AP4_FAILED(r)) { + // stop, but don't fail + break; + } + if (code_point == '"' || code_point == '\\') { + output_size += 2; + } else if (code_point <= 0x1F) { + output_size += 6; + } else { + output_size += chars_available; + } + input_length -= chars_available; + input += chars_available; + } + + // Shortcut + if (output_size == result.GetLength()) { + return result; + } + + // Compute the escaped string in a temporary buffer + char* buffer = new char[output_size]; + char* escaped = buffer; + input = (const AP4_UI08*)string; + input_length = string_length; + while (input_length) { + AP4_Size chars_available = input_length; + AP4_UI32 code_point = 0; + AP4_Result r = ReadUTF8(input, &chars_available, &code_point); + if (AP4_FAILED(r)) { + // stop, but don't fail + break; + } + if (code_point == '"' || code_point == '\\') { + *escaped++ = '\\'; + *escaped++ = (char)code_point; + } else if (code_point <= 0x1F) { + *escaped++ = '\\'; + *escaped++ = 'u'; + *escaped++ = '0'; + *escaped++ = '0'; + *escaped++ = AP4_NibbleHex(code_point >> 4); + *escaped++ = AP4_NibbleHex(code_point & 0x0F); + } else { + for (AP4_Size i = 0; i < chars_available; i++) { + *escaped++ = (char)input[i]; + } + } + input_length -= chars_available; + input += chars_available; + } + + // Copy the buffer to a final string + result.Assign(buffer, output_size); + delete[] buffer; + + return result; +} + +/*---------------------------------------------------------------------- | AP4_JsonInspector::StartAtom +---------------------------------------------------------------------*/ void @@ -1026,7 +1172,7 @@ m_Stream->WriteString("{\n"); m_Stream->WriteString(prefix); m_Stream->WriteString(" \"name\":\""); - m_Stream->WriteString(name); + m_Stream->WriteString(EscapeString(name).GetChars()); m_Stream->Write("\"", 1); m_Stream->WriteString(",\n"); m_Stream->WriteString(prefix); @@ -1039,7 +1185,7 @@ m_Stream->WriteString(" \"size\":"); AP4_FormatString(val, sizeof(val), "%lld", size); m_Stream->WriteString(val); - + ++m_Depth; m_Items.SetItemCount(m_Depth+1); m_Items[m_Depth] = 0; @@ -1094,9 +1240,9 @@ m_Stream->WriteString(",\n"); m_Stream->WriteString(prefix); m_Stream->Write("\"", 1); - m_Stream->WriteString(name); + m_Stream->WriteString(EscapeString(name).GetChars()); m_Stream->Write("\":\"", 3); - m_Stream->WriteString(value); + m_Stream->WriteString(EscapeString(value).GetChars()); m_Stream->Write("\"", 1); } @@ -1112,8 +1258,8 @@ m_Stream->WriteString(prefix); char str[32]; - AP4_FormatString(str, sizeof(str), - "%lld", + AP4_FormatString(str, sizeof(str), + "%lld", value); m_Stream->Write("\"", 1); m_Stream->WriteString(name); @@ -1133,11 +1279,11 @@ m_Stream->WriteString(prefix); char str[32]; - AP4_FormatString(str, sizeof(str), - "%f", + AP4_FormatString(str, sizeof(str), + "%f", value); m_Stream->Write("\"", 1); - m_Stream->WriteString(name); + m_Stream->WriteString(EscapeString(name).GetChars()); m_Stream->Write("\":", 2); m_Stream->WriteString(str); } @@ -1146,8 +1292,8 @@ | AP4_JsonInspector::AddField +---------------------------------------------------------------------*/ void -AP4_JsonInspector::AddField(const char* name, - const unsigned char* bytes, +AP4_JsonInspector::AddField(const char* name, + const unsigned char* bytes, AP4_Size byte_count, FormatHint /* hint */) { @@ -1157,7 +1303,7 @@ m_Stream->WriteString(prefix); m_Stream->Write("\"", 1); - m_Stream->WriteString(name); + m_Stream->WriteString(EscapeString(name).GetChars()); m_Stream->Write("\":\"", 3); m_Stream->WriteString("["); unsigned int offset = 1;
View file
bento4-1.6.0r634.tar.gz/Source/C++/Core/Ap4Atom.h -> bento4-1.6.0r636.tar.gz/Source/C++/Core/Ap4Atom.h
Changed
@@ -184,6 +184,9 @@ void AddField(const char* name, const unsigned char* bytes, AP4_Size size, FormatHint hint); private: + // methods + static AP4_String EscapeString(const char* string); + // members AP4_ByteStream* m_Stream; AP4_Cardinal m_Depth;
View file
bento4-1.6.0r634.tar.gz/Source/C++/Core/Ap4CommonEncryption.cpp -> bento4-1.6.0r636.tar.gz/Source/C++/Core/Ap4CommonEncryption.cpp
Changed
@@ -1455,8 +1455,12 @@ case AP4_ATOM_TYPE_AVC2: case AP4_ATOM_TYPE_AVC3: case AP4_ATOM_TYPE_AVC4: + case AP4_ATOM_TYPE_DVAV: + case AP4_ATOM_TYPE_DVA1: case AP4_ATOM_TYPE_HEV1: case AP4_ATOM_TYPE_HVC1: + case AP4_ATOM_TYPE_DVHE: + case AP4_ATOM_TYPE_DVH1: enc_format = AP4_ATOM_TYPE_ENCV; break; @@ -1629,13 +1633,17 @@ if (format == AP4_ATOM_TYPE_AVC1 || format == AP4_ATOM_TYPE_AVC2 || format == AP4_ATOM_TYPE_AVC3 || - format == AP4_ATOM_TYPE_AVC4) { + format == AP4_ATOM_TYPE_AVC4 || + format == AP4_ATOM_TYPE_DVAV || + format == AP4_ATOM_TYPE_DVA1) { 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) { + format == AP4_ATOM_TYPE_HVC1 || + format == AP4_ATOM_TYPE_DVHE || + format == AP4_ATOM_TYPE_DVH1) { AP4_HvccAtom* hvcc = AP4_DYNAMIC_CAST(AP4_HvccAtom, entries[0]->GetChild(AP4_ATOM_TYPE_HVCC)); if (hvcc) { nalu_length_size = hvcc->GetNaluLengthSize();
View file
bento4-1.6.0r634.tar.gz/Source/C++/Core/Ap4Config.h -> bento4-1.6.0r636.tar.gz/Source/C++/Core/Ap4Config.h
Changed
@@ -99,6 +99,11 @@ #define AP4_ftell ftell #endif +/* MinGW-w64 */ +#if defined(__MINGW32__) || defined (__MINGW64__) +#define AP4_CONFIG_HAVE_FOPEN_S +#endif + /* Symbian */ #if defined(__SYMBIAN32__) #undef APT_CONFIG_HAVE_NEW_H
View file
bento4-1.6.0r634.tar.gz/Source/C++/Core/Ap4CttsAtom.cpp -> bento4-1.6.0r636.tar.gz/Source/C++/Core/Ap4CttsAtom.cpp
Changed
@@ -74,8 +74,20 @@ m_LookupCache.sample = 0; m_LookupCache.entry_index = 0; + if (size < AP4_FULL_ATOM_HEADER_SIZE + 4) { + return; + } + + // read the number of entries AP4_UI32 entry_count; stream.ReadUI32(entry_count); + + // check that there's enough data + if (((size - AP4_FULL_ATOM_HEADER_SIZE - 4) / 8) < entry_count) { + return; + } + + // read the entries m_Entries.SetItemCount(entry_count); unsigned char* buffer = new unsigned char[entry_count*8]; AP4_Result result = stream.Read(buffer, entry_count*8);
View file
bento4-1.6.0r634.tar.gz/Source/C++/Core/Ap4FtypAtom.cpp -> bento4-1.6.0r636.tar.gz/Source/C++/Core/Ap4FtypAtom.cpp
Changed
@@ -46,7 +46,7 @@ m_MajorBrand(0), m_MinorVersion(0) { - if (size < 16) return; + if (size < AP4_ATOM_HEADER_SIZE + 8) return; stream.ReadUI32(m_MajorBrand); stream.ReadUI32(m_MinorVersion); size -= 16;
View file
bento4-1.6.0r634.tar.gz/Source/C++/Core/Ap4MdhdAtom.cpp -> bento4-1.6.0r636.tar.gz/Source/C++/Core/Ap4MdhdAtom.cpp
Changed
@@ -66,8 +66,11 @@ m_TimeScale(time_scale), m_Duration(duration) { - m_Language.Assign(language, 3); - + if (strlen(language) == 3) { + m_Language.Assign(language, 3); + } else { + m_Language = "und"; + } if (duration > 0xFFFFFFFF) { m_Version = 1; m_Size32 += 12; @@ -146,13 +149,18 @@ } // write the language - AP4_UI08 l0 = m_Language[0]-0x60; - AP4_UI08 l1 = m_Language[1]-0x60; - AP4_UI08 l2 = m_Language[2]-0x60; - result = stream.WriteUI08((l0<<2 | l1>>3)&0xFF); - if (AP4_FAILED(result)) return result; - result = stream.WriteUI08((l1<<5 | l2)&0xFF); - if (AP4_FAILED(result)) return result; + if (m_Language.GetLength() == 3) { + AP4_UI08 l0 = m_Language[0]-0x60; + AP4_UI08 l1 = m_Language[1]-0x60; + AP4_UI08 l2 = m_Language[2]-0x60; + result = stream.WriteUI08((l0<<2 | l1>>3)&0xFF); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI08((l1<<5 | l2)&0xFF); + if (AP4_FAILED(result)) return result; + } else { + result = stream.WriteUI16(0); + if (AP4_FAILED(result)) return result; + } // pre-defined return stream.WriteUI16(0); @@ -168,6 +176,20 @@ } /*---------------------------------------------------------------------- +| AP4_MdhdAtom::SetLanguage ++---------------------------------------------------------------------*/ +AP4_Result +AP4_MdhdAtom::SetLanguage(const char* language) +{ + if (strlen(language) != 3) { + return AP4_ERROR_INVALID_PARAMETERS; + } + m_Language = language; + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- | AP4_MdhdAtom::InspectFields +---------------------------------------------------------------------*/ AP4_Result
View file
bento4-1.6.0r634.tar.gz/Source/C++/Core/Ap4MdhdAtom.h -> bento4-1.6.0r636.tar.gz/Source/C++/Core/Ap4MdhdAtom.h
Changed
@@ -67,6 +67,7 @@ AP4_UI32 GetTimeScale() { return m_TimeScale; } void SetTimeScale(AP4_UI32 timescale) { m_TimeScale = timescale; } const AP4_String& GetLanguage() { return m_Language; } + AP4_Result SetLanguage(const char* language); private: // methods
View file
bento4-1.6.0r634.tar.gz/Source/C++/Core/Ap4SaizAtom.cpp -> bento4-1.6.0r636.tar.gz/Source/C++/Core/Ap4SaizAtom.cpp
Changed
@@ -85,7 +85,7 @@ stream.ReadUI32(m_SampleCount); remains -= 5; if (m_DefaultSampleInfoSize == 0) { - // means that the sample info entries have different sizes + // means that the sample info entries have different sizes if (m_SampleCount > remains) m_SampleCount = remains; // sanity check AP4_Cardinal sample_count = m_SampleCount; m_Entries.SetItemCount(sample_count);
View file
bento4-1.6.0r634.tar.gz/Source/C++/Core/Ap4StszAtom.cpp -> bento4-1.6.0r636.tar.gz/Source/C++/Core/Ap4StszAtom.cpp
Changed
@@ -69,28 +69,32 @@ AP4_UI08 version, AP4_UI32 flags, AP4_ByteStream& stream) : - AP4_Atom(AP4_ATOM_TYPE_STSZ, size, version, flags) + AP4_Atom(AP4_ATOM_TYPE_STSZ, size, version, flags), + m_SampleSize(0), + m_SampleCount(0) { + if (size < AP4_FULL_ATOM_HEADER_SIZE + 8) { + return; + } + stream.ReadUI32(m_SampleSize); - stream.ReadUI32(m_SampleCount); + AP4_UI32 sample_count; + stream.ReadUI32(sample_count); if (m_SampleSize == 0) { // means that the samples have different sizes // check for overflow - if (m_SampleCount > (size-8)/4) { - m_SampleCount = 0; + if (m_SampleCount > (size - AP4_FULL_ATOM_HEADER_SIZE - 8) / 4) { return; } // read the entries - AP4_Cardinal sample_count = m_SampleCount; - m_Entries.SetItemCount(sample_count); - unsigned char* buffer = new unsigned char[sample_count*4]; + unsigned char* buffer = new unsigned char[sample_count * 4]; AP4_Result result = stream.Read(buffer, sample_count*4); if (AP4_FAILED(result)) { delete[] buffer; - m_Entries.Clear(); - m_SampleCount = 0; return; } + m_SampleCount = sample_count; + m_Entries.SetItemCount((AP4_Cardinal)sample_count); for (unsigned int i=0; i<sample_count; i++) { m_Entries[i] = AP4_BytesToUInt32BE(&buffer[i*4]); }
View file
bento4-1.6.0r634.tar.gz/Source/C++/Core/Ap4Stz2Atom.cpp -> bento4-1.6.0r636.tar.gz/Source/C++/Core/Ap4Stz2Atom.cpp
Changed
@@ -72,29 +72,40 @@ AP4_UI08 version, AP4_UI32 flags, AP4_ByteStream& stream) : - AP4_Atom(AP4_ATOM_TYPE_STZ2, size, version, flags) + AP4_Atom(AP4_ATOM_TYPE_STZ2, size, version, flags), + m_FieldSize(0), + m_SampleCount(0) { + if (size < AP4_FULL_ATOM_HEADER_SIZE + 8) { + return; + } + AP4_UI08 reserved; stream.ReadUI08(reserved); stream.ReadUI08(reserved); stream.ReadUI08(reserved); - stream.ReadUI08(m_FieldSize); - stream.ReadUI32(m_SampleCount); - if (m_FieldSize != 4 && m_FieldSize != 8 && m_FieldSize != 16) { - // illegale field size + AP4_UI08 field_size; + stream.ReadUI08(field_size); + if (field_size != 4 && field_size != 8 && field_size != 16) { + // illegal field size return; } + AP4_UI32 sample_count; + stream.ReadUI32(sample_count); - AP4_Cardinal sample_count = m_SampleCount; - m_Entries.SetItemCount(sample_count); - unsigned int table_size = (sample_count*m_FieldSize+7)/8; - if ((table_size+8) > size) return; + m_FieldSize = field_size; + m_SampleCount = sample_count; + unsigned int table_size = (sample_count * field_size + 7) / 8; + if (table_size > size - AP4_FULL_ATOM_HEADER_SIZE - 8) { + return; + } unsigned char* buffer = new unsigned char[table_size]; AP4_Result result = stream.Read(buffer, table_size); if (AP4_FAILED(result)) { delete[] buffer; return; } + m_Entries.SetItemCount((AP4_Cardinal)sample_count); switch (m_FieldSize) { case 4: for (unsigned int i=0; i<sample_count; i++) {
View file
bento4-1.6.0r634.tar.gz/Source/C++/Core/Ap4Track.cpp -> bento4-1.6.0r636.tar.gz/Source/C++/Core/Ap4Track.cpp
Changed
@@ -556,3 +556,19 @@ } return NULL; } + +/*---------------------------------------------------------------------- +| AP4_Track::SetTrackLanguage ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Track::SetTrackLanguage(const char* language) +{ + if (strlen(language) != 3) { + return AP4_ERROR_INVALID_PARAMETERS; + } + + if (AP4_MdhdAtom* mdhd = AP4_DYNAMIC_CAST(AP4_MdhdAtom, m_TrakAtom->FindChild("mdia/mdhd"))) { + return mdhd->SetLanguage(language); + } + return AP4_ERROR_INVALID_STATE; +}
View file
bento4-1.6.0r634.tar.gz/Source/C++/Core/Ap4Track.h -> bento4-1.6.0r636.tar.gz/Source/C++/Core/Ap4Track.h
Changed
@@ -133,6 +133,7 @@ AP4_UI64 GetMediaDuration() const; // in the timescale of the media const char* GetTrackName() const; const char* GetTrackLanguage() const; + AP4_Result SetTrackLanguage(const char* language); AP4_Result Attach(AP4_MoovAtom* moov); protected:
View file
bento4-1.6.0r634.tar.gz/Source/Python/utils/mp4-dash.py -> bento4-1.6.0r636.tar.gz/Source/Python/utils/mp4-dash.py
Changed
@@ -27,6 +27,7 @@ import json import math import operator +import struct from functools import reduce from subtitles import SubtitlesFile from mp4utils import MakePsshBox,\ @@ -57,7 +58,7 @@ # setup main options VERSION = "2.0.0" -SDK_REVISION = '634' +SDK_REVISION = '636' SCRIPT_PATH = path.abspath(path.dirname(__file__)) sys.path += [SCRIPT_PATH] @@ -115,6 +116,8 @@ CENC_2013_NAMESPACE = 'urn:mpeg:cenc:2013' +DASHIF_NAMESPACE = 'https://dashif.org/' + DASH_DEFAULT_ROLE_NAMESPACE = 'urn:mpeg:dash:role:2011' DASH_MEDIA_SEGMENT_URL_PATTERN_SMOOTH = "/QualityLevels($Bandwidth$)/Fragments(%s=$Time$)" @@ -294,11 +297,17 @@ if options.clearkey: container.append(xml.Comment(' Clear Key ')) xml.register_namespace('ckey', CLEARKEY_CKEY_NAMESPACE) + xml.register_namespace('dashif', DASHIF_NAMESPACE) cp = xml.SubElement(container, 'ContentProtection', schemeIdUri=CLEARKEY_SCHEME_ID_URI, value=CLEARKEY_CONTENT_PROTECTION_VALUE) if options.clearkey_license_uri: + # First entry with the legacy namespace ck_license = xml.SubElement(cp, '{'+CLEARKEY_CKEY_NAMESPACE+'}Laurl', Lic_type=CLEARKEY_LICENSE_TYPE) ck_license.text = options.clearkey_license_uri + # Second entry with the dashif namespace + ck_license = xml.SubElement(cp, '{'+DASHIF_NAMESPACE+'}laurl') + ck_license.text = options.clearkey_license_uri + # Marlin if options.marlin: container.append(xml.Comment(' Marlin ')) @@ -336,8 +345,7 @@ container.append(xml.Comment(' Widevine ')) cp = xml.SubElement(container, 'ContentProtection', schemeIdUri=WIDEVINE_SCHEME_ID_URI) if options.widevine_header: - pssh_payload = ComputeWidevineHeader(options.widevine_header, options.encryption_cenc_scheme, default_kid) - pssh_box = MakePsshBox(bytes.fromhex(WIDEVINE_PSSH_SYSTEM_ID), pssh_payload) + pssh_box = ComputeWidevinePssh(options.widevine_header, options.encryption_cenc_scheme, default_kid) pssh_b64 = Base64Encode(pssh_box) pssh = xml.SubElement(cp, '{' + CENC_2013_NAMESPACE + '}pssh') pssh.text = pssh_b64 @@ -494,6 +502,9 @@ language = audio_tracks[0].language if (language != 'und') or options.always_output_lang: kwargs['lang'] = language + label = audio_tracks[0].label + if label != '': + kwargs['label'] = label adaptation_set = xml.SubElement(*args, **kwargs) # see if we have descriptors @@ -638,8 +649,7 @@ def ComputeHlsWidevineKeyLine(options, track): # V2 key line kid = track.key_info['kid'] - widevine_header = ComputeWidevineHeader(options.widevine_header, options.encryption_cenc_scheme, kid) - pssh_box = MakePsshBox(bytes.fromhex(WIDEVINE_PSSH_SYSTEM_ID), widevine_header) + pssh_box = ComputeWidevinePssh(options.widevine_header, options.encryption_cenc_scheme, kid) key_line = 'URI="data:text/plain;base64,{}",KEYFORMAT="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed",KEYID=0x{},KEYFORMATVERSIONS="1"'.format( Base64Encode(pssh_box), kid @@ -827,7 +837,7 @@ audio_groups = {} for adaptation_set_name, audio_tracks in list(audio_sets.items()): language = audio_tracks[0].language - language_name = LanguageNames.get(language, language) + language_name = audio_tracks[0].language_name audio_group_name = adaptation_set_name[0]+'/'+adaptation_set_name[2] audio_groups[audio_group_name] = { @@ -861,10 +871,11 @@ media_playlist_name = options.hls_media_playlist_name media_playlist_path = media_subdir+'/'+media_playlist_name + group_name = audio_track.label if audio_track.label != '' else language_name master_playlist_file.write('#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="{}",LANGUAGE="{}",NAME="{}",AUTOSELECT=YES,DEFAULT={},URI="{}"\n'.format( audio_group_name, language, - language_name, + group_name, 'YES' if select_as_default else 'NO', media_playlist_path)) select_as_default = False @@ -949,7 +960,7 @@ # only accept IMSC1 tracks continue language = subtitles_track.language - language_name = LanguageNames.get(language, language) + language_name = subtitles_track.language_name if options.on_demand or not options.split: media_subdir = '' @@ -1004,7 +1015,11 @@ # process the audio tracks for audio_track in audio_tracks: - stream_name = "audio_"+audio_track.language + stream_name = audio_track.label + if stream_name == '': + stream_name = audio_track.language_name + if stream_name == '' or stream_name == 'Unknown': + stream_name = "audio_"+audio_track.language audio_url_pattern="QualityLevels({bitrate})/Fragments(%s={start time})" % (stream_name) stream_index = xml.SubElement(client_manifest, 'StreamIndex', @@ -1241,6 +1256,7 @@ audio_adaptation_sets = {} video_adaptation_sets = {} subtitles_adaptation_sets = {} + label_indexes = {} for media_source in media_sources: track_id = media_source.spec['track'] track_type = media_source.spec['type'] @@ -1285,21 +1301,43 @@ language = options.language_map[language] track.language = language + # track language name + track.language_name = media_source.spec.get('+language_name', LanguageNames.get(language, language)) + + # track representation id + custom_representation_id = media_source.spec.get('+representation_id') + if custom_representation_id: + track.representation_id = custom_representation_id + # video scan type if track.type == 'video': track.scan_type = media_source.spec.get('+scan_type', track.scan_type) + # label + track.label = media_source.spec.get('+label', '') + + # update label indexes (so that we can use numbers instead of strings for labels) + for track in tracks: + if track.label not in label_indexes: + label_indexes[track.label] = len(label_indexes) + 1 + # process audio tracks for track in [t for t in tracks if t.type == 'audio']: adaptation_set_name = ('audio', track.language, track.codec_family) + + # add the label index + adaptation_set_name += (str(label_indexes[track.label]),) + + # lookup the adaptation set and start a new one if no entry is found adaptation_set = audio_adaptation_sets.get(adaptation_set_name, []) - audio_adaptation_sets[adaptation_set_name] = adaptation_set - # only keep this track if there isn't already a track with the same codec at the same bitrate (within 10%) + # only keep this track if there isn't already a track with the same + # codec at the same bitrate (within 10%) with_same_bandwidth = [t for t in adaptation_set if abs(float(t.bandwidth-track.bandwidth)/float(t.bandwidth)) < 0.1] if with_same_bandwidth: continue + audio_adaptation_sets[adaptation_set_name] = adaptation_set adaptation_set.append(track) track.order_index = len(adaptation_set) @@ -1324,6 +1362,30 @@ adaptation_set.append(track) track.order_index = len(adaptation_set) + # Try to simplify the adaptation set names where there's unnecessary sub-classification + # NOTE: in this version, we only try to simplify based on the last element of the name + # and we only try to simplify audio adaptation sets, because they are the only ones with + # labels. This should be updated when/if we add support for labels on other types. + for adaptation_set in [audio_adaptation_sets]: + prefixed = {} + + # skip empty sets + if not adaptation_set: + continue + + for name in adaptation_set: + prefix = name[:-1] + entry = prefixed.get(name[:-1], [0, name]) + entry[0] += 1 + prefixed[prefix] = entry + + for prefix in prefixed: + [count, name] = prefixed[prefix] + if count == 1: + # there's only one entry with that prefix, we can simplify + adaptation_set[prefix] = adaptation_set[name] + del adaptation_set[name] + return (audio_adaptation_sets, video_adaptation_sets, subtitles_adaptation_sets, mp4_files) ############################################# @@ -1495,12 +1557,23 @@ # Widevine if options.widevine_header: - widevine_header = ComputeWidevineHeader(options.widevine_header, options.encryption_cenc_scheme, default_kid) + pssh = ComputeWidevinePssh(options.widevine_header, options.encryption_cenc_scheme, default_kid) + pssh_version = pssh[8] + if pssh_version == 0: + pssh_payload_offset = 32 + elif pssh_version == 1: + kid_count = struct.unpack('>I', pssh[28:32])[0] + pssh_payload_offset = 32 + (16 * kid_count) + 4 + if pssh_payload_offset > len(pssh): + raise Exception('invalid pssh format') + else: + raise Exception('pssh version > 1 is not supported') + pssh_payload = pssh[pssh_payload_offset:] pssh_file = tempfile.NamedTemporaryFile(dir=options.output_dir, delete=False) - pssh_file.write(widevine_header) + pssh_file.write(pssh_payload) TempFiles.append(pssh_file.name) pssh_file.close() # necessary on Windows - args += ['--pssh', WIDEVINE_PSSH_SYSTEM_ID+':'+pssh_file.name] + args += ['--pssh' if pssh_version == 0 else '--pssh-v1', WIDEVINE_PSSH_SYSTEM_ID+':'+pssh_file.name] # Primetime if options.primetime_metadata: @@ -1515,6 +1588,28 @@ media_source.filename = encrypted_file.name ############################################# +def ComputeWidevinePssh(header_spec, encryption_scheme, kid): + if header_spec.startswith('#'): + # The header spec is a base-64 encoded precomputed byte array + header = Base64Decode(header_spec[1:]) + if not header: + raise Exception('invalid base64 encoding') + + # The header may be a raw header or a full PSSH box, find out which + if len(header) > 8: + (box_length, box_type) = struct.unpack('>I4s', header[:8]) + if box_length == len(header) and box_type == b'pssh': + # That looks like a valid PSSH box + return header + + else: + # The header spec is a set of properties + header = ComputeWidevineHeader(header_spec, encryption_scheme, kid) + + # Wrap the header in a PSSH box + return MakePsshBox(bytes.fromhex(WIDEVINE_PSSH_SYSTEM_ID), header) + +############################################# FileNameMap = {} def MapFileName(from_name, to_name): global FileNameMap @@ -1648,7 +1743,7 @@ parser.add_option('', "--widevine-header", dest="widevine_header", metavar='<widevine-header>', default=None, help="Add a Widevine entry in the MPD, and a Widevine PSSH box in the init segments. The use of this option implies the --widevine option. " + "The <widevine-header> argument can be either: " + - "(1) the character '#' followed by a Widevine header encoded in Base64, or " + + "(1) the character '#' followed by a Widevine header encoded in Base64 (either a complete PSSH box or just the PSSH box payload), or " + "(2) one or more <name>:<value> pair(s) (separated by '#' if more than one) specifying fields of a Widevine header (field names include 'provider' [string], 'content_id' [byte array in hex], 'policy' [string])") parser.add_option('', "--primetime", dest="primetime", action="store_true", default=False, help="Add Primetime signaling to the MPD (requires an encrypted input, or the --encryption-key option)") @@ -1917,19 +2012,23 @@ for adaptation_sets in [audio_sets, video_sets, subtitles_sets]: for adaptation_set_name, tracks in list(adaptation_sets.items()): for track in tracks: + if not hasattr(track, 'representation_id'): + if options.split: + track.representation_id = '/'.join(adaptation_set_name) + if len(tracks) > 1: + track.representation_id += '/'+str(track.order_index) + else: + track.representation_id = '-'.join(adaptation_set_name) + if len(tracks) > 1: + track.representation_id += '-'+str(track.order_index) + if options.split: - track.representation_id = '/'.join(adaptation_set_name) - if len(tracks) > 1: - track.representation_id += '/'+str(track.order_index) track.init_segment_name = SPLIT_INIT_SEGMENT_NAME + elif options.on_demand: + track.parent.media_name = ONDEMAND_MEDIA_FILE_PATTERN % (options.media_prefix, track.representation_id) else: - track.representation_id = '-'.join(adaptation_set_name) - if len(tracks) > 1: - track.representation_id += '-'+str(track.order_index) - if options.on_demand: - track.parent.media_name = ONDEMAND_MEDIA_FILE_PATTERN % (options.media_prefix, track.representation_id) - else: - track.init_segment_name = NOSPLIT_INIT_FILE_PATTERN % (track.representation_id) + track.init_segment_name = NOSPLIT_INIT_FILE_PATTERN % (track.representation_id) + track.stream_id = adaptation_set_name[0] if adaptation_set_name[0] == 'audio': track.stream_id += '_'+track.language @@ -1980,15 +2079,9 @@ if options.split: for adaptation_sets in [audio_sets, video_sets, subtitles_sets]: for adaptation_set_name, tracks in list(adaptation_sets.items()): - base_dir = options.output_dir - for subdir in adaptation_set_name: - base_dir = path.join(base_dir, subdir) - MakeNewDir(base_dir) for track in tracks: - out_dir = base_dir - if len(tracks) > 1: - out_dir = path.join(out_dir, str(track.order_index)) - MakeNewDir(out_dir) + out_dir = path.join(options.output_dir, track.representation_id) + MakeNewDir(out_dir, recursive=True) print('Splitting media file ('+adaptation_set_name[0]+')', GetMappedFileName(track.parent.media_source.filename)) Mp4Split(options, track.parent.media_source.filename,
View file
bento4-1.6.0r634.tar.gz/Source/Python/utils/mp4-hls.py -> bento4-1.6.0r636.tar.gz/Source/Python/utils/mp4-hls.py
Changed
@@ -31,7 +31,7 @@ # setup main options VERSION = "1.2.0" -SDK_REVISION = '634' +SDK_REVISION = '636' SCRIPT_PATH = path.abspath(path.dirname(__file__)) sys.path += [SCRIPT_PATH]
View file
bento4-1.6.0r634.tar.gz/Source/Python/utils/mp4utils.py -> bento4-1.6.0r636.tar.gz/Source/Python/utils/mp4utils.py
Changed
@@ -378,6 +378,7 @@ self.max_segment_bitrate = 0 self.bandwidth = 0 self.language = '' + self.language_name = '' self.order_index = 0 self.key_info = {} self.id = info['id'] @@ -430,6 +431,7 @@ self.channels = sample_desc['channels'] self.language = info['language'] + self.language_name = LanguageNames.get(LanguageCodeMap.get(self.language, 'und'), '') def update(self, options): # compute the total number of samples @@ -714,13 +716,15 @@ break return int(bandwidth) -def MakeNewDir(dir, exit_if_exists=False, severity=None): +def MakeNewDir(dir, exit_if_exists=False, severity=None, recursive=False): if path.exists(dir): if severity: sys.stderr.write(severity+': ') sys.stderr.write('directory "'+dir+'" already exists\n') if exit_if_exists: sys.exit(1) + elif recursive: + os.makedirs(dir) else: os.mkdir(dir) @@ -1185,36 +1189,30 @@ return buffer def ComputeWidevineHeader(header_spec, encryption_scheme, kid_hex): - # construct the base64 header - if header_spec.startswith('#'): - header_b64 = header_spec[1:] - header = Base64Decode(header_b64) - if not header: - raise Exception('invalid base64 encoding') - return header - else: - try: - pairs = header_spec.split('#') - fields = {} - for pair in pairs: - name, value = pair.split(':', 1) - fields[name] = value - except: - raise Exception('invalid syntax for argument') - - protobuf_fields = [(1, 1), (2, bytes.fromhex(kid_hex))] - if 'provider' in fields: - protobuf_fields.append((3, fields['provider'])) - if 'content_id' in fields: - protobuf_fields.append((4, bytes.fromhex(fields['content_id']))) - if 'policy' in fields: - protobuf_fields.append((6, fields['policy'])) - - if encryption_scheme != 'cenc': - four_cc = struct.unpack('>I', encryption_scheme.encode('ascii'))[0] - protobuf_fields.append((9, four_cc)) - - return WidevineMakeHeader(protobuf_fields) + try: + pairs = header_spec.split('#') + fields = {} + for pair in pairs: + name, value = pair.split(':', 1) + fields[name] = value + except: + raise Exception('invalid syntax for argument') + + protobuf_fields = [(2, bytes.fromhex(kid_hex))] + if 'provider' in fields: + protobuf_fields.append((3, fields['provider'])) + if 'content_id' in fields: + protobuf_fields.append((4, bytes.fromhex(fields['content_id']))) + if 'policy' in fields: + protobuf_fields.append((6, fields['policy'])) + + if encryption_scheme == 'cenc': + protobuf_fields.append((1, 1)) + + four_cc = struct.unpack('>I', encryption_scheme.encode('ascii'))[0] + protobuf_fields.append((9, four_cc)) + + return WidevineMakeHeader(protobuf_fields) ############################################# # Module Exports
View file
bento4-1.6.0r634.tar.gz/Source/Python/utils/wv-request.py -> bento4-1.6.0r636.tar.gz/Source/Python/utils/wv-request.py
Changed
@@ -5,6 +5,7 @@ import aes import hashlib import base64 +import struct from optparse import OptionParser WV_DEFAULT_SERVER_URL = 'https://license.uat.widevine.com/cenc/getcontentkey' @@ -41,6 +42,8 @@ help="List of track types, separated by ','") parser.add_option('-l', '--policy', dest="policy", default='', help="Policy") +parser.add_option('-s', '--protection-scheme', dest="protection_scheme", default='', + help="Protection Scheme ('cenc', 'cbc1', 'cens', 'cbcs'), defaults to 'cenc'") (options, args) = parser.parse_args() if not options.content_id: @@ -54,6 +57,9 @@ 'policy': options.policy } +if options.protection_scheme: + rq_payload['protection_scheme'] = struct.unpack('>I',options.protection_scheme.encode("ascii"))[0] + if options.track_types: rq_payload['tracks'] = [{'type': track_type} for track_type in options.track_types.split(',')] else:
View file
bento4-1.6.0r634.tar.gz/tasks/build.py -> bento4-1.6.0r636.tar.gz/tasks/build.py
Changed
@@ -19,7 +19,7 @@ shutil.rmtree(target_dir, ignore_errors=True) try: os.makedirs(target_dir) - except: + except FileExistsError: pass with ctx.cd(target_dir): generator = ''
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
.