Codebase list kodi-inputstream-adaptive / upstream/19.0.0+ds1+git20211021.1.4d9f17f
Import upstream version 19.0.0+ds1+git20211021.1.4d9f17f Debian Janitor 2 years ago
209 changed file(s) with 16729 addition(s) and 4291 deletion(s). Raw diff Collapse all Expand all
0 ---
1 name: Problem report
2 about: Create an extensive report to help us document a problem
3
4 ---
5 <!--- Please fill out this template to the best of your ability. You can always edit this issue once you have created it. -->
6 <!--- Read the following link before you create a new problem report: https://kodi.wiki/view/HOW-TO:Submit_a_bug_report -->
7 ## Bug report
8 ### Describe the bug
9 Here is a clear and concise description of what the problem is:
10 <!--- Provide a more detailed introduction to the issue itself, and why you consider it to be a bug -->
11 <!--- A bug report that is not clear will be closed -->
12 <!--- Put your text below this line -->
13
14
15
16 ## Expected Behavior
17 Here is a clear and concise description of what was expected to happen:
18 <!--- Tell us what should happen -->
19 <!--- Put your text below this line -->
20
21
22
23 ## Actual Behavior
24 <!--- Tell us what happens instead -->
25 <!--- Put your text below this line -->
26
27
28
29 ## Possible Fix
30 <!--- Not obligatory, but suggest a fix or reason for the bug -->
31 <!--- Put your text below this line -->
32
33
34
35 ### To Reproduce
36 Steps to reproduce the behavior:
37 <!--- Provide a link to a live example, or an unambiguous set of steps to -->
38 <!--- reproduce this bug. Include code to reproduce, if relevant -->
39 <!--- Put your text below this line -->
40 1.
41 2.
42 3.
43
44
45 ### Debuglog
46 <!--- Put your text below this line -->
47 <!--- A debuglog is always mandatory when creating an issue. Provide one! -->
48 The debuglog can be found here:
49
50
51 ### MPD/M3U8s/ISM
52 <!--- Put your text below this line -->
53 <!--- Manifest(s) are always mandatory when creating an issue. Provide them! -->
54 An example or copy of a manifest (or manifests for HLS - master and variants) can be found here:
55
56
57 ### Screenshots
58 Here are some links or screenshots to help explain the problem:
59 <!--- Put your text below this line -->
60
61
62
63 ## Additional context or screenshots (if appropriate)
64 Here is some additional context or explanation that might help:
65 <!--- How has this bug affected you? What were you trying to accomplish? -->
66 <!--- Put your text below this line -->
67
68
69
70 ### Your Environment
71 Used Operating system:
72 <!--- Include as many relevant details about the environment you experienced the bug in -->
73 <!--- Put your text below this line. Checkboxes can easily be ticked once issue is created -->
74 - [ ] Android
75 - [ ] iOS
76 - [ ] tvOS
77 - [ ] Linux
78 - [ ] OSX
79 - [ ] Windows
80 - [ ] Windows UWP
81
82 - Operating system version/name:
83 - Kodi version:
84 - inputstream.adaptive version:
85
86
87
88 <!--- End of this issue -->
89 *note: Once the issue is made we require you to update it with new information should that be required.
90 Team Kodi will consider your problem report however, we will not make any promises the problem will be solved.*
0 name: Build and run tests
1 on: [push, pull_request]
2 env:
3 app_id: inputstream.adaptive
4
5 jobs:
6 build:
7 runs-on: ${{ matrix.os }}
8 strategy:
9 fail-fast: false
10 matrix:
11 include:
12 - os: ubuntu-18.04
13 CC: gcc
14 CXX: g++
15 - os: ubuntu-18.04
16 CC: clang
17 CXX: clang++
18 - os: macos-10.15
19 steps:
20 - name: Checkout Kodi repo
21 uses: actions/checkout@v2
22 with:
23 repository: xbmc/xbmc
24 ref: master
25 path: xbmc
26 - name: Checkout inputstream.adaptive repo
27 uses: actions/checkout@v2
28 with:
29 path: ${{ env.app_id }}
30 - name: Configure
31 env:
32 CC: ${{ matrix.CC }}
33 CXX: ${{ matrix.CXX }}
34 run: |
35 cd ${app_id} && mkdir -p build && cd build
36 cmake -DADDONS_TO_BUILD=${app_id} -DADDON_SRC_PREFIX=${{ github.workspace }} -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/xbmc/addons -DPACKAGE_ZIP=1 ${{ github.workspace }}/xbmc/cmake/addons
37 - name: Build
38 env:
39 CC: ${{ matrix.CC }}
40 CXX: ${{ matrix.CXX }}
41 run: |
42 cd ${app_id}/build
43 make
44 - name: Run tests
45 run: |
46 cd ${app_id}/build/${app_id}-prefix/src/${app_id}-build
47 make CTEST_OUTPUT_ON_FAILURE=1 GTEST_COLOR=1 test
0 name: Changelog and Release
1 # Update the changelog and news(optionally), bump the version, and create a release
2 #
3 # The release is created on the given branch, release and tag name format will be <version>-<branch> and
4 # the body of the release will be created from the changelog.txt or news element in the addon.xml.in
5 #
6 # options:
7 # - version_type: 'minor' / 'micro' # whether to do a minor or micro version bump
8 # - changelog_text: string to add to the changelog and news
9 # - update_news: 'true' / 'false' # whether to update the news in the addon.xml.in
10 # - add_date: 'true' / 'false' # Add date to version number in changelog and news. ie. v1.0.1 (2021-7-17)
11
12 on:
13 workflow_dispatch:
14 inputs:
15 version_type:
16 description: 'Create a ''minor'' or ''micro'' release?'
17 required: true
18 default: 'minor'
19 changelog_text:
20 description: 'Input the changes you''d like to add to the changelogs. Your text should be encapsulated in "''s with line feeds represented by literal \n''s. ie. "This is the first change\nThis is the second change"'
21 required: true
22 default: ''
23 update_news:
24 description: 'Update news in addon.xml.in? [true|false]'
25 required: true
26 default: 'true'
27 add_date:
28 description: 'Add date to version number in changelog and news. ie. "v1.0.1 (2021-7-17)" [true|false]'
29 required: true
30 default: 'true'
31
32 jobs:
33 default:
34 runs-on: ubuntu-latest
35 name: Changelog and Release
36
37 steps:
38
39 # Checkout the current repository into a directory (repositories name)
40 - name: Checkout Repository
41 uses: actions/checkout@v2
42 with:
43 fetch-depth: 0
44 path: ${{ github.event.repository.name }}
45
46 # Checkout the required scripts from kodi-pvr/pvr-scripts into the 'scripts' directory
47 - name: Checkout Scripts
48 uses: actions/checkout@v2
49 with:
50 fetch-depth: 0
51 repository: kodi-pvr/pvr-scripts
52 path: scripts
53
54 # Install all dependencies required by the following steps
55 # - libxml2-utils, xmlstarlet: reading news and version from addon.xml.in
56 - name: Install dependencies
57 run: |
58 sudo apt-get install libxml2-utils xmlstarlet
59
60 # Setup python version 3.9
61 - name: Set up Python
62 uses: actions/setup-python@v2
63 with:
64 python-version: '3.9'
65
66 # Run the python script to increment the version, changelog and news
67 - name: Increment version and update changelogs
68 run: |
69 arguments=
70 if [[ ${{ github.event.inputs.update_news }} == true ]] ;
71 then
72 arguments=$(echo $arguments && echo --update-news)
73 fi
74 if [[ ${{ github.event.inputs.add_date }} == true ]] ;
75 then
76 arguments=$(echo $arguments && echo --add-date)
77 fi
78 python3 ../scripts/changelog_and_release.py ${{ github.event.inputs.version_type }} ${{ github.event.inputs.changelog_text }} $arguments
79 working-directory: ${{ github.event.repository.name }}
80
81 # Create the variables required by the following steps
82 # - steps.required-variables.outputs.changes: latest entry in the changelog.txt (if exists), or addon.xml.in news element
83 # - steps.required-variables.outputs.version: version element from addon.xml.in
84 # - steps.required-variables.outputs.branch: branch of the triggering ref
85 # - steps.required-variables.outputs.today: today's date in format '%Y-%m-%d'
86 - name: Get required variables
87 id: required-variables
88 run: |
89 changes=$(cat "$(find . -name changelog.txt)" | awk -v RS= 'NR==1')
90 if [ -z "$changes" ] ;
91 then
92 changes=$(xmlstarlet fo -R "$(find . -name addon.xml.in)" | xmlstarlet sel -t -v 'string(/addon/extension/news)' | awk -v RS= 'NR==1')
93 fi
94 changes="${changes//'%'/'%25'}"
95 changes="${changes//$'\n'/'%0A'}"
96 changes="${changes//$'\r'/'%0D'}"
97 changes="${changes//$'\\n'/'%0A'}"
98 changes="${changes//$'\\r'/'%0D'}"
99 echo ::set-output name=changes::$changes
100 version=$(xmlstarlet fo -R "$(find . -name addon.xml.in)" | xmlstarlet sel -t -v 'string(/addon/@version)')
101 echo ::set-output name=version::$version
102 branch=$(echo ${GITHUB_REF#refs/heads/})
103 echo ::set-output name=branch::$branch
104 echo ::set-output name=today::$(date +'%Y-%m-%d')
105 working-directory: ${{ github.event.repository.name }}
106
107 # Create a commit of the incremented version and changelog, news changes
108 # Commit message (add_date=false): changelog and version v{steps.required-variables.outputs.version}
109 # Commit message (add_date=true): changelog and version v{steps.required-variables.outputs.version} ({steps.required-variables.outputs.today})
110 - name: Commit changes
111 run: |
112 git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
113 git config --local user.name "github-actions[bot]"
114 commit_message="changelog and version v${{ steps.required-variables.outputs.version }}"
115 if [[ ${{ github.event.inputs.add_date }} == true ]] ;
116 then
117 commit_message="$commit_message (${{ steps.required-variables.outputs.today }})"
118 fi
119 git commit -m "$commit_message" -a
120 working-directory: ${{ github.event.repository.name }}
121
122 # Push the commit(s) created above to the triggering branch
123 - name: Push changes
124 uses: ad-m/github-push-action@master
125 with:
126 branch: ${{ github.ref }}
127 directory: ${{ github.event.repository.name }}
128
129 # Sleep for 60 seconds to allow for any delays in the push
130 - name: Sleep for 60 seconds
131 run: sleep 60s
132 shell: bash
133
134 # Create a release at {steps.required-variables.outputs.branch}
135 # - tag and release name format: {steps.required-variables.outputs.version}-{steps.required-variables.outputs.branch} ie. 20.0.0-Nexus
136 # - release body: {steps.required-variables.outputs.changes}
137 - name: Create Release
138 id: create-release
139 uses: actions/create-release@v1
140 env:
141 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
142 with:
143 tag_name: ${{ steps.required-variables.outputs.version }}-${{ steps.required-variables.outputs.branch }}
144 release_name: ${{ steps.required-variables.outputs.version }}-${{ steps.required-variables.outputs.branch }}
145 body: ${{ steps.required-variables.outputs.changes }}
146 draft: false
147 prerelease: false
148 commitish: ${{ steps.required-variables.outputs.branch }}
0 name: Increment version when languages are updated
1
2 on:
3 push:
4 branches: [ Matrix, Nexus ]
5 paths:
6 - '**resource.language.**strings.po'
7
8 jobs:
9 default:
10 if: github.repository == 'xbmc/inputstream.adaptive'
11 runs-on: ubuntu-latest
12 name: Increment add-on version when languages are updated
13
14 steps:
15
16 - name: Checkout Repository
17 uses: actions/checkout@v2
18 with:
19 fetch-depth: 0
20 path: ${{ github.event.repository.name }}
21
22 - name: Checkout Scripts
23 uses: actions/checkout@v2
24 with:
25 fetch-depth: 0
26 repository: xbmc/weblate-supplementary-scripts
27 path: scripts
28
29 - name: Set up Python
30 uses: actions/setup-python@v2
31 with:
32 python-version: '3.9'
33
34 - name: Get changed files
35 uses: trilom/file-changes-action@v1.2.4
36
37 - name: Increment add-on version
38 run: |
39 python3 ../scripts/binary/increment_version.py $HOME/files.json -c -n -d
40 working-directory: ${{ github.event.repository.name }}
41
42 - name: Install dependencies
43 run: |
44 sudo apt-get install libxml2-utils xmlstarlet
45
46 - name: Get required variables
47 id: required-variables
48 run: |
49 version=$(xmlstarlet fo -R "$(find . -name addon.xml.in)" | xmlstarlet sel -t -v 'string(/addon/@version)')
50 echo ::set-output name=version::$version
51 working-directory: ${{ github.event.repository.name }}
52
53 - name: Create PR for incrementing add-on versions
54 uses: peter-evans/create-pull-request@v3.10.0
55 with:
56 commit-message: Add-on version incremented to ${{ steps.required-variables.outputs.version }} from Weblate
57 title: Add-on version incremented to ${{ steps.required-variables.outputs.version }} from Weblate
58 body: Add-on version incremented triggered by ${{ github.sha }}
59 branch: inc-ver
60 delete-branch: true
61 path: ./${{ github.event.repository.name }}
0 name: Make Release
1 # Create a release on the given branch
2 # Release and tag name format will be <version>-<branch>
3 # The body of the release will be created from the changelog.txt or news element in the addon.xml.in
4
5 on: workflow_dispatch
6
7 jobs:
8 default:
9 runs-on: ubuntu-latest
10 name: Make Release
11
12 steps:
13
14 # Checkout the current repository into a directory (repositories name)
15 - name: Checkout Repository
16 uses: actions/checkout@v2
17 with:
18 fetch-depth: 0
19 path: ${{ github.event.repository.name }}
20
21 # Install all dependencies required by the following steps
22 # - libxml2-utils, xmlstarlet: reading news and version from addon.xml.in
23 - name: Install dependencies
24 run: |
25 sudo apt-get install libxml2-utils xmlstarlet
26
27 # Create the variables required by the following steps
28 # - steps.required-variables.outputs.changes: latest entry in the changelog.txt (if exists), or addon.xml.in news element
29 # - steps.required-variables.outputs.version: version element from addon.xml.in
30 # - steps.required-variables.outputs.branch: branch of the triggering ref
31 - name: Get required variables
32 id: required-variables
33 run: |
34 changes=$(cat "$(find . -name changelog.txt)" | awk -v RS= 'NR==1')
35 if [ -z "$changes" ] ;
36 then
37 changes=$(xmlstarlet fo -R "$(find . -name addon.xml.in)" | xmlstarlet sel -t -v 'string(/addon/extension/news)' | awk -v RS= 'NR==1')
38 fi
39 changes="${changes//'%'/'%25'}"
40 changes="${changes//$'\n'/'%0A'}"
41 changes="${changes//$'\r'/'%0D'}"
42 changes="${changes//$'\\n'/'%0A'}"
43 changes="${changes//$'\\r'/'%0D'}"
44 echo ::set-output name=changes::$changes
45 version=$(xmlstarlet fo -R "$(find . -name addon.xml.in)" | xmlstarlet sel -t -v 'string(/addon/@version)')
46 echo ::set-output name=version::$version
47 branch=$(echo ${GITHUB_REF#refs/heads/})
48 echo ::set-output name=branch::$branch
49 working-directory: ${{ github.event.repository.name }}
50
51 # Create a release at {steps.required-variables.outputs.branch}
52 # - tag and release name format: {steps.required-variables.outputs.version}-{steps.required-variables.outputs.branch} ie. 20.0.0-Nexus
53 # - release body: {steps.required-variables.outputs.changes}
54 - name: Create Release
55 id: create-release
56 uses: actions/create-release@v1
57 env:
58 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
59 with:
60 tag_name: ${{ steps.required-variables.outputs.version }}-${{ steps.required-variables.outputs.branch }}
61 release_name: ${{ steps.required-variables.outputs.version }}-${{ steps.required-variables.outputs.branch }}
62 body: ${{ steps.required-variables.outputs.changes }}
63 draft: false
64 prerelease: false
65 commitish: ${{ steps.required-variables.outputs.branch }}
0 name: Sync addon metadata translations
1
2 on:
3 push:
4 branches: [ Matrix, Nexus ]
5 paths:
6 - '**addon.xml.in'
7 - '**resource.language.**strings.po'
8
9 jobs:
10 default:
11 if: github.repository == 'xbmc/inputstream.adaptive'
12 runs-on: ubuntu-latest
13
14 strategy:
15
16 fail-fast: false
17 matrix:
18 python-version: [ 3.9 ]
19
20 steps:
21
22 - name: Checkout repository
23 uses: actions/checkout@v2
24 with:
25 path: project
26
27 - name: Checkout sync_addon_metadata_translations repository
28 uses: actions/checkout@v2
29 with:
30 repository: xbmc/sync_addon_metadata_translations
31 path: sync_addon_metadata_translations
32
33 - name: Set up Python ${{ matrix.python-version }}
34 uses: actions/setup-python@v2
35 with:
36 python-version: ${{ matrix.python-version }}
37
38 - name: Install dependencies
39 run: |
40 python -m pip install --upgrade pip
41 python -m pip install sync_addon_metadata_translations/
42
43 - name: Run sync-addon-metadata-translations
44 run: |
45 sync-addon-metadata-translations
46 working-directory: ./project
47
48 - name: Create PR for sync-addon-metadata-translations changes
49 uses: peter-evans/create-pull-request@v3.10.0
50 with:
51 commit-message: Sync of addon metadata translations
52 title: Sync of addon metadata translations
53 body: Sync of addon metadata translations triggered by ${{ github.sha }}
54 branch: amt-sync
55 delete-branch: true
56 path: ./project
57 reviewers: gade01
0 # build artifacts
1 build/
2 inputstream.*/addon.xml
3
4 # Debian build files
5 debian/changelog
6 debian/files
7 debian/*.log
8 debian/*.substvars
9 debian/.debhelper/
10 debian/tmp/
11 debian/kodi-pvr-*/
12 obj-x86_64-linux-gnu/
13
14 # commonly used editors
15 # vim
16 *.swp
17
18 # Eclipse
19 *.project
20 *.cproject
21 .classpath
22 *.sublime-*
23 .settings/
24
25 # KDevelop 4
26 *.kdev4
27
28 # gedit
29 *~
30
31 # CLion
32 /.idea
33
34 # clion
35 .idea/
36
37 # to prevent add after a "git format-patch VALUE" and "git add ." call
38 /*.patch
39
40 # Visual Studio Code
41 .vscode
42
43 # to prevent add if project code opened by Visual Studio over CMake file
44 .vs/
45
46 #testfiles
47 *.mpd_current
88 set(ADP_SOURCES
99 src/main.cpp
1010 src/common/AdaptiveTree.cpp
11 src/common/RepresentationChooser.cpp
1112 src/parser/DASHTree.cpp
1213 src/parser/HLSTree.cpp
1314 src/parser/SmoothTree.cpp
3132 src/SSD_dll.h
3233 src/common/AdaptiveStream.h
3334 src/common/AdaptiveTree.h
35 src/common/RepresentationChooser.h
3436 src/parser/DASHTree.h
3537 src/parser/HLSTree.h
3638 src/parser/SmoothTree.h
0 buildPlugin(version: "Matrix")
0 buildPlugin(version: "Nexus")
00 [![License: GPL-2.0-or-later](https://img.shields.io/badge/License-GPL%20v2+-blue.svg)](LICENSE.GPL)
1 [![Build Status](https://dev.azure.com/teamkodi/binary-addons/_apis/build/status/xbmc.inputstream.adaptive?branchName=Matrix)](https://dev.azure.com/teamkodi/binary-addons/_build/latest?definitionId=79&branchName=Matrix)
2 [![Build and run tests](https://github.com/xbmc/inputstream.adaptive/actions/workflows/build.yml/badge.svg?branch=Matrix)](https://github.com/xbmc/inputstream.adaptive/actions/workflows/build.yml)
3 [![Build Status](https://jenkins.kodi.tv/view/Addons/job/xbmc/job/inputstream.adaptive/job/Matrix/badge/icon)](https://jenkins.kodi.tv/blue/organizations/jenkins/xbmc%2Finputstream.rtmp/branches/)
1 [![Build Status](https://dev.azure.com/teamkodi/binary-addons/_apis/build/status/xbmc.inputstream.adaptive?branchName=Nexus)](https://dev.azure.com/teamkodi/binary-addons/_build/latest?definitionId=79&branchName=Nexus)
2 [![Build and run tests](https://github.com/xbmc/inputstream.adaptive/actions/workflows/build.yml/badge.svg?branch=Nexus)](https://github.com/xbmc/inputstream.adaptive/actions/workflows/build.yml)
3 [![Build Status](https://jenkins.kodi.tv/view/Addons/job/xbmc/job/inputstream.adaptive/job/Nexus/badge/icon)](https://jenkins.kodi.tv/blue/organizations/jenkins/xbmc%2Finputstream.rtmp/branches/)
44
55 # inputstream.adaptive
66
2222
2323 build_script:
2424 - cd ..
25 - git clone --branch Matrix --depth=1 https://github.com/xbmc/xbmc.git
25 - git clone --branch master --depth=1 https://github.com/xbmc/xbmc.git
2626 - cd %app_id%
2727 - mkdir build
2828 - cd build
33 trigger:
44 branches:
55 include:
6 - Matrix
6 - Nexus
77 - releases/*
88 paths:
99 include:
5555
5656 - script: |
5757 cd ..
58 git clone --branch Matrix --depth=1 https://github.com/xbmc/xbmc.git kodi
58 git clone --branch master --depth=1 https://github.com/xbmc/xbmc.git kodi
5959 cd $(Build.SourcesDirectory)
6060 mkdir build
6161 cd build
00 <?xml version="1.0" encoding="UTF-8"?>
11 <addon
22 id="inputstream.adaptive"
3 version="19.0.0"
3 version="20.0.2"
44 name="InputStream Adaptive"
55 provider-name="peak3d">
66 <requires>@ADDON_DEPENDS@</requires>
1414 <extension point="xbmc.addon.metadata">
1515 <platform>@PLATFORM@</platform>
1616 <news>
17 v19.0.0 (2021-09-14)
18 - Change test builds to released 'Kodi 19 Matrix'
19 - Increase version to 19.0.0
17 v20.0.2 (2021-10-09)
18 - Fix crash when no data sent to DemuxRead
19 - Update Bento4 lib
20 - Fix pixellation issue when seeking to head
21 - [DASH] support suggestedPresentationDelay
22 - increase 'no-seek' area default for live streams to 16 seconds
23
24 v20.0.1 (2021-09-28)
25 - Adaptive bitrate switching and buffering initial support!
26 - Change default license if no pipes in license url
27 - Remove old unused Android ndk files
28 - Better WebVTT format checking
29 - [DASH] handle adaptationset switching tag to merge adaptationsets
30
31 v20.0.0 (2021-09-14)
32 - Change test builds to 'Kodi 20 Nexus'
33 - Increase version to 20.0.0
2034 - With start of Kodi 20 Nexus, takes addon as major the same version number as Kodi.
2135 This done to know easier to which Kodi the addon works.
2236
3131 # The maximum bandwidth which should not be exceeded. 0=unlimited
3232 msgctxt "#30102"
3333 msgid "Max. Bandwidth (Bit/s)"
34 msgstr ""
35
36 # Assured buffer length duration (seconds)
37 msgctxt "#30200"
38 msgid "Assured Buffer Duration (sec)"
39 msgstr ""
40
41 # Max buffer length duration (seconds)
42 msgctxt "#30201"
43 msgid "Max Buffer Duration (sec)"
44 msgstr ""
45
46 # Ignore Window Display Resolution Change
47 msgctxt "#30202"
48 msgid "Ignore Window Change"
3449 msgstr ""
3550
3651 # Absolute path to the folder containing the decrypters
55 msgstr ""
66 "Project-Id-Version: inputstream.adaptive\n"
77 "POT-Creation-Date: \n"
8 "PO-Revision-Date: 2020-03-28 19:02+0100\n"
9 "Last-Translator: arvvoid\n"
8 "PO-Revision-Date: 2021-10-16 22:28+0200\n"
9 "Last-Translator: dsardelic\n"
1010 "Language-Team: Croatian\n"
1111 "Language: hr_HR\n"
1212 "MIME-Version: 1.0\n"
1717
1818 msgctxt "Addon Summary"
1919 msgid "InputStream client for adaptive streams"
20 msgstr ""
20 msgstr "InputStream klijent za adaptivne tokove"
2121
2222 msgctxt "Addon Description"
2323 msgid "InputStream client for adaptive streams"
24 msgstr ""
24 msgstr "InputStream klijent za adaptivne tokove"
2525
2626 msgctxt "#30100"
2727 msgid "General"
3030 # The minimum bandwidth which should not be deceeded.
3131 msgctxt "#30101"
3232 msgid "Min. Bandwidth (Bit/s)"
33 msgstr "Minimalna propusnost (bit/s)"
33 msgstr "Min. propusnost (bit/s)"
3434
3535 # The maximum bandwidth which should not be exceeded. 0=unlimited
3636 msgctxt "#30102"
3737 msgid "Max. Bandwidth (Bit/s)"
38 msgstr "Maksimalna propusnost (bit/s)"
38 msgstr "Maks. propusnost (bit/s)"
3939
4040 # Absolute path to the folder containing the decrypters
4141 msgctxt "#30103"
4242 msgid "Decrypter path"
43 msgstr "Apsolutni put do mape koja sadrži dekripter"
43 msgstr "Putanja prema mapi s dekripterima"
4444
4545 # Maximum Resolution
4646 msgctxt "#30110"
4747 msgid "Max. Resolution general decoder"
48 msgstr "Maksimalna rezolucija opći dekoder"
48 msgstr "Maks. razlučivost općeg dekodera"
4949
5050 msgctxt "#30111"
5151 msgid "Stream Selection"
52 msgstr "Odabir stream-a"
52 msgstr "Odabir toka"
5353
5454 msgctxt "#30112"
5555 msgid "Media"
5858 # Maximum allowed resolution if decoded through secure path
5959 msgctxt "#30113"
6060 msgid "Max. Resolution secure decoder"
61 msgstr "Maksimalna rezolucija za sigurni dekoder"
61 msgstr "Maks. razlučivost sigurnog dekodera"
6262
6363 # Select streams without respecting HDCP status
6464 msgctxt "#30114"
6565 msgid "Override HDCP status"
66 msgstr "Zanemari HDCP status"
66 msgstr "Nadjačaj HDCP status"
6767
6868 # Do not respect display resolution when selecting streams
6969 msgctxt "#30115"
7070 msgid "Ignore Display Resolution"
71 msgstr "Zanemari rezoluciju ekrana"
71 msgstr "Zanemari razlučivost zaslona"
7272
7373 msgctxt "#30120"
7474 msgid "Expert"
75 msgstr "Stručnjak"
75 msgstr "Stručne"
7676
7777 msgctxt "#30121"
7878 msgid "Enable Pre-Release Features"
79 msgstr "Omogući eksperimentalne značajke"
79 msgstr "Omogući još neobjavljene značajke"
8080
8181 msgctxt "#30122"
8282 msgid "Don't use secure decoder if possible"
83 msgstr ""
83 msgstr "Ukoliko je moguće, ne koristi sigurni dekoder"
8484
8585 msgctxt "#30150"
8686 msgid "Max"
104104
105105 msgctxt "#30155"
106106 msgid "Automatically select streams"
107 msgstr ""
107 msgstr "Automatski odaberi tokove"
108108
109109 msgctxt "#30156"
110110 msgid "Manually select all streams"
111 msgstr ""
111 msgstr "Ručno odaberi sve tokove"
112112
113113 msgctxt "#30157"
114114 msgid "All"
125125 # Show all video streams
126126 msgctxt "#30160"
127127 msgid "Manually select video stream"
128 msgstr ""
128 msgstr "Ručno odaberi video tok"
129129
130130 msgctxt "#30161"
131131 msgid "Video + Subtitles"
132132 msgstr "Video + Titlovi"
133
134 # Assured buffer length duration (seconds)
135 msgctxt "#30200"
136 msgid "Assured Buffer Duration (sec)"
137 msgstr "Osigurano trajanje međuspremnika (sek)"
138
139 # Max buffer length duration (seconds)
140 msgctxt "#30201"
141 msgid "Max Buffer Duration (sec)"
142 msgstr "Maks. trajanje međuspremnika (sek)"
143
144 # Ignore Window Display Resolution Change
145 msgctxt "#30202"
146 msgid "Ignore Window Change"
147 msgstr "Ignoriraj promjenu prozora"
1212 <default>0</default>
1313 <control type="edit" format="integer" />
1414 </setting>
15 <setting id="ASSUREDBUFFERDURATION" type="integer" label="30200">
16 <level>1</level>
17 <default>60</default>
18 <control type="edit" format="integer" />
19 </setting>
20 <setting id="MAXBUFFERDURATION" type="integer" label="30201">
21 <level>1</level>
22 <default>120</default>
23 <control type="edit" format="integer" />
24 </setting>
25 <setting id="IGNOREWINDOWCHANGE" type="boolean" label="30202">
26 <level>1</level>
27 <default>true</default>
28 <control type="toggle" />
29 </setting>
1530 <setting id="MAXRESOLUTION" type="integer" label="30110">
1631 <level>0</level>
1732 <default>0</default>
0 /*****************************************************************
1 |
2 | AP4 - AC-3 Sync Frame Parser
3 |
4 | Copyright 2002-2020 Axiomatic Systems, LLC
5 |
6 |
7 | This file is part of Bento4/AP4 (MP4 Atom Processing Library).
8 |
9 | Unless you have obtained Bento4 under a difference license,
10 | this version of Bento4 is Bento4|GPL.
11 | Bento4|GPL is free software; you can redistribute it and/or modify
12 | it under the terms of the GNU General Public License as published by
13 | the Free Software Foundation; either version 2, or (at your option)
14 | any later version.
15 |
16 | Bento4|GPL is distributed in the hope that it will be useful,
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | GNU General Public License for more details.
20 |
21 | You should have received a copy of the GNU General Public License
22 | along with Bento4|GPL; see the file COPYING. If not, write to the
23 | Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
24 | 02111-1307, USA.
25 |
26 ****************************************************************/
27
28 /*----------------------------------------------------------------------
29 | includes
30 +---------------------------------------------------------------------*/
31 #include "Ap4BitStream.h"
32 #include "Ap4Ac3Parser.h"
33 #include "Ap4Utils.h"
34
35 /*----------------------------------------------------------------------+
36 | AP4_Ac3Header::AP4_Ac3Header
37 +----------------------------------------------------------------------*/
38 AP4_Ac3Header::AP4_Ac3Header(const AP4_UI08* bytes)
39 {
40 AP4_BitReader bits(bytes, AP4_AC3_HEADER_SIZE);
41 bits.SkipBits(16); // sync word
42 bits.SkipBits(16); // crc1
43 m_Fscod = bits.ReadBits(2);
44 m_Frmsizecod = bits.ReadBits(6); // frmsizecod
45 m_FrameSize = FRAME_SIZE_CODE_ARY_AC3[m_Fscod][m_Frmsizecod] * 2;
46
47 m_Bsid = bits.ReadBits(5);
48 m_Bsmod = bits.ReadBits(3);
49 m_Acmod = bits.ReadBits(3);
50 if((m_Acmod & 0x1) && (m_Acmod != 0x1)){
51 bits.SkipBits(2); //cmixlev
52 }
53 if(m_Acmod & 0x4){
54 bits.SkipBits(2); //surmixlev
55 }
56 if(m_Acmod == 0x2){
57 bits.SkipBits(2); //dsurmod
58 }
59 m_Lfeon = bits.ReadBit();
60 m_ChannelCount = GLOBAL_CHANNEL_ARY[m_Acmod] + m_Lfeon;
61 bits.SkipBits(5); // dialnorm
62 if(bits.ReadBit()){ // compre
63 bits.SkipBits(8); // compr
64 }
65 if(bits.ReadBit()){ // langcode
66 bits.SkipBits(8); // langcod
67 }
68 if(bits.ReadBit()){ // audprodie
69 bits.SkipBits(5); // mixlevel
70 bits.SkipBits(2); // roomtyp
71 }
72 if (m_Acmod == 0){
73 bits.SkipBits(5); // dialnorm2
74 if(bits.ReadBit()){ // compr2e
75 bits.SkipBits(8); // compr2
76 }
77 if(bits.ReadBit()){ // langcod2e
78 bits.SkipBits(8); // langcod2
79 }
80 if(bits.ReadBit()){ // audprodi2e
81 bits.SkipBits(5); // mixlevel2
82 bits.SkipBits(2); // roomtyp2
83 }
84 }
85 bits.SkipBits(1); // copyrightb
86 bits.SkipBits(1); // origbs
87 if(bits.ReadBit()){ // timecod1e
88 bits.SkipBits(14); // timecod1
89 }
90 if(bits.ReadBit()){ //timecod2e
91 bits.SkipBits(14); // timecod2
92 }
93 m_Addbsie = bits.ReadBit();
94 if (m_Addbsie){
95 m_Addbsil = bits.ReadBits(6);
96 for (unsigned int idx = 0 ; idx < (m_Addbsil + 1); idx ++){
97 m_addbsi[idx] = bits.ReadBits(8);
98 }
99 } else {
100 m_Addbsil = 0;
101 AP4_SetMemory(m_addbsi, 0, sizeof (m_addbsi));
102 }
103 m_HeadSize = (bits.GetBitsRead() / 8) + ((bits.GetBitsRead() % 8 == 0) ? 0: 1);
104 }
105
106 /*----------------------------------------------------------------------+
107 | AP4_Ac3Header::MatchFixed
108 |
109 | Check that two fixed headers are the same
110 |
111 +----------------------------------------------------------------------*/
112 bool
113 AP4_Ac3Header::MatchFixed(AP4_Ac3Header& frame, AP4_Ac3Header& next_frame)
114 {
115 return true;
116 }
117
118 /*----------------------------------------------------------------------+
119 | AP4_Ac3Header::Check
120 +----------------------------------------------------------------------*/
121 AP4_Result
122 AP4_Ac3Header::Check()
123 {
124 if (m_Bsid > 8) {
125 return AP4_FAILURE;
126 }
127 return AP4_SUCCESS;
128 }
129
130 /*----------------------------------------------------------------------+
131 | AP4_Ac3Parser::AP4_Ac3Parser
132 +----------------------------------------------------------------------*/
133 AP4_Ac3Parser::AP4_Ac3Parser() :
134 m_FrameCount(0)
135 {
136 }
137
138 /*----------------------------------------------------------------------+
139 | AP4_Ac3Parser::~AP4_Ac3Parser
140 +----------------------------------------------------------------------*/
141 AP4_Ac3Parser::~AP4_Ac3Parser()
142 {
143 }
144
145 /*----------------------------------------------------------------------+
146 | AP4_Ac3Parser::Reset
147 +----------------------------------------------------------------------*/
148 AP4_Result
149 AP4_Ac3Parser::Reset()
150 {
151 m_FrameCount = 0;
152
153 return AP4_SUCCESS;
154 }
155
156 /*----------------------------------------------------------------------+
157 | AP4_Ac3Parser::Feed
158 +----------------------------------------------------------------------*/
159 AP4_Result
160 AP4_Ac3Parser::Feed(const AP4_UI08* buffer,
161 AP4_Size* buffer_size,
162 AP4_Flags flags)
163 {
164 AP4_Size free_space;
165
166 /* update flags */
167 m_Bits.m_Flags = flags;
168
169 /* possible shortcut */
170 if (buffer == NULL ||
171 buffer_size == NULL ||
172 *buffer_size == 0) {
173 return AP4_SUCCESS;
174 }
175
176 /* see how much data we can write */
177 free_space = m_Bits.GetBytesFree();
178 if (*buffer_size > free_space) *buffer_size = free_space;
179 if (*buffer_size == 0) return AP4_SUCCESS;
180
181 /* write the data */
182 return m_Bits.WriteBytes(buffer, *buffer_size);
183 }
184
185 /*----------------------------------------------------------------------+
186 | AP4_Ac3Parser::FindHeader
187 +----------------------------------------------------------------------*/
188 AP4_Result
189 AP4_Ac3Parser::FindHeader(AP4_UI08* header)
190 {
191 AP4_Size available = m_Bits.GetBytesAvailable();
192
193 /* look for the sync pattern */
194 while (available-- >= AP4_AC3_HEADER_SIZE) {
195 m_Bits.PeekBytes(header, 2); // ac3 header begins with 0x0B77
196
197 if( (((header[0] << 8) | header[1]) == AP4_AC3_SYNC_WORD_BIG_ENDIAN) ||
198 (((header[0] << 8) | header[1]) == AP4_AC3_SYNC_WORD_LITTLE_ENDIAN) ){
199 // Little Endian
200 if (((header[0] << 8) | header[1]) == AP4_AC3_SYNC_WORD_LITTLE_ENDIAN) {
201 m_LittleEndian = true;
202 } else {
203 m_LittleEndian = false;
204 }
205 /* found a sync pattern, read the entire the header */
206 m_Bits.PeekBytes(header, AP4_AC3_HEADER_SIZE);
207
208 return AP4_SUCCESS;
209 } else {
210 m_Bits.ReadByte(); // skip
211 }
212 }
213
214 return AP4_ERROR_NOT_ENOUGH_DATA;
215 }
216
217 /*----------------------------------------------------------------------+
218 | AP4_Ac3Parser::FindFrame
219 +----------------------------------------------------------------------*/
220 AP4_Result
221 AP4_Ac3Parser::FindFrame(AP4_Ac3Frame& frame)
222 {
223 unsigned int available;
224 unsigned char raw_header[AP4_AC3_HEADER_SIZE];
225 AP4_Result result;
226
227 /* align to the start of the next byte */
228 m_Bits.ByteAlign();
229
230 /* find a frame header */
231 result = FindHeader(raw_header);
232 if (AP4_FAILED(result)) return result;
233
234 if (m_LittleEndian) {
235 AP4_ByteSwap16(raw_header, AP4_AC3_HEADER_SIZE);
236 }
237
238 /* parse the header */
239 AP4_Ac3Header ac3_header(raw_header);
240
241 /* check the header */
242 result = ac3_header.Check();
243 if (AP4_FAILED(result)) {
244 m_Bits.SkipBytes(2);
245 goto fail;
246 }
247
248 /* check if we have enough data to peek at the next header */
249 available = m_Bits.GetBytesAvailable();
250 if (available >= ac3_header.m_FrameSize + AP4_AC3_HEADER_SIZE) {
251 // enough to peek at the header of the next frame
252 unsigned char peek_raw_header[AP4_AC3_HEADER_SIZE];
253
254 m_Bits.SkipBytes(ac3_header.m_FrameSize);
255 m_Bits.PeekBytes(peek_raw_header, AP4_AC3_HEADER_SIZE);
256 m_Bits.SkipBytes(-((int)ac3_header.m_FrameSize));
257
258 if (m_LittleEndian) {
259 AP4_ByteSwap16(peek_raw_header, AP4_AC3_HEADER_SIZE);
260 }
261 /* check the header */
262 AP4_Ac3Header peek_ac3_header(peek_raw_header);
263 result = peek_ac3_header.Check();
264 if (AP4_FAILED(result)) {
265 m_Bits.SkipBytes(ac3_header.m_FrameSize + 2);
266 goto fail;
267 }
268
269 /* check that the fixed part of this header is the same as the */
270 /* fixed part of the previous header */
271 else if (!AP4_Ac3Header::MatchFixed(ac3_header, peek_ac3_header)) {
272 m_Bits.SkipBytes(ac3_header.m_FrameSize + 2);
273 goto fail;
274 }
275 } else if (available < ac3_header.m_FrameSize || (m_Bits.m_Flags & AP4_BITSTREAM_FLAG_EOS) == 0) {
276 // not enough for a frame, or not at the end (in which case we'll want to peek at the next header)
277 return AP4_ERROR_NOT_ENOUGH_DATA;
278 }
279 frame.m_Info.m_ChannelCount = ac3_header.m_ChannelCount;
280 frame.m_Info.m_SampleRate = FSCOD_AC3[ac3_header.m_Fscod];
281 frame.m_Info.m_FrameSize = ac3_header.m_FrameSize;
282 frame.m_Info.m_Ac3StreamInfo.fscod = ac3_header.m_Fscod;
283 frame.m_Info.m_Ac3StreamInfo.bsid = ac3_header.m_Bsid;
284 frame.m_Info.m_Ac3StreamInfo.bsmod = ac3_header.m_Bsmod;
285 frame.m_Info.m_Ac3StreamInfo.acmod = ac3_header.m_Acmod;
286 frame.m_Info.m_Ac3StreamInfo.lfeon = ac3_header.m_Lfeon;
287 frame.m_Info.m_Ac3StreamInfo.bit_rate_code = ac3_header.m_Frmsizecod / 2;
288
289 frame.m_LittleEndian = m_LittleEndian;
290
291 /* set the frame source */
292 frame.m_Source = &m_Bits;
293
294 return AP4_SUCCESS;
295
296 fail:
297 /* skip the header and return (only skip the first byte in */
298 /* case this was a false header that hides one just after) */
299 //m_Bits.SkipBytes(-(AP4_ADTS_HEADER_SIZE-1));
300 return AP4_ERROR_CORRUPTED_BITSTREAM;
301 }
302
303 /*----------------------------------------------------------------------+
304 | AP4_Ac3Parser::GetBytesFree
305 +----------------------------------------------------------------------*/
306 AP4_Size
307 AP4_Ac3Parser::GetBytesFree()
308 {
309 return (m_Bits.GetBytesFree());
310 }
311
312 /*----------------------------------------------------------------------+
313 | AP4_Ac3Parser::GetBytesAvailable
314 +----------------------------------------------------------------------*/
315 AP4_Size
316 AP4_Ac3Parser::GetBytesAvailable()
317 {
318 return (m_Bits.GetBytesAvailable());
319 }
0 /*****************************************************************
1 |
2 | AP4 - AC-3 Sync Frame Parser
3 |
4 | Copyright 2002-2020 Axiomatic Systems, LLC
5 |
6 |
7 | This file is part of Bento4/AP4 (MP4 Atom Processing Library).
8 |
9 | Unless you have obtained Bento4 under a difference license,
10 | this version of Bento4 is Bento4|GPL.
11 | Bento4|GPL is free software; you can redistribute it and/or modify
12 | it under the terms of the GNU General Public License as published by
13 | the Free Software Foundation; either version 2, or (at your option)
14 | any later version.
15 |
16 | Bento4|GPL is distributed in the hope that it will be useful,
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | GNU General Public License for more details.
20 |
21 | You should have received a copy of the GNU General Public License
22 | along with Bento4|GPL; see the file COPYING. If not, write to the
23 | Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
24 | 02111-1307, USA.
25 |
26 ****************************************************************/
27
28 #ifndef _AP4_AC3_PARSER_H_
29 #define _AP4_AC3_PARSER_H_
30
31 /*----------------------------------------------------------------------
32 | includes
33 +---------------------------------------------------------------------*/
34 #include "Ap4Types.h"
35 #include "Ap4BitStream.h"
36 #include "Ap4Dac3Atom.h"
37 #include "Ap4Eac3Parser.h"
38
39 /*----------------------------------------------------------------------
40 | constants
41 +---------------------------------------------------------------------*/
42 #define AP4_AC3_HEADER_SIZE 32 /* The header size for AC-3 parser, syncinfo() + bsi() */
43 #define AP4_AC3_SYNC_WORD_BIG_ENDIAN 0x0B77 /* Big endian, 16 sync bits */
44 #define AP4_AC3_SYNC_WORD_LITTLE_ENDIAN 0x770B /* Little endian, 16 sync bits */
45
46 const AP4_UI32 FRAME_SIZE_CODE_ARY_AC3[3][38] = {
47 {64,64,80,80,96,96,112,112,128,128,160,160,192,192,224,224,256,256,320,320,384,384,448,448,512,512,640,640,768,768,896,896,1024,1024,1152,1152,1280,1280},
48 {69,70,87,88,104,105,121,122,139,140,174,175,208,209,243,244,278,279,348,349,417,418,487,488,557,558696,697,835,836,976,977,1114,1115,1253,1254,1393,1394},
49 {96,96,120,120,144,144,168,168,192,192,240,240,288,288,336,336,384,384,480,480,576,576,672,672,768,768,960,960,1152,1152,1344,1344,1536,1536,1728,1728,1920,1920}};
50 const AP4_UI32 FSCOD_AC3[4] = {48000, 44100, 32000, 0};
51
52 /*----------------------------------------------------------------------
53 | types
54 +---------------------------------------------------------------------*/
55 class AP4_Ac3Header {
56 public:
57 // constructor
58 AP4_Ac3Header(const AP4_UI08* bytes);
59
60 // methods
61 AP4_Result Check();
62
63 AP4_UI32 m_HeadSize;
64 AP4_UI32 m_FrameSize;
65 AP4_UI32 m_ChannelCount;
66
67 // AC-3 sysninfo()
68 AP4_UI32 m_Fscod;
69 AP4_UI32 m_Frmsizecod;
70
71 // AC-3 bsi()
72 AP4_UI32 m_Bsid;
73 AP4_UI32 m_Bsmod;
74 AP4_UI32 m_Acmod;
75 AP4_UI32 m_Lfeon;
76 AP4_UI32 m_Addbsie;
77 AP4_UI32 m_Addbsil; // 6 bits
78 AP4_UI08 m_addbsi[65]; // (addbsil+1)×8
79
80 // class methods
81 static bool MatchFixed(AP4_Ac3Header& frame, AP4_Ac3Header& next_frame);
82 };
83
84 typedef struct {
85 AP4_UI32 m_ChannelCount;
86 AP4_UI32 m_FrameSize;
87 AP4_UI32 m_SampleRate;
88 AP4_Dac3Atom::StreamInfo m_Ac3StreamInfo;
89 } AP4_Ac3FrameInfo;
90
91 typedef struct {
92 AP4_BitStream* m_Source;
93 AP4_Ac3FrameInfo m_Info;
94 AP4_Flags m_LittleEndian;
95 } AP4_Ac3Frame;
96
97 class AP4_Ac3Parser {
98 public:
99 // constructor and destructor
100 AP4_Ac3Parser();
101 virtual ~AP4_Ac3Parser();
102
103 // methods
104 AP4_Result Reset();
105 AP4_Result Feed(const AP4_UI08* buffer,
106 AP4_Size* buffer_size,
107 AP4_Flags flags = 0);
108 AP4_Result FindFrame(AP4_Ac3Frame& frame);
109 AP4_Result Skip(AP4_Size size);
110 AP4_Size GetBytesFree();
111 AP4_Size GetBytesAvailable();
112
113 private:
114 // methods
115 AP4_Result FindHeader(AP4_UI08* header);
116
117 // members
118 AP4_BitStream m_Bits;
119 AP4_Cardinal m_FrameCount;
120 AP4_Flags m_LittleEndian;
121 };
122
123 #endif // _AP4_AC3_PARSER_H_
0 /*****************************************************************
1 |
2 | AP4 - AC4 Sync Frame Parser
3 |
4 | Copyright 2002-2020 Axiomatic Systems, LLC
5 |
6 |
7 | This file is part of Bento4/AP4 (MP4 Atom Processing Library).
8 |
9 | Unless you have obtained Bento4 under a difference license,
10 | this version of Bento4 is Bento4|GPL.
11 | Bento4|GPL is free software; you can redistribute it and/or modify
12 | it under the terms of the GNU General Public License as published by
13 | the Free Software Foundation; either version 2, or (at your option)
14 | any later version.
15 |
16 | Bento4|GPL is distributed in the hope that it will be useful,
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | GNU General Public License for more details.
20 |
21 | You should have received a copy of the GNU General Public License
22 | along with Bento4|GPL; see the file COPYING. If not, write to the
23 | Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
24 | 02111-1307, USA.
25 |
26 ****************************************************************/
27
28 /*----------------------------------------------------------------------
29 | includes
30 +---------------------------------------------------------------------*/
31 #include "Ap4BitStream.h"
32 #include "Ap4Ac4Parser.h"
33
34 bool AP4_Ac4Header::m_DeprecatedV0 = true;
35 /*----------------------------------------------------------------------+
36 | AP4_Ac4Header::AP4_Ac4Header
37 +----------------------------------------------------------------------*/
38 AP4_Ac4Header::AP4_Ac4Header(const AP4_UI08* bytes, unsigned int size)
39 {
40 /* Read the entire the frame */
41 AP4_BitReader bits(bytes, size);
42
43 m_SyncWord = bits.ReadBits(16);
44 m_HeaderSize = 2;
45 if (m_SyncWord == AP4_AC4_SYNC_WORD_CRC){
46 m_CrcSize = 2;
47 }else {
48 m_CrcSize = 0;
49 }
50 m_FrameSize = bits.ReadBits(16);
51 m_HeaderSize += 2;
52 if (m_FrameSize == 0xFFFF){
53 m_FrameSize = bits.ReadBits(24);
54 m_HeaderSize += 3;
55 }
56
57 /* Begin to parse TOC */
58 m_BitstreamVersion = bits.ReadBits(2);
59 if (m_BitstreamVersion == 3) {
60 m_BitstreamVersion = AP4_Ac4VariableBits(bits, 2);
61 }
62 m_SequenceCounter = bits.ReadBits(10);
63 m_BWaitFrames = bits.ReadBit();
64 if (m_BWaitFrames) {
65 m_WaitFrames = bits.ReadBits(3);
66 if (m_WaitFrames > 0){ m_BrCode = bits.ReadBits(2);}
67 }else {
68 m_WaitFrames = -1;
69 }
70
71 m_FsIndex = bits.ReadBit();
72 m_FrameRateIndex = bits.ReadBits(4);
73 m_BIframeGlobal = bits.ReadBit();
74 m_BSinglePresentation = bits.ReadBit();
75 if (m_BSinglePresentation == 1){
76 m_NPresentations = 1;
77 m_BMorePresentations = 0;
78 }else{
79 m_BMorePresentations = bits.ReadBit();
80 if (m_BMorePresentations == 1){
81 m_NPresentations = AP4_Ac4VariableBits(bits, 2) + 2;
82 }else{
83 m_NPresentations = 0;
84 }
85 }
86 m_PayloadBase = 0;
87 m_BPayloadBase = bits.ReadBit();
88 if (m_BPayloadBase == 1){
89 m_PayloadBase = bits.ReadBits(5) + 1;
90 if (m_PayloadBase == 0x20){
91 m_PayloadBase += AP4_Ac4VariableBits(bits, 3);
92 }
93 }
94 if (m_BitstreamVersion <= 1){
95 if (m_DeprecatedV0){
96 m_DeprecatedV0 = false;
97 printf("Warning: Bitstream version 0 is deprecated\n");
98 }
99 }else{
100 m_BProgramId = bits.ReadBit();
101 if (m_BProgramId == 1){
102 m_ShortProgramId = bits.ReadBits(16);
103 m_BProgramUuidPresent = bits.ReadBit();
104 if (m_BProgramUuidPresent == 1){
105 for (int cnt = 0; cnt < 16; cnt++){
106 m_ProgramUuid[cnt] = bits.ReadBits(8);
107 }
108 }else {
109 memcpy(m_ProgramUuid,"ONDEL TEAM UUID\0", 16);
110 }
111 }else {
112 m_ShortProgramId = 0;
113 m_BProgramUuidPresent = 0;
114 memcpy(m_ProgramUuid, "ONDEL TEAM UUID\0", 16);
115 }
116 unsigned int maxGroupIndex = 0;
117 unsigned int *firstPresentationSubstreamGroupIndexes = NULL;
118 unsigned int firstPresentationNSubstreamGroups = 0;
119
120 if (m_NPresentations > 0){
121 m_PresentationV1= new AP4_Dac4Atom::Ac4Dsi::PresentationV1[m_NPresentations];
122 AP4_SetMemory(m_PresentationV1, 0, m_NPresentations * sizeof(m_PresentationV1[0]));
123 } else {
124 m_PresentationV1 = NULL;
125 }
126 // ac4_presentation_v1_info()
127 for (unsigned int pres_idx = 0; pres_idx < m_NPresentations; pres_idx++){
128 AP4_Dac4Atom::Ac4Dsi::PresentationV1& presentation = m_PresentationV1[pres_idx];
129 presentation.ParsePresentationV1Info(bits,
130 m_BitstreamVersion,
131 m_FrameRateIndex,
132 pres_idx,
133 maxGroupIndex,
134 &firstPresentationSubstreamGroupIndexes,
135 firstPresentationNSubstreamGroups);
136 }
137 unsigned int bObjorAjoc = 0;
138 unsigned int channelCount = 0;
139 unsigned int speakerGroupIndexMask = 0;
140 AP4_Dac4Atom::Ac4Dsi::SubStreamGroupV1 *substream_groups = new AP4_Dac4Atom::Ac4Dsi::SubStreamGroupV1[maxGroupIndex + 1];
141 AP4_SetMemory(substream_groups, 0, (maxGroupIndex + 1) * sizeof(substream_groups[0]));
142 for (unsigned int sg = 0 ; (sg < (maxGroupIndex + 1)) && (m_NPresentations > 0); sg ++) {
143 AP4_Dac4Atom::Ac4Dsi::SubStreamGroupV1 &substream_group = substream_groups[sg];
144 AP4_Result pres_index = GetPresentationIndexBySGIndex(sg);
145 if (pres_index == AP4_FAILURE) {
146 break;
147 }
148 unsigned int localChannelCount = 0;
149 unsigned int frame_rate_factor = (m_PresentationV1[pres_index].d.v1.dsi_frame_rate_multiply_info == 0)? 1: (m_PresentationV1[pres_index].d.v1.dsi_frame_rate_multiply_info * 2);
150 substream_group.ParseSubstreamGroupInfo(bits,
151 m_BitstreamVersion,
152 GetPresentationVersionBySGIndex(sg),
153 Ap4_Ac4SubstreamGroupPartOfDefaultPresentation(sg, firstPresentationSubstreamGroupIndexes, firstPresentationNSubstreamGroups),
154 frame_rate_factor,
155 m_FsIndex,
156 localChannelCount,
157 speakerGroupIndexMask,
158 bObjorAjoc);
159 if (channelCount < localChannelCount) { channelCount = localChannelCount;}
160 }
161
162 for (unsigned int pres_idx = 0; pres_idx < m_NPresentations; pres_idx++){
163 m_PresentationV1[pres_idx].d.v1.substream_groups = new AP4_Dac4Atom::Ac4Dsi::SubStreamGroupV1[m_PresentationV1[pres_idx].d.v1.n_substream_groups];
164 for (unsigned int sg = 0; sg < m_PresentationV1[pres_idx].d.v1.n_substream_groups; sg++){
165 // TODO: Default Copy Construct Function
166 m_PresentationV1[pres_idx].d.v1.substream_groups[sg] = substream_groups[m_PresentationV1[pres_idx].d.v1.substream_group_indexs[sg]];
167 m_PresentationV1[pres_idx].d.v1.dolby_atmos_indicator |= m_PresentationV1[pres_idx].d.v1.substream_groups[sg].d.v1.dolby_atmos_indicator;
168 }
169 }
170 delete[] substream_groups;
171
172 if (bObjorAjoc == 0){
173 m_ChannelCount = AP4_Ac4ChannelCountFromSpeakerGroupIndexMask(speakerGroupIndexMask);
174 }else {
175 m_ChannelCount = channelCount;
176 }
177 }
178 }
179
180 /*----------------------------------------------------------------------+
181 | AP4_Ac4Header::MatchFixed
182 |
183 | Check that two fixed headers are the same
184 |
185 +----------------------------------------------------------------------*/
186 bool
187 AP4_Ac4Header::MatchFixed(AP4_Ac4Header& frame, AP4_Ac4Header& next_frame)
188 {
189 // Some parameter shall be const which defined in AC-4 in ISO-BMFF specs
190 // TODO: More constraints will be added
191 if ((frame.m_FsIndex == next_frame.m_FsIndex) &&
192 (frame.m_FrameRateIndex == next_frame.m_FrameRateIndex)){
193 return true;
194 }else {
195 return false;
196 }
197
198 }
199
200 /*----------------------------------------------------------------------+
201 | AP4_Ac4Header::Check
202 +----------------------------------------------------------------------*/
203 AP4_Result
204 AP4_Ac4Header::Check()
205 {
206 // Bitstream version
207 if (m_BitstreamVersion != 2) {
208 return AP4_FAILURE;
209 }
210 if ((m_FsIndex == 0 && m_FrameRateIndex != 13) || (m_FsIndex == 1 && m_FrameRateIndex >13)){
211 return AP4_FAILURE;
212 }
213
214 return AP4_SUCCESS;
215 }
216
217 /*----------------------------------------------------------------------+
218 | AP4_Ac4Header::GetPresentationVersionBySGIndex
219 +----------------------------------------------------------------------*/
220 AP4_Result
221 AP4_Ac4Header::GetPresentationVersionBySGIndex(unsigned int substream_group_index)
222 {
223 for (unsigned int idx = 0; idx < m_NPresentations; idx++){
224 for (unsigned int sg = 0; sg < m_PresentationV1[idx].d.v1.n_substream_groups; sg++){
225 if (substream_group_index == m_PresentationV1[idx].d.v1.substream_group_indexs[sg]) {
226 return m_PresentationV1[idx].presentation_version;
227 }
228 }
229 }
230 return AP4_FAILURE;
231 }
232
233 /*----------------------------------------------------------------------+
234 | AP4_Ac4Header::GetPresentationIndexBySGIndex
235 +----------------------------------------------------------------------*/
236 AP4_Result
237 AP4_Ac4Header::GetPresentationIndexBySGIndex(unsigned int substream_group_index)
238 {
239 for (unsigned int idx = 0; idx < m_NPresentations; idx++){
240 for (unsigned int sg = 0; sg < m_PresentationV1[idx].d.v1.n_substream_groups; sg++){
241 if (substream_group_index == m_PresentationV1[idx].d.v1.substream_group_indexs[sg]) {
242 return idx;
243 }
244 }
245 }
246 return AP4_FAILURE;
247 }
248
249 /*----------------------------------------------------------------------+
250 | AP4_Ac4Parser::AP4_Ac4Parser
251 +----------------------------------------------------------------------*/
252 AP4_Ac4Parser::AP4_Ac4Parser() :
253 m_FrameCount(0)
254 {
255 }
256
257 /*----------------------------------------------------------------------+
258 | AP4_Ac4Parser::~AP4_Ac4Parser
259 +----------------------------------------------------------------------*/
260 AP4_Ac4Parser::~AP4_Ac4Parser()
261 {
262 }
263
264 /*----------------------------------------------------------------------+
265 | AP4_Ac4Parser::Reset
266 +----------------------------------------------------------------------*/
267 AP4_Result
268 AP4_Ac4Parser::Reset()
269 {
270 m_FrameCount = 0;
271
272 return AP4_SUCCESS;
273 }
274
275 /*----------------------------------------------------------------------+
276 | AP4_Ac4Parser::Feed
277 +----------------------------------------------------------------------*/
278 AP4_Result
279 AP4_Ac4Parser::Feed(const AP4_UI08* buffer,
280 AP4_Size* buffer_size,
281 AP4_Flags flags)
282 {
283 AP4_Size free_space;
284
285 /* update flags */
286 m_Bits.m_Flags = flags;
287
288 /* possible shortcut */
289 if (buffer == NULL ||
290 buffer_size == NULL ||
291 *buffer_size == 0) {
292 return AP4_SUCCESS;
293 }
294
295 /* see how much data we can write */
296 free_space = m_Bits.GetBytesFree();
297 if (*buffer_size > free_space) *buffer_size = free_space;
298 if (*buffer_size == 0) return AP4_SUCCESS;
299
300 /* write the data */
301 return m_Bits.WriteBytes(buffer, *buffer_size);
302 }
303
304 /*----------------------------------------------------------------------+
305 | AP4_Ac4Parser::FindHeader
306 +----------------------------------------------------------------------*/
307 AP4_Result
308 AP4_Ac4Parser::FindHeader(AP4_UI08* header)
309 {
310 AP4_Size available = m_Bits.GetBytesAvailable();
311
312 /* look for the sync pattern */
313 while (available-- >= AP4_AC4_HEADER_SIZE) {
314 m_Bits.PeekBytes(header, 2);
315
316 if ((((header[0] << 8) | header[1]) == AP4_AC4_SYNC_WORD_CRC) || (((header[0] << 8) | header[1]) == AP4_AC4_SYNC_WORD)) {
317 /* found a sync pattern, read the entire the header */
318 m_Bits.PeekBytes(header, AP4_AC4_HEADER_SIZE);
319
320 return AP4_SUCCESS;
321 } else {
322 m_Bits.SkipBytes(1);
323 }
324 }
325
326 return AP4_ERROR_NOT_ENOUGH_DATA;
327 }
328 /*----------------------------------------------------------------------+
329 | AP4_Ac4Parser::GetSyncFrameSize
330 +----------------------------------------------------------------------*/
331 AP4_UI32
332 AP4_Ac4Parser::GetSyncFrameSize(AP4_BitReader &bits)
333 {
334 unsigned int sync_word = bits.ReadBits(16);
335 unsigned int frame_size = bits.ReadBits(16);
336 unsigned int head_size = 4;
337 if (frame_size == 0xFFFF){
338 frame_size = bits.ReadBits(24);
339 head_size += 3;
340 }
341 if (sync_word == AP4_AC4_SYNC_WORD_CRC) {
342 head_size += 2;
343 }
344 return (head_size + frame_size);
345 }
346
347 /*----------------------------------------------------------------------+
348 | AP4_Ac4Parser::FindFrame
349 +----------------------------------------------------------------------*/
350 AP4_Result
351 AP4_Ac4Parser::FindFrame(AP4_Ac4Frame& frame)
352 {
353 unsigned int available;
354 unsigned char *raw_header = new unsigned char[AP4_AC4_HEADER_SIZE];
355 AP4_Result result;
356
357 /* align to the start of the next byte */
358 m_Bits.ByteAlign();
359
360 /* find a frame header */
361 result = FindHeader(raw_header);
362 if (AP4_FAILED(result)) return result;
363
364 // duplicated work, just to get the frame size
365 AP4_BitReader tmp_bits(raw_header, AP4_AC4_HEADER_SIZE);
366 unsigned int sync_frame_size = GetSyncFrameSize(tmp_bits);
367 if (sync_frame_size > (AP4_BITSTREAM_BUFFER_SIZE - 1)) {
368 return AP4_ERROR_NOT_ENOUGH_DATA;
369 }
370
371 delete[] raw_header;
372 raw_header = new unsigned char[sync_frame_size];
373 /*
374 * Error handling to skip the 'fake' sync word.
375 * - the maximum sync frame size is about (AP4_BITSTREAM_BUFFER_SIZE - 1) bytes.
376 */
377 if (m_Bits.GetBytesAvailable() < sync_frame_size ) {
378 if (m_Bits.GetBytesAvailable() == (AP4_BITSTREAM_BUFFER_SIZE - 1)) {
379 // skip the sync word, assume it's 'fake' sync word
380 m_Bits.SkipBytes(2);
381 }
382 return AP4_ERROR_NOT_ENOUGH_DATA;
383 }
384 // copy the whole frame becasue toc size is unknown
385 m_Bits.PeekBytes(raw_header, sync_frame_size);
386 /* parse the header */
387 AP4_Ac4Header ac4_header(raw_header, sync_frame_size);
388
389 // Place before goto statement to resolve Xcode compiler issue
390 unsigned int bit_rate_mode = 0;
391
392 /* check the header */
393 result = ac4_header.Check();
394 if (AP4_FAILED(result)) {
395 m_Bits.SkipBytes(sync_frame_size);
396 goto fail;
397 }
398
399 /* check if we have enough data to peek at the next header */
400 available = m_Bits.GetBytesAvailable();
401 // TODO: find the proper AP4_AC4_MAX_TOC_SIZE or just parse what this step need ?
402 if (available >= ac4_header.m_FrameSize + ac4_header.m_HeaderSize + ac4_header.m_CrcSize + AP4_AC4_HEADER_SIZE + AP4_AC4_MAX_TOC_SIZE) {
403 // enough to peek at the header of the next frame
404 unsigned char *peek_raw_header = new unsigned char[AP4_AC4_HEADER_SIZE];
405
406 m_Bits.SkipBytes(ac4_header.m_FrameSize + ac4_header.m_HeaderSize + ac4_header.m_CrcSize);
407 m_Bits.PeekBytes(peek_raw_header, AP4_AC4_HEADER_SIZE);
408
409 // duplicated work, just to get the frame size
410 AP4_BitReader peak_tmp_bits(peek_raw_header, AP4_AC4_HEADER_SIZE);
411 unsigned int peak_sync_frame_size = GetSyncFrameSize(peak_tmp_bits);
412
413 delete[] peek_raw_header;
414 peek_raw_header = new unsigned char[peak_sync_frame_size];
415 // copy the whole frame becasue toc size is unknown
416 if (m_Bits.GetBytesAvailable() < (peak_sync_frame_size)) {
417 peak_sync_frame_size = m_Bits.GetBytesAvailable();
418 }
419 m_Bits.PeekBytes(peek_raw_header, peak_sync_frame_size);
420
421 m_Bits.SkipBytes(-((int)(ac4_header.m_FrameSize + ac4_header.m_HeaderSize + ac4_header.m_CrcSize)));
422
423 /* check the header */
424 AP4_Ac4Header peek_ac4_header(peek_raw_header, peak_sync_frame_size);
425 result = peek_ac4_header.Check();
426 if (AP4_FAILED(result)) {
427 // TODO: need to reserve current sync frame ?
428 m_Bits.SkipBytes(sync_frame_size + peak_sync_frame_size);
429 goto fail;
430 }
431
432 /* check that the fixed part of this header is the same as the */
433 /* fixed part of the previous header */
434 if (!AP4_Ac4Header::MatchFixed(ac4_header, peek_ac4_header)) {
435 // TODO: need to reserve current sync frame ?
436 m_Bits.SkipBytes(sync_frame_size + peak_sync_frame_size);
437 goto fail;
438 }
439 } else if (available < (ac4_header.m_FrameSize + ac4_header.m_HeaderSize + ac4_header.m_CrcSize) || (m_Bits.m_Flags & AP4_BITSTREAM_FLAG_EOS) == 0) {
440 // not enough for a frame, or not at the end (in which case we'll want to peek at the next header)
441 return AP4_ERROR_NOT_ENOUGH_DATA;
442 }
443
444 m_Bits.SkipBytes(ac4_header.m_HeaderSize);
445
446 /* fill in the frame info */
447 frame.m_Info.m_HeaderSize = ac4_header.m_HeaderSize;
448 frame.m_Info.m_FrameSize = ac4_header.m_FrameSize;
449 frame.m_Info.m_CRCSize = ac4_header.m_CrcSize;
450 frame.m_Info.m_ChannelCount = ac4_header.m_ChannelCount;
451 frame.m_Info.m_SampleDuration = (ac4_header.m_FsIndex == 0)? 2048 : AP4_Ac4SampleDeltaTable [ac4_header.m_FrameRateIndex];
452 frame.m_Info.m_MediaTimeScale = (ac4_header.m_FsIndex == 0)? 44100: AP4_Ac4MediaTimeScaleTable[ac4_header.m_FrameRateIndex];
453 frame.m_Info.m_Iframe = ac4_header.m_BIframeGlobal;
454
455 /* fill the AC4 DSI info */
456 frame.m_Info.m_Ac4Dsi.ac4_dsi_version = 1;
457 frame.m_Info.m_Ac4Dsi.d.v1.bitstream_version = ac4_header.m_BitstreamVersion;
458 frame.m_Info.m_Ac4Dsi.d.v1.fs_index = ac4_header.m_FsIndex;
459 frame.m_Info.m_Ac4Dsi.d.v1.fs = AP4_Ac4SamplingFrequencyTable[frame.m_Info.m_Ac4Dsi.d.v1.fs_index];
460 frame.m_Info.m_Ac4Dsi.d.v1.frame_rate_index = ac4_header.m_FrameRateIndex;
461 frame.m_Info.m_Ac4Dsi.d.v1.b_program_id = ac4_header.m_BProgramId;
462 frame.m_Info.m_Ac4Dsi.d.v1.short_program_id = ac4_header.m_ShortProgramId;
463 frame.m_Info.m_Ac4Dsi.d.v1.b_uuid = ac4_header.m_BProgramUuidPresent;
464 AP4_CopyMemory(frame.m_Info.m_Ac4Dsi.d.v1.program_uuid, ac4_header.m_ProgramUuid, 16);
465
466 // Calcuate the bit rate mode according to ETSI TS 103 190-2 V1.2.1 Annex B
467 if (ac4_header.m_WaitFrames == 0) { bit_rate_mode = 1;}
468 else if (ac4_header.m_WaitFrames >= 1 && ac4_header.m_WaitFrames <= 6) { bit_rate_mode = 2;}
469 else if (ac4_header.m_WaitFrames > 6) { bit_rate_mode = 3;}
470
471 frame.m_Info.m_Ac4Dsi.d.v1.ac4_bitrate_dsi.bit_rate_mode = bit_rate_mode;
472 frame.m_Info.m_Ac4Dsi.d.v1.ac4_bitrate_dsi.bit_rate = 0; // unknown, fixed value now
473 frame.m_Info.m_Ac4Dsi.d.v1.ac4_bitrate_dsi.bit_rate_precision = 0xffffffff; // unknown, fixed value now
474 frame.m_Info.m_Ac4Dsi.d.v1.n_presentations = ac4_header.m_NPresentations;
475 frame.m_Info.m_Ac4Dsi.d.v1.presentations = ac4_header.m_PresentationV1;
476
477 /* set the frame source */
478 frame.m_Source = &m_Bits;
479
480 return AP4_SUCCESS;
481
482 fail:
483 /* skip the header and return (only skip the first byte in */
484 /* case this was a false header that hides one just after) */
485 return AP4_ERROR_CORRUPTED_BITSTREAM;
486 }
487
488 /*----------------------------------------------------------------------+
489 | AP4_Ac4Parser::GetBytesFree
490 +----------------------------------------------------------------------*/
491 AP4_Size
492 AP4_Ac4Parser::GetBytesFree()
493 {
494 return (m_Bits.GetBytesFree());
495 }
496
497 /*----------------------------------------------------------------------+
498 | AP4_Ac4Parser::GetBytesAvailable
499 +----------------------------------------------------------------------*/
500 AP4_Size
501 AP4_Ac4Parser::GetBytesAvailable()
502 {
503 return (m_Bits.GetBytesAvailable());
504 }
0 /*****************************************************************
1 |
2 | AP4 - AC4 Sync Frame Parser
3 |
4 | Copyright 2002-2020 Axiomatic Systems, LLC
5 |
6 |
7 | This file is part of Bento4/AP4 (MP4 Atom Processing Library).
8 |
9 | Unless you have obtained Bento4 under a difference license,
10 | this version of Bento4 is Bento4|GPL.
11 | Bento4|GPL is free software; you can redistribute it and/or modify
12 | it under the terms of the GNU General Public License as published by
13 | the Free Software Foundation; either version 2, or (at your option)
14 | any later version.
15 |
16 | Bento4|GPL is distributed in the hope that it will be useful,
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | GNU General Public License for more details.
20 |
21 | You should have received a copy of the GNU General Public License
22 | along with Bento4|GPL; see the file COPYING. If not, write to the
23 | Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
24 | 02111-1307, USA.
25 |
26 ****************************************************************/
27
28 #ifndef _AP4_AC4_PARSER_H_
29 #define _AP4_AC4_PARSER_H_
30
31 /*----------------------------------------------------------------------
32 | includes
33 +---------------------------------------------------------------------*/
34 #include "Ap4Types.h"
35 #include "Ap4BitStream.h"
36 #include "Ap4Dac4Atom.h"
37
38 /*----------------------------------------------------------------------
39 | constants
40 +---------------------------------------------------------------------*/
41 #define AP4_AC4_HEADER_SIZE 7 /* The header size for AC-4 parser, only include (sync word + frame size) */
42 #define AP4_AC4_MAX_TOC_SIZE 512 /* Ths assumption of max toc size */
43 #define AP4_AC4_SYNC_WORD 0xAC40 /* 16 sync bits without CRC */
44 #define AP4_AC4_SYNC_WORD_CRC 0xAC41 /* 16 sync bits with CRC */
45
46 /*----------------------------------------------------------------------
47 | types
48 +---------------------------------------------------------------------*/
49 class AP4_Ac4Header {
50 public:
51 // constructor
52 AP4_Ac4Header(const AP4_UI08* bytes, unsigned int size);
53
54 // methods
55 AP4_Result Check();
56
57 // AC-4 Sync Frame Inforamtion
58 AP4_UI32 m_SyncWord;
59 AP4_UI32 m_HeaderSize;
60 AP4_UI32 m_FrameSize;
61 AP4_UI32 m_CrcSize;
62
63 // AC-4 Channel Count
64 AP4_UI32 m_ChannelCount;
65
66 // Ac-4 General/High Level TOC Information
67 AP4_UI32 m_BitstreamVersion;
68 AP4_UI32 m_SequenceCounter;
69 AP4_UI32 m_BWaitFrames;
70 AP4_UI32 m_WaitFrames;
71 AP4_UI32 m_BrCode;
72 AP4_UI32 m_FsIndex;
73 AP4_UI32 m_FrameRateIndex;
74 AP4_UI32 m_BIframeGlobal;
75 AP4_UI32 m_BSinglePresentation;
76 AP4_UI32 m_BMorePresentations;
77 AP4_UI32 m_NPresentations;
78 AP4_UI32 m_BPayloadBase;
79 AP4_UI32 m_PayloadBase;
80 AP4_UI32 m_BProgramId;
81 AP4_UI32 m_ShortProgramId;
82 AP4_UI32 m_BProgramUuidPresent;
83 AP4_Byte m_ProgramUuid[16];
84
85 static bool m_DeprecatedV0;
86
87 // AC-4 Presentation Information
88 AP4_Dac4Atom::Ac4Dsi::PresentationV1 *m_PresentationV1;
89 // class methods
90 static bool MatchFixed(AP4_Ac4Header& frame, AP4_Ac4Header& next_frame);
91
92 private:
93 AP4_Result GetPresentationVersionBySGIndex(unsigned int substream_group_index);
94 AP4_Result GetPresentationIndexBySGIndex (unsigned int substream_group_index);
95 };
96
97 typedef struct {
98 AP4_UI32 m_HeaderSize;
99 AP4_UI32 m_FrameSize;
100 AP4_UI32 m_CRCSize;
101 AP4_UI32 m_ChannelCount;
102 AP4_UI32 m_SampleDuration;
103 AP4_UI32 m_MediaTimeScale;
104 AP4_UI32 m_Iframe;
105 AP4_Dac4Atom::Ac4Dsi m_Ac4Dsi;
106 } AP4_Ac4FrameInfo;
107
108 typedef struct {
109 AP4_BitStream* m_Source;
110 AP4_Ac4FrameInfo m_Info;
111 } AP4_Ac4Frame;
112
113 class AP4_Ac4Parser {
114 public:
115 // constructor and destructor
116 AP4_Ac4Parser();
117 virtual ~AP4_Ac4Parser();
118
119 // methods
120 AP4_Result Reset();
121 AP4_Result Feed(const AP4_UI08* buffer,
122 AP4_Size* buffer_size,
123 AP4_Flags flags = 0);
124 AP4_Result FindFrame(AP4_Ac4Frame& frame);
125 AP4_Result Skip(AP4_Size size);
126 AP4_Size GetBytesFree();
127 AP4_Size GetBytesAvailable();
128
129 private:
130 // methods
131 AP4_Result FindHeader(AP4_UI08* header);
132 AP4_UI32 GetSyncFrameSize(AP4_BitReader &bits);
133
134 // members
135 AP4_BitStream m_Bits;
136 AP4_Cardinal m_FrameCount;
137 };
138
139 #endif // _AP4_AC4_PARSER_H_
3939 #define AP4_ADTS_SYNC_MASK 0xFFF6 /* 12 sync bits plus 2 layer bits */
4040 #define AP4_ADTS_SYNC_PATTERN 0xFFF0 /* 12 sync bits=1 layer=0 */
4141
42 const unsigned long
42 const AP4_UI32
4343 AP4_AdtsSamplingFrequencyTable[16] =
4444 {
4545 96000,
3737 /*----------------------------------------------------------------------
3838 | constants
3939 +---------------------------------------------------------------------*/
40 extern const unsigned long AP4_AdtsSamplingFrequencyTable[16];
40 extern const AP4_UI32 AP4_AdtsSamplingFrequencyTable[16];
4141
4242 /*----------------------------------------------------------------------
4343 | types
8383 AP4_AacStandard m_Standard;
8484 AP4_AacProfile m_Profile;
8585 unsigned int m_SamplingFrequencyIndex;
86 unsigned long m_SamplingFrequency;
86 AP4_UI32 m_SamplingFrequency;
8787 unsigned int m_ChannelConfiguration;
8888 unsigned int m_FrameLength;
8989 } AP4_AacFrameInfo;
3333 /*----------------------------------------------------------------------
3434 | debugging
3535 +---------------------------------------------------------------------*/
36 //#define AP4_AVC_PARSER_ENABLE_DEBUG
3637 #if defined(AP4_AVC_PARSER_ENABLE_DEBUG)
3738 #define DBG_PRINTF_0(_x0) printf(_x0)
3839 #define DBG_PRINTF_1(_x0, _x1) printf(_x0, _x1)
7475 case 15: return "Subset sequence parameter set";
7576 case 19: return "Coded slice of an auxiliary coded picture without partitioning";
7677 case 20: return "Coded slice in scalable extension";
78 case 28: return "Dolby Vision RPU NAL units";
79 case 30: return "Dolby Vision EL NAL units";
7780 default: return NULL;
7881 }
7982 }
117120 default: return NULL;
118121 }
119122 }
120
121123
122124 const int SAR[17][2] = {
123125 { 0, 1 },
138140 { 3, 2 },
139141 { 2, 1 },
140142 };
141
142143 /*----------------------------------------------------------------------
143144 | AP4_AvcNalParser::AP4_AvcNalParser
144145 +---------------------------------------------------------------------*/
179180 }
180181
181182 delete m_SliceHeader;
183
184 // cleanup any un-transfered buffers
185 for (unsigned int i=0; i<m_AccessUnitData.ItemCount(); i++) {
186 delete m_AccessUnitData[i];
187 }
188 }
189
190 /*----------------------------------------------------------------------
191 | ReadGolomb
192 +---------------------------------------------------------------------*/
193 unsigned int
194 AP4_AvcFrameParser::ReadGolomb(AP4_BitReader& bits)
195 {
196 unsigned int leading_zeros = 0;
197 while (bits.ReadBit() == 0) {
198 leading_zeros++;
199 if (leading_zeros > 32) return 0; // safeguard
200 }
201 if (leading_zeros) {
202 return (1<<leading_zeros)-1+bits.ReadBits(leading_zeros);
203 } else {
204 return 0;
205 }
206 }
207
208 /*----------------------------------------------------------------------
209 | SignedGolomb
210 +---------------------------------------------------------------------*/
211 int
212 AP4_AvcFrameParser::SignedGolomb(unsigned int code_num)
213 {
214 if (code_num % 2) {
215 return (code_num+1)/2;
216 } else {
217 return -((int)code_num/2);
218 }
182219 }
183220
184221 /*----------------------------------------------------------------------
192229 constraint_set3_flag(0),
193230 level_idc(0),
194231 seq_parameter_set_id(0),
195 chroma_format_idc(0),
232 chroma_format_idc(1),
196233 separate_colour_plane_flag(0),
197234 bit_depth_luma_minus8(0),
198235 bit_depth_chroma_minus8(0),
247284 }
248285
249286 /*----------------------------------------------------------------------
250 | ReadGolomb
251 +---------------------------------------------------------------------*/
252 unsigned int
253 AP4_AvcFrameParser::ReadGolomb(AP4_BitReader& bits)
254 {
255 unsigned int leading_zeros = 0;
256 while (bits.ReadBit() == 0) {
257 leading_zeros++;
258 if (leading_zeros > 32) return 0; // safeguard
259 }
260 if (leading_zeros) {
261 return (1 << leading_zeros) - 1 + bits.ReadBits(leading_zeros);
262 }
263 else {
264 return 0;
265 }
266 }
267
268 /*----------------------------------------------------------------------
269 | ReadGolomb
270 +---------------------------------------------------------------------*/
271 int
272 AP4_AvcFrameParser::SignedGolomb(unsigned int code_num)
273 {
274 if (code_num % 2) {
275 return (code_num + 1) / 2;
276 }
277 else {
278 return -((int)code_num / 2);
279 }
280 }
281
282 /*----------------------------------------------------------------------
283287 | AP4_AvcSequenceParameterSet::GetInfo
284288 +---------------------------------------------------------------------*/
285289 bool
289293 unsigned int nheight = (2-frame_mbs_only_flag) * (pic_height_in_map_units_minus1+1) * 16;
290294
291295 if (frame_cropping_flag) {
292 unsigned int crop_h = 2*(frame_crop_left_offset+frame_crop_right_offset);
293 unsigned int crop_v = 2*(frame_crop_top_offset+frame_crop_bottom_offset)*(2-frame_mbs_only_flag);
294 if (crop_h < nwidth) nwidth -= crop_h;
295 if (crop_v < nheight) nheight -= crop_v;
296 }
296 unsigned int crop_h = 2*(frame_crop_left_offset+frame_crop_right_offset);
297 unsigned int crop_v = 2*(frame_crop_top_offset+frame_crop_bottom_offset)*(2-frame_mbs_only_flag);
298 if (crop_h < nwidth) nwidth -= crop_h;
299 if (crop_v < nheight) nheight -= crop_v;
300 }
297301 if (nwidth != width || nheight != height)
298302 {
299 width = nwidth;
300 height = nheight;
301 return true;
303 width = nwidth;
304 height = nheight;
305 return true;
302306 }
303307 return false;
304308 }
332336 return ret;
333337 }
334338
335
336339 /*----------------------------------------------------------------------
337340 | AP4_AvcFrameParser::ParseSPS
338341 +---------------------------------------------------------------------*/
339342 AP4_Result
340 AP4_AvcFrameParser::ParseSPS(const unsigned char* data, unsigned int data_size, AP4_AvcSequenceParameterSet& sps)
343 AP4_AvcFrameParser::ParseSPS(const unsigned char* data,
344 unsigned int data_size,
345 AP4_AvcSequenceParameterSet& sps)
341346 {
342347 sps.raw_bytes.SetData(data, data_size);
343348 AP4_DataBuffer unescaped(data, data_size);
473478 }
474479 }
475480
481
476482 sps.chroma_loc_info_present_flag = bits.ReadBit();
477483 if (sps.chroma_loc_info_present_flag) {
478484 sps.chroma_sample_loc_type_top_field = ReadGolomb(bits);
479485 sps.chroma_sample_loc_type_bottom_field = ReadGolomb(bits);
480486 }
481487
482 if(bits.PeekBit() && bits.BitsLeft() < 10)
488 if (bits.PeekBit() && bits.BitsLeft() < 10)
483489 return AP4_SUCCESS;
484490
485491 sps.timing_info_present_flag = bits.ReadBit();
534540 | AP4_AvcFrameParser::ParsePPS
535541 +---------------------------------------------------------------------*/
536542 AP4_Result
537 AP4_AvcFrameParser::ParsePPS(const unsigned char* data, unsigned int data_size, AP4_AvcPictureParameterSet& pps)
543 AP4_AvcFrameParser::ParsePPS(const unsigned char* data,
544 unsigned int data_size,
545 AP4_AvcPictureParameterSet& pps)
538546 {
539547 pps.raw_bytes.SetData(data, data_size);
540548 AP4_DataBuffer unescaped(data, data_size);
609617 | AP4_AvcSliceHeader::AP4_AvcSliceHeader
610618 +---------------------------------------------------------------------*/
611619 AP4_AvcSliceHeader::AP4_AvcSliceHeader() :
620 size(0),
612621 first_mb_in_slice(0),
613622 slice_type(0),
614623 pic_parameter_set_id(0),
618627 bottom_field_flag(0),
619628 idr_pic_id(0),
620629 pic_order_cnt_lsb(0),
621 redundant_pic_cnt(0)
630 redundant_pic_cnt(0),
631 direct_spatial_mv_pred_flag(0),
632 num_ref_idx_active_override_flag(0),
633 num_ref_idx_l0_active_minus1(0),
634 num_ref_idx_l1_active_minus1(0),
635 ref_pic_list_reordering_flag_l0(0),
636 reordering_of_pic_nums_idc(0),
637 abs_diff_pic_num_minus1(0),
638 long_term_pic_num(0),
639 ref_pic_list_reordering_flag_l1(0),
640 luma_log2_weight_denom(0),
641 chroma_log2_weight_denom(0),
642 cabac_init_idc(0),
643 slice_qp_delta(0),
644 sp_for_switch_flag(0),
645 slice_qs_delta(0),
646 disable_deblocking_filter_idc(0),
647 slice_alpha_c0_offset_div2(0),
648 slice_beta_offset_div2(0),
649 slice_group_change_cycle(0),
650 no_output_of_prior_pics_flag(0),
651 long_term_reference_flag(0),
652 difference_of_pic_nums_minus1(0),
653 long_term_frame_idx(0),
654 max_long_term_frame_idx_plus1(0)
622655 {
623656 delta_pic_order_cnt[0] = delta_pic_order_cnt[1] = 0;
624657 }
627660 | AP4_AvcFrameParser::ParseSliceHeader
628661 +---------------------------------------------------------------------*/
629662 AP4_Result
630 AP4_AvcFrameParser::ParseSliceHeader(const AP4_UI08* data,
631 unsigned int data_size,
632 unsigned int nal_unit_type,
633 AP4_AvcSliceHeader& slice_header)
663 AP4_AvcFrameParser::ParseSliceHeader(const AP4_UI08* data,
664 unsigned int data_size,
665 unsigned int nal_unit_type,
666 unsigned int nal_ref_idc,
667 AP4_AvcSliceHeader& slice_header)
634668 {
635669 AP4_DataBuffer unescaped(data, data_size);
636670 AP4_NalParser::Unescape(unescaped);
637671 AP4_BitReader bits(unescaped.GetData(), unescaped.GetDataSize());
638672
639 bits.SkipBits(8); // NAL Unit Type
640
673 // init the computer fields
674 slice_header.size = 0;
675
641676 slice_header.first_mb_in_slice = ReadGolomb(bits);
642677 slice_header.slice_type = ReadGolomb(bits);
643678 slice_header.pic_parameter_set_id = ReadGolomb(bits);
681716 slice_header.redundant_pic_cnt = ReadGolomb(bits);
682717 }
683718
684 /* skip the rest for now */
719 unsigned int slice_type = slice_header.slice_type % 5; // this seems to be implicit in the spec
720
721 if (slice_type == AP4_AVC_SLICE_TYPE_B) {
722 slice_header.direct_spatial_mv_pred_flag = bits.ReadBit();
723 }
724
725 if (slice_type == AP4_AVC_SLICE_TYPE_P ||
726 slice_type == AP4_AVC_SLICE_TYPE_SP ||
727 slice_type == AP4_AVC_SLICE_TYPE_B) {
728 slice_header.num_ref_idx_active_override_flag = bits.ReadBit();
729
730 if (slice_header.num_ref_idx_active_override_flag) {
731 slice_header.num_ref_idx_l0_active_minus1 = ReadGolomb(bits);
732 if ((slice_header.slice_type % 5) == AP4_AVC_SLICE_TYPE_B) {
733 slice_header.num_ref_idx_l1_active_minus1 = ReadGolomb(bits);
734 }
735 } else {
736 slice_header.num_ref_idx_l0_active_minus1 = pps->num_ref_idx_10_active_minus1;
737 slice_header.num_ref_idx_l1_active_minus1 = pps->num_ref_idx_11_active_minus1;
738 }
739 }
740
741 // ref_pic_list_reordering
742 if ((slice_header.slice_type % 5) != 2 && (slice_header.slice_type % 5) != 4) {
743 slice_header.ref_pic_list_reordering_flag_l0 = bits.ReadBit();
744 if (slice_header.ref_pic_list_reordering_flag_l0) {
745 do {
746 slice_header.reordering_of_pic_nums_idc = ReadGolomb(bits);
747 if (slice_header.reordering_of_pic_nums_idc == 0 ||
748 slice_header.reordering_of_pic_nums_idc == 1) {
749 slice_header.abs_diff_pic_num_minus1 = ReadGolomb(bits);
750 } else if (slice_header.reordering_of_pic_nums_idc == 2) {
751 slice_header.long_term_pic_num = ReadGolomb(bits);
752 }
753 } while (slice_header.reordering_of_pic_nums_idc != 3);
754 }
755 }
756 if ((slice_header.slice_type % 5) == 1) {
757 slice_header.ref_pic_list_reordering_flag_l1 = bits.ReadBit();
758 if (slice_header.ref_pic_list_reordering_flag_l1) {
759 do {
760 slice_header.reordering_of_pic_nums_idc = ReadGolomb(bits);
761 if (slice_header.reordering_of_pic_nums_idc == 0 ||
762 slice_header.reordering_of_pic_nums_idc == 1) {
763 slice_header.abs_diff_pic_num_minus1 = ReadGolomb(bits);
764 } else if (slice_header.reordering_of_pic_nums_idc == 2) {
765 slice_header.long_term_pic_num = ReadGolomb(bits);
766 }
767 } while (slice_header.reordering_of_pic_nums_idc != 3);
768 }
769 }
770
771 if ((pps->weighted_pred_flag &&
772 (slice_type == AP4_AVC_SLICE_TYPE_P || slice_type == AP4_AVC_SLICE_TYPE_SP)) ||
773 (pps->weighted_bipred_idc == 1 && slice_type == AP4_AVC_SLICE_TYPE_B)) {
774 // pred_weight_table
775 slice_header.luma_log2_weight_denom = ReadGolomb(bits);
776
777 if (sps->chroma_format_idc != 0) {
778 slice_header.chroma_log2_weight_denom = ReadGolomb(bits);
779 }
780
781 for (unsigned int i=0; i<=slice_header.num_ref_idx_l0_active_minus1; i++) {
782 unsigned int luma_weight_l0_flag = bits.ReadBit();
783 if (luma_weight_l0_flag) {
784 /* slice_header.luma_weight_l0[i] = SignedGolomb( */ ReadGolomb(bits);
785 /* slice_header.luma_offset_l0[i] = SignedGolomb( */ ReadGolomb(bits);
786 }
787 if (sps->chroma_format_idc != 0) {
788 unsigned int chroma_weight_l0_flag = bits.ReadBit();
789 if (chroma_weight_l0_flag) {
790 for (unsigned int j=0; j<2; j++) {
791 /* slice_header.chroma_weight_l0[i][j] = SignedGolomb( */ ReadGolomb(bits);
792 /* slice_header.chroma_offset_l0[i][j] = SignedGolomb( */ ReadGolomb(bits);
793 }
794 }
795 }
796 }
797 if ((slice_header.slice_type % 5) == 1) {
798 for (unsigned int i=0; i<=slice_header.num_ref_idx_l1_active_minus1; i++) {
799 unsigned int luma_weight_l1_flag = bits.ReadBit();
800 if (luma_weight_l1_flag) {
801 /* slice_header.luma_weight_l1[i] = SignedGolomb( */ ReadGolomb(bits);
802 /* slice_header.luma_offset_l1[i] = SignedGolomb( */ ReadGolomb(bits);
803 }
804 if (sps->chroma_format_idc != 0) {
805 unsigned int chroma_weight_l1_flag = bits.ReadBit();
806 if (chroma_weight_l1_flag) {
807 for (unsigned int j=0; j<2; j++) {
808 /* slice_header.chroma_weight_l1[i][j] = SignedGolomb( */ ReadGolomb(bits);
809 /* slice_header.chroma_offset_l1[i][j] = SignedGolomb( */ ReadGolomb(bits);
810 }
811 }
812 }
813 }
814 }
815 }
816
817 if (nal_ref_idc != 0) {
818 // dec_ref_pic_marking
819 if (nal_unit_type == AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_OF_IDR_PICTURE) {
820 slice_header.no_output_of_prior_pics_flag = bits.ReadBit();
821 slice_header.long_term_reference_flag = bits.ReadBit();
822 } else {
823 unsigned int adaptive_ref_pic_marking_mode_flag = bits.ReadBit();
824 if (adaptive_ref_pic_marking_mode_flag) {
825 unsigned int memory_management_control_operation = 0;
826 do {
827 memory_management_control_operation = ReadGolomb(bits);
828 if (memory_management_control_operation == 1 || memory_management_control_operation == 3) {
829 slice_header.difference_of_pic_nums_minus1 = ReadGolomb(bits);
830 }
831 if (memory_management_control_operation == 2) {
832 slice_header.long_term_pic_num = ReadGolomb(bits);
833 }
834 if (memory_management_control_operation == 3 || memory_management_control_operation == 6) {
835 slice_header.long_term_frame_idx = ReadGolomb(bits);
836 }
837 if (memory_management_control_operation == 4) {
838 slice_header.max_long_term_frame_idx_plus1 = ReadGolomb(bits);
839 }
840 } while (memory_management_control_operation != 0);
841 }
842 }
843 }
844 if (pps->entropy_coding_mode_flag && slice_type != AP4_AVC_SLICE_TYPE_I && slice_type != AP4_AVC_SLICE_TYPE_SI) {
845 slice_header.cabac_init_idc = ReadGolomb(bits);
846 }
847 slice_header.slice_qp_delta = ReadGolomb(bits);
848 if (slice_type == AP4_AVC_SLICE_TYPE_SP || slice_type == AP4_AVC_SLICE_TYPE_SI) {
849 if (slice_type == AP4_AVC_SLICE_TYPE_SP) {
850 slice_header.sp_for_switch_flag = bits.ReadBit();
851 }
852 slice_header.slice_qs_delta = SignedGolomb(ReadGolomb(bits));
853 }
854 if (pps->deblocking_filter_control_present_flag) {
855 slice_header.disable_deblocking_filter_idc = ReadGolomb(bits);
856 if (slice_header.disable_deblocking_filter_idc != 1) {
857 slice_header.slice_alpha_c0_offset_div2 = SignedGolomb(ReadGolomb(bits));
858 slice_header.slice_beta_offset_div2 = SignedGolomb(ReadGolomb(bits));
859 }
860 }
861 if (pps->num_slice_groups_minus1 > 0 &&
862 pps->slice_group_map_type >= 3 &&
863 pps->slice_group_map_type <= 5) {
864 slice_header.slice_group_change_cycle = ReadGolomb(bits);
865 }
866
867 /* compute the size */
868 slice_header.size = bits.GetBitsRead();
685869
686870 return AP4_SUCCESS;
687871 }
763947 return true;
764948 }
765949
766 #if defined(AP4_AVC_PARSER_ENABLE_DEBUG)
767 /*----------------------------------------------------------------------
768 | PrintSliceInfo
769 +---------------------------------------------------------------------*/
770 static void
771 PrintSliceInfo(const AP4_AvcSliceHeader& slice_header)
772 {
773 const char* slice_type_name = AP4_AvcNalParser::SliceTypeName(slice_header.slice_type);
774 if (slice_type_name == NULL) slice_type_name = "?";
775 DBG_PRINTF_4(" pps_id=%d, frame_num=%d, slice_type=%d (%s), ",
776 slice_header.pic_parameter_set_id,
777 slice_header.frame_num,
778 slice_header.slice_type,
779 slice_type_name);
780 }
781 #endif
782
783 /*----------------------------------------------------------------------
784 | AP4_AvcFrameParser::MaybeNewAccessUnit
950 /*----------------------------------------------------------------------
951 | AP4_AvcFrameParser::CheckIfAccessUnitIsCompleted
785952 +---------------------------------------------------------------------*/
786953 void
787 AP4_AvcFrameParser::MaybeNewAccessUnit(AccessUnitInfo& access_unit_info)
954 AP4_AvcFrameParser::CheckIfAccessUnitIsCompleted(AccessUnitInfo& access_unit_info)
788955 {
789956 if (m_SliceHeader == NULL) {
790957 return;
9611128 return AP4_ERROR_INVALID_PARAMETERS;
9621129
9631130 if ((*data & 0x1F) == AP4_AVC_NAL_UNIT_TYPE_SPS)
964 return ParseSPS(data, data_size, sps);
1131 {
1132 AP4_AvcFrameParser fp;
1133 return fp.ParseSPS(data, data_size, sps);
1134 }
9651135 data_size -= nalSize;
9661136 }
9671137 return AP4_SUCCESS;
9721142 +---------------------------------------------------------------------*/
9731143 AP4_Result
9741144 AP4_AvcFrameParser::Feed(const void* data,
975 AP4_Size data_size,
976 AP4_Size& bytes_consumed,
977 AccessUnitInfo& access_unit_info,
978 bool eos)
1145 AP4_Size data_size,
1146 AP4_Size& bytes_consumed,
1147 AccessUnitInfo& access_unit_info,
1148 bool eos)
9791149 {
9801150 const AP4_DataBuffer* nal_unit = NULL;
9811151
982 // default return values
983 access_unit_info.Reset();
984
9851152 // feed the NAL unit parser
9861153 AP4_Result result = m_NalParser.Feed(data, data_size, bytes_consumed, nal_unit, eos);
9871154 if (AP4_FAILED(result)) {
9881155 return result;
9891156 }
990 if (nal_unit && nal_unit->GetDataSize()) {
991 const unsigned char* nal_unit_payload = (const unsigned char*)nal_unit->GetData();
992 unsigned int nal_unit_size = nal_unit->GetDataSize();
993 unsigned int nal_unit_type = nal_unit_payload[0]&0x1F;
994 const char* nal_unit_type_name = AP4_AvcNalParser::NaluTypeName(nal_unit_type);
995 unsigned int nal_ref_idc = (nal_unit_payload[0]>>5)&3;
1157
1158 if (bytes_consumed < data_size) {
1159 // there will be more to parse
1160 eos = false;
1161 }
1162
1163 return Feed(nal_unit ? nal_unit->GetData() : NULL,
1164 nal_unit ? nal_unit->GetDataSize() : 0,
1165 access_unit_info,
1166 eos);
1167 }
1168
1169 /*----------------------------------------------------------------------
1170 | AP4_AvcFrameParser::Feed
1171 +---------------------------------------------------------------------*/
1172 AP4_Result
1173 AP4_AvcFrameParser::Feed(const AP4_UI08* nal_unit,
1174 AP4_Size nal_unit_size,
1175 AccessUnitInfo& access_unit_info,
1176 bool last_unit)
1177 {
1178 AP4_Result result;
1179
1180 // default return values
1181 access_unit_info.Reset();
1182
1183 if (nal_unit && nal_unit_size) {
1184 unsigned int nal_unit_type = nal_unit[0]&0x1F;
1185 const char* nal_unit_type_name = AP4_AvcNalParser::NaluTypeName(nal_unit_type);
1186 unsigned int nal_ref_idc = (nal_unit[0]>>5)&3;
9961187 if (nal_unit_type_name == NULL) nal_unit_type_name = "UNKNOWN";
9971188 DBG_PRINTF_5("NALU %5d: ref=%d, size=%5d, type=%02d (%s) ",
9981189 m_TotalNalUnitCount,
10011192 nal_unit_type,
10021193 nal_unit_type_name);
10031194 if (nal_unit_type == AP4_AVC_NAL_UNIT_TYPE_ACCESS_UNIT_DELIMITER) {
1004 unsigned int primary_pic_type = (nal_unit_payload[1]>>5);
1195 unsigned int primary_pic_type = (nal_unit[1]>>5);
10051196 const char* primary_pic_type_name = AP4_AvcNalParser::PrimaryPicTypeName(primary_pic_type);
10061197 if (primary_pic_type_name == NULL) primary_pic_type_name = "UNKNOWN";
10071198 DBG_PRINTF_2("[%d:%s]\n", primary_pic_type, primary_pic_type_name);
10081199
1009 MaybeNewAccessUnit(access_unit_info);
1200 CheckIfAccessUnitIsCompleted(access_unit_info);
10101201 } else if (nal_unit_type == AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_OF_NON_IDR_PICTURE ||
10111202 nal_unit_type == AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_OF_IDR_PICTURE ||
1012 nal_unit_type == AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_A ||
1013 nal_unit_type == AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_B ||
1014 nal_unit_type == AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_C) {
1203 nal_unit_type == AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_A) {
10151204 AP4_AvcSliceHeader* slice_header = new AP4_AvcSliceHeader;
1016 result = ParseSliceHeader(nal_unit_payload,
1017 nal_unit_size,
1205 result = ParseSliceHeader(nal_unit+1,
1206 nal_unit_size-1,
10181207 nal_unit_type,
1208 nal_ref_idc,
10191209 *slice_header);
10201210 if (AP4_FAILED(result)) {
10211211 return AP4_ERROR_INVALID_FORMAT;
10231213
10241214 const char* slice_type_name = AP4_AvcNalParser::SliceTypeName(slice_header->slice_type);
10251215 if (slice_type_name == NULL) slice_type_name = "?";
1026 DBG_PRINTF_4(" pps_id=%d, frame_num=%d, slice_type=%d (%s), ",
1216 DBG_PRINTF_5(" pps_id=%d, header_size=%d, frame_num=%d, slice_type=%d (%s), ",
10271217 slice_header->pic_parameter_set_id,
1218 slice_header->size,
10281219 slice_header->frame_num,
10291220 slice_header->slice_type,
10301221 slice_type_name);
10331224 if (m_SliceHeader &&
10341225 !SameFrame(m_NalUnitType, m_NalRefIdc, *m_SliceHeader,
10351226 nal_unit_type, nal_ref_idc, *slice_header)) {
1036 MaybeNewAccessUnit(access_unit_info);
1227 CheckIfAccessUnitIsCompleted(access_unit_info);
10371228 m_AccessUnitVclNalUnitCount = 1;
10381229 } else {
10391230 // continuation of an access unit
10421233 }
10431234
10441235 // buffer this NAL unit
1045 AppendNalUnitData(nal_unit_payload, nal_unit_size);
1236 AppendNalUnitData(nal_unit, nal_unit_size);
10461237 delete m_SliceHeader;
10471238 m_SliceHeader = slice_header;
10481239 m_NalUnitType = nal_unit_type;
10491240 m_NalRefIdc = nal_ref_idc;
10501241 } else if (nal_unit_type == AP4_AVC_NAL_UNIT_TYPE_PPS) {
10511242 AP4_AvcPictureParameterSet* pps = new AP4_AvcPictureParameterSet;
1052 result = ParsePPS(nal_unit_payload, nal_unit_size, *pps);
1243 result = ParsePPS(nal_unit, nal_unit_size, *pps);
10531244 if (AP4_FAILED(result)) {
10541245 DBG_PRINTF_0("PPS ERROR!!!\n");
10551246 delete pps;
10591250 DBG_PRINTF_2("PPS sps_id=%d, pps_id=%d\n", pps->seq_parameter_set_id, pps->pic_parameter_set_id);
10601251
10611252 // keep the PPS with the NAL unit (this is optional)
1062 AppendNalUnitData(nal_unit_payload, nal_unit_size);
1063 MaybeNewAccessUnit(access_unit_info);
1253 AppendNalUnitData(nal_unit, nal_unit_size);
1254 CheckIfAccessUnitIsCompleted(access_unit_info);
10641255 }
10651256 } else if (nal_unit_type == AP4_AVC_NAL_UNIT_TYPE_SPS) {
10661257 AP4_AvcSequenceParameterSet* sps = new AP4_AvcSequenceParameterSet;
1067 result = ParseSPS(nal_unit_payload, nal_unit_size, *sps);
1258 result = ParseSPS(nal_unit, nal_unit_size, *sps);
10681259 if (AP4_FAILED(result)) {
10691260 DBG_PRINTF_0("SPS ERROR!!!\n");
10701261 delete sps;
10721263 delete m_SPS[sps->seq_parameter_set_id];
10731264 m_SPS[sps->seq_parameter_set_id] = sps;
10741265 DBG_PRINTF_1("SPS sps_id=%d\n", sps->seq_parameter_set_id);
1075 MaybeNewAccessUnit(access_unit_info);
1266 CheckIfAccessUnitIsCompleted(access_unit_info);
10761267 }
10771268 } else if (nal_unit_type == AP4_AVC_NAL_UNIT_TYPE_SEI) {
1078 AppendNalUnitData(nal_unit_payload, nal_unit_size);
1079 MaybeNewAccessUnit(access_unit_info);
1269 AppendNalUnitData(nal_unit, nal_unit_size);
1270 CheckIfAccessUnitIsCompleted(access_unit_info);
10801271 DBG_PRINTF_0("\n");
10811272 } else if (nal_unit_type >= 14 && nal_unit_type <= 18) {
1082 MaybeNewAccessUnit(access_unit_info);
1273 CheckIfAccessUnitIsCompleted(access_unit_info);
10831274 DBG_PRINTF_0("\n");
1275 } else if (nal_unit_type == AP4_AVC_NAL_UNIT_TYPE_UNSPECIFIED28) {
1276 AppendNalUnitData(nal_unit, nal_unit_size);
1277 CheckIfAccessUnitIsCompleted(access_unit_info);
1278 DBG_PRINTF_0("\n");
1279 } else if (nal_unit_type == AP4_AVC_NAL_UNIT_TYPE_UNSPECIFIED30) {
1280 AppendNalUnitData(nal_unit, nal_unit_size);
1281 CheckIfAccessUnitIsCompleted(access_unit_info);
1282 DBG_PRINTF_0("\n");
10841283 } else {
10851284 DBG_PRINTF_0("\n");
10861285 }
10881287 }
10891288
10901289 // flush if needed
1091 if (eos && bytes_consumed == data_size && access_unit_info.nal_units.ItemCount() == 0) {
1290 if (last_unit && access_unit_info.nal_units.ItemCount() == 0) {
10921291 DBG_PRINTF_0("------ last unit\n");
1093 MaybeNewAccessUnit(access_unit_info);
1292 CheckIfAccessUnitIsCompleted(access_unit_info);
10941293 }
10951294
10961295 return AP4_SUCCESS;
11101309 decode_order = 0;
11111310 display_order = 0;
11121311 }
1113
3737 #include "Ap4NalParser.h"
3838 #include "Ap4Array.h"
3939 #include "Ap4Utils.h"
40
4140
4241 /*----------------------------------------------------------------------
4342 | constants
6059 const unsigned int AP4_AVC_NAL_UNIT_TYPE_SUBSET_SPS = 15;
6160 const unsigned int AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_OF_AUXILIARY_PICTURE = 19;
6261 const unsigned int AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_IN_SCALABLE_EXTENSION = 20;
62 const unsigned int AP4_AVC_NAL_UNIT_TYPE_UNSPECIFIED28 = 28;
63 const unsigned int AP4_AVC_NAL_UNIT_TYPE_UNSPECIFIED30 = 30;
64
65 const unsigned int AP4_AVC_SLICE_TYPE_P = 0;
66 const unsigned int AP4_AVC_SLICE_TYPE_B = 1;
67 const unsigned int AP4_AVC_SLICE_TYPE_I = 2;
68 const unsigned int AP4_AVC_SLICE_TYPE_SP = 3;
69 const unsigned int AP4_AVC_SLICE_TYPE_SI = 4;
6370
6471 const unsigned int AP4_AVC_SPS_MAX_ID = 255;
6572 const unsigned int AP4_AVC_SPS_MAX_NUM_REF_FRAMES_IN_PIC_ORDER_CNT_CYCLE = 256;
180187 struct AP4_AvcSliceHeader {
181188 AP4_AvcSliceHeader();
182189
190 unsigned int size; // not from the bitstream, this is computed after parsing
191
183192 unsigned int first_mb_in_slice;
184193 unsigned int slice_type;
185194 unsigned int pic_parameter_set_id;
190199 unsigned int idr_pic_id;
191200 unsigned int pic_order_cnt_lsb;
192201 int delta_pic_order_cnt[2];
193 unsigned int redundant_pic_cnt;
202 unsigned int redundant_pic_cnt;
203 unsigned int direct_spatial_mv_pred_flag;
204 unsigned int num_ref_idx_active_override_flag;
205 unsigned int num_ref_idx_l0_active_minus1;
206 unsigned int num_ref_idx_l1_active_minus1;
207 unsigned int ref_pic_list_reordering_flag_l0;
208 unsigned int reordering_of_pic_nums_idc;
209 unsigned int abs_diff_pic_num_minus1;
210 unsigned int long_term_pic_num;
211 unsigned int ref_pic_list_reordering_flag_l1;
212 unsigned int luma_log2_weight_denom;
213 unsigned int chroma_log2_weight_denom;
214 unsigned int cabac_init_idc;
215 unsigned int slice_qp_delta;
216 unsigned int sp_for_switch_flag;
217 int slice_qs_delta;
218 unsigned int disable_deblocking_filter_idc;
219 int slice_alpha_c0_offset_div2;
220 int slice_beta_offset_div2;
221 unsigned int slice_group_change_cycle;
222 unsigned int no_output_of_prior_pics_flag;
223 unsigned int long_term_reference_flag;
224 unsigned int difference_of_pic_nums_minus1;
225 unsigned int long_term_frame_idx;
226 unsigned int max_long_term_frame_idx_plus1;
194227 };
195228
196229 /*----------------------------------------------------------------------
201234 static const char* NaluTypeName(unsigned int nalu_type);
202235 static const char* PrimaryPicTypeName(unsigned int primary_pic_type);
203236 static const char* SliceTypeName(unsigned int slice_type);
204
237
205238 AP4_AvcNalParser();
206239 };
207240
232265 /**
233266 * Feed some data to the parser and look for the next NAL Unit.
234267 *
235 * @param data: Pointer to the memory buffer with the data to feed.
236 * @param data_size: Size in bytes of the buffer pointed to by the
268 * @param data Pointer to the memory buffer with the data to feed.
269 * @param data_size Size in bytes of the buffer pointed to by the
237270 * data pointer.
238 * @param bytes_consumed: Number of bytes from the data buffer that were
271 * @param bytes_consumed Number of bytes from the data buffer that were
239272 * consumed and stored by the parser.
240 * @param access_unit_info: Reference to a AccessUnitInfo structure that will
273 * @param access_unit_info Reference to a AccessUnitInfo structure that will
241274 * contain information about any access unit found in the data. If no
242275 * access unit was found, the nal_units field of this structure will be an
243276 * empty array.
244 * @param eos: Boolean flag that indicates if this buffer is the last
277 * @param eos Boolean flag that indicates if this buffer is the last
245278 * buffer in the stream/file (End Of Stream).
246279 *
247280 * @result: AP4_SUCCESS is the call succeeds, or an error code if it
261294 * responsible for freeing this data by calling AccessUnitInfo::Reset()
262295 */
263296 AP4_Result Feed(const void* data,
264 AP4_Size data_size,
265 AP4_Size& bytes_consumed,
266 AccessUnitInfo& access_unit_info,
267 bool eos=false);
268
269 AP4_AvcSequenceParameterSet** GetSequenceParameterSets() { return &m_SPS[0]; }
270 AP4_AvcPictureParameterSet** GetPictureParameterSets() { return &m_PPS[0]; }
271
272 static AP4_Result ParseSPS(const unsigned char* data,
273 unsigned int data_size,
274 AP4_AvcSequenceParameterSet& sps);
275 static AP4_Result ParsePPS(const unsigned char* data,
276 unsigned int data_size,
277 AP4_AvcPictureParameterSet& pps);
278
279 static unsigned int
280 ReadGolomb(AP4_BitReader& bits);
281
282 static int
283 SignedGolomb(unsigned int code_num);
284
285 private:
286 // methods
297 AP4_Size data_size,
298 AP4_Size& bytes_consumed,
299 AccessUnitInfo& access_unit_info,
300 bool eos=false);
301
302 AP4_Result Feed(const AP4_UI08* nal_unit,
303 AP4_Size nal_unit_size,
304 AccessUnitInfo& access_unit_info,
305 bool last_unit=false);
306
307 AP4_AvcSequenceParameterSet** GetSequenceParameterSets() { return &m_SPS[0]; }
308 AP4_AvcPictureParameterSet** GetPictureParameterSets() { return &m_PPS[0]; }
309 const AP4_AvcSliceHeader* GetSliceHeader() { return m_SliceHeader; }
310
311 AP4_Result ParseSPS(const unsigned char* data,
312 unsigned int data_size,
313 AP4_AvcSequenceParameterSet& sps);
314 AP4_Result ParsePPS(const unsigned char* data,
315 unsigned int data_size,
316 AP4_AvcPictureParameterSet& pps);
287317 AP4_Result ParseSliceHeader(const AP4_UI08* data,
288318 unsigned int data_size,
289319 unsigned int nal_unit_type,
320 unsigned int nal_ref_idc,
290321 AP4_AvcSliceHeader& slice_header);
322
323 static unsigned int ReadGolomb(AP4_BitReader& bits);
324 static int SignedGolomb(unsigned int code_num);
325
326 private:
327 // methods
291328 bool SameFrame(unsigned int nal_unit_type_1, unsigned int nal_ref_idc_1, AP4_AvcSliceHeader& sh1,
292329 unsigned int nal_unit_type_2, unsigned int nal_ref_idc_2, AP4_AvcSliceHeader& sh2);
293330 AP4_AvcSequenceParameterSet* GetSliceSPS(AP4_AvcSliceHeader& sh);
294 void MaybeNewAccessUnit(AccessUnitInfo& access_unit_info);
331 void CheckIfAccessUnitIsCompleted(AccessUnitInfo& access_unit_info);
295332 void AppendNalUnitData(const unsigned char* data, unsigned int data_size);
296333
297334 // members
315352 unsigned int m_PrevFrameNumOffset;
316353 int m_PrevPicOrderCntMsb;
317354 unsigned int m_PrevPicOrderCntLsb;
318
319355 };
320356
321357 #endif // _AP4_AVC_PARSER_H_
4040 const int AP4_ERROR_BASE_BITSTREAM = -10000;
4141
4242 // the max frame size we can handle
43 const unsigned int AP4_BITSTREAM_BUFFER_SIZE = 8192;
43 const unsigned int AP4_BITSTREAM_BUFFER_SIZE = 32768;
4444
4545 // flags
4646 #define AP4_BITSTREAM_FLAG_EOS 0x01
0 /*****************************************************************
1 |
2 | AP4 - E-AC-3 Sync Frame Parser
3 |
4 | Copyright 2002-2020 Axiomatic Systems, LLC
5 |
6 |
7 | This file is part of Bento4/AP4 (MP4 Atom Processing Library).
8 |
9 | Unless you have obtained Bento4 under a difference license,
10 | this version of Bento4 is Bento4|GPL.
11 | Bento4|GPL is free software; you can redistribute it and/or modify
12 | it under the terms of the GNU General Public License as published by
13 | the Free Software Foundation; either version 2, or (at your option)
14 | any later version.
15 |
16 | Bento4|GPL is distributed in the hope that it will be useful,
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | GNU General Public License for more details.
20 |
21 | You should have received a copy of the GNU General Public License
22 | along with Bento4|GPL; see the file COPYING. If not, write to the
23 | Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
24 | 02111-1307, USA.
25 |
26 ****************************************************************/
27
28 /*----------------------------------------------------------------------
29 | includes
30 +---------------------------------------------------------------------*/
31 #include "Ap4BitStream.h"
32 #include "Ap4Eac3Parser.h"
33 #include "Ap4Utils.h"
34
35 /*----------------------------------------------------------------------+
36 | AP4_Eac3Header::AP4_Eac3Header
37 +----------------------------------------------------------------------*/
38 AP4_Eac3Header::AP4_Eac3Header(const AP4_UI08* bytes)
39 {
40 AP4_BitReader bits(bytes, AP4_EAC3_HEADER_SIZE);
41 bits.SkipBits(16); // sync word
42
43 m_Strmtyp = bits.ReadBits(2);
44 m_Substreamid = bits.ReadBits(3);
45 m_Frmsiz = bits.ReadBits(11);
46 m_FrameSize = (m_Frmsiz + 1) * 2;
47
48 m_Fscod = bits.ReadBits(2);
49 unsigned char numblkscod = 0;
50 unsigned int blks_per_frm = 0;
51 if (m_Fscod == 0x3){
52 fprintf(stderr, "ERROR: Half sample rate unsupported\n");
53 return;
54 }else{
55 numblkscod = bits.ReadBits(2);
56 if (numblkscod == 0x3){
57 blks_per_frm = 6;
58 }else {
59 blks_per_frm = numblkscod + 1;
60 }
61 }
62
63 m_Acmod = bits.ReadBits(3);
64 m_Lfeon = bits.ReadBits(1);
65 m_ChannelCount = GLOBAL_CHANNEL_ARY[m_Acmod] + m_Lfeon;
66
67 m_Bsid = bits.ReadBits(5);
68 if (!((m_Bsid > 10) && (m_Bsid <=16))){
69 fprintf(stderr, "ERROR: Unsupported bitstream id\n");
70 return;
71 }
72
73 /* unsigned char dialnorm = */ bits.ReadBits(5); // dialnorm
74 // unsigned char compr;
75 if (bits.ReadBit()) { // compre
76 /* compr = */ bits.ReadBits(8);
77 }
78
79 if (m_Acmod == 0x0){ // if 1+1 mode (dual mono, so some items need a second value)
80 bits.SkipBits(5); // dialnorm2
81 if (bits.ReadBit()) { // compr2e
82 bits.SkipBits(8); // compr2
83 }
84 }
85
86 if (m_Strmtyp == 0x1) { // if dependent stream
87 m_Chanmape = bits.ReadBit();
88 if (m_Chanmape) {
89 m_Chanmap = bits.ReadBits(16);
90 }else {
91 //TODO: Derive chanmap from the acmod and lfeon parameters
92 m_Chanmap = 0;
93 }
94 }else {
95 m_Chanmape = 0;
96 m_Chanmap = 0;
97 }
98
99 // Extract mixing metadata
100 // unsigned char dmixmod, ltrtcmixlev, lorocmixlev, ltrtsurmixlev, lorosurmixlev, lfemixlevcod;
101 if (bits.ReadBit()){ // mixmdate
102 if (m_Acmod > 0x2) {
103 /* dmixmod = */ bits.ReadBits(2);
104 }
105 if ((m_Acmod & 0x1) && (m_Acmod > 0x2)) {
106 /* ltrtcmixlev = */ bits.ReadBits(3);
107 /* lorocmixlev = */ bits.ReadBits(3);
108 }
109 if (m_Acmod & 0x4) {
110 /* ltrtsurmixlev = */ bits.ReadBits(3);
111 /* lorosurmixlev = */ bits.ReadBits(3);
112 }
113 if (m_Lfeon) {
114 if (bits.ReadBit()) { // lfemixlevcode
115 /* lfemixlevcod = */ bits.ReadBits(5);
116 }
117 }
118 if (m_Strmtyp == 0x0) { // if independent stream
119 // unsigned char pgmscl, extpgmscl;
120 if (bits.ReadBit()) { // pgmscle
121 /* pgmscl = */ bits.ReadBits(6);
122 }
123
124 if (m_Acmod == 0x0){ // if 1+1 mode (dual mono, so some items need a second value)
125 if(bits.ReadBit()) { // pgmscl2e
126 bits.SkipBits(6); // pgmscl2
127 }
128 }
129
130 if(bits.ReadBit()) { // extpgmscle
131 /* extpgmscl = */ bits.ReadBits(6);
132 }
133
134 char mixdef = bits.ReadBits(2);
135 if(mixdef == 0x1) { bits.SkipBits(5) ;} // premixcmpsel, drcsrc, premixcmpscl
136 else if (mixdef == 0x2) { bits.SkipBits(12);} // mixdata
137 else if (mixdef == 0x3) {
138 char mixdeflen = bits.ReadBits(5);
139 unsigned int mixdefbits = 1; // the initial value represents mixdata2e
140 if(bits.ReadBit()){ // mixdata2e
141 bits.SkipBits(5); // premixcmpsel, drcsrc, premixcmpscl
142 mixdefbits += 5;
143
144 mixdefbits += 1; // extpgmlscle
145 if(bits.ReadBit()) {
146 bits.SkipBits(4); // extpgmlscl
147 mixdefbits += 4;
148 }
149
150 mixdefbits += 1; // extpgmcscle
151 if(bits.ReadBit()) {
152 bits.SkipBits(4); // extpgmcscl
153 mixdefbits += 4;
154 }
155
156 mixdefbits += 1; // extpgmrscle
157 if(bits.ReadBit()) {
158 bits.SkipBits(4); // extpgmrscl
159 mixdefbits += 4;
160 }
161
162 mixdefbits += 1; // extpgmlsscle
163 if(bits.ReadBit()) {
164 bits.SkipBits(4); // extpgmlsscl
165 mixdefbits += 4;
166 }
167
168 mixdefbits += 1; // extpgmrsscle
169 if(bits.ReadBit()) {
170 bits.SkipBits(4); // extpgmrsscl
171 mixdefbits += 4;
172 }
173
174 mixdefbits += 1; // extpgmlfescle
175 if(bits.ReadBit()) {
176 bits.SkipBits(4); // extpgmlfescl
177 mixdefbits += 4;
178 }
179
180 mixdefbits += 1; // dmixscle
181 if(bits.ReadBit()) {
182 bits.SkipBits(4); // dmixscl
183 mixdefbits += 4;
184 }
185
186 mixdefbits += 1;
187 if(bits.ReadBit()){ // addche
188 mixdefbits += 1;
189 if(bits.ReadBit()) { // extpgmaux1scle
190 bits.SkipBits(4); // extpgmaux1scl
191 mixdefbits += 4;
192 }
193
194 mixdefbits += 1;
195 if(bits.ReadBit()) { // extpgmaux2scle
196 bits.SkipBits(4); // extpgmaux2scl
197 mixdefbits += 4;
198 }
199 }
200 } // if(bits.ReadBit()){ // mixdata2e
201
202 mixdefbits += 1;
203 if(bits.ReadBit()){ // mixdata3e
204 bits.SkipBits(5); // spchdat
205 mixdefbits += 5;
206
207 mixdefbits += 1;
208 if(bits.ReadBit()){ // addspchdate
209 bits.SkipBits(7); // spchdat1, spchan1att
210 mixdefbits += 7;
211
212 mixdefbits += 1;
213 if(bits.ReadBit()){ // addspdat1e
214 bits.SkipBits(8); // spchdat2, spchan2att
215 mixdefbits += 8;
216 }
217 }
218 } // if(bits.ReadBit()){ // mixdata3e
219
220 bits.SkipBits(8 * (mixdeflen + 2) - mixdefbits); // mixdatafill
221 }
222
223 if (m_Acmod < 0x2) { // if mono or dual mono source
224 if(bits.ReadBit()){ // paninfoe
225 bits.SkipBits(8 + 6); // panmean, paninfo
226 }
227 if (m_Acmod == 0x0) { // if 1+1 mode (dual mono - some items need a second value)
228 if(bits.ReadBit()){ // paninfo2e
229 bits.SkipBits(8 + 6); // panmean2, paninfo2
230 }
231 }
232 }
233
234 if (bits.ReadBit()){ // frmmixcfginfoe
235 if (blks_per_frm == 1) {
236 bits.SkipBits(5); // blkmixcfginfo[0]
237 }else{
238 for (unsigned int idx = 0; idx < blks_per_frm; idx++){
239 if(bits.ReadBit()){ // blkmixcfginfoe
240 bits.SkipBits(5); // blkmixcfginfo[blk]
241 }
242 }
243 }
244 }
245 } // if (m_Strmtyp == 0x0)
246 }
247
248 m_Infomdate = bits.ReadBit();
249 if (m_Infomdate){
250 m_Bsmod = bits.ReadBits(3);
251 // unsigned char copyrightb, origbs, dsurexmod;
252 /* copyrightb = */ bits.ReadBits(1);
253 /* origbs = */ bits.ReadBits(1);
254
255 if (m_Acmod == 0x2) { // if in 2/0 mode
256 bits.SkipBits(4); // dsurmod, dheadphonmod
257 }
258 if (m_Acmod >= 0x6) { // if both surround channels exist
259 /* dsurexmod = */ bits.ReadBits(2);
260 }
261 if(bits.ReadBit()){ // audprodie
262 bits.SkipBits(8); // mixlevel, roomtyp, adconvtyp
263 }
264 if (m_Acmod == 0x0) { //if 1+1 mode (dual mono, so some items need a second value)
265 if(bits.ReadBit()){ // audprodi2e
266 bits.SkipBits(8); // mixlevel2, roomtyp2, adconvtyp2
267 }
268 }
269 if (m_Fscod < 0x3) { // if not half sample rate
270 bits.SkipBits(1); // sourcefscod
271 }
272 } else { // if (m_Infomdate)
273 m_Bsmod = 0;
274 }
275
276 m_Convsync = 1;
277 if ((m_Strmtyp == 0x0) && (numblkscod != 0x3)){
278 m_Convsync = bits.ReadBits(1);
279 }
280
281 if (m_Strmtyp == 0x2) { // if bit stream converted from AC-3
282 unsigned char blkid = 0;
283 if (numblkscod == 0x3) {
284 blkid = 1;
285 }else {
286 blkid = bits.ReadBits(1);
287 }
288 if (blkid) {bits.SkipBits(6); } // frmsizecod
289 }
290
291 m_Addbsie = bits.ReadBit();
292 if (m_Addbsie){
293 m_Addbsil = bits.ReadBits(6);
294 for (unsigned int idx = 0 ; idx < (m_Addbsil + 1); idx ++){
295 m_Addbsi[idx] = bits.ReadBits(8);
296 }
297 } else {
298 m_Addbsil = 0;
299 AP4_SetMemory(m_Addbsi, 0, sizeof (m_Addbsi));
300 }
301 m_HeadSize = (bits.GetBitsRead() / 8) + ((bits.GetBitsRead() % 8 == 0) ? 0: 1);
302 }
303
304 /*----------------------------------------------------------------------+
305 | AP4_Eac3Header::MatchFixed
306 |
307 | Check that two fixed headers are the same
308 |
309 +----------------------------------------------------------------------*/
310 bool
311 AP4_Eac3Header::MatchFixed(AP4_Eac3Header& frame, AP4_Eac3Header& next_frame)
312 {
313 if (frame.m_Acmod == next_frame.m_Acmod &&
314 frame.m_Bsid == next_frame.m_Bsid &&
315 frame.m_Bsmod == next_frame.m_Bsmod &&
316 frame.m_Lfeon == next_frame.m_Lfeon &&
317 frame.m_Fscod == next_frame.m_Fscod ) {
318 return true;
319 } else {
320 return false;
321 }
322 }
323
324 /*----------------------------------------------------------------------+
325 | AP4_Eac3Header::Check
326 +----------------------------------------------------------------------*/
327 AP4_Result
328 AP4_Eac3Header::Check()
329 {
330 if (m_Fscod == 1 || m_Fscod == 2) {
331 fprintf(stderr, "WARN: The sample rate is NOT 48 kHz\n");
332 } else if (m_Fscod == 3) {
333 return AP4_FAILURE;
334 }
335 if (m_Bsid < 10 || m_Bsid > 16) {
336 return AP4_FAILURE;
337 }
338 if (m_Substreamid != 0) {
339 fprintf(stderr, "ERROR: Only single independent substream (I0) or single depenpent substream (D0) is allowed in a DD+ stream\n");
340 return AP4_FAILURE;
341 }
342 return AP4_SUCCESS;
343 }
344
345 /*----------------------------------------------------------------------+
346 | AP4_Eac3Parser::AP4_Eac3Parser
347 +----------------------------------------------------------------------*/
348 AP4_Eac3Parser::AP4_Eac3Parser() :
349 m_FrameCount(0)
350 {
351 }
352
353 /*----------------------------------------------------------------------+
354 | AP4_Eac3Parser::~AP4_Eac3Parser
355 +----------------------------------------------------------------------*/
356 AP4_Eac3Parser::~AP4_Eac3Parser()
357 {
358 }
359
360 /*----------------------------------------------------------------------+
361 | AP4_Eac3Parser::Reset
362 +----------------------------------------------------------------------*/
363 AP4_Result
364 AP4_Eac3Parser::Reset()
365 {
366 m_FrameCount = 0;
367
368 return AP4_SUCCESS;
369 }
370
371 /*----------------------------------------------------------------------+
372 | AP4_Eac3Parser::Feed
373 +----------------------------------------------------------------------*/
374 AP4_Result
375 AP4_Eac3Parser::Feed(const AP4_UI08* buffer,
376 AP4_Size* buffer_size,
377 AP4_Flags flags)
378 {
379 AP4_Size free_space;
380
381 /* update flags */
382 m_Bits.m_Flags = flags;
383
384 /* possible shortcut */
385 if (buffer == NULL ||
386 buffer_size == NULL ||
387 *buffer_size == 0) {
388 return AP4_SUCCESS;
389 }
390
391 /* see how much data we can write */
392 free_space = m_Bits.GetBytesFree();
393 if (*buffer_size > free_space) *buffer_size = free_space;
394 if (*buffer_size == 0) return AP4_SUCCESS;
395
396 /* write the data */
397 return m_Bits.WriteBytes(buffer, *buffer_size);
398 }
399
400 /*----------------------------------------------------------------------+
401 | AP4_Eac3Parser::FindHeader
402 +----------------------------------------------------------------------*/
403 AP4_Result
404 AP4_Eac3Parser::FindHeader(AP4_UI08* header, AP4_Size& skip_size)
405 {
406 AP4_Size available = m_Bits.GetBytesAvailable();
407
408 /* look for the sync pattern */
409 while (available-- >= AP4_EAC3_HEADER_SIZE) {
410 m_Bits.PeekBytes(header, 2);
411
412 if( (((header[0] << 8) | header[1]) == AP4_EAC3_SYNC_WORD_BIG_ENDIAN) ||
413 (((header[0] << 8) | header[1]) == AP4_EAC3_SYNC_WORD_LITTLE_ENDIAN) ){
414 if (((header[0] << 8) | header[1]) == AP4_EAC3_SYNC_WORD_LITTLE_ENDIAN) {
415 m_LittleEndian = true;
416 } else {
417 m_LittleEndian = false;
418 }
419 /* found a sync pattern, read the entire the header */
420 m_Bits.PeekBytes(header, AP4_EAC3_HEADER_SIZE);
421
422 return AP4_SUCCESS;
423 } else {
424 m_Bits.ReadByte(); // skip
425 skip_size++;
426 }
427 }
428
429 return AP4_ERROR_NOT_ENOUGH_DATA;
430 }
431
432 /*----------------------------------------------------------------------+
433 | AP4_Eac3Parser::FindFrame
434 +----------------------------------------------------------------------*/
435 AP4_Result
436 AP4_Eac3Parser::FindFrame(AP4_Eac3Frame& frame)
437 {
438 bool dependent_stream_exist = false;
439 unsigned int dependent_stream_chan_loc = 0;
440 unsigned int dependent_stream_length = 0;
441 unsigned int skip_size = 0;
442 unsigned int available;
443 unsigned char raw_header[AP4_EAC3_HEADER_SIZE];
444 AP4_Result result;
445
446 /* align to the start of the next byte */
447 m_Bits.ByteAlign();
448
449 /* find a frame header */
450 result = FindHeader(raw_header, skip_size);
451 if (AP4_FAILED(result)) return result;
452
453 if (m_LittleEndian) {
454 AP4_ByteSwap16(raw_header, AP4_EAC3_HEADER_SIZE);
455 }
456
457 /* parse the header */
458 AP4_Eac3Header eac3_header(raw_header);
459
460 /* check the header */
461 result = eac3_header.Check();
462 if (AP4_FAILED(result)) {
463 goto fail;
464 }
465
466 /* check if we have enough data to peek at the next header */
467 available = m_Bits.GetBytesAvailable();
468 if (available >= eac3_header.m_FrameSize + AP4_EAC3_HEADER_SIZE) {
469 // enough to peek at the header of the next frame
470 unsigned char peek_raw_header[AP4_EAC3_HEADER_SIZE];
471
472 m_Bits.SkipBytes(eac3_header.m_FrameSize);
473 skip_size = 0;
474 result = FindHeader(peek_raw_header, skip_size);
475 if (AP4_FAILED(result)) return result;
476 m_Bits.SkipBytes(-((int)(eac3_header.m_FrameSize + skip_size)));
477
478 if (m_LittleEndian) {
479 AP4_ByteSwap16(peek_raw_header, AP4_EAC3_HEADER_SIZE);
480 }
481 /* check the header */
482 AP4_Eac3Header peek_eac3_header(peek_raw_header);
483 result = peek_eac3_header.Check();
484 if (AP4_FAILED(result)) {
485 goto fail;
486 }
487
488 // TODO: Only support 7.1-channel now
489 if (peek_eac3_header.m_Strmtyp == 1) {
490 dependent_stream_exist = true;
491 if (peek_eac3_header.m_Chanmape == 0){
492 goto fail;
493 }else {
494 if (peek_eac3_header.m_Chanmap & 0x200) {
495 dependent_stream_chan_loc |= 0x2;
496 dependent_stream_length = peek_eac3_header.m_FrameSize;
497 eac3_header.m_ChannelCount += 2;
498 } else {
499 fprintf(stderr, "ERROR: Only support 7.1-channel (I0 + D0). For other D0, the tool doesn't support yet.\n");
500 goto fail;
501 }
502 }
503 }
504
505 /* check that the fixed part of this header is the same as the */
506 /* fixed part of the previous header */
507 else if (!AP4_Eac3Header::MatchFixed(eac3_header, peek_eac3_header)) {
508 goto fail;
509 }
510 } else if (available < eac3_header.m_FrameSize || (m_Bits.m_Flags & AP4_BITSTREAM_FLAG_EOS) == 0) {
511 // not enough for a frame, or not at the end (in which case we'll want to peek at the next header)
512 return AP4_ERROR_NOT_ENOUGH_DATA;
513 }
514
515 /* fill in the frame info */
516 frame.m_Info.m_ChannelCount = eac3_header.m_ChannelCount;
517 if (dependent_stream_exist) {
518 frame.m_Info.m_FrameSize = eac3_header.m_FrameSize + dependent_stream_length;
519 }else {
520 frame.m_Info.m_FrameSize = eac3_header.m_FrameSize;
521 }
522 frame.m_Info.m_SampleRate = EAC3_SAMPLE_RATE_ARY[eac3_header.m_Fscod];
523 frame.m_Info.m_Eac3SubStream.fscod = eac3_header.m_Fscod;
524 frame.m_Info.m_Eac3SubStream.bsid = eac3_header.m_Bsid;
525 frame.m_Info.m_Eac3SubStream.bsmod = eac3_header.m_Bsmod;
526 frame.m_Info.m_Eac3SubStream.acmod = eac3_header.m_Acmod;
527 frame.m_Info.m_Eac3SubStream.lfeon = eac3_header.m_Lfeon;
528 if (dependent_stream_exist) {
529 frame.m_Info.m_Eac3SubStream.num_dep_sub = 1;
530 frame.m_Info.m_Eac3SubStream.chan_loc = dependent_stream_chan_loc;
531 }else {
532 frame.m_Info.m_Eac3SubStream.num_dep_sub = 0;
533 frame.m_Info.m_Eac3SubStream.chan_loc = 0;
534 }
535
536 frame.m_Info.complexity_index_type_a = 0;
537 if (eac3_header.m_Addbsie && (eac3_header.m_Addbsil == 1) && (eac3_header.m_Addbsi[0] == 0x1)){
538 frame.m_Info.complexity_index_type_a = eac3_header.m_Addbsi[1];
539 }
540
541 /* set the little endian flag */
542 frame.m_LittleEndian = m_LittleEndian;
543
544 /* set the frame source */
545 frame.m_Source = &m_Bits;
546
547 return AP4_SUCCESS;
548
549 fail:
550 return AP4_ERROR_CORRUPTED_BITSTREAM;
551 }
552
553 /*----------------------------------------------------------------------+
554 | AP4_Eac3Parser::GetBytesFree
555 +----------------------------------------------------------------------*/
556 AP4_Size
557 AP4_Eac3Parser::GetBytesFree()
558 {
559 return (m_Bits.GetBytesFree());
560 }
561
562 /*----------------------------------------------------------------------+
563 | AP4_Eac3Parser::GetBytesAvailable
564 +----------------------------------------------------------------------*/
565 AP4_Size
566 AP4_Eac3Parser::GetBytesAvailable()
567 {
568 return (m_Bits.GetBytesAvailable());
569 }
0 /*****************************************************************
1 |
2 | AP4 - E-AC-3 Sync Frame Parser
3 |
4 | Copyright 2002-2020 Axiomatic Systems, LLC
5 |
6 |
7 | This file is part of Bento4/AP4 (MP4 Atom Processing Library).
8 |
9 | Unless you have obtained Bento4 under a difference license,
10 | this version of Bento4 is Bento4|GPL.
11 | Bento4|GPL is free software; you can redistribute it and/or modify
12 | it under the terms of the GNU General Public License as published by
13 | the Free Software Foundation; either version 2, or (at your option)
14 | any later version.
15 |
16 | Bento4|GPL is distributed in the hope that it will be useful,
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | GNU General Public License for more details.
20 |
21 | You should have received a copy of the GNU General Public License
22 | along with Bento4|GPL; see the file COPYING. If not, write to the
23 | Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
24 | 02111-1307, USA.
25 |
26 ****************************************************************/
27
28 #ifndef _AP4_EAC3_PARSER_H_
29 #define _AP4_EAC3_PARSER_H_
30
31 /*----------------------------------------------------------------------
32 | includes
33 +---------------------------------------------------------------------*/
34 #include "Ap4Types.h"
35 #include "Ap4BitStream.h"
36 #include "Ap4Dec3Atom.h"
37
38 /*----------------------------------------------------------------------
39 | constants
40 +---------------------------------------------------------------------*/
41 #define AP4_EAC3_HEADER_SIZE 64 /* The header size for E-AC-3 parser, syncinfo() + bsi() */
42 #define AP4_EAC3_SYNC_WORD_BIG_ENDIAN 0x0B77 /* Big endian, 16 sync bits */
43 #define AP4_EAC3_SYNC_WORD_LITTLE_ENDIAN 0x770B /* Little endian, 16 sync bits */
44
45 const AP4_UI08 GLOBAL_CHANNEL_ARY[] = {2, 1, 2, 3, 3, 4, 4, 5}; /* Channel count number from acmod value */
46 const AP4_UI32 EAC3_SAMPLE_RATE_ARY[] = {48000, 44100, 32000}; /* Sample rate from fscode vale */
47
48 /*----------------------------------------------------------------------
49 | types
50 +---------------------------------------------------------------------*/
51 class AP4_Eac3Header {
52 public:
53 // constructor
54 AP4_Eac3Header(const AP4_UI08* bytes);
55
56 // methods
57 AP4_Result Check();
58
59 AP4_UI32 m_HeadSize;
60 AP4_UI32 m_ChannelCount;
61 AP4_UI32 m_FrameSize;
62
63 // E-AC-3 bsi()
64 AP4_UI32 m_Strmtyp;
65 AP4_UI32 m_Substreamid;
66 AP4_UI32 m_Frmsiz;
67 AP4_UI32 m_Fscod;
68 AP4_UI32 m_Acmod;
69 AP4_UI32 m_Lfeon;
70 AP4_UI32 m_Bsid;
71 AP4_UI32 m_Chanmape;
72 AP4_UI32 m_Chanmap;
73 AP4_UI32 m_Infomdate;
74 AP4_UI32 m_Bsmod;
75 AP4_UI32 m_Convsync;
76 AP4_UI32 m_Addbsie;
77 AP4_UI32 m_Addbsil; // 6 bits
78 AP4_UI08 m_Addbsi[65]; // (addbsil + 1)* 8
79
80 // class methods
81 static bool MatchFixed(AP4_Eac3Header& frame, AP4_Eac3Header& next_frame);
82 };
83
84 typedef struct {
85 AP4_UI32 m_ChannelCount;
86 AP4_UI32 m_FrameSize;
87 AP4_UI32 m_SampleRate;
88 AP4_Dec3Atom::SubStream m_Eac3SubStream;
89 AP4_UI32 complexity_index_type_a;
90 } AP4_Eac3FrameInfo;
91
92 typedef struct {
93 AP4_BitStream* m_Source;
94 AP4_Eac3FrameInfo m_Info;
95 AP4_Flags m_LittleEndian;
96 } AP4_Eac3Frame;
97
98 class AP4_Eac3Parser {
99 public:
100 // constructor and destructor
101 AP4_Eac3Parser();
102 virtual ~AP4_Eac3Parser();
103
104 // methods
105 AP4_Result Reset();
106 AP4_Result Feed(const AP4_UI08* buffer,
107 AP4_Size* buffer_size,
108 AP4_Flags flags = 0);
109 AP4_Result FindFrame(AP4_Eac3Frame& frame);
110 AP4_Result Skip(AP4_Size size);
111 AP4_Size GetBytesFree();
112 AP4_Size GetBytesAvailable();
113
114 private:
115 // methods
116 AP4_Result FindHeader(AP4_UI08* header, AP4_Size& skip_size);
117
118 // members
119 AP4_BitStream m_Bits;
120 AP4_Cardinal m_FrameCount;
121 AP4_Flags m_LittleEndian;
122 };
123
124 #endif // _AP4_EAC3_PARSER_H_
3232 #include "Ap4Utils.h"
3333
3434 /*----------------------------------------------------------------------
35 | AP4_HevcParser::NaluTypeName
35 | debugging
36 +---------------------------------------------------------------------*/
37 #define AP4_HEVC_PARSER_ENABLE_DEBUG 0
38
39 #if AP4_HEVC_PARSER_ENABLE_DEBUG
40 #define DBG_PRINTF_0(_x0) printf(_x0)
41 #define DBG_PRINTF_1(_x0, _x1) printf(_x0, _x1)
42 #define DBG_PRINTF_2(_x0, _x1, _x2) printf(_x0, _x1, _x2)
43 #define DBG_PRINTF_3(_x0, _x1, _x2, _x3) printf(_x0, _x1, _x2, _x3)
44 #define DBG_PRINTF_4(_x0, _x1, _x2, _x3, _x4) printf(_x0, _x1, _x2, _x3, _x4)
45 #define DBG_PRINTF_5(_x0, _x1, _x2, _x3, _x4, _x5) printf(_x0, _x1, _x2, _x3, _x4, _x5)
46 #define DBG_PRINTF_6(_x0, _x1, _x2, _x3, _x4, _x5, _x6) printf(_x0, _x1, _x2, _x3, _x4, _x5, _x6)
47 #define DBG_PRINTF_7(_x0, _x1, _x2, _x3, _x4, _x5, _x6, _x7) printf(_x0, _x1, _x2, _x3, _x4, _x5, _x6, _x7)
48 #else
49 #define DBG_PRINTF_0(_x0)
50 #define DBG_PRINTF_1(_x0, _x1)
51 #define DBG_PRINTF_2(_x0, _x1, _x2)
52 #define DBG_PRINTF_3(_x0, _x1, _x2, _x3)
53 #define DBG_PRINTF_4(_x0, _x1, _x2, _x3, _x4)
54 #define DBG_PRINTF_5(_x0, _x1, _x2, _x3, _x4, _x5)
55 #define DBG_PRINTF_6(_x0, _x1, _x2, _x3, _x4, _x5, _x6)
56 #define DBG_PRINTF_7(_x0, _x1, _x2, _x3, _x4, _x5, _x6, _x7)
57 #endif
58
59 /*----------------------------------------------------------------------
60 | AP4_HevcNalParser::NaluTypeName
3661 +---------------------------------------------------------------------*/
3762 const char*
38 AP4_HevcParser::NaluTypeName(unsigned int nalu_type)
63 AP4_HevcNalParser::NaluTypeName(unsigned int nalu_type)
3964 {
4065 switch (nalu_type) {
4166 case 0: return "TRAIL_N - Coded slice segment of a non-TSA, non-STSA trailing picture";
79104 case 38: return "FD_NUT - Filler data";
80105 case 39: return "PREFIX_SEI_NUT - Supplemental enhancement information";
81106 case 40: return "SUFFIX_SEI_NUT - Supplemental enhancement information";
107 case 62: return "Dolby Vision RPU NAL units";
108 case 63: return "Dolby Vision EL NAL units";
82109 default: return NULL;
83110 }
84111 }
85112
86113 /*----------------------------------------------------------------------
87 | AP4_HevcParser::PicTypeName
114 | AP4_HevcNalParser::PicTypeName
88115 +---------------------------------------------------------------------*/
89116 const char*
90 AP4_HevcParser::PicTypeName(unsigned int primary_pic_type)
117 AP4_HevcNalParser::PicTypeName(unsigned int primary_pic_type)
91118 {
92119 switch (primary_pic_type) {
93120 case 0: return "I";
98125 }
99126
100127 /*----------------------------------------------------------------------
101 | AP4_HevcParser::SliceTypeName
128 | AP4_HevcNalParser::SliceTypeName
102129 +---------------------------------------------------------------------*/
103130 const char*
104 AP4_HevcParser::SliceTypeName(unsigned int slice_type)
131 AP4_HevcNalParser::SliceTypeName(unsigned int slice_type)
105132 {
106133 switch (slice_type) {
107 case 0: return "B";
108 case 1: return "P";
109 case 2: return "I";
134 case AP4_HEVC_SLICE_TYPE_B: return "B";
135 case AP4_HEVC_SLICE_TYPE_P: return "P";
136 case AP4_HEVC_SLICE_TYPE_I: return "I";
110137 default: return NULL;
111138 }
112139 }
113140
114141 /*----------------------------------------------------------------------
115 | AP4_AvcParser::AP4_AvcParser
116 +---------------------------------------------------------------------*/
117 AP4_HevcParser::AP4_HevcParser() :
142 | ReadGolomb
143 +---------------------------------------------------------------------*/
144 static unsigned int
145 ReadGolomb(AP4_BitReader& bits)
146 {
147 unsigned int leading_zeros = 0;
148 while (bits.ReadBit() == 0) {
149 leading_zeros++;
150 if (leading_zeros > 32) return 0; // safeguard
151 }
152 if (leading_zeros) {
153 return (1<<leading_zeros)-1+bits.ReadBits(leading_zeros);
154 } else {
155 return 0;
156 }
157 }
158
159 /*----------------------------------------------------------------------
160 | SignedGolomb
161 +---------------------------------------------------------------------*/
162 static int
163 SignedGolomb(unsigned int code_num)
164 {
165 if (code_num % 2) {
166 return (code_num+1)/2;
167 } else {
168 return -((int)code_num/2);
169 }
170 }
171
172 /*----------------------------------------------------------------------
173 | BitsNeeded
174 +---------------------------------------------------------------------*/
175 static unsigned int
176 BitsNeeded(unsigned int num_values)
177 {
178 unsigned int bits_needed = 1;
179 while (num_values > (unsigned int)(1 << bits_needed)) {
180 ++bits_needed;
181 }
182
183 return bits_needed;
184 }
185
186 /*----------------------------------------------------------------------
187 | AP4_HevcNalParser::AP4_HevcNalParser
188 +---------------------------------------------------------------------*/
189 AP4_HevcNalParser::AP4_HevcNalParser() :
118190 AP4_NalParser()
119191 {
120192 }
193
194 /*----------------------------------------------------------------------
195 | scaling_list_data
196 +---------------------------------------------------------------------*/
197 static void
198 scaling_list_data(AP4_BitReader& bits)
199 {
200 for (unsigned int sizeId = 0; sizeId < 4; sizeId++) {
201 for (unsigned int matrixId = 0; matrixId < (unsigned int)((sizeId == 3)?2:6); matrixId++) {
202 unsigned int flag = bits.ReadBit(); // scaling_list_pred_mode_flag[ sizeId ][ matrixId ]
203 if (!flag) {
204 ReadGolomb(bits); // scaling_list_pred_matrix_id_delta[ sizeId ][ matrixId ]
205 } else {
206 // nextCoef = 8;
207 unsigned int coefNum = (1 << (4+(sizeId << 1)));
208 if (coefNum > 64) coefNum = 64;
209 if (sizeId > 1) {
210 ReadGolomb(bits); // scaling_list_dc_coef_minus8[ sizeId − 2 ][ matrixId ]
211 // nextCoef = scaling_list_dc_coef_minus8[ sizeId − 2 ][ matrixId ] + 8
212 }
213 for (unsigned i = 0; i < coefNum; i++) {
214 ReadGolomb(bits); // scaling_list_delta_coef
215 // nextCoef = ( nextCoef + scaling_list_delta_coef + 256 ) % 256
216 // ScalingList[ sizeId ][ matrixId ][ i ] = nextCoef
217 }
218 }
219 }
220 }
221 }
222
223 /*----------------------------------------------------------------------
224 | st_ref_pic_set
225 +---------------------------------------------------------------------*/
226 static AP4_Result
227 parse_st_ref_pic_set(AP4_HevcShortTermRefPicSet* rps,
228 const AP4_HevcSequenceParameterSet* sps,
229 unsigned int stRpsIdx,
230 unsigned int num_short_term_ref_pic_sets,
231 AP4_BitReader& bits) {
232 AP4_SetMemory(rps, 0, sizeof(*rps));
233
234 unsigned int inter_ref_pic_set_prediction_flag = 0;
235 if (stRpsIdx != 0) {
236 inter_ref_pic_set_prediction_flag = bits.ReadBit();
237 }
238 if (inter_ref_pic_set_prediction_flag) {
239 unsigned int delta_idx_minus1 = 0;
240 if (stRpsIdx == num_short_term_ref_pic_sets) {
241 delta_idx_minus1 = ReadGolomb(bits);
242 }
243 /* delta_rps_sign = */ bits.ReadBit();
244 /* abs_delta_rps_minus1 = */ ReadGolomb(bits);
245 if (delta_idx_minus1+1 > stRpsIdx) return AP4_ERROR_INVALID_FORMAT; // should not happen
246 unsigned int RefRpsIdx = stRpsIdx - (delta_idx_minus1 + 1);
247 unsigned int NumDeltaPocs = sps->short_term_ref_pic_sets[RefRpsIdx].num_delta_pocs;
248 for (unsigned j=0; j<=NumDeltaPocs; j++) {
249 unsigned int used_by_curr_pic_flag /*[j]*/ = bits.ReadBit();
250 unsigned int use_delta_flag /*[j]*/ = 1;
251 if (!used_by_curr_pic_flag /*[j]*/) {
252 use_delta_flag /*[j]*/ = bits.ReadBit();
253 }
254 if (used_by_curr_pic_flag /*[j]*/ || use_delta_flag /*[j]*/) {
255 rps->num_delta_pocs++;
256 }
257 }
258 } else {
259 rps->num_negative_pics = ReadGolomb(bits);
260 rps->num_positive_pics = ReadGolomb(bits);
261 if (rps->num_negative_pics > 16 || rps->num_positive_pics > 16) {
262 return AP4_ERROR_INVALID_FORMAT;
263 }
264 rps->num_delta_pocs = rps->num_negative_pics + rps->num_positive_pics;
265 for (unsigned int i=0; i<rps->num_negative_pics; i++) {
266 rps->delta_poc_s0_minus1[i] = ReadGolomb(bits);
267 rps->used_by_curr_pic_s0_flag[i] = bits.ReadBit();
268 }
269 for (unsigned i=0; i<rps->num_positive_pics; i++) {
270 rps->delta_poc_s1_minus1[i] = ReadGolomb(bits);
271 rps->used_by_curr_pic_s1_flag[i] = bits.ReadBit();
272 }
273 }
274
275 return AP4_SUCCESS;
276 }
277
278 /*----------------------------------------------------------------------
279 | NumPicTotalCurr
280 +---------------------------------------------------------------------*/
281 static unsigned int
282 NumPicTotalCurr(const AP4_HevcShortTermRefPicSet* rps,
283 const AP4_HevcSliceSegmentHeader* slice_segment_header)
284 {
285 // compute NumPicTotalCurr
286 unsigned int nptc = 0;
287 if (rps) {
288 for (unsigned int i=0; i<rps->num_negative_pics; i++) {
289 if (rps->used_by_curr_pic_s0_flag[i]) {
290 ++nptc;
291 }
292 }
293 for (unsigned int i=0; i<rps->num_positive_pics; i++) {
294 if (rps->used_by_curr_pic_s1_flag[i]) {
295 ++nptc;
296 }
297 }
298 }
299 for (unsigned int i=0; i<slice_segment_header->num_long_term_sps + slice_segment_header->num_long_term_pics; i++) {
300 if (slice_segment_header->used_by_curr_pic_lt_flag[i]) {
301 ++nptc;
302 }
303 }
304 // TODO: for now we assume pps_curr_pic_ref_enabled is 0
305 //if (pps_curr_pic_ref_enabled) {
306 // ++nptc;
307 //}
308
309 return nptc;
310 }
311
312 /*----------------------------------------------------------------------
313 | AP4_HevcSliceSegmentHeader::Parse
314 +---------------------------------------------------------------------*/
315 AP4_Result
316 AP4_HevcSliceSegmentHeader::Parse(const AP4_UI08* data,
317 unsigned int data_size,
318 unsigned int nal_unit_type,
319 AP4_HevcPictureParameterSet** picture_parameter_sets,
320 AP4_HevcSequenceParameterSet** sequence_parameter_sets) {
321 // initialize all members to 0
322 AP4_SetMemory(this, 0, sizeof(*this));
323
324 // some fields default to 1
325 pic_output_flag = 1;
326
327 // start the parser
328 AP4_DataBuffer unescaped(data, data_size);
329 AP4_NalParser::Unescape(unescaped);
330 AP4_BitReader bits(unescaped.GetData(), unescaped.GetDataSize());
331
332 first_slice_segment_in_pic_flag = bits.ReadBit();
333 if (nal_unit_type >= AP4_HEVC_NALU_TYPE_BLA_W_LP && nal_unit_type <= AP4_HEVC_NALU_TYPE_RSV_IRAP_VCL23) {
334 no_output_of_prior_pics_flag = bits.ReadBit();
335 }
336 slice_pic_parameter_set_id = ReadGolomb(bits);
337 if (slice_pic_parameter_set_id > AP4_HEVC_PPS_MAX_ID) {
338 return AP4_ERROR_INVALID_FORMAT;
339 }
340 const AP4_HevcPictureParameterSet* pps = picture_parameter_sets[slice_pic_parameter_set_id];
341 if (pps == NULL) {
342 return AP4_ERROR_INVALID_FORMAT;
343 }
344 const AP4_HevcSequenceParameterSet* sps = sequence_parameter_sets[pps->pps_seq_parameter_set_id];
345 if (sps == NULL) {
346 return AP4_ERROR_INVALID_FORMAT;
347 }
348
349 // PicSizeInCtbsY = PicWidthInCtbsY * PicHeightInCtbsY
350 // PicWidthInCtbsY = Ceil( pic_width_in_luma_samples / CtbSizeY )
351 // PicHeightInCtbsY = Ceil( pic_height_in_luma_samples / CtbSizeY )
352 // CtbSizeY = 1 << CtbLog2SizeY
353 // CtbLog2SizeY = MinCbLog2SizeY + log2_diff_max_min_luma_coding_block_size
354 // MinCbLog2SizeY = log2_min_luma_coding_block_size_minus3 + 3
355 unsigned int MinCbLog2SizeY = sps->log2_min_luma_coding_block_size_minus3 + 3;
356 unsigned int CtbLog2SizeY = MinCbLog2SizeY + sps->log2_diff_max_min_luma_coding_block_size;
357 unsigned int CtbSizeY = 1 << CtbLog2SizeY;
358 unsigned int PicWidthInCtbsY = (sps->pic_width_in_luma_samples + CtbSizeY - 1) / CtbSizeY;
359 unsigned int PicHeightInCtbsY = (sps->pic_height_in_luma_samples + CtbSizeY - 1) / CtbSizeY;
360 unsigned int PicSizeInCtbsY = PicWidthInCtbsY * PicHeightInCtbsY;
361
362 if (!first_slice_segment_in_pic_flag) {
363 if (pps->dependent_slice_segments_enabled_flag) {
364 dependent_slice_segment_flag = bits.ReadBit();
365 }
366
367 unsigned int bits_needed = BitsNeeded(PicSizeInCtbsY);
368 if (bits_needed) {
369 slice_segment_address = bits.ReadBits(bits_needed);
370 }
371 }
372
373 if (!dependent_slice_segment_flag) {
374 if (pps->num_extra_slice_header_bits) {
375 bits.ReadBits(pps->num_extra_slice_header_bits); // slice_reserved_flag[...]
376 }
377
378 slice_type = ReadGolomb(bits);
379 if (slice_type != AP4_HEVC_SLICE_TYPE_B && slice_type != AP4_HEVC_SLICE_TYPE_P && slice_type != AP4_HEVC_SLICE_TYPE_I) {
380 return AP4_ERROR_INVALID_FORMAT;
381 }
382 if (pps->output_flag_present_flag) {
383 pic_output_flag = bits.ReadBit();
384 }
385 if (sps->separate_colour_plane_flag) {
386 colour_plane_id = bits.ReadBits(2);
387 }
388 unsigned int slice_sao_luma_flag = 0;
389 unsigned int slice_sao_chroma_flag = 0;
390 unsigned int slice_deblocking_filter_disabled_flag = 0;
391 unsigned int slice_temporal_mvp_enabled_flag = 0;
392 const AP4_HevcShortTermRefPicSet* rps = NULL;
393 if (nal_unit_type != AP4_HEVC_NALU_TYPE_IDR_W_RADL && nal_unit_type != AP4_HEVC_NALU_TYPE_IDR_N_LP) {
394 slice_pic_order_cnt_lsb = bits.ReadBits(sps->log2_max_pic_order_cnt_lsb_minus4+4);
395 short_term_ref_pic_set_sps_flag = bits.ReadBit();
396 if (!short_term_ref_pic_set_sps_flag) {
397 AP4_Result result = parse_st_ref_pic_set(&short_term_ref_pic_set,
398 sps,
399 sps->num_short_term_ref_pic_sets,
400 sps->num_short_term_ref_pic_sets,
401 bits);
402 if (AP4_FAILED(result)) return result;
403 rps = &short_term_ref_pic_set;
404 } else if (sps->num_short_term_ref_pic_sets > 1) {
405 short_term_ref_pic_set_idx = bits.ReadBits(BitsNeeded(sps->num_short_term_ref_pic_sets));
406 rps = &sps->short_term_ref_pic_sets[short_term_ref_pic_set_idx];
407 }
408
409 if (sps->long_term_ref_pics_present_flag) {
410 if (sps->num_long_term_ref_pics_sps > 0) {
411 num_long_term_sps = ReadGolomb(bits);
412 }
413 num_long_term_pics = ReadGolomb(bits);
414
415 if (num_long_term_sps > sps->num_long_term_ref_pics_sps) {
416 return AP4_ERROR_INVALID_FORMAT;
417 }
418 if (num_long_term_sps + num_long_term_pics > AP4_HEVC_MAX_LT_REFS) {
419 return AP4_ERROR_INVALID_FORMAT;
420 }
421 for (unsigned int i=0; i<num_long_term_sps + num_long_term_pics; i++) {
422 if (i < num_long_term_sps) {
423 if (sps->num_long_term_ref_pics_sps > 1) {
424 /* lt_idx_sps[i] = */ bits.ReadBits(BitsNeeded(sps->num_long_term_ref_pics_sps));
425 }
426 } else {
427 /* poc_lsb_lt[i] = */ bits.ReadBits(sps->log2_max_pic_order_cnt_lsb_minus4+4);
428 used_by_curr_pic_lt_flag[i] = bits.ReadBit();
429 }
430 unsigned int delta_poc_msb_present_flag /*[i]*/ = bits.ReadBit();
431 if (delta_poc_msb_present_flag /*[i]*/) {
432 /* delta_poc_msb_cycle_lt[i] = */ ReadGolomb(bits);
433 }
434 }
435 }
436 if (sps->sps_temporal_mvp_enabled_flag) {
437 slice_temporal_mvp_enabled_flag = bits.ReadBit();
438 }
439 }
440 if (sps->sample_adaptive_offset_enabled_flag) {
441 slice_sao_luma_flag = bits.ReadBit();
442 unsigned int ChromaArrayType = sps->separate_colour_plane_flag ? 0 : sps->chroma_format_idc;
443 if (ChromaArrayType) {
444 slice_sao_chroma_flag = bits.ReadBit();
445 }
446 }
447 if (slice_type == AP4_HEVC_SLICE_TYPE_P || slice_type == AP4_HEVC_SLICE_TYPE_B) {
448 unsigned int num_ref_idx_l0_active_minus1 = pps->num_ref_idx_l0_default_active_minus1;
449 unsigned int num_ref_idx_l1_active_minus1 = pps->num_ref_idx_l1_default_active_minus1;
450 unsigned int num_ref_idx_active_override_flag = bits.ReadBit();
451 if (num_ref_idx_active_override_flag) {
452 num_ref_idx_l0_active_minus1 = ReadGolomb(bits);
453 if (slice_type == AP4_HEVC_SLICE_TYPE_B) {
454 num_ref_idx_l1_active_minus1 = ReadGolomb(bits);
455 }
456 }
457 if (num_ref_idx_l0_active_minus1 > 14 || num_ref_idx_l1_active_minus1 > 14) {
458 return AP4_ERROR_INVALID_FORMAT;
459 }
460 unsigned int nptc = NumPicTotalCurr(rps, this);
461 if (pps->lists_modification_present_flag && nptc > 1) {
462 // ref_pic_lists_modification
463 unsigned int ref_pic_list_modification_flag_l0 = bits.ReadBit();
464 if (ref_pic_list_modification_flag_l0) {
465 for (unsigned int i=0; i<=num_ref_idx_l0_active_minus1; i++) {
466 /* list_entry_l0[i]; */ bits.ReadBits(BitsNeeded(nptc));
467 }
468 }
469 if (slice_type == AP4_HEVC_SLICE_TYPE_B) {
470 unsigned int ref_pic_list_modification_flag_l1 = bits.ReadBit();
471 if (ref_pic_list_modification_flag_l1) {
472 for (unsigned int i=0; i<=num_ref_idx_l1_active_minus1; i++) {
473 /* list_entry_l1[i]; */ bits.ReadBits(BitsNeeded(nptc));
474 }
475 }
476 }
477 }
478 if (slice_type == AP4_HEVC_SLICE_TYPE_B) {
479 /* mvd_l1_zero_flag = */ bits.ReadBit();
480 }
481 if (pps->cabac_init_present_flag) {
482 /* cabac_init_flag = */ bits.ReadBit();
483 }
484 if (slice_temporal_mvp_enabled_flag) {
485 unsigned int collocated_from_l0_flag = 1;
486 if (slice_type == AP4_HEVC_SLICE_TYPE_B) {
487 collocated_from_l0_flag = bits.ReadBit();
488 }
489 if (( collocated_from_l0_flag && num_ref_idx_l0_active_minus1 > 0) ||
490 (!collocated_from_l0_flag && num_ref_idx_l1_active_minus1 > 0)) {
491 /* collocated_ref_idx = */ ReadGolomb(bits);
492 }
493 }
494 if ((pps->weighted_pred_flag && slice_type == AP4_HEVC_SLICE_TYPE_P) ||
495 (pps->weighted_bipred_flag && slice_type == AP4_HEVC_SLICE_TYPE_B)) {
496 // +++ pred_weight_table()
497 /* luma_log2_weight_denom = */ ReadGolomb(bits);
498 if (sps->chroma_format_idc != 0) {
499 /* delta_chroma_log2_weight_denom = */ /* SignedGolomb( */ ReadGolomb(bits) /*)*/;
500 }
501 unsigned int luma_weight_l0_flag[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
502 for (unsigned int i=0; i<=num_ref_idx_l0_active_minus1; i++) {
503 luma_weight_l0_flag[i] = bits.ReadBit();
504 }
505 unsigned int chroma_weight_l0_flag[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
506 if (sps->chroma_format_idc != 0) {
507 for (unsigned int i=0; i<=num_ref_idx_l0_active_minus1; i++) {
508 chroma_weight_l0_flag[i] = bits.ReadBit();
509 }
510 }
511 for (unsigned int i=0; i<=num_ref_idx_l0_active_minus1; i++) {
512 if (luma_weight_l0_flag[i]) {
513 /* delta_luma_weight_l0[i] = */ /*SignedGolomb(*/ ReadGolomb(bits) /*)*/;
514 /* luma_offset_l0[i] = */ /*SignedGolomb(*/ ReadGolomb(bits) /*)*/;
515 }
516 if (chroma_weight_l0_flag[i]) {
517 for (unsigned int j=0; j<2; j++) {
518 /* delta_chroma_weight_l0[i][j] = */ /*SignedGolomb(*/ ReadGolomb(bits) /*)*/;
519 /* delta_chroma_offset_l0[i][j] = */ /*SignedGolomb(*/ ReadGolomb(bits) /*)*/;
520 }
521 }
522 }
523 if (slice_type == AP4_HEVC_SLICE_TYPE_B) {
524 unsigned int luma_weight_l1_flag[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
525 for (unsigned int i=0; i<=num_ref_idx_l1_active_minus1; i++) {
526 luma_weight_l1_flag[i] = bits.ReadBit();
527 }
528 unsigned int chroma_weight_l1_flag[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
529 if (sps->chroma_format_idc != 0) {
530 for (unsigned int i=0; i<=num_ref_idx_l1_active_minus1; i++) {
531 chroma_weight_l1_flag[i] = bits.ReadBit();
532 }
533 }
534 for (unsigned int i=0; i<=num_ref_idx_l1_active_minus1; i++) {
535 if (luma_weight_l1_flag[i]) {
536 /* delta_luma_weight_l1[i] = */ /*SignedGolomb(*/ ReadGolomb(bits) /*)*/;
537 /* luma_offset_l1[i] = */ /*SignedGolomb(*/ ReadGolomb(bits) /*)*/;
538 }
539 if (chroma_weight_l1_flag[i]) {
540 for (unsigned int j=0; j<2; j++) {
541 /* delta_chroma_weight_l1[i][j] = */ /*SignedGolomb(*/ ReadGolomb(bits) /*)*/;
542 /* delta_chroma_offset_l1[i][j] = */ /*SignedGolomb(*/ ReadGolomb(bits) /*)*/;
543 }
544 }
545 }
546 }
547 // --- pred_weight_table()
548 }
549 /* five_minus_max_num_merge_cand = */ ReadGolomb(bits);
550 }
551 /* slice_qp_delta = */ /*SignedGolomb(*/ ReadGolomb(bits) /*)*/;
552 if (pps->pps_slice_chroma_qp_offsets_present_flag) {
553 /* slice_cb_qp_offset = */ /*SignedGolomb(*/ ReadGolomb(bits) /*)*/;
554 /* slice_cr_qp_offset = */ /*SignedGolomb(*/ ReadGolomb(bits) /*)*/;
555 }
556 unsigned int deblocking_filter_override_flag = 0;
557 if (pps->deblocking_filter_override_enabled_flag) {
558 deblocking_filter_override_flag = bits.ReadBit();
559 }
560 if (deblocking_filter_override_flag) {
561 slice_deblocking_filter_disabled_flag = bits.ReadBit();
562 if (!slice_deblocking_filter_disabled_flag) {
563 /* slice_beta_offset_div2 = */ /*SignedGolomb(*/ ReadGolomb(bits) /*)*/;
564 /* slice_tc_offset_div2 = */ /*SignedGolomb(*/ ReadGolomb(bits) /*)*/;
565 }
566 }
567 if (pps->pps_loop_filter_across_slices_enabled_flag &&
568 (slice_sao_luma_flag || slice_sao_chroma_flag || !slice_deblocking_filter_disabled_flag)) {
569 /* slice_loop_filter_across_slices_enabled_flag = */ bits.ReadBit();
570 }
571 }
572
573 if (pps->tiles_enabled_flag || pps->entropy_coding_sync_enabled_flag) {
574 num_entry_point_offsets = ReadGolomb(bits);
575 if (num_entry_point_offsets > 0 ) {
576 offset_len_minus1 = ReadGolomb(bits);
577 if (offset_len_minus1 > 31) {
578 return AP4_ERROR_INVALID_FORMAT;
579 }
580 for (unsigned int i=0; i<num_entry_point_offsets; i++) {
581 bits.ReadBits(offset_len_minus1+1);
582 }
583 }
584 }
585
586 if (pps->slice_segment_header_extension_present_flag) {
587 unsigned int slice_segment_header_extension_length = ReadGolomb(bits);
588 for (unsigned int i=0; i<slice_segment_header_extension_length; i++) {
589 bits.ReadBits(8); // slice_segment_header_extension_data_byte[i]
590 }
591 }
592
593 // byte_alignment()
594 bits.ReadBit(); // alignment_bit_equal_to_one
595 unsigned int bits_read = bits.GetBitsRead();
596 if (bits_read % 8) {
597 bits.ReadBits(8-(bits_read%8));
598 }
599
600 /* compute the size */
601 size = bits.GetBitsRead();
602 DBG_PRINTF_2("*** slice segment header size=%d bits (%d bytes)\n", size, size/8);
603
604 return AP4_SUCCESS;
605 }
606
607 /*----------------------------------------------------------------------
608 | AP4_HevcProfileTierLevel::AP4_HevcProfileTierLevel
609 +---------------------------------------------------------------------*/
610 AP4_HevcProfileTierLevel::AP4_HevcProfileTierLevel() :
611 general_profile_space(0),
612 general_tier_flag(0),
613 general_profile_idc(0),
614 general_profile_compatibility_flags(0),
615 general_constraint_indicator_flags(0),
616 general_level_idc(0)
617 {
618 AP4_SetMemory(&sub_layer_info[0], 0, sizeof(sub_layer_info));
619 }
620
621 /*----------------------------------------------------------------------
622 | AP4_HevcProfileTierLevel::Parse
623 +---------------------------------------------------------------------*/
624 AP4_Result
625 AP4_HevcProfileTierLevel::Parse(AP4_BitReader& bits, unsigned int max_num_sub_layers_minus_1)
626 {
627 // profile_tier_level
628 general_profile_space = bits.ReadBits(2);
629 general_tier_flag = bits.ReadBit();
630 general_profile_idc = bits.ReadBits(5);
631 general_profile_compatibility_flags = bits.ReadBits(32);
632
633 general_constraint_indicator_flags = ((AP4_UI64)bits.ReadBits(16)) << 32;
634 general_constraint_indicator_flags |= bits.ReadBits(32);
635
636 general_level_idc = bits.ReadBits(8);
637 for (unsigned int i = 0; i < max_num_sub_layers_minus_1; i++) {
638 sub_layer_info[i].sub_layer_profile_present_flag = bits.ReadBit();
639 sub_layer_info[i].sub_layer_level_present_flag = bits.ReadBit();
640 }
641 if (max_num_sub_layers_minus_1) {
642 for (unsigned int i = max_num_sub_layers_minus_1; i < 8; i++) {
643 bits.ReadBits(2); // reserved_zero_2bits[i]
644 }
645 }
646 for (unsigned int i = 0; i < max_num_sub_layers_minus_1; i++) {
647 if (sub_layer_info[i].sub_layer_profile_present_flag) {
648 sub_layer_info[i].sub_layer_profile_space = bits.ReadBits(2);
649 sub_layer_info[i].sub_layer_tier_flag = bits.ReadBit();
650 sub_layer_info[i].sub_layer_profile_idc = bits.ReadBits(5);
651 sub_layer_info[i].sub_layer_profile_compatibility_flags = bits.ReadBits(32);
652 sub_layer_info[i].sub_layer_progressive_source_flag = bits.ReadBit();
653 sub_layer_info[i].sub_layer_interlaced_source_flag = bits.ReadBit();
654 sub_layer_info[i].sub_layer_non_packed_constraint_flag = bits.ReadBit();
655 sub_layer_info[i].sub_layer_frame_only_constraint_flag = bits.ReadBit();
656 bits.ReadBits(32); bits.ReadBits(12); // sub_layer_reserved_zero_44bits
657 }
658 if (sub_layer_info[i].sub_layer_level_present_flag) {
659 sub_layer_info[i].sub_layer_level_idc = bits.ReadBits(8);
660 }
661 }
662
663 return AP4_SUCCESS;
664 }
665
666 /*----------------------------------------------------------------------
667 | AP4_HevcPictureParameterSet::AP4_HevcPictureParameterSet
668 +---------------------------------------------------------------------*/
669 AP4_HevcPictureParameterSet::AP4_HevcPictureParameterSet() :
670 pps_pic_parameter_set_id(0),
671 pps_seq_parameter_set_id(0),
672 dependent_slice_segments_enabled_flag(0),
673 output_flag_present_flag(0),
674 num_extra_slice_header_bits(0),
675 sign_data_hiding_enabled_flag(0),
676 cabac_init_present_flag(0),
677 num_ref_idx_l0_default_active_minus1(0),
678 num_ref_idx_l1_default_active_minus1(0),
679 init_qp_minus26(0),
680 constrained_intra_pred_flag(0),
681 transform_skip_enabled_flag(0),
682 cu_qp_delta_enabled_flag(0),
683 diff_cu_qp_delta_depth(0),
684 pps_cb_qp_offset(0),
685 pps_cr_qp_offset(0),
686 pps_slice_chroma_qp_offsets_present_flag(0),
687 weighted_pred_flag(0),
688 weighted_bipred_flag(0),
689 transquant_bypass_enabled_flag(0),
690 tiles_enabled_flag(0),
691 entropy_coding_sync_enabled_flag(0),
692 num_tile_columns_minus1(0),
693 num_tile_rows_minus1(0),
694 uniform_spacing_flag(1),
695 loop_filter_across_tiles_enabled_flag(1),
696 pps_loop_filter_across_slices_enabled_flag(0),
697 deblocking_filter_control_present_flag(0),
698 deblocking_filter_override_enabled_flag(0),
699 pps_deblocking_filter_disabled_flag(0),
700 pps_beta_offset_div2(0),
701 pps_tc_offset_div2(0),
702 pps_scaling_list_data_present_flag(0),
703 lists_modification_present_flag(0),
704 log2_parallel_merge_level_minus2(0),
705 slice_segment_header_extension_present_flag(0)
706 {
707 }
708
709 /*----------------------------------------------------------------------
710 | AP4_HevcPictureParameterSet::Parse
711 +---------------------------------------------------------------------*/
712 AP4_Result
713 AP4_HevcPictureParameterSet::Parse(const unsigned char* data, unsigned int data_size)
714 {
715 raw_bytes.SetData(data, data_size);
716
717 AP4_DataBuffer unescaped(data, data_size);
718 AP4_NalParser::Unescape(unescaped);
719 AP4_BitReader bits(unescaped.GetData(), unescaped.GetDataSize());
720
721 bits.SkipBits(16); // NAL Unit Header
722
723 pps_pic_parameter_set_id = ReadGolomb(bits);
724 if (pps_pic_parameter_set_id > AP4_HEVC_PPS_MAX_ID) {
725 return AP4_ERROR_INVALID_FORMAT;
726 }
727 pps_seq_parameter_set_id = ReadGolomb(bits);
728 if (pps_seq_parameter_set_id > AP4_HEVC_SPS_MAX_ID) {
729 return AP4_ERROR_INVALID_FORMAT;
730 }
731 dependent_slice_segments_enabled_flag = bits.ReadBit();
732 output_flag_present_flag = bits.ReadBit();
733 num_extra_slice_header_bits = bits.ReadBits(3);
734 sign_data_hiding_enabled_flag = bits.ReadBit();
735 cabac_init_present_flag = bits.ReadBit();
736 num_ref_idx_l0_default_active_minus1 = ReadGolomb(bits);
737 num_ref_idx_l1_default_active_minus1 = ReadGolomb(bits);
738 init_qp_minus26 = SignedGolomb(ReadGolomb(bits));
739 constrained_intra_pred_flag = bits.ReadBit();
740 transform_skip_enabled_flag = bits.ReadBit();
741 cu_qp_delta_enabled_flag = bits.ReadBit();
742 if (cu_qp_delta_enabled_flag) {
743 diff_cu_qp_delta_depth = ReadGolomb(bits);
744 }
745 pps_cb_qp_offset = SignedGolomb(ReadGolomb(bits));
746 pps_cr_qp_offset = SignedGolomb(ReadGolomb(bits));
747 pps_slice_chroma_qp_offsets_present_flag = bits.ReadBit();
748 weighted_pred_flag = bits.ReadBit();
749 weighted_bipred_flag = bits.ReadBit();
750 transquant_bypass_enabled_flag = bits.ReadBit();
751 tiles_enabled_flag = bits.ReadBit();
752 entropy_coding_sync_enabled_flag = bits.ReadBit();
753 if (tiles_enabled_flag) {
754 num_tile_columns_minus1 = ReadGolomb(bits);
755 num_tile_rows_minus1 = ReadGolomb(bits);
756 uniform_spacing_flag = bits.ReadBit();
757 if (!uniform_spacing_flag) {
758 for (unsigned int i=0; i<num_tile_columns_minus1; i++) {
759 ReadGolomb(bits); // column_width_minus1[i]
760 }
761 for (unsigned int i = 0; i < num_tile_rows_minus1; i++) {
762 ReadGolomb(bits); // row_height_minus1[i]
763 }
764 }
765 loop_filter_across_tiles_enabled_flag = bits.ReadBit();
766 }
767 pps_loop_filter_across_slices_enabled_flag = bits.ReadBit();
768 deblocking_filter_control_present_flag = bits.ReadBit();
769 if (deblocking_filter_control_present_flag) {
770 deblocking_filter_override_enabled_flag = bits.ReadBit();
771 pps_deblocking_filter_disabled_flag = bits.ReadBit();
772 if (!pps_deblocking_filter_disabled_flag) {
773 pps_beta_offset_div2 = SignedGolomb(ReadGolomb(bits));
774 pps_tc_offset_div2 = SignedGolomb(ReadGolomb(bits));
775 }
776 }
777 pps_scaling_list_data_present_flag = bits.ReadBit();
778 if (pps_scaling_list_data_present_flag) {
779 scaling_list_data(bits);
780 }
781 lists_modification_present_flag = bits.ReadBit();
782 log2_parallel_merge_level_minus2 = ReadGolomb(bits);
783 slice_segment_header_extension_present_flag = bits.ReadBit();
784
785 return AP4_SUCCESS;
786 }
787
788 /*----------------------------------------------------------------------
789 | AP4_HevcSequenceParameterSet::AP4_HevcSequenceParameterSet
790 +---------------------------------------------------------------------*/
791 AP4_HevcSequenceParameterSet::AP4_HevcSequenceParameterSet() :
792 sps_video_parameter_set_id(0),
793 sps_max_sub_layers_minus1(0),
794 sps_temporal_id_nesting_flag(0),
795 sps_seq_parameter_set_id(0),
796 chroma_format_idc(0),
797 separate_colour_plane_flag(0),
798 pic_width_in_luma_samples(0),
799 pic_height_in_luma_samples(0),
800 conformance_window_flag(0),
801 conf_win_left_offset(0),
802 conf_win_right_offset(0),
803 conf_win_top_offset(0),
804 conf_win_bottom_offset(0),
805 bit_depth_luma_minus8(0),
806 bit_depth_chroma_minus8(0),
807 log2_max_pic_order_cnt_lsb_minus4(0),
808 sps_sub_layer_ordering_info_present_flag(0),
809 log2_min_luma_coding_block_size_minus3(0),
810 log2_diff_max_min_luma_coding_block_size(0),
811 log2_min_transform_block_size_minus2(0),
812 log2_diff_max_min_transform_block_size(0),
813 max_transform_hierarchy_depth_inter(0),
814 max_transform_hierarchy_depth_intra(0),
815 scaling_list_enabled_flag(0),
816 sps_scaling_list_data_present_flag(0),
817 amp_enabled_flag(0),
818 sample_adaptive_offset_enabled_flag(0),
819 pcm_enabled_flag(0),
820 pcm_sample_bit_depth_luma_minus1(0),
821 pcm_sample_bit_depth_chroma_minus1(0),
822 log2_min_pcm_luma_coding_block_size_minus3(0),
823 log2_diff_max_min_pcm_luma_coding_block_size(0),
824 pcm_loop_filter_disabled_flag(0),
825 num_short_term_ref_pic_sets(0),
826 long_term_ref_pics_present_flag(0),
827 num_long_term_ref_pics_sps(0),
828 sps_temporal_mvp_enabled_flag(0),
829 strong_intra_smoothing_enabled_flag(0)
830 {
831 AP4_SetMemory(&profile_tier_level, 0, sizeof(profile_tier_level));
832 for (unsigned int i=0; i<8; i++) {
833 sps_max_dec_pic_buffering_minus1[i] = 0;
834 sps_max_num_reorder_pics[i] = 0;
835 sps_max_latency_increase_plus1[i] = 0;
836 }
837 AP4_SetMemory(short_term_ref_pic_sets, 0, sizeof(short_term_ref_pic_sets));
838 }
839
840 /*----------------------------------------------------------------------
841 | AP4_HevcSequenceParameterSet::Parse
842 +---------------------------------------------------------------------*/
843 AP4_Result
844 AP4_HevcSequenceParameterSet::Parse(const unsigned char* data, unsigned int data_size)
845 {
846 raw_bytes.SetData(data, data_size);
847
848 AP4_DataBuffer unescaped(data, data_size);
849 AP4_NalParser::Unescape(unescaped);
850 AP4_BitReader bits(unescaped.GetData(), unescaped.GetDataSize());
851
852 bits.SkipBits(16); // NAL Unit Header
853
854 sps_video_parameter_set_id = bits.ReadBits(4);
855 sps_max_sub_layers_minus1 = bits.ReadBits(3);
856 sps_temporal_id_nesting_flag = bits.ReadBit();
857
858 AP4_Result result = profile_tier_level.Parse(bits, sps_max_sub_layers_minus1);
859 if (AP4_FAILED(result)) {
860 return result;
861 }
862
863 sps_seq_parameter_set_id = ReadGolomb(bits);
864 if (sps_seq_parameter_set_id > AP4_HEVC_SPS_MAX_ID) {
865 return AP4_ERROR_INVALID_FORMAT;
866 }
867
868 chroma_format_idc = ReadGolomb(bits);
869 if (chroma_format_idc == 3) {
870 separate_colour_plane_flag = bits.ReadBit();
871 }
872 pic_width_in_luma_samples = ReadGolomb(bits);
873 pic_height_in_luma_samples = ReadGolomb(bits);
874 conformance_window_flag = bits.ReadBit();
875
876 if (conformance_window_flag) {
877 conf_win_left_offset = ReadGolomb(bits);
878 conf_win_right_offset = ReadGolomb(bits);
879 conf_win_top_offset = ReadGolomb(bits);
880 conf_win_bottom_offset = ReadGolomb(bits);
881 }
882 bit_depth_luma_minus8 = ReadGolomb(bits);
883 bit_depth_chroma_minus8 = ReadGolomb(bits);
884 log2_max_pic_order_cnt_lsb_minus4 = ReadGolomb(bits);
885 if (log2_max_pic_order_cnt_lsb_minus4 > 16) {
886 return AP4_ERROR_INVALID_FORMAT;
887 }
888 sps_sub_layer_ordering_info_present_flag = bits.ReadBit();
889 for (unsigned int i = (sps_sub_layer_ordering_info_present_flag ? 0 : sps_max_sub_layers_minus1);
890 i <= sps_max_sub_layers_minus1;
891 i++) {
892 sps_max_dec_pic_buffering_minus1[i] = ReadGolomb(bits);
893 sps_max_num_reorder_pics[i] = ReadGolomb(bits);
894 sps_max_latency_increase_plus1[i] = ReadGolomb(bits);
895 }
896 log2_min_luma_coding_block_size_minus3 = ReadGolomb(bits);
897 log2_diff_max_min_luma_coding_block_size = ReadGolomb(bits);
898 log2_min_transform_block_size_minus2 = ReadGolomb(bits);
899 log2_diff_max_min_transform_block_size = ReadGolomb(bits);
900 max_transform_hierarchy_depth_inter = ReadGolomb(bits);
901 max_transform_hierarchy_depth_intra = ReadGolomb(bits);
902 scaling_list_enabled_flag = bits.ReadBit();
903 if (scaling_list_enabled_flag) {
904 sps_scaling_list_data_present_flag = bits.ReadBit();
905 if (sps_scaling_list_data_present_flag) {
906 scaling_list_data(bits);
907 }
908 }
909 amp_enabled_flag = bits.ReadBit();
910 sample_adaptive_offset_enabled_flag = bits.ReadBit();
911 pcm_enabled_flag = bits.ReadBit();
912 if (pcm_enabled_flag) {
913 pcm_sample_bit_depth_luma_minus1 = bits.ReadBits(4);
914 pcm_sample_bit_depth_chroma_minus1 = bits.ReadBits(4);
915 log2_min_pcm_luma_coding_block_size_minus3 = ReadGolomb(bits);
916 log2_diff_max_min_pcm_luma_coding_block_size = ReadGolomb(bits);
917 pcm_loop_filter_disabled_flag = bits.ReadBit();
918 }
919 num_short_term_ref_pic_sets = ReadGolomb(bits);
920 if (num_short_term_ref_pic_sets > AP4_HEVC_SPS_MAX_RPS) {
921 return AP4_ERROR_INVALID_FORMAT;
922 }
923 for (unsigned int i=0; i<num_short_term_ref_pic_sets; i++) {
924 result = parse_st_ref_pic_set(&short_term_ref_pic_sets[i], this, i, num_short_term_ref_pic_sets, bits);
925 if (AP4_FAILED(result)) return result;
926 }
927 long_term_ref_pics_present_flag = bits.ReadBit();
928 if (long_term_ref_pics_present_flag) {
929 num_long_term_ref_pics_sps = ReadGolomb(bits);
930 for (unsigned int i=0; i<num_long_term_ref_pics_sps; i++) {
931 /* lt_ref_pic_poc_lsb_sps[i] = */ bits.ReadBits(log2_max_pic_order_cnt_lsb_minus4 + 4);
932 /* used_by_curr_pic_lt_sps_flag[i] = */ bits.ReadBit();
933 }
934 }
935 sps_temporal_mvp_enabled_flag = bits.ReadBit();
936 strong_intra_smoothing_enabled_flag = bits.ReadBit();
937
938 return AP4_SUCCESS;
939 }
940
941 /*----------------------------------------------------------------------
942 | AP4_HevcSequenceParameterSet::GetInfo
943 +---------------------------------------------------------------------*/
944 void
945 AP4_HevcSequenceParameterSet::GetInfo(unsigned int& width, unsigned int& height)
946 {
947 width = pic_width_in_luma_samples;
948 height = pic_height_in_luma_samples;
949 }
950
951 /*----------------------------------------------------------------------
952 | AP4_HevcVideoParameterSet::AP4_HevcVideoParameterSet
953 +---------------------------------------------------------------------*/
954 AP4_HevcVideoParameterSet::AP4_HevcVideoParameterSet() :
955 vps_video_parameter_set_id(0),
956 vps_max_layers_minus1(0),
957 vps_max_sub_layers_minus1(0),
958 vps_temporal_id_nesting_flag(0),
959 vps_sub_layer_ordering_info_present_flag(0),
960 vps_max_layer_id(0),
961 vps_num_layer_sets_minus1(0),
962 vps_timing_info_present_flag(0),
963 vps_num_units_in_tick(0),
964 vps_time_scale(0),
965 vps_poc_proportional_to_timing_flag(0),
966 vps_num_ticks_poc_diff_one_minus1(0)
967 {
968 AP4_SetMemory(&profile_tier_level, 0, sizeof(profile_tier_level));
969 for (unsigned int i=0; i<8; i++) {
970 vps_max_dec_pic_buffering_minus1[i] = 0;
971 vps_max_num_reorder_pics[i] = 0;
972 vps_max_latency_increase_plus1[i] = 0;
973 }
974 }
975
976 /*----------------------------------------------------------------------
977 | AP4_HevcVideoParameterSet::GetInfo
978 +---------------------------------------------------------------------*/
979 void
980 AP4_HevcVideoParameterSet::GetInfo(unsigned int& time_scale, unsigned int& num_units)
981 {
982 time_scale = vps_time_scale;
983 num_units = vps_num_units_in_tick;
984 }
985
986 /*----------------------------------------------------------------------
987 | AP4_HevcVideoParameterSet::Parse
988 +---------------------------------------------------------------------*/
989 AP4_Result
990 AP4_HevcVideoParameterSet::Parse(const unsigned char* data, unsigned int data_size)
991 {
992 raw_bytes.SetData(data, data_size);
993
994 AP4_DataBuffer unescaped(data, data_size);
995 AP4_NalParser::Unescape(unescaped);
996 AP4_BitReader bits(unescaped.GetData(), unescaped.GetDataSize());
997
998 bits.SkipBits(16); // NAL Unit Header
999
1000 vps_video_parameter_set_id = bits.ReadBits(4);
1001 /* vps_reserved_three_2bits */ bits.ReadBits(2);
1002 vps_max_layers_minus1 = bits.ReadBits(6);
1003 vps_max_sub_layers_minus1 = bits.ReadBits(3);
1004 vps_temporal_id_nesting_flag = bits.ReadBit();
1005 /* vps_reserved_0xffff_16bits */ bits.ReadBits(16);
1006 profile_tier_level.Parse(bits, vps_max_sub_layers_minus1);
1007 vps_sub_layer_ordering_info_present_flag = bits.ReadBit();
1008 for (unsigned int i = (vps_sub_layer_ordering_info_present_flag ? 0 : vps_max_sub_layers_minus1);
1009 i <= vps_max_sub_layers_minus1;
1010 i++) {
1011 vps_max_dec_pic_buffering_minus1[i] = ReadGolomb(bits);
1012 vps_max_num_reorder_pics[i] = ReadGolomb(bits);
1013 vps_max_latency_increase_plus1[i] = ReadGolomb(bits);
1014 }
1015 vps_max_layer_id = bits.ReadBits(6);
1016 vps_num_layer_sets_minus1 = ReadGolomb(bits);
1017 for (unsigned int i = 1; i <= vps_num_layer_sets_minus1; i++) {
1018 for (unsigned int j = 0; j <= vps_max_layer_id; j++) {
1019 bits.ReadBit();
1020 }
1021 }
1022 vps_timing_info_present_flag = bits.ReadBit();
1023 if (vps_timing_info_present_flag) {
1024 vps_num_units_in_tick = bits.ReadBits(32);
1025 vps_time_scale = bits.ReadBits(32);
1026 vps_poc_proportional_to_timing_flag = bits.ReadBit();
1027 if (vps_poc_proportional_to_timing_flag) {
1028 vps_num_ticks_poc_diff_one_minus1 = ReadGolomb(bits);
1029 }
1030 }
1031
1032 return AP4_SUCCESS;
1033 }
1034
1035 /*----------------------------------------------------------------------
1036 | AP4_HevcFrameParser::AP4_HevcFrameParser
1037 +---------------------------------------------------------------------*/
1038 AP4_HevcFrameParser::AP4_HevcFrameParser() :
1039 m_CurrentSlice(NULL),
1040 m_CurrentNalUnitType(0),
1041 m_CurrentTemporalId(0),
1042 m_TotalNalUnitCount(0),
1043 m_TotalAccessUnitCount(0),
1044 m_AccessUnitFlags(0),
1045 m_VclNalUnitsInAccessUnit(0),
1046 m_PrevTid0Pic_PicOrderCntMsb(0),
1047 m_PrevTid0Pic_PicOrderCntLsb(0)
1048 {
1049 for (unsigned int i=0; i<=AP4_HEVC_PPS_MAX_ID; i++) {
1050 m_PPS[i] = NULL;
1051 }
1052 for (unsigned int i=0; i<=AP4_HEVC_SPS_MAX_ID; i++) {
1053 m_SPS[i] = NULL;
1054 }
1055 for (unsigned int i=0; i<=AP4_HEVC_VPS_MAX_ID; i++) {
1056 m_VPS[i] = NULL;
1057 }
1058 }
1059
1060 /*----------------------------------------------------------------------
1061 | AP4_HevcFrameParser::~AP4_HevcFrameParser
1062 +---------------------------------------------------------------------*/
1063 AP4_HevcFrameParser::~AP4_HevcFrameParser()
1064 {
1065 delete m_CurrentSlice;
1066
1067 for (unsigned int i=0; i<=AP4_HEVC_PPS_MAX_ID; i++) {
1068 delete m_PPS[i];
1069 }
1070 for (unsigned int i=0; i<=AP4_HEVC_SPS_MAX_ID; i++) {
1071 delete m_SPS[i];
1072 }
1073 for (unsigned int i=0; i<=AP4_HEVC_VPS_MAX_ID; i++) {
1074 delete m_VPS[i];
1075 }
1076
1077 // cleanup any un-transfered buffers
1078 for (unsigned int i=0; i<m_AccessUnitData.ItemCount(); i++) {
1079 delete m_AccessUnitData[i];
1080 }
1081 }
1082
1083 /*----------------------------------------------------------------------
1084 | AP4_HevcFrameParser::AppendNalUnitData
1085 +---------------------------------------------------------------------*/
1086 void
1087 AP4_HevcFrameParser::AppendNalUnitData(const unsigned char* data, unsigned int data_size)
1088 {
1089 m_AccessUnitData.Append(new AP4_DataBuffer(data, data_size));
1090 }
1091
1092 /*----------------------------------------------------------------------
1093 | AP4_HevcFrameParser::CheckIfAccessUnitIsCompleted
1094 +---------------------------------------------------------------------*/
1095 void
1096 AP4_HevcFrameParser::CheckIfAccessUnitIsCompleted(AccessUnitInfo& access_unit_info)
1097 {
1098 if (!m_VclNalUnitsInAccessUnit || !m_CurrentSlice) {
1099 return;
1100 }
1101 DBG_PRINTF_0("\n>>>>>>> New Access Unit\n");
1102
1103 AP4_HevcSequenceParameterSet* sps = m_SPS[m_CurrentSlice->slice_pic_parameter_set_id];
1104 if (sps == NULL) return;
1105
1106 unsigned int MaxPicOrderCntLsb = (1 << (sps->log2_max_pic_order_cnt_lsb_minus4+4));
1107 bool NoRaslOutputFlag = false;
1108 if (m_AccessUnitFlags & AP4_HEVC_ACCESS_UNIT_FLAG_IS_IRAP) {
1109 if ((m_AccessUnitFlags & AP4_HEVC_ACCESS_UNIT_FLAG_IS_IDR) ||
1110 (m_AccessUnitFlags & AP4_HEVC_ACCESS_UNIT_FLAG_IS_BLA)
1111 /* TODO: check for end-of-sequence */) {
1112 NoRaslOutputFlag = true;
1113 }
1114 }
1115 unsigned int PrevPicOrderCntLsb = 0;
1116 unsigned int PrevPicOrderCntMsb = 0;
1117 if (!((m_AccessUnitFlags & AP4_HEVC_ACCESS_UNIT_FLAG_IS_IRAP) && NoRaslOutputFlag)) {
1118 PrevPicOrderCntLsb = m_PrevTid0Pic_PicOrderCntLsb;
1119 PrevPicOrderCntMsb = m_PrevTid0Pic_PicOrderCntMsb;
1120 }
1121 unsigned int PicOrderCntMsb = 0;
1122 if (m_CurrentSlice->slice_pic_order_cnt_lsb < PrevPicOrderCntLsb &&
1123 (PrevPicOrderCntLsb - m_CurrentSlice->slice_pic_order_cnt_lsb) >= (MaxPicOrderCntLsb / 2)) {
1124 PicOrderCntMsb = PrevPicOrderCntMsb + MaxPicOrderCntLsb;
1125 } else if (m_CurrentSlice->slice_pic_order_cnt_lsb > PrevPicOrderCntLsb &&
1126 (m_CurrentSlice->slice_pic_order_cnt_lsb - PrevPicOrderCntLsb) > (MaxPicOrderCntLsb / 2)) {
1127 PicOrderCntMsb = PrevPicOrderCntMsb - MaxPicOrderCntLsb;
1128 } else {
1129 PicOrderCntMsb = PrevPicOrderCntMsb;
1130 }
1131
1132 if (m_CurrentNalUnitType == AP4_HEVC_NALU_TYPE_BLA_N_LP ||
1133 m_CurrentNalUnitType == AP4_HEVC_NALU_TYPE_BLA_W_LP ||
1134 m_CurrentNalUnitType == AP4_HEVC_NALU_TYPE_BLA_W_RADL) {
1135 PicOrderCntMsb = 0;
1136 }
1137 unsigned int PicOrderCntVal = PicOrderCntMsb + m_CurrentSlice->slice_pic_order_cnt_lsb;
1138
1139 if (m_CurrentTemporalId == 0 && (
1140 !(m_AccessUnitFlags & AP4_HEVC_ACCESS_UNIT_FLAG_IS_RADL) ||
1141 !(m_AccessUnitFlags & AP4_HEVC_ACCESS_UNIT_FLAG_IS_RASL) ||
1142 !(m_AccessUnitFlags & AP4_HEVC_ACCESS_UNIT_FLAG_IS_SUBLAYER_NON_REF))) {
1143 m_PrevTid0Pic_PicOrderCntLsb = m_CurrentSlice->slice_pic_order_cnt_lsb;
1144 m_PrevTid0Pic_PicOrderCntMsb = PicOrderCntMsb;
1145 }
1146
1147 // emit the access unit (transfer ownership)
1148 access_unit_info.nal_units = m_AccessUnitData;
1149 access_unit_info.decode_order = m_TotalAccessUnitCount;
1150 access_unit_info.is_random_access = (m_AccessUnitFlags & AP4_HEVC_ACCESS_UNIT_FLAG_IS_IRAP) ? true : false;
1151 access_unit_info.display_order = PicOrderCntVal;
1152 m_AccessUnitData.Clear();
1153 m_VclNalUnitsInAccessUnit = 0;
1154 m_AccessUnitFlags = 0;
1155 delete m_CurrentSlice;
1156 m_CurrentSlice = NULL;
1157 ++m_TotalAccessUnitCount;
1158 }
1159
1160 /*----------------------------------------------------------------------
1161 | AP4_HevcFrameParser::Feed
1162 +---------------------------------------------------------------------*/
1163 AP4_Result
1164 AP4_HevcFrameParser::Feed(const void* data,
1165 AP4_Size data_size,
1166 AP4_Size& bytes_consumed,
1167 AccessUnitInfo& access_unit_info,
1168 bool eos)
1169 {
1170 const AP4_DataBuffer* nal_unit = NULL;
1171
1172 // feed the NAL unit parser
1173 AP4_Result result = m_NalParser.Feed(data, data_size, bytes_consumed, nal_unit, eos);
1174 if (AP4_FAILED(result)) {
1175 return result;
1176 }
1177
1178 if (bytes_consumed < data_size) {
1179 // there will be more to parse
1180 eos = false;
1181 }
1182
1183 return Feed(nal_unit ? nal_unit->GetData() : NULL,
1184 nal_unit ? nal_unit->GetDataSize() : 0,
1185 access_unit_info,
1186 eos);
1187 }
1188
1189 /*----------------------------------------------------------------------
1190 | AP4_HevcFrameParser::Feed
1191 +---------------------------------------------------------------------*/
1192 AP4_Result
1193 AP4_HevcFrameParser::Feed(const AP4_UI08* nal_unit,
1194 AP4_Size nal_unit_size,
1195 AccessUnitInfo& access_unit_info,
1196 bool last_unit)
1197 {
1198 AP4_Result result;
1199
1200 // default return values
1201 access_unit_info.Reset();
1202
1203 if (nal_unit && nal_unit_size >= 2) {
1204 unsigned int nal_unit_type = (nal_unit[0] >> 1) & 0x3F;
1205 unsigned int nuh_layer_id = (((nal_unit[0] & 1) << 5) | (nal_unit[1] >> 3));
1206 unsigned int nuh_temporal_id = nal_unit[1] & 0x7;
1207 (void)nuh_layer_id;
1208
1209 if (nuh_temporal_id-- == 0) {
1210 // illegal value, ignore this NAL unit
1211 return AP4_SUCCESS;
1212 }
1213
1214 m_CurrentNalUnitType = nal_unit_type;
1215 m_CurrentTemporalId = nuh_temporal_id;
1216 const char* nal_unit_type_name = AP4_HevcNalParser::NaluTypeName(nal_unit_type);
1217 if (nal_unit_type_name == NULL) nal_unit_type_name = "UNKNOWN";
1218 DBG_PRINTF_6("NALU %5d: layer_id=%d, temporal_id=%d, size=%5d, type=%02d (%s) ",
1219 m_TotalNalUnitCount,
1220 nuh_layer_id,
1221 nuh_temporal_id,
1222 nal_unit_size,
1223 nal_unit_type,
1224 nal_unit_type_name);
1225
1226 // parse the NAL unit details and react accordingly
1227 if (nal_unit_type < AP4_HEVC_NALU_TYPE_VPS_NUT) {
1228 // this is a VCL NAL Unit
1229 AP4_HevcSliceSegmentHeader* slice_header = new AP4_HevcSliceSegmentHeader;
1230 result = slice_header->Parse(nal_unit+2, nal_unit_size-2, nal_unit_type, &m_PPS[0], &m_SPS[0]);
1231 if (AP4_FAILED(result)) {
1232 DBG_PRINTF_1("VCL parsing failed (%d)", result);
1233 return AP4_ERROR_INVALID_FORMAT;
1234 }
1235
1236 #if defined(AP4_HEVC_PARSER_ENABLE_DEBUG)
1237 const char* slice_type_name = AP4_HevcNalParser::SliceTypeName(slice_header->slice_type);
1238 if (slice_type_name == NULL) slice_type_name = "?";
1239 DBG_PRINTF_5(" pps_id=%d, first=%s, slice_type=%d (%s), size=%d, ",
1240 slice_header->slice_pic_parameter_set_id,
1241 slice_header->first_slice_segment_in_pic_flag?"YES":"NO",
1242 slice_header->slice_type,
1243 slice_type_name,
1244 slice_header->size);
1245 #endif
1246 if (slice_header->first_slice_segment_in_pic_flag) {
1247 CheckIfAccessUnitIsCompleted(access_unit_info);
1248 }
1249
1250 // compute access unit flags
1251 m_AccessUnitFlags = 0;
1252 if (nal_unit_type >= AP4_HEVC_NALU_TYPE_BLA_W_LP && nal_unit_type <= AP4_HEVC_NALU_TYPE_RSV_IRAP_VCL23) {
1253 m_AccessUnitFlags |= AP4_HEVC_ACCESS_UNIT_FLAG_IS_IRAP;
1254 }
1255 if (nal_unit_type == AP4_HEVC_NALU_TYPE_IDR_W_RADL || nal_unit_type == AP4_HEVC_NALU_TYPE_IDR_N_LP) {
1256 m_AccessUnitFlags |= AP4_HEVC_ACCESS_UNIT_FLAG_IS_IDR;
1257 }
1258 if (nal_unit_type >= AP4_HEVC_NALU_TYPE_BLA_W_LP && nal_unit_type <= AP4_HEVC_NALU_TYPE_BLA_N_LP) {
1259 m_AccessUnitFlags |= AP4_HEVC_ACCESS_UNIT_FLAG_IS_BLA;
1260 }
1261 if (nal_unit_type == AP4_HEVC_NALU_TYPE_RADL_N || nal_unit_type == AP4_HEVC_NALU_TYPE_RADL_R) {
1262 m_AccessUnitFlags |= AP4_HEVC_ACCESS_UNIT_FLAG_IS_RADL;
1263 }
1264 if (nal_unit_type == AP4_HEVC_NALU_TYPE_RASL_N || nal_unit_type == AP4_HEVC_NALU_TYPE_RASL_R) {
1265 m_AccessUnitFlags |= AP4_HEVC_ACCESS_UNIT_FLAG_IS_RASL;
1266 }
1267 if (nal_unit_type <= AP4_HEVC_NALU_TYPE_RSV_VCL_R15 && ((nal_unit_type & 1) == 0)) {
1268 m_AccessUnitFlags |= AP4_HEVC_ACCESS_UNIT_FLAG_IS_SUBLAYER_NON_REF;
1269 }
1270
1271 // make this the current slice if this is the first slice in the access unit
1272 if (m_CurrentSlice == NULL) {
1273 m_CurrentSlice = slice_header;
1274 }
1275
1276 // buffer this NAL unit
1277 AppendNalUnitData(nal_unit, nal_unit_size);
1278 ++m_VclNalUnitsInAccessUnit;
1279 } else if (nal_unit_type == AP4_HEVC_NALU_TYPE_AUD_NUT) {
1280 unsigned int pic_type = (nal_unit[1]>>5);
1281 const char* pic_type_name = AP4_HevcNalParser::PicTypeName(pic_type);
1282 if (pic_type_name == NULL) pic_type_name = "UNKNOWN";
1283 DBG_PRINTF_2("[%d:%s]\n", pic_type, pic_type_name);
1284
1285 CheckIfAccessUnitIsCompleted(access_unit_info);
1286 } else if (nal_unit_type == AP4_HEVC_NALU_TYPE_PPS_NUT) {
1287 AP4_HevcPictureParameterSet* pps = new AP4_HevcPictureParameterSet;
1288 result = pps->Parse(nal_unit, nal_unit_size);
1289 if (AP4_FAILED(result)) {
1290 DBG_PRINTF_0("PPS ERROR!!!");
1291 delete pps;
1292 return AP4_ERROR_INVALID_FORMAT;
1293 }
1294 delete m_PPS[pps->pps_pic_parameter_set_id];
1295 m_PPS[pps->pps_pic_parameter_set_id] = pps;
1296 DBG_PRINTF_2("PPS pps_id=%d, sps_id=%d", pps->pps_pic_parameter_set_id, pps->pps_seq_parameter_set_id);
1297
1298 // keep the PPS with the NAL unit (this is optional)
1299 AppendNalUnitData(nal_unit, nal_unit_size);
1300 CheckIfAccessUnitIsCompleted(access_unit_info);
1301 } else if (nal_unit_type == AP4_HEVC_NALU_TYPE_SPS_NUT) {
1302 AP4_HevcSequenceParameterSet* sps = new AP4_HevcSequenceParameterSet;
1303 result = sps->Parse(nal_unit, nal_unit_size);
1304 if (AP4_FAILED(result)) {
1305 DBG_PRINTF_0("SPS ERROR!!!\n");
1306 delete sps;
1307 return AP4_ERROR_INVALID_FORMAT;
1308 }
1309 delete m_SPS[sps->sps_seq_parameter_set_id];
1310 m_SPS[sps->sps_seq_parameter_set_id] = sps;
1311 DBG_PRINTF_2("SPS sps_id=%d, vps_id=%d", sps->sps_seq_parameter_set_id, sps->sps_video_parameter_set_id);
1312
1313 // keep the SPS with the NAL unit (this is optional)
1314 AppendNalUnitData(nal_unit, nal_unit_size);
1315 CheckIfAccessUnitIsCompleted(access_unit_info);
1316 } else if (nal_unit_type == AP4_HEVC_NALU_TYPE_VPS_NUT) {
1317 AP4_HevcVideoParameterSet* vps = new AP4_HevcVideoParameterSet;
1318 result = vps->Parse(nal_unit, nal_unit_size);
1319 if (AP4_FAILED(result)) {
1320 DBG_PRINTF_0("VPS ERROR!!!\n");
1321 delete vps;
1322 return AP4_ERROR_INVALID_FORMAT;
1323 }
1324 delete m_VPS[vps->vps_video_parameter_set_id];
1325 m_VPS[vps->vps_video_parameter_set_id] = vps;
1326 DBG_PRINTF_1("VPS vps_id=%d", vps->vps_video_parameter_set_id);
1327
1328 // keep the VPS with the NAL unit (this is optional)
1329 AppendNalUnitData(nal_unit, nal_unit_size);
1330 CheckIfAccessUnitIsCompleted(access_unit_info);
1331 } else if (nal_unit_type == AP4_HEVC_NALU_TYPE_EOS_NUT ||
1332 nal_unit_type == AP4_HEVC_NALU_TYPE_EOB_NUT) {
1333 CheckIfAccessUnitIsCompleted(access_unit_info);
1334 } else if (nal_unit_type == AP4_HEVC_NALU_TYPE_PREFIX_SEI_NUT) {
1335 CheckIfAccessUnitIsCompleted(access_unit_info);
1336 AppendNalUnitData(nal_unit, nal_unit_size);
1337 } else if (nal_unit_type == AP4_HEVC_NALU_TYPE_SUFFIX_SEI_NUT){
1338 AppendNalUnitData(nal_unit, nal_unit_size);
1339 } else if (nal_unit_type == AP4_HEVC_NALU_TYPE_UNSPEC62) {
1340 AppendNalUnitData(nal_unit, nal_unit_size);
1341 } else if (nal_unit_type == AP4_HEVC_NALU_TYPE_UNSPEC63) {
1342 AppendNalUnitData(nal_unit, nal_unit_size);
1343 }
1344 DBG_PRINTF_0("\n");
1345 m_TotalNalUnitCount++;
1346 }
1347
1348 // flush if needed
1349 if (last_unit && access_unit_info.nal_units.ItemCount() == 0) {
1350 DBG_PRINTF_0("------ last unit\n");
1351 CheckIfAccessUnitIsCompleted(access_unit_info);
1352 }
1353
1354 return AP4_SUCCESS;
1355 }
1356
1357 /*----------------------------------------------------------------------
1358 | AP4_HevFrameParser::AccessUnitInfo::Reset
1359 +---------------------------------------------------------------------*/
1360 AP4_Result
1361 AP4_HevcFrameParser::ParseSliceSegmentHeader(const AP4_UI08* data,
1362 unsigned int data_size,
1363 unsigned int nal_unit_type,
1364 AP4_HevcSliceSegmentHeader& slice_header)
1365 {
1366 return slice_header.Parse(data, data_size, nal_unit_type, &m_PPS[0], &m_SPS[0]);
1367 }
1368
1369 /*----------------------------------------------------------------------
1370 | AP4_HevFrameParser::AccessUnitInfo::Reset
1371 +---------------------------------------------------------------------*/
1372 void
1373 AP4_HevcFrameParser::AccessUnitInfo::Reset()
1374 {
1375 for (unsigned int i=0; i<nal_units.ItemCount(); i++) {
1376 delete nal_units[i];
1377 }
1378 nal_units.Clear();
1379 is_random_access = false;
1380 decode_order = 0;
1381 display_order = 0;
1382 }
3535 #include "Ap4Results.h"
3636 #include "Ap4DataBuffer.h"
3737 #include "Ap4NalParser.h"
38 #include "Ap4Array.h"
39 #include "Ap4Utils.h"
3840
3941 /*----------------------------------------------------------------------
4042 | constants
4951 const unsigned int AP4_HEVC_NALU_TYPE_RADL_R = 7;
5052 const unsigned int AP4_HEVC_NALU_TYPE_RASL_N = 8;
5153 const unsigned int AP4_HEVC_NALU_TYPE_RASL_R = 9;
54 const unsigned int AP4_HEVC_NALU_TYPE_RSV_VCL_N10 = 10;
55 const unsigned int AP4_HEVC_NALU_TYPE_RSV_VCL_R11 = 11;
56 const unsigned int AP4_HEVC_NALU_TYPE_RSV_VCL_N12 = 12;
57 const unsigned int AP4_HEVC_NALU_TYPE_RSV_VCL_R13 = 13;
58 const unsigned int AP4_HEVC_NALU_TYPE_RSV_VCL_N14 = 14;
59 const unsigned int AP4_HEVC_NALU_TYPE_RSV_VCL_R15 = 15;
5260 const unsigned int AP4_HEVC_NALU_TYPE_BLA_W_LP = 16;
5361 const unsigned int AP4_HEVC_NALU_TYPE_BLA_W_RADL = 17;
5462 const unsigned int AP4_HEVC_NALU_TYPE_BLA_N_LP = 18;
5563 const unsigned int AP4_HEVC_NALU_TYPE_IDR_W_RADL = 19;
5664 const unsigned int AP4_HEVC_NALU_TYPE_IDR_N_LP = 20;
5765 const unsigned int AP4_HEVC_NALU_TYPE_CRA_NUT = 21;
66 const unsigned int AP4_HEVC_NALU_TYPE_RSV_IRAP_VCL22 = 22;
67 const unsigned int AP4_HEVC_NALU_TYPE_RSV_IRAP_VCL23 = 23;
68 const unsigned int AP4_HEVC_NALU_TYPE_RSV_VCL24 = 24;
69 const unsigned int AP4_HEVC_NALU_TYPE_RSV_VCL25 = 25;
70 const unsigned int AP4_HEVC_NALU_TYPE_RSV_VCL26 = 26;
71 const unsigned int AP4_HEVC_NALU_TYPE_RSV_VCL27 = 27;
72 const unsigned int AP4_HEVC_NALU_TYPE_RSV_VCL28 = 28;
73 const unsigned int AP4_HEVC_NALU_TYPE_RSV_VCL29 = 29;
74 const unsigned int AP4_HEVC_NALU_TYPE_RSV_VCL30 = 30;
75 const unsigned int AP4_HEVC_NALU_TYPE_RSV_VCL31 = 31;
5876 const unsigned int AP4_HEVC_NALU_TYPE_VPS_NUT = 32;
5977 const unsigned int AP4_HEVC_NALU_TYPE_SPS_NUT = 33;
6078 const unsigned int AP4_HEVC_NALU_TYPE_PPS_NUT = 34;
6482 const unsigned int AP4_HEVC_NALU_TYPE_FD_NUT = 38;
6583 const unsigned int AP4_HEVC_NALU_TYPE_PREFIX_SEI_NUT = 39;
6684 const unsigned int AP4_HEVC_NALU_TYPE_SUFFIX_SEI_NUT = 40;
67
68 /*----------------------------------------------------------------------
69 | AP4_HevcParser
70 +---------------------------------------------------------------------*/
71 class AP4_HevcParser : public AP4_NalParser {
85 const unsigned int AP4_HEVC_NALU_TYPE_RSV_NVCL41 = 41;
86 const unsigned int AP4_HEVC_NALU_TYPE_RSV_NVCL42 = 42;
87 const unsigned int AP4_HEVC_NALU_TYPE_RSV_NVCL43 = 43;
88 const unsigned int AP4_HEVC_NALU_TYPE_RSV_NVCL44 = 44;
89 const unsigned int AP4_HEVC_NALU_TYPE_RSV_NVCL45 = 45;
90 const unsigned int AP4_HEVC_NALU_TYPE_RSV_NVCL46 = 46;
91 const unsigned int AP4_HEVC_NALU_TYPE_RSV_NVCL47 = 47;
92 const unsigned int AP4_HEVC_NALU_TYPE_UNSPEC62 = 62;
93 const unsigned int AP4_HEVC_NALU_TYPE_UNSPEC63 = 63;
94
95 const unsigned int AP4_HEVC_PPS_MAX_ID = 63;
96 const unsigned int AP4_HEVC_SPS_MAX_ID = 15;
97 const unsigned int AP4_HEVC_VPS_MAX_ID = 15;
98 const unsigned int AP4_HEVC_SPS_MAX_RPS = 64;
99 const unsigned int AP4_HEVC_MAX_LT_REFS = 32;
100
101 const unsigned int AP4_HEVC_ACCESS_UNIT_FLAG_IS_IDR = 0x01;
102 const unsigned int AP4_HEVC_ACCESS_UNIT_FLAG_IS_IRAP = 0x02;
103 const unsigned int AP4_HEVC_ACCESS_UNIT_FLAG_IS_BLA = 0x04;
104 const unsigned int AP4_HEVC_ACCESS_UNIT_FLAG_IS_RADL = 0x08;
105 const unsigned int AP4_HEVC_ACCESS_UNIT_FLAG_IS_RASL = 0x10;
106 const unsigned int AP4_HEVC_ACCESS_UNIT_FLAG_IS_SUBLAYER_NON_REF = 0x20;
107
108 const unsigned int AP4_HEVC_SLICE_TYPE_B = 0;
109 const unsigned int AP4_HEVC_SLICE_TYPE_P = 1;
110 const unsigned int AP4_HEVC_SLICE_TYPE_I = 2;
111
112 /*----------------------------------------------------------------------
113 | class references
114 +---------------------------------------------------------------------*/
115 struct AP4_HevcSliceSegmentHeader;
116
117 /*----------------------------------------------------------------------
118 | AP4_HevcProfileTierLevel
119 +---------------------------------------------------------------------*/
120 struct AP4_HevcProfileTierLevel {
121 AP4_HevcProfileTierLevel();
122
123 // methods
124 AP4_Result Parse(AP4_BitReader& bits, unsigned int max_num_sub_layers_minus_1);
125
126 unsigned int general_profile_space;
127 unsigned int general_tier_flag;
128 unsigned int general_profile_idc;
129 AP4_UI32 general_profile_compatibility_flags;
130
131 // this is a synthetic field that includes 48 bits starting with:
132 // general_progressive_source_flag (1 bit)
133 // general_interlaced_source_flag (1 bit)
134 // general_non_packed_constraint_flag (1 bit)
135 // general_frame_only_constraint_flag (1 bit)
136 // general_reserved_zero_44bits (44 bits)
137 AP4_UI64 general_constraint_indicator_flags;
138
139 unsigned int general_level_idc;
140 struct {
141 unsigned char sub_layer_profile_present_flag;
142 unsigned char sub_layer_level_present_flag;
143 unsigned char sub_layer_profile_space;
144 unsigned char sub_layer_tier_flag;
145 unsigned char sub_layer_profile_idc;
146 AP4_UI32 sub_layer_profile_compatibility_flags;
147 unsigned char sub_layer_progressive_source_flag;
148 unsigned char sub_layer_interlaced_source_flag;
149 unsigned char sub_layer_non_packed_constraint_flag;
150 unsigned char sub_layer_frame_only_constraint_flag;
151 unsigned char sub_layer_level_idc;
152 } sub_layer_info[8];
153 };
154
155 /*----------------------------------------------------------------------
156 | AP4_HevcShortTermRefPicSet
157 +---------------------------------------------------------------------*/
158 typedef struct {
159 unsigned int delta_poc_s0_minus1[16];
160 unsigned int delta_poc_s1_minus1[16];
161 unsigned int used_by_curr_pic_s0_flag[16];
162 unsigned int used_by_curr_pic_s1_flag[16];
163 unsigned int num_negative_pics;
164 unsigned int num_positive_pics;
165 unsigned int num_delta_pocs;
166 } AP4_HevcShortTermRefPicSet;
167
168 /*----------------------------------------------------------------------
169 | AP4_HevcPictureParameterSet
170 +---------------------------------------------------------------------*/
171 struct AP4_HevcPictureParameterSet {
172 AP4_HevcPictureParameterSet();
173
174 // methods
175 AP4_Result Parse(const unsigned char* data, unsigned int data_size);
176
177 AP4_DataBuffer raw_bytes;
178 unsigned int pps_pic_parameter_set_id;
179 unsigned int pps_seq_parameter_set_id;
180 unsigned int dependent_slice_segments_enabled_flag;
181 unsigned int output_flag_present_flag;
182 unsigned int num_extra_slice_header_bits;
183 unsigned int sign_data_hiding_enabled_flag;
184 unsigned int cabac_init_present_flag;
185 unsigned int num_ref_idx_l0_default_active_minus1;
186 unsigned int num_ref_idx_l1_default_active_minus1;
187 int init_qp_minus26;
188 unsigned int constrained_intra_pred_flag;
189 unsigned int transform_skip_enabled_flag;
190 unsigned int cu_qp_delta_enabled_flag;
191 unsigned int diff_cu_qp_delta_depth;
192 int pps_cb_qp_offset;
193 int pps_cr_qp_offset;
194 unsigned int pps_slice_chroma_qp_offsets_present_flag;
195 unsigned int weighted_pred_flag;
196 unsigned int weighted_bipred_flag;
197 unsigned int transquant_bypass_enabled_flag;
198 unsigned int tiles_enabled_flag;
199 unsigned int entropy_coding_sync_enabled_flag;
200 unsigned int num_tile_columns_minus1;
201 unsigned int num_tile_rows_minus1;
202 unsigned int uniform_spacing_flag;
203 unsigned int loop_filter_across_tiles_enabled_flag;
204 unsigned int pps_loop_filter_across_slices_enabled_flag;
205 unsigned int deblocking_filter_control_present_flag;
206 unsigned int deblocking_filter_override_enabled_flag;
207 unsigned int pps_deblocking_filter_disabled_flag;
208 int pps_beta_offset_div2;
209 int pps_tc_offset_div2;
210 unsigned int pps_scaling_list_data_present_flag;
211 unsigned int lists_modification_present_flag;
212 unsigned int log2_parallel_merge_level_minus2;
213 unsigned int slice_segment_header_extension_present_flag;
214 };
215
216 /*----------------------------------------------------------------------
217 | AP4_HevcSequenceParameterSet
218 +---------------------------------------------------------------------*/
219 struct AP4_HevcSequenceParameterSet {
220 AP4_HevcSequenceParameterSet();
221
222 // methods
223 AP4_Result Parse(const unsigned char* data, unsigned int data_size);
224 void GetInfo(unsigned int& width, unsigned int& height);
225
226 AP4_DataBuffer raw_bytes;
227 unsigned int sps_video_parameter_set_id;
228 unsigned int sps_max_sub_layers_minus1;
229 unsigned int sps_temporal_id_nesting_flag;
230 AP4_HevcProfileTierLevel profile_tier_level;
231 unsigned int sps_seq_parameter_set_id;
232 unsigned int chroma_format_idc;
233 unsigned int separate_colour_plane_flag;
234 unsigned int pic_width_in_luma_samples;
235 unsigned int pic_height_in_luma_samples;
236 unsigned int conformance_window_flag;
237 unsigned int conf_win_left_offset;
238 unsigned int conf_win_right_offset;
239 unsigned int conf_win_top_offset;
240 unsigned int conf_win_bottom_offset;
241 unsigned int bit_depth_luma_minus8;
242 unsigned int bit_depth_chroma_minus8;
243 unsigned int sps_max_dec_pic_buffering_minus1[8];
244 unsigned int sps_max_num_reorder_pics[8];
245 unsigned int sps_max_latency_increase_plus1[8];
246 unsigned int log2_max_pic_order_cnt_lsb_minus4;
247 unsigned int sps_sub_layer_ordering_info_present_flag;
248 unsigned int log2_min_luma_coding_block_size_minus3;
249 unsigned int log2_diff_max_min_luma_coding_block_size;
250 unsigned int log2_min_transform_block_size_minus2;
251 unsigned int log2_diff_max_min_transform_block_size;
252 unsigned int max_transform_hierarchy_depth_inter;
253 unsigned int max_transform_hierarchy_depth_intra;
254 unsigned int scaling_list_enabled_flag;
255 unsigned int sps_scaling_list_data_present_flag;
256 // skipped scaling list data
257 unsigned int amp_enabled_flag;
258 unsigned int sample_adaptive_offset_enabled_flag;
259 unsigned int pcm_enabled_flag;
260 unsigned int pcm_sample_bit_depth_luma_minus1;
261 unsigned int pcm_sample_bit_depth_chroma_minus1;
262 unsigned int log2_min_pcm_luma_coding_block_size_minus3;
263 unsigned int log2_diff_max_min_pcm_luma_coding_block_size;
264 unsigned int pcm_loop_filter_disabled_flag;
265 unsigned int num_short_term_ref_pic_sets;
266 unsigned int long_term_ref_pics_present_flag;
267 unsigned int num_long_term_ref_pics_sps;
268 unsigned int sps_temporal_mvp_enabled_flag;
269 unsigned int strong_intra_smoothing_enabled_flag;
270
271 AP4_HevcShortTermRefPicSet short_term_ref_pic_sets[AP4_HEVC_SPS_MAX_RPS];
272 };
273
274 /*----------------------------------------------------------------------
275 | AP4_HevcVideoParameterSet
276 +---------------------------------------------------------------------*/
277 struct AP4_HevcVideoParameterSet {
278 AP4_HevcVideoParameterSet();
279
280 // methods
281 AP4_Result Parse(const unsigned char* data, unsigned int data_size);
282 void GetInfo(unsigned int& time_scale, unsigned int& num_units);
283
284 AP4_DataBuffer raw_bytes;
285 unsigned int vps_video_parameter_set_id;
286 unsigned int vps_max_layers_minus1;
287 unsigned int vps_max_sub_layers_minus1;
288 unsigned int vps_temporal_id_nesting_flag;
289 AP4_HevcProfileTierLevel profile_tier_level;
290 unsigned int vps_sub_layer_ordering_info_present_flag;
291 unsigned int vps_max_dec_pic_buffering_minus1[8];
292 unsigned int vps_max_num_reorder_pics[8];
293 unsigned int vps_max_latency_increase_plus1[8];
294 unsigned int vps_max_layer_id;
295 unsigned int vps_num_layer_sets_minus1;
296 unsigned int vps_timing_info_present_flag;
297 unsigned int vps_num_units_in_tick;
298 unsigned int vps_time_scale;
299 unsigned int vps_poc_proportional_to_timing_flag;
300 unsigned int vps_num_ticks_poc_diff_one_minus1;
301 };
302
303 /*----------------------------------------------------------------------
304 | AP4_HevcSliceSegmentHeader
305 +---------------------------------------------------------------------*/
306 struct AP4_HevcSliceSegmentHeader {
307 AP4_HevcSliceSegmentHeader() {} // leave members uninitialized on purpose
308
309 AP4_Result Parse(const AP4_UI08* data,
310 unsigned int data_size,
311 unsigned int nal_unit_type,
312 AP4_HevcPictureParameterSet** picture_parameter_sets,
313 AP4_HevcSequenceParameterSet** sequence_parameter_sets);
314
315 unsigned int size; // size of the parsed data
316
317 unsigned int first_slice_segment_in_pic_flag;
318 unsigned int no_output_of_prior_pics_flag;
319 unsigned int slice_pic_parameter_set_id;
320 unsigned int dependent_slice_segment_flag;
321 unsigned int slice_segment_address;
322 unsigned int slice_type;
323 unsigned int pic_output_flag;
324 unsigned int colour_plane_id;
325 unsigned int slice_pic_order_cnt_lsb;
326 unsigned int short_term_ref_pic_set_sps_flag;
327 unsigned int short_term_ref_pic_set_idx;
328 unsigned int num_entry_point_offsets;
329 unsigned int offset_len_minus1;
330 unsigned int num_long_term_sps;
331 unsigned int num_long_term_pics;
332
333 AP4_HevcShortTermRefPicSet short_term_ref_pic_set;
334 unsigned int used_by_curr_pic_lt_flag[AP4_HEVC_MAX_LT_REFS];
335 };
336
337 /*----------------------------------------------------------------------
338 | AP4_HevcNalParser
339 +---------------------------------------------------------------------*/
340 class AP4_HevcNalParser : public AP4_NalParser {
72341 public:
73342 static const char* NaluTypeName(unsigned int nalu_type);
74343 static const char* PicTypeName(unsigned int primary_pic_type);
75344 static const char* SliceTypeName(unsigned int slice_type);
76345
77 AP4_HevcParser();
346 AP4_HevcNalParser();
347 };
348
349 /*----------------------------------------------------------------------
350 | AP4_HevcFrameParser
351 +---------------------------------------------------------------------*/
352 class AP4_HevcFrameParser {
353 public:
354 // types
355 struct AccessUnitInfo {
356 AP4_Array<AP4_DataBuffer*> nal_units;
357 bool is_random_access;
358 AP4_UI32 decode_order;
359 AP4_UI32 display_order;
360
361 void Reset();
362 };
363
364 // methods
365 AP4_HevcFrameParser();
366 ~AP4_HevcFrameParser();
367
368 /**
369 * Feed some data to the parser and look for the next NAL Unit.
370 *
371 * @param data Pointer to the memory buffer with the data to feed.
372 * @param data_size Size in bytes of the buffer pointed to by the
373 * data pointer.
374 * @param bytes_consumed Number of bytes from the data buffer that were
375 * consumed and stored by the parser.
376 * @param access_unit_info Reference to a AccessUnitInfo structure that will
377 * contain information about any access unit found in the data. If no
378 * access unit was found, the nal_units field of this structure will be an
379 * empty array.
380 * @param eos Boolean flag that indicates if this buffer is the last
381 * buffer in the stream/file (End Of Stream).
382 *
383 * @result: AP4_SUCCESS is the call succeeds, or an error code if it
384 * fails.
385 *
386 * The caller must not feed the same data twice. When this method
387 * returns, the caller should inspect the value of bytes_consumed and
388 * advance the input stream source accordingly, such that the next
389 * buffer passed to this method will be exactly bytes_consumed bytes
390 * after what was passed in this call. After all the input data has
391 * been supplied to the parser (eos=true), the caller also should
392 * this method with an empty buffer (data=NULL and/or data_size=0) until
393 * no more data is returned, because there may be buffered data still
394 * available.
395 *
396 * When data is returned in the access_unit_info structure, the caller is
397 * responsible for freeing this data by calling AccessUnitInfo::Reset()
398 */
399 AP4_Result Feed(const void* data,
400 AP4_Size data_size,
401 AP4_Size& bytes_consumed,
402 AccessUnitInfo& access_unit_info,
403 bool eos=false);
404
405 AP4_Result Feed(const AP4_UI08* nal_unit,
406 AP4_Size nal_unit_size,
407 AccessUnitInfo& access_unit_info,
408 bool last_unit=false);
409
410 AP4_Result ParseSliceSegmentHeader(const AP4_UI08* data,
411 unsigned int data_size,
412 unsigned int nal_unit_type,
413 AP4_HevcSliceSegmentHeader& slice_header);
414
415 AP4_HevcVideoParameterSet** GetVideoParameterSets() { return &m_VPS[0]; }
416 AP4_HevcSequenceParameterSet** GetSequenceParameterSets() { return &m_SPS[0]; }
417 AP4_HevcPictureParameterSet** GetPictureParameterSets() { return &m_PPS[0]; }
418
419 private:
420 // methods
421 void CheckIfAccessUnitIsCompleted(AccessUnitInfo& access_unit_info);
422 void AppendNalUnitData(const unsigned char* data, unsigned int data_size);
423
424 // members
425 AP4_HevcNalParser m_NalParser;
426 AP4_HevcSliceSegmentHeader* m_CurrentSlice;
427 unsigned int m_CurrentNalUnitType;
428 unsigned int m_CurrentTemporalId;
429 AP4_HevcPictureParameterSet* m_PPS[AP4_HEVC_PPS_MAX_ID+1];
430 AP4_HevcSequenceParameterSet* m_SPS[AP4_HEVC_SPS_MAX_ID+1];
431 AP4_HevcVideoParameterSet* m_VPS[AP4_HEVC_VPS_MAX_ID+1];
432
433 // accumulator for NAL unit data
434 unsigned int m_TotalNalUnitCount;
435 unsigned int m_TotalAccessUnitCount;
436 AP4_Array<AP4_DataBuffer*> m_AccessUnitData;
437 AP4_UI32 m_AccessUnitFlags;
438 unsigned int m_VclNalUnitsInAccessUnit;
439
440 // picture order counting
441 unsigned int m_PrevTid0Pic_PicOrderCntMsb;
442 unsigned int m_PrevTid0Pic_PicOrderCntLsb;
78443 };
79444
80445 #endif // _AP4_HEVC_PARSER_H_
306306 case AP4_MPEG4_AUDIO_OBJECT_TYPE_ER_AAC_LD:
307307 case AP4_MPEG4_AUDIO_OBJECT_TYPE_ER_TWINVQ:
308308 case AP4_MPEG4_AUDIO_OBJECT_TYPE_ER_BSAC:
309 case AP4_MPEG4_AUDIO_OBJECT_TYPE_USAC:
309310 result = ParseGASpecificInfo(bits);
310311 if (result == AP4_SUCCESS) {
311312 if (m_Extension.m_ObjectType != AP4_MPEG4_AUDIO_OBJECT_TYPE_SBR &&
5353 AP4_Size in_size = data.GetDataSize();
5454
5555 for (unsigned int i=0; i<in_size; i++) {
56 if (zero_count >= 2 && in[i] == 3 && i+1 < in_size && in[i+1] <= 3) {
56 if (zero_count == 2 && in[i] == 3 && i+1 < in_size && in[i+1] <= 3) {
5757 ++bytes_removed;
5858 zero_count = 0;
5959 } else {
6060 out[i-bytes_removed] = in[i];
6161 if (in[i] == 0) {
6262 ++zero_count;
63 } else {
64 zero_count = 0;
6365 }
6466 }
6567 }
6668 data.SetDataSize(in_size-bytes_removed);
69 }
70
71 /*----------------------------------------------------------------------
72 | AP4_NalParser::CountEmulationPreventionBytes
73 +---------------------------------------------------------------------*/
74 unsigned int
75 AP4_NalParser::CountEmulationPreventionBytes(const AP4_UI08* data,
76 unsigned int data_size,
77 unsigned int unescaped_size)
78 {
79 unsigned int zero_count = 0;
80 unsigned int bytes_produced = 0;
81 unsigned int emulation_prevention_bytes = 0;
82
83 // shortcut
84 if (data_size <= 2) {
85 // no escaping possible in just 2 bytes
86 return 0;
87 }
88
89 for (unsigned int i=0; i<data_size; i++) {
90 if (zero_count == 2 && data[i] == 3 && i+1 < data_size && data[i+1] <= 3) {
91 ++emulation_prevention_bytes;
92 zero_count = 0;
93 } else {
94 if (++bytes_produced >= unescaped_size) {
95 break;
96 }
97 if (data[i] == 0) {
98 ++zero_count;
99 } else {
100 zero_count = 0;
101 }
102 }
103 }
104 return emulation_prevention_bytes;
67105 }
68106
69107 /*----------------------------------------------------------------------
4141 class AP4_NalParser {
4242 public:
4343 // class methods
44
45 /**
46 * Remove emulation prevention bytes from a buffer.
47 */
4448 static void Unescape(AP4_DataBuffer& data);
4549
50 /**
51 * Count how many emualation prevention bytes are encountered until
52 * a certain number of bytes can be produced from an escaped buffer
53 */
54 static unsigned int CountEmulationPreventionBytes(const AP4_UI08* data,
55 unsigned int data_size,
56 unsigned int unescaped_size);
57
58 // constructor
4659 AP4_NalParser();
4760
4861 /**
4962 * Feed some data to the parser and look for the next NAL Unit.
5063 *
51 * @param data: Pointer to the memory buffer with the data to feed.
52 * @param data_size: Size in bytes of the buffer pointed to by the
64 * @param data Pointer to the memory buffer with the data to feed.
65 * @param data_size Size in bytes of the buffer pointed to by the
5366 * data pointer.
54 * @param bytes_consumed: Number of bytes from the data buffer that were
67 * @param bytes_consumed Number of bytes from the data buffer that were
5568 * consumed and stored by the parser.
56 * @param nalu: Reference to a pointer to a buffer object that contains
69 * @param nalu Reference to a pointer to a buffer object that contains
5770 * a NAL unit found in the previously fed data, or a NULL pointer if no
5871 * NAL unit can be found so far.
59 * @param eos: Boolean flag that indicates if this buffer is the last
72 * @param eos Boolean flag that indicates if this buffer is the last
6073 * buffer in the stream/file (End Of Stream).
6174 *
6275 * @result: AP4_SUCCESS is the call succeeds, or an error code if it
+0
-63
lib/libbento4/Core/AP4TrafAtom.cpp less more
0 /*****************************************************************
1 |
2 | AP4 - Traf Atoms
3 |
4 | Copyright 2002-2008 Axiomatic Systems, LLC
5 |
6 |
7 | This file is part of Bento4/AP4 (MP4 Atom Processing Library).
8 |
9 | Unless you have obtained Bento4 under a difference license,
10 | this version of Bento4 is Bento4|GPL.
11 | Bento4|GPL is free software; you can redistribute it and/or modify
12 | it under the terms of the GNU General Public License as published by
13 | the Free Software Foundation; either version 2, or (at your option)
14 | any later version.
15 |
16 | Bento4|GPL is distributed in the hope that it will be useful,
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | GNU General Public License for more details.
20 |
21 | You should have received a copy of the GNU General Public License
22 | along with Bento4|GPL; see the file COPYING. If not, write to the
23 | Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
24 | 02111-1307, USA.
25 |
26 ****************************************************************/
27
28 /*----------------------------------------------------------------------
29 | includes
30 +---------------------------------------------------------------------*/
31 #include "Ap4Atom.h"
32 #include "Ap4TrafAtom.h"
33
34 /*----------------------------------------------------------------------
35 | dynamic cast support
36 +---------------------------------------------------------------------*/
37 AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_TrafAtom)
38
39 /*----------------------------------------------------------------------
40 | AP4_TrafAtom::AP4_TrafAtom
41 +---------------------------------------------------------------------*/
42 AP4_TrafAtom::AP4_TrafAtom(Type type) :
43 AP4_ContainerAtom(type)
44 {
45 }
46
47 /*----------------------------------------------------------------------
48 | AP4_ContainerAtom::Clone
49 +---------------------------------------------------------------------*/
50 AP4_Atom*
51 AP4_TrafAtom::Clone()
52 {
53 AP4_TrafAtom* clone(new AP4_TrafAtom(m_Type));
54
55 AP4_List<AP4_Atom>::Item* child_item = m_Children.FirstItem();
56 while (child_item) {
57 AP4_Atom* child_clone = child_item->GetData()->Clone();
58 if (child_clone) clone->AddChild(child_clone);
59 child_item = child_item->GetNext();
60 }
61 return clone;
62 }
266266 #include "Ap4SttsAtom.h"
267267 #include "Ap4CttsAtom.h"
268268 #include "Ap4StssAtom.h"
269 #include "Ap4ElstAtom.h"
269270 #include "Ap4FtypAtom.h"
270271 #include "Ap4VmhdAtom.h"
271272 #include "Ap4SmhdAtom.h"
288289 #include "Ap4OddaAtom.h"
289290 #include "Ap4AvccAtom.h"
290291 #include "Ap4HvccAtom.h"
292 #include "Ap4DvccAtom.h"
293 #include "Ap4VpccAtom.h"
294 #include "Ap4Av1cAtom.h"
291295 #include "Ap4Marlin.h"
292296 #include "Ap4GrpiAtom.h"
293297 #include "Ap48bdlAtom.h"
307311 #include "Ap4TfraAtom.h"
308312 #include "Ap4SbgpAtom.h"
309313 #include "Ap4MfroAtom.h"
314 #include "Ap4Dac3Atom.h"
310315 #include "Ap4Dec3Atom.h"
316 #include "Ap4Dac4Atom.h"
311317 #include "Ap4SidxAtom.h"
312318 #include "../Codecs/Ap4AdtsParser.h"
319 #include "../Codecs/Ap4Ac4Parser.h"
313320 #include "../Codecs/Ap4AvcParser.h"
321 #include "../Codecs/Ap4Eac3Parser.h"
322 #include "../Codecs/Ap4Ac3Parser.h"
323 #include "../Codecs/Ap4HevcParser.h"
314324 #include "Ap4SegmentBuilder.h"
315 #include "Ap4VpcCAtom.h"
316325
317326 /*----------------------------------------------------------------------
318327 | global functions
0 /*****************************************************************
1 |
2 | AP4 - AC-4 Utilities
3 |
4 | Copyright 2002-2020 Axiomatic Systems, LLC
5 |
6 |
7 | This file is part of Bento4/AP4 (MP4 Atom Processing Library).
8 |
9 | Unless you have obtained Bento4 under a difference license,
10 | this version of Bento4 is Bento4|GPL.
11 | Bento4|GPL is free software; you can redistribute it and/or modify
12 | it under the terms of the GNU General Public License as published by
13 | the Free Software Foundation; either version 2, or (at your option)
14 | any later version.
15 |
16 | Bento4|GPL is distributed in the hope that it will be useful,
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | GNU General Public License for more details.
20 |
21 | You should have received a copy of the GNU General Public License
22 | along with Bento4|GPL; see the file COPYING. If not, write to the
23 | Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
24 | 02111-1307, USA.
25 |
26 ****************************************************************/
27
28 /*----------------------------------------------------------------------
29 | includes
30 +---------------------------------------------------------------------*/
31 #include "Ap4Ac4Utils.h"
32
33 AP4_UI32
34 AP4_Ac4VariableBits(AP4_BitReader &data, int nBits)
35 {
36 AP4_UI32 value = 0;
37 AP4_UI32 b_moreBits;
38 do{
39 value += data.ReadBits(nBits);
40 b_moreBits = data.ReadBit();
41 if (b_moreBits == 1) {
42 value <<= nBits;
43 value += (1<<nBits);
44 }
45 } while (b_moreBits == 1);
46 return value;
47 }
48
49 AP4_Result
50 AP4_Ac4ChannelCountFromSpeakerGroupIndexMask(unsigned int speakerGroupIndexMask)
51 {
52
53 unsigned int channelCount= 0;
54 if ((speakerGroupIndexMask & 1) != 0) { // 0: L,R 0b1
55 channelCount += 2;
56 }
57 if ((speakerGroupIndexMask & 2) != 0) { // 1: C 0b10
58 channelCount += 1;
59 }
60 if ((speakerGroupIndexMask & 4) != 0) { // 2: Ls,Rs 0b100
61 channelCount += 2;
62 }
63 if ((speakerGroupIndexMask & 8) != 0) { // 3: Lb,Rb 0b1000
64 channelCount += 2;
65 }
66 if ((speakerGroupIndexMask & 16) != 0) { // 4: Tfl,Tfr 0b10000
67 channelCount += 2;
68 }
69 if ((speakerGroupIndexMask & 32) != 0) { // 5: Tbl,Tbr 0b100000
70 channelCount += 2;
71 }
72 if ((speakerGroupIndexMask & 64) != 0) { // 6: LFE 0b1000000
73 channelCount += 1;
74 }
75 if ((speakerGroupIndexMask & 128) != 0) { // 7: TL,TR 0b10000000
76 channelCount += 2;
77 }
78 if ((speakerGroupIndexMask & 256) != 0) { // 8: Tsl,Tsr 0b100000000
79 channelCount += 2;
80 }
81 if ((speakerGroupIndexMask & 512) != 0) { // 9: Tfc
82 channelCount += 1;
83 }
84 if ((speakerGroupIndexMask & 1024) != 0) { // 10: Tbc
85 channelCount += 1;
86 }
87 if ((speakerGroupIndexMask & 2048) != 0) { // 11: Tc
88 channelCount += 1;
89 }
90 if ((speakerGroupIndexMask & 4096) != 0) { // 12: LFE2
91 channelCount += 1;
92 }
93 if ((speakerGroupIndexMask & 8192) != 0) { // 13: Bfl,Bfr
94 channelCount += 2;
95 }
96 if ((speakerGroupIndexMask & 16384) != 0) { // 14: Bfc
97 channelCount += 1;
98 }
99 if ((speakerGroupIndexMask & 32768) != 0) { // 15: Cb
100 channelCount += 1;
101 }
102 if ((speakerGroupIndexMask & 65536) != 0) { // 16: Lscr,Rscr
103 channelCount += 2;
104 }
105 if ((speakerGroupIndexMask & 131072) != 0) { // 17: Lw,Rw
106 channelCount += 2;
107 }
108 if ((speakerGroupIndexMask & 262144) != 0) { // 18: Vhl,Vhr
109 channelCount += 2;
110 }
111 return channelCount;
112 }
0 /*****************************************************************
1 |
2 | AP4 - AC-4 Utilities
3 |
4 | Copyright 2002-2020 Axiomatic Systems, LLC
5 |
6 |
7 | This file is part of Bento4/AP4 (MP4 Atom Processing Library).
8 |
9 | Unless you have obtained Bento4 under a difference license,
10 | this version of Bento4 is Bento4|GPL.
11 | Bento4|GPL is free software; you can redistribute it and/or modify
12 | it under the terms of the GNU General Public License as published by
13 | the Free Software Foundation; either version 2, or (at your option)
14 | any later version.
15 |
16 | Bento4|GPL is distributed in the hope that it will be useful,
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | GNU General Public License for more details.
20 |
21 | You should have received a copy of the GNU General Public License
22 | along with Bento4|GPL; see the file COPYING. If not, write to the
23 | Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
24 | 02111-1307, USA.
25 |
26 ****************************************************************/
27
28 #ifndef _AP4_AC4_UTILS_H_
29 #define _AP4_AC4_UTILS_H_
30
31 /*----------------------------------------------------------------------
32 | includes
33 +---------------------------------------------------------------------*/
34 #include "Ap4Utils.h"
35
36 /*----------------------------------------------------------------------
37 | constants
38 +---------------------------------------------------------------------*/
39 const unsigned int AP4_CH_MODE_LENGTH = 16; /* AC-4 ch_mode length */
40 const unsigned int AP4_AC4_FRAME_RATE_NUM = 14; /* AC-4 frame rate number */
41 const unsigned int AP4_AC4_SUBSTREAM_GROUP_NUM = 3; /* AC-4 Maximum substream group if presentation_config < 5 */
42
43 const unsigned char
44 SUPER_SET_CH_MODE[AP4_CH_MODE_LENGTH][AP4_CH_MODE_LENGTH] =
45 {
46 {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12,13,14,15},
47 {1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12,13,14,15},
48 {2, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12,13,14,15},
49 {3, 3, 3, 3, 4, 5, 6, 7, 8, 9, 10,11,12,13,14,15},
50 {4, 4, 4, 4, 4, 6, 6, 8, 8, 10,10,12,12,14,14,15},
51 {5, 5, 5, 5, 6, 5, 6, 7, 8, 9, 10,11,12,13,14,15},
52 {6, 6, 6, 6, 6, 6, 6, 6, 8, 6, 10,12,12,14,14,15},
53 {7, 7, 7, 7, 8, 7, 6, 7, 8, 9, 10,12,12,13,14,15},
54 {8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10,11,12,14,14,15},
55 {9, 9, 9, 9, 10,9, 10,9, 9, 9, 10,11,12,13,14,15},
56 {10,10,10,10,10,10,10,10,10,10,10,10,12,13,14,15},
57 {11,11,11,11,12,11,12,11,12,11,12,11,13,13,14,15},
58 {12,12,12,12,12,12,12,12,12,12,12,12,12,13,14,15},
59 {13,13,13,13,14,13,14,13,14,13,14,13,14,13,14,15},
60 {14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,15},
61 {15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15}
62 };
63
64 // ch_mode - TS 103 190-2 table 78
65 const int CH_MODE_MONO = 0;
66 const int CH_MODE_STEREO = 1;
67 const int CH_MODE_3_0 = 2;
68 const int CH_MODE_5_0 = 3;
69 const int CH_MODE_5_1 = 4;
70 const int CH_MODE_70_34 = 5;
71 const int CH_MODE_71_34 = 6;
72 const int CH_MODE_70_52 = 7;
73 const int CH_MODE_71_52 = 8;
74 const int CH_MODE_70_322 = 9;
75 const int CH_MODE_71_322 = 10;
76 const int CH_MODE_7_0_4 = 11;
77 const int CH_MODE_7_1_4 = 12;
78 const int CH_MODE_9_0_4 = 13;
79 const int CH_MODE_9_1_4 = 14;
80 const int CH_MODE_22_2 = 15;
81 const int CH_MODE_RESERVED = 16;
82
83 // speaker group index mask, indexed by ch_mode - TS 103 190-2 A.27
84 const int
85 AC4_SPEAKER_GROUP_INDEX_MASK_BY_CH_MODE[] =
86 {
87 2, // 0b10 - 1.0
88 1, // 0b01 - 2.0
89 3, // 0b11 - 3.0
90 7, // 0b0000111 - 5.0
91 71, // 0b1000111 - 5.1
92 15, // 0b0001111 - 7.0: 3/4/0
93 79, // 0b1001111 - 7.1: 3/4/0.1
94 131079, // 0b100000000000000111 - 7.0: 5/2/0
95 131143, // 0b100000000001000111 - 7.1: 5/2/0.1
96 262151, // 0b1000000000000000111 - 7.0: 3/2/2
97 262215, // 0b1000000000001000111 - 7.1: 3/2/2.1
98 63, // 0b0111111 - 7.0.4
99 127, // 0b1111111 - 7.1.4
100 65599, // 0b10000000000111111 - 9.0.4
101 65663, // 0b10000000001111111 - 9.1.4
102 196479, // 0b101111111101111111 - 22.2
103 0 // reserved
104 };
105
106 const AP4_UI32
107 AP4_Ac4SamplingFrequencyTable[] =
108 {
109 44100, // 44.1 kHz
110 48000 // 48 kHz
111 };
112
113 const AP4_UI32
114 AP4_Ac4SampleDeltaTable[AP4_AC4_FRAME_RATE_NUM] =
115 {
116 2002,
117 2000,
118 1920,
119 8008, // 29.97 fps, using 240 000 media time scale
120 1600,
121 1001,
122 1000,
123 960,
124 4004, // 59.97 fps
125 800,
126 480,
127 2002, // 119.88 fps
128 400,
129 2048 // 23.44 fps, AC-4 native frame rate
130 };
131
132 const AP4_UI32
133 AP4_Ac4MediaTimeScaleTable[AP4_AC4_FRAME_RATE_NUM] =
134 {
135 48000,
136 48000,
137 48000,
138 240000, //29.97 fps
139 48000,
140 48000,
141 48000,
142 48000,
143 240000, // 59.97 fps
144 48000,
145 48000,
146 240000, // 119.88 fps
147 48000,
148 48000,
149 };
150
151 /*----------------------------------------------------------------------
152 | struct
153 +---------------------------------------------------------------------*/
154 struct AP4_Ac4EmdfInfo{
155 AP4_UI08 emdf_version;
156 AP4_UI16 key_id;
157 AP4_UI08 b_emdf_payloads_substream_info;
158 AP4_UI16 substream_index;
159 AP4_UI08 protectionLengthPrimary;
160 AP4_UI08 protectionLengthSecondary;
161 AP4_UI08 protection_bits_primary[16];
162 AP4_UI08 protection_bits_Secondary[16];
163 };
164
165 /*----------------------------------------------------------------------
166 | non-inline functions
167 +---------------------------------------------------------------------*/
168 AP4_UI32
169 AP4_Ac4VariableBits(AP4_BitReader &data, int nBits);
170
171 AP4_Result
172 AP4_Ac4ChannelCountFromSpeakerGroupIndexMask(unsigned int speakerGroupIndexMask);
173
174 /*----------------------------------------------------------------------
175 | inline functions
176 +---------------------------------------------------------------------*/
177 inline AP4_Result
178 AP4_Ac4SuperSet(int lvalue, int rvalue)
179 {
180 if ((lvalue == -1) || (lvalue > 15)) return rvalue;
181 if ((rvalue == -1) || (rvalue > 15)) return lvalue;
182 return SUPER_SET_CH_MODE[lvalue][rvalue];
183 }
184
185 inline AP4_Result
186 Ap4_Ac4SubstreamGroupPartOfDefaultPresentation(unsigned int substreamGroupIndex, unsigned int presSubstreamGroupIndexes[], unsigned int presNSubstreamGroups)
187 {
188 int partOf = false;
189 for (unsigned int idx = 0; idx < presNSubstreamGroups; idx ++) {
190 if (presSubstreamGroupIndexes[idx] == substreamGroupIndex) { partOf = true; }
191 }
192 return partOf;
193 }
194
195 inline AP4_UI32
196 AP4_SetMaxGroupIndex(unsigned int groupIndex, unsigned int maxGroupIndex)
197 {
198 if (groupIndex > maxGroupIndex) { maxGroupIndex = groupIndex; }
199 return maxGroupIndex;
200 }
201
202 inline void
203 AP4_ByteAlign(AP4_BitWriter &bits)
204 {
205 unsigned int byte_align_nums = 8 - (bits.GetBitCount() % 8 == 0 ? 8: bits.GetBitCount() % 8);
206 if (byte_align_nums){ bits.Write(0, byte_align_nums); }
207 }
208
209 inline void
210 Ap4_Ac4UpdatePresBytes(const unsigned char* buffer, unsigned int idx, unsigned char value)
211 { unsigned char *data = const_cast<unsigned char*>(buffer);
212 *(data + idx) = value;
213 }
214
215 #endif // _AP4_AC4_UTILS_H_
5050 {
5151 AP4_UI08 version;
5252 AP4_UI32 flags;
53 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
5354 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
5455 if (version > 1) return NULL;
5556 return new AP4_AinfAtom(size, version, flags, stream);
00 /*****************************************************************
11 |
2 | AP4 - Atoms
2 | AP4 - Atoms
33 |
44 | Copyright 2002-2008 Axiomatic Systems, LLC
55 |
5656 AP4_Atom::TypeFromString(const char* s)
5757 {
5858 // convert the name into an atom type
59 return ((AP4_UI32)s[0])<<24 |
59 return ((AP4_UI32)s[0])<<24 |
6060 ((AP4_UI32)s[1])<<16 |
6161 ((AP4_UI32)s[2])<< 8 |
6262 ((AP4_UI32)s[3]);
6565 /*----------------------------------------------------------------------
6666 | AP4_Atom::AP4_Atom
6767 +---------------------------------------------------------------------*/
68 AP4_Atom::AP4_Atom(Type type, AP4_UI32 size /* = AP4_ATOM_HEADER_SIZE */) :
68 AP4_Atom::AP4_Atom(Type type, AP4_UI32 size /* = AP4_ATOM_HEADER_SIZE */) :
6969 m_Type(type),
7070 m_Size32(size),
7171 m_Size64(0),
7979 /*----------------------------------------------------------------------
8080 | AP4_Atom::AP4_Atom
8181 +---------------------------------------------------------------------*/
82 AP4_Atom::AP4_Atom(Type type, AP4_UI64 size, bool force_64) :
82 AP4_Atom::AP4_Atom(Type type, AP4_UI64 size, bool force_64) :
8383 m_Type(type),
8484 m_Size32(0),
8585 m_Size64(0),
9494 /*----------------------------------------------------------------------
9595 | AP4_Atom::AP4_Atom
9696 +---------------------------------------------------------------------*/
97 AP4_Atom::AP4_Atom(Type type,
98 AP4_UI32 size,
99 AP4_UI08 version,
97 AP4_Atom::AP4_Atom(Type type,
98 AP4_UI32 size,
99 AP4_UI08 version,
100100 AP4_UI32 flags) :
101101 m_Type(type),
102102 m_Size32(size),
111111 /*----------------------------------------------------------------------
112112 | AP4_Atom::AP4_Atom
113113 +---------------------------------------------------------------------*/
114 AP4_Atom::AP4_Atom(Type type,
114 AP4_Atom::AP4_Atom(Type type,
115115 AP4_UI64 size,
116116 bool force_64,
117 AP4_UI08 version,
117 AP4_UI08 version,
118118 AP4_UI32 flags) :
119119 m_Type(type),
120120 m_Size32(0),
131131 | AP4_Atom::ReadFullHeader
132132 +---------------------------------------------------------------------*/
133133 AP4_Result
134 AP4_Atom::ReadFullHeader(AP4_ByteStream& stream,
135 AP4_UI08& version,
134 AP4_Atom::ReadFullHeader(AP4_ByteStream& stream,
135 AP4_UI08& version,
136136 AP4_UI32& flags)
137137 {
138138 AP4_UI32 header;
274274 char name[5];
275275 AP4_FormatFourCharsPrintable(name, m_Type);
276276 name[4] = '\0';
277 inspector.StartAtom(name,
277 inspector.StartAtom(name,
278278 m_Version,
279279 m_Flags,
280280 GetHeaderSize(),
287287 | AP4_Atom::Detach
288288 +---------------------------------------------------------------------*/
289289 AP4_Result
290 AP4_Atom::Detach()
290 AP4_Atom::Detach()
291291 {
292292 if (m_Parent) {
293293 return m_Parent->RemoveChild(this);
303303 AP4_Atom::Clone()
304304 {
305305 AP4_Atom* clone = NULL;
306
306
307307 // check the size (refuse to clone atoms that are too large)
308308 AP4_LargeSize size = GetSize();
309309 if (size > AP4_ATOM_MAX_CLONE_SIZE) return NULL;
310310
311311 // create a memory byte stream to which we can serialize
312312 AP4_MemoryByteStream* mbs = new AP4_MemoryByteStream((AP4_Size)GetSize());
313
313
314314 // serialize to memory
315 if (AP4_FAILED(Write(*mbs))) goto end;
316
317 // create the clone for the serialized form
315 if (AP4_FAILED(Write(*mbs))) {
316 mbs->Release();
317 return NULL;
318 }
319
320 // create the clone from the serialized form
318321 mbs->Seek(0);
319 AP4_DefaultAtomFactory::Instance.CreateAtomFromStream(*mbs, clone);
320
321 end:
322 AP4_DefaultAtomFactory atom_factory;
323 atom_factory.CreateAtomFromStream(*mbs, clone);
324
322325 // release the memory stream
323326 mbs->Release();
324327
328331 /*----------------------------------------------------------------------
329332 | AP4_UnknownAtom::AP4_UnknownAtom
330333 +---------------------------------------------------------------------*/
331 AP4_UnknownAtom::AP4_UnknownAtom(Type type,
334 AP4_UnknownAtom::AP4_UnknownAtom(Type type,
332335 AP4_UI64 size,
333 AP4_ByteStream& stream) :
336 AP4_ByteStream& stream) :
334337 AP4_Atom(type, size),
335338 m_SourceStream(&stream)
336339 {
343346 stream.Read(m_Payload.UseData(), payload_size);
344347 return;
345348 }
346
349
347350 // store source stream position
348351 stream.Tell(m_SourcePosition);
349352
368371 /*----------------------------------------------------------------------
369372 | AP4_UnknownAtom::AP4_UnknownAtom
370373 +---------------------------------------------------------------------*/
371 AP4_UnknownAtom::AP4_UnknownAtom(Type type,
374 AP4_UnknownAtom::AP4_UnknownAtom(Type type,
372375 const AP4_UI08* payload,
373376 AP4_Size payload_size) :
374377 AP4_Atom(type, AP4_ATOM_HEADER_SIZE+payload_size, false),
417420 if (m_SourceStream == NULL) {
418421 return stream.Write(m_Payload.GetData(), m_Payload.GetDataSize());
419422 }
420
423
421424 // remember the source position
422425 AP4_Position position;
423426 m_SourceStream->Tell(position);
440443 /*----------------------------------------------------------------------
441444 | AP4_UnknownAtom::Clone
442445 +---------------------------------------------------------------------*/
443 AP4_Atom*
446 AP4_Atom*
444447 AP4_UnknownAtom::Clone()
445448 {
446449 return new AP4_UnknownAtom(*this);
459462 /*----------------------------------------------------------------------
460463 | AP4_NullTerminatedStringAtom::AP4_NullTerminatedStringAtom
461464 +---------------------------------------------------------------------*/
462 AP4_NullTerminatedStringAtom::AP4_NullTerminatedStringAtom(AP4_Atom::Type type,
463 AP4_UI64 size,
465 AP4_NullTerminatedStringAtom::AP4_NullTerminatedStringAtom(AP4_Atom::Type type,
466 AP4_UI64 size,
464467 AP4_ByteStream& stream) :
465468 AP4_Atom(type, size)
466469 {
467 AP4_Size str_size = (AP4_Size)size-AP4_ATOM_HEADER_SIZE;
468 char* str = new char[str_size];
469 stream.Read(str, str_size);
470 str[str_size-1] = '\0'; // force null-termination
471 m_Value = str;
470 AP4_Size str_size = (AP4_Size)size - AP4_ATOM_HEADER_SIZE;
471
472 if (str_size) {
473 char* str = new char[str_size];
474 stream.Read(str, str_size);
475 str[str_size - 1] = '\0'; // force null-termination
476 m_Value = str;
477 delete[] str;
478 }
472479 }
473480
474481 /*----------------------------------------------------------------------
601608 AP4_Result result = m_Children.Find(AP4_AtomFinder(type, index), atom);
602609 if (AP4_SUCCEEDED(result)) {
603610 return atom;
604 } else {
611 } else {
605612 return NULL;
606613 }
607614 }
631638 | AP4_AtomParent::FindChild
632639 +---------------------------------------------------------------------*/
633640 AP4_Atom*
634 AP4_AtomParent::FindChild(const char* path,
641 AP4_AtomParent::FindChild(const char* path,
635642 bool auto_create,
636643 bool auto_create_full)
637644 {
641648 // walk the path
642649 while (path[0] && path[1] && path[2] && path[3]) {
643650 // we have 4 valid chars
644 const char* tail;
645 int index = 0;
646 if (path[4] == '\0') {
647 tail = NULL;
648 } else if (path[4] == '/') {
649 // separator
650 tail = &path[5];
651 } else if (path[4] == '[') {
652 const char* x = &path[5];
651 const char* end = &path[4];
652
653 // look for the end or a separator
654 while (*end != '\0' && *end != '/' && *end != '[') {
655 ++end;
656 }
657
658 // decide if this is a 4-character code or a UUID
659 AP4_UI08 uuid[16];
660 AP4_Atom::Type type = 0;
661 bool is_uuid = false;
662 if (end == path+4) {
663 // 4-character code
664 type = AP4_ATOM_TYPE(path[0], path[1], path[2], path[3]);
665 } else if (end == path+32) {
666 // UUID
667 is_uuid = true;
668 AP4_ParseHex(path, uuid, sizeof(uuid));
669 } else {
670 // malformed path
671 return NULL;
672 }
673
674 // parse the array index, if any
675 int index = 0;
676 if (*end == '[') {
677 const char* x = end+1;
653678 while (*x >= '0' && *x <= '9') {
654679 index = 10*index+(*x++ - '0');
655680 }
656 if (x[0] == ']') {
657 if (x[1] == '\0') {
658 tail = NULL;
659 } else {
660 tail = x+2;
661 }
662 } else {
681 if (*x != ']') {
663682 // malformed path
664683 return NULL;
665684 }
666 } else {
685 end = x+1;
686 }
687
688 // check what's at the end now
689 if (*end == '/') {
690 ++end;
691 } else if (*end != '\0') {
667692 // malformed path
668693 return NULL;
669694 }
670695
671696 // look for this atom in the current list
672 AP4_Atom::Type type = AP4_ATOM_TYPE(path[0], path[1], path[2], path[3]);
673 AP4_Atom* atom = parent->GetChild(type, index);
697 AP4_Atom* atom = NULL;
698 if (is_uuid) {
699 atom = parent->GetChild(uuid, index);
700 } else {
701 atom = parent->GetChild(type, index);
702 }
674703 if (atom == NULL) {
675704 // not found
676705 if (auto_create && (index == 0)) {
685714 }
686715 }
687716
688 if (tail) {
689 path = tail;
717 if (*end) {
718 path = end;
690719 // if this atom is an atom parent, recurse
691720 parent = AP4_DYNAMIC_CAST(AP4_ContainerAtom, atom);
692721 if (parent == NULL) return NULL;
697726
698727 // not found
699728 return NULL;
729 }
730
731 /*----------------------------------------------------------------------
732 | AP4_AtomParent::CopyChildren
733 +---------------------------------------------------------------------*/
734 AP4_Result
735 AP4_AtomParent::CopyChildren(AP4_AtomParent& destination) const
736 {
737 for (AP4_List<AP4_Atom>::Item* child = m_Children.FirstItem(); child; child=child->GetNext()) {
738 AP4_Atom* child_clone = child->GetData()->Clone();
739 destination.AddChild(child_clone);
740 }
741
742 return AP4_SUCCESS;
700743 }
701744
702745 /*----------------------------------------------------------------------
744787 for (unsigned int i=0; i<indent; i++) {
745788 prefix[i] = ' ';
746789 }
747 prefix[indent] = '\0';
790 prefix[indent] = '\0';
748791 }
749792
750793 /*----------------------------------------------------------------------
751794 | AP4_PrintInspector::AP4_PrintInspector
752795 +---------------------------------------------------------------------*/
753796 AP4_PrintInspector::AP4_PrintInspector(AP4_ByteStream& stream, AP4_Cardinal indent) :
754 m_Stream(&stream),
755 m_Indent(indent)
797 m_Stream(&stream)
756798 {
757799 m_Stream->AddReference();
800 PushContext(Context::TOP_LEVEL);
758801 }
759802
760803 /*----------------------------------------------------------------------
763806 AP4_PrintInspector::~AP4_PrintInspector()
764807 {
765808 m_Stream->Release();
809 }
810
811 /*----------------------------------------------------------------------
812 | AP4_PrintInspector::PushContext
813 +---------------------------------------------------------------------*/
814 void
815 AP4_PrintInspector::PushContext(Context::Type type)
816 {
817 m_Contexts.Append(Context(type));
818 }
819
820 /*----------------------------------------------------------------------
821 | AP4_PrintInspector::PopContext
822 +---------------------------------------------------------------------*/
823 void
824 AP4_PrintInspector::PopContext()
825 {
826 m_Contexts.RemoveLast();
827 }
828
829 /*----------------------------------------------------------------------
830 | AP4_PrintInspector::PrintPrefix
831 +---------------------------------------------------------------------*/
832 void
833 AP4_PrintInspector::PrintPrefix()
834 {
835 if (LastContext().m_Type == Context::COMPACT_OBJECT) {
836 if (LastContext().m_ArrayIndex++) {
837 m_Stream->WriteString(", ");
838 }
839 return;
840 }
841
842 if (m_Contexts.ItemCount() >= 1) {
843 char prefix[256];
844 AP4_MakePrefixString((m_Contexts.ItemCount() - 1) * 2, prefix, sizeof(prefix));
845 m_Stream->WriteString(prefix);
846
847 if (LastContext().m_Type == Context::ARRAY) {
848 char index[32];
849 AP4_FormatString(index, sizeof(index), "(%8d) ", (int)LastContext().m_ArrayIndex);
850 m_Stream->WriteString(index);
851 ++LastContext().m_ArrayIndex;
852 }
853 }
854 }
855
856 /*----------------------------------------------------------------------
857 | AP4_PrintInspector::PrintSuffix
858 +---------------------------------------------------------------------*/
859 void
860 AP4_PrintInspector::PrintSuffix()
861 {
862 if (LastContext().m_Type != Context::COMPACT_OBJECT) {
863 m_Stream->WriteString("\n");
864 }
766865 }
767866
768867 /*----------------------------------------------------------------------
775874 AP4_Size header_size,
776875 AP4_UI64 size)
777876 {
877 PrintPrefix();
878 PushContext(Context::ATOM);
879
778880 // write atom name
779881 char info[128];
780882 char extra[32] = "";
781883 if (header_size == 28 || header_size == 12 || header_size == 20) {
782884 if (version && flags) {
783 AP4_FormatString(extra, sizeof(extra),
885 AP4_FormatString(extra, sizeof(extra),
784886 ", version=%d, flags=%x",
785887 version,
786888 flags);
787889 } else if (version) {
788 AP4_FormatString(extra, sizeof(extra),
890 AP4_FormatString(extra, sizeof(extra),
789891 ", version=%d",
790892 version);
791893 } else if (flags) {
792 AP4_FormatString(extra, sizeof(extra),
894 AP4_FormatString(extra, sizeof(extra),
793895 ", flags=%x",
794896 flags);
795897 }
796898 }
797 AP4_FormatString(info, sizeof(info),
798 "size=%d+%lld%s",
799 header_size,
800 size-header_size,
899 AP4_FormatString(info, sizeof(info),
900 "size=%d+%lld%s",
901 header_size,
902 size-header_size,
801903 extra);
802904
803 char prefix[256];
804 AP4_MakePrefixString(m_Indent, prefix, sizeof(prefix));
805 m_Stream->WriteString(prefix);
806905 m_Stream->WriteString("[");
807906 m_Stream->WriteString(name);
808907 m_Stream->Write("] ", 2);
809908 m_Stream->WriteString(info);
810 m_Stream->Write("\n", 1);
811
812 m_Indent += 2;
909
910 PrintSuffix();
813911 }
814912
815913 /*----------------------------------------------------------------------
818916 void
819917 AP4_PrintInspector::EndAtom()
820918 {
821 m_Indent -= 2;
919 PopContext();
822920 }
823921
824922 /*----------------------------------------------------------------------
829927 AP4_Size header_size,
830928 AP4_UI64 size)
831929 {
930 PrintPrefix();
931 PushContext(Context::ATOM);
932
832933 // write atom name
833934 char info[128];
834 AP4_FormatString(info, sizeof(info),
835 "size=%d+%lld",
836 header_size,
935 AP4_FormatString(info, sizeof(info),
936 "size=%d+%lld",
937 header_size,
837938 size-header_size);
838939
839 char prefix[256];
840 AP4_MakePrefixString(m_Indent, prefix, sizeof(prefix));
841 m_Stream->WriteString(prefix);
842940 m_Stream->Write("[", 1);
843941 m_Stream->WriteString(name);
844942 m_Stream->Write("] ", 2);
845943 m_Stream->WriteString(info);
846 m_Stream->Write("\n", 1);
847
848 m_Indent += 2;
944
945 PrintSuffix();
849946 }
850947
851948 /*----------------------------------------------------------------------
854951 void
855952 AP4_PrintInspector::EndDescriptor()
856953 {
857 m_Indent -= 2;
954 EndAtom();
955 }
956
957 /*----------------------------------------------------------------------
958 | AP4_PrintInspector::StartArray
959 +---------------------------------------------------------------------*/
960 void
961 AP4_PrintInspector::StartArray(const char* name, unsigned int /* element_count */)
962 {
963 PrintPrefix();
964 PushContext(Context::ARRAY);
965
966 if (name) {
967 m_Stream->WriteString(name);
968 m_Stream->WriteString(":");
969 }
970
971 PrintSuffix();
972 }
973
974 /*----------------------------------------------------------------------
975 | AP4_PrintInspector::EndArray
976 +---------------------------------------------------------------------*/
977 void
978 AP4_PrintInspector::EndArray()
979 {
980 PopContext();
981 }
982
983 /*----------------------------------------------------------------------
984 | AP4_PrintInspector::StartObject
985 +---------------------------------------------------------------------*/
986 void
987 AP4_PrintInspector::StartObject(const char* name, unsigned int /* field_count */, bool compact)
988 {
989 PrintPrefix();
990 PushContext(compact ? Context::COMPACT_OBJECT : Context::OBJECT);
991
992 if (name) {
993 m_Stream->WriteString(name);
994 m_Stream->WriteString(": ");
995 }
996
997 PrintSuffix();
998 }
999
1000 /*----------------------------------------------------------------------
1001 | AP4_PrintInspector::EndObject
1002 +---------------------------------------------------------------------*/
1003 void
1004 AP4_PrintInspector::EndObject()
1005 {
1006 if (LastContext().m_Type == Context::COMPACT_OBJECT) {
1007 m_Stream->WriteString("\n");
1008 }
1009 PopContext();
8581010 }
8591011
8601012 /*----------------------------------------------------------------------
8631015 void
8641016 AP4_PrintInspector::AddField(const char* name, const char* value, FormatHint)
8651017 {
866 char prefix[256];
867 AP4_MakePrefixString(m_Indent, prefix, sizeof(prefix));
868 m_Stream->WriteString(prefix);
869
870 m_Stream->WriteString(name);
871 m_Stream->WriteString(" = ");
1018 PrintPrefix();
1019
1020 if (name) {
1021 m_Stream->WriteString(name);
1022 m_Stream->WriteString(" = ");
1023 }
8721024 m_Stream->WriteString(value);
873 m_Stream->Write("\n", 1);
1025
1026 PrintSuffix();
8741027 }
8751028
8761029 /*----------------------------------------------------------------------
8791032 void
8801033 AP4_PrintInspector::AddField(const char* name, AP4_UI64 value, FormatHint hint)
8811034 {
882 char prefix[256];
883 AP4_MakePrefixString(m_Indent, prefix, sizeof(prefix));
884 m_Stream->WriteString(prefix);
885
1035 PrintPrefix();
1036
1037 if (name) {
1038 m_Stream->WriteString(name);
1039 m_Stream->WriteString(" = ");
1040 }
8861041 char str[32];
887 AP4_FormatString(str, sizeof(str),
888 hint == HINT_HEX ? "%llx":"%lld",
1042 AP4_FormatString(str, sizeof(str),
1043 hint == HINT_HEX ? "%llx":"%lld",
8891044 value);
890 m_Stream->WriteString(name);
891 m_Stream->WriteString(" = ");
8921045 m_Stream->WriteString(str);
893 m_Stream->Write("\n", 1);
1046
1047 PrintSuffix();
8941048 }
8951049
8961050 /*----------------------------------------------------------------------
8991053 void
9001054 AP4_PrintInspector::AddFieldF(const char* name, float value, FormatHint /*hint*/)
9011055 {
902 char prefix[256];
903 AP4_MakePrefixString(m_Indent, prefix, sizeof(prefix));
904 m_Stream->WriteString(prefix);
905
1056 PrintPrefix();
1057
1058 if (name) {
1059 m_Stream->WriteString(name);
1060 m_Stream->WriteString(" = ");
1061 }
9061062 char str[32];
907 AP4_FormatString(str, sizeof(str),
908 "%f",
1063 AP4_FormatString(str, sizeof(str),
1064 "%f",
9091065 value);
910 m_Stream->WriteString(name);
911 m_Stream->WriteString(" = ");
9121066 m_Stream->WriteString(str);
913 m_Stream->Write("\n", 1);
1067
1068 PrintSuffix();
9141069 }
9151070
9161071 /*----------------------------------------------------------------------
9171072 | AP4_PrintInspector::AddField
9181073 +---------------------------------------------------------------------*/
9191074 void
920 AP4_PrintInspector::AddField(const char* name,
921 const unsigned char* bytes,
1075 AP4_PrintInspector::AddField(const char* name,
1076 const unsigned char* bytes,
9221077 AP4_Size byte_count,
9231078 FormatHint /* hint */)
9241079 {
925 char prefix[256];
926 AP4_MakePrefixString(m_Indent, prefix, sizeof(prefix));
927 m_Stream->WriteString(prefix);
928
929 m_Stream->WriteString(name);
930 m_Stream->WriteString(" = [");
931 unsigned int offset = 1;
932 char byte[4];
933 for (unsigned int i=0; i<byte_count; i++) {
934 AP4_FormatString(byte, 4, " %02x", bytes[i]);
935 m_Stream->Write(&byte[offset], 3-offset);
936 offset = 0;
937 }
938 m_Stream->Write("]\n", 2);
939 }
940
941 /*----------------------------------------------------------------------
942 | AP4_JsonInspector::AP4_JsonInspector
943 +---------------------------------------------------------------------*/
944 AP4_JsonInspector::AP4_JsonInspector(AP4_ByteStream& stream) :
945 m_Stream(&stream),
946 m_Depth(0)
947 {
948 m_Items.SetItemCount(1);
949 m_Items[0] = 0;
950 m_Stream->AddReference();
951 m_Stream->WriteString("[\n");
952 }
953
954 /*----------------------------------------------------------------------
955 | AP4_JsonInspector::~AP4_JsonInspector
956 +---------------------------------------------------------------------*/
957 AP4_JsonInspector::~AP4_JsonInspector()
958 {
959 m_Stream->WriteString("\n]\n");
960 m_Stream->Release();
961 }
962
963 /*----------------------------------------------------------------------
964 | AP4_JsonInspector::StartAtom
965 +---------------------------------------------------------------------*/
966 void
967 AP4_JsonInspector::StartAtom(const char* name,
968 AP4_UI08 /*version*/,
969 AP4_UI32 /*flags*/,
970 AP4_Size header_size,
971 AP4_UI64 size)
972 {
973 char prefix[256];
974 AP4_MakePrefixString(m_Depth*2, prefix, sizeof(prefix));
975
976 if (m_Items[m_Depth]) {
977 m_Stream->WriteString(",\n");
978 } else {
979 if (m_Depth != 0 || m_Items[0] != 0) {
980 m_Stream->WriteString(",\n");
981 m_Stream->WriteString(prefix);
982 m_Stream->WriteString("\"children\":[\n");
983 }
984 }
985 m_Stream->WriteString(prefix);
986 m_Stream->WriteString("{\n");
987 m_Stream->WriteString(prefix);
988 m_Stream->WriteString(" \"name\":\"");
989 m_Stream->WriteString(name);
990 m_Stream->Write("\"", 1);
991 m_Stream->WriteString(",\n");
992 m_Stream->WriteString(prefix);
993 m_Stream->WriteString(" \"header_size\":");
994 char val[32];
995 AP4_FormatString(val, sizeof(val), "%d", header_size);
996 m_Stream->WriteString(val);
997 m_Stream->WriteString(",\n");
998 m_Stream->WriteString(prefix);
999 m_Stream->WriteString(" \"size\":");
1000 AP4_FormatString(val, sizeof(val), "%lld", size);
1001 m_Stream->WriteString(val);
1002
1003 ++m_Depth;
1004 m_Items.SetItemCount(m_Depth+1);
1005 m_Items[m_Depth] = 0;
1006 }
1007
1008 /*----------------------------------------------------------------------
1009 | AP4_JsonInspector::EndAtom
1010 +---------------------------------------------------------------------*/
1011 void
1012 AP4_JsonInspector::EndAtom()
1013 {
1014 if (m_Items[m_Depth]) {
1015 m_Stream->Write("]",1);
1016 }
1017 --m_Depth;
1018 ++m_Items[m_Depth];
1019 char prefix[256];
1020 AP4_MakePrefixString(m_Depth*2, prefix, sizeof(prefix));
1021 m_Stream->WriteString("\n");
1022 m_Stream->WriteString(prefix);
1023 m_Stream->WriteString("}");
1024 }
1025
1026 /*----------------------------------------------------------------------
1027 | AP4_JsonInspector::StartDescriptor
1028 +---------------------------------------------------------------------*/
1029 void
1030 AP4_JsonInspector::StartDescriptor(const char* name,
1031 AP4_Size header_size,
1032 AP4_UI64 size)
1033 {
1034 StartAtom(name, 0, 0, header_size, size);
1035 }
1036
1037 /*----------------------------------------------------------------------
1038 | AP4_JsonInspector::EndDescriptor
1039 +---------------------------------------------------------------------*/
1040 void
1041 AP4_JsonInspector::EndDescriptor()
1042 {
1043 EndAtom();
1044 }
1045
1046 /*----------------------------------------------------------------------
1047 | AP4_JsonInspector::AddField
1048 +---------------------------------------------------------------------*/
1049 void
1050 AP4_JsonInspector::AddField(const char* name, const char* value, FormatHint)
1051 {
1052 char prefix[256];
1053 AP4_MakePrefixString(m_Depth*2, prefix, sizeof(prefix));
1054 m_Stream->WriteString(",\n");
1055 m_Stream->WriteString(prefix);
1056 m_Stream->Write("\"", 1);
1057 m_Stream->WriteString(name);
1058 m_Stream->Write("\":\"", 3);
1059 m_Stream->WriteString(value);
1060 m_Stream->Write("\"", 1);
1061 }
1062
1063 /*----------------------------------------------------------------------
1064 | AP4_JsonInspector::AddField
1065 +---------------------------------------------------------------------*/
1066 void
1067 AP4_JsonInspector::AddField(const char* name, AP4_UI64 value, FormatHint /* hint */)
1068 {
1069 char prefix[256];
1070 AP4_MakePrefixString(m_Depth*2, prefix, sizeof(prefix));
1071 m_Stream->WriteString(",\n");
1072 m_Stream->WriteString(prefix);
1073
1074 char str[32];
1075 AP4_FormatString(str, sizeof(str),
1076 "%lld",
1077 value);
1078 m_Stream->Write("\"", 1);
1079 m_Stream->WriteString(name);
1080 m_Stream->Write("\":", 2);
1081 m_Stream->WriteString(str);
1082 }
1083
1084 /*----------------------------------------------------------------------
1085 | AP4_JsonInspector::AddFieldF
1086 +---------------------------------------------------------------------*/
1087 void
1088 AP4_JsonInspector::AddFieldF(const char* name, float value, FormatHint /*hint*/)
1089 {
1090 char prefix[256];
1091 AP4_MakePrefixString(m_Depth*2, prefix, sizeof(prefix));
1092 m_Stream->WriteString(",\n");
1093 m_Stream->WriteString(prefix);
1094
1095 char str[32];
1096 AP4_FormatString(str, sizeof(str),
1097 "%f",
1098 value);
1099 m_Stream->Write("\"", 1);
1100 m_Stream->WriteString(name);
1101 m_Stream->Write("\":", 2);
1102 m_Stream->WriteString(str);
1103 }
1104
1105 /*----------------------------------------------------------------------
1106 | AP4_JsonInspector::AddField
1107 +---------------------------------------------------------------------*/
1108 void
1109 AP4_JsonInspector::AddField(const char* name,
1110 const unsigned char* bytes,
1111 AP4_Size byte_count,
1112 FormatHint /* hint */)
1113 {
1114 char prefix[256];
1115 AP4_MakePrefixString(m_Depth*2, prefix, sizeof(prefix));
1116 m_Stream->WriteString(",\n");
1117 m_Stream->WriteString(prefix);
1118
1119 m_Stream->Write("\"", 1);
1120 m_Stream->WriteString(name);
1121 m_Stream->Write("\":\"", 3);
1080 PrintPrefix();
1081
1082 if (name) {
1083 m_Stream->WriteString(name);
1084 m_Stream->WriteString(" = ");
1085 }
11221086 m_Stream->WriteString("[");
11231087 unsigned int offset = 1;
11241088 char byte[4];
11271091 m_Stream->Write(&byte[offset], 3-offset);
11281092 offset = 0;
11291093 }
1130 m_Stream->Write("]", 1);
1131 m_Stream->Write("\"", 1);
1132 }
1133
1134
1094 m_Stream->WriteString("]");
1095
1096 PrintSuffix();
1097 }
1098
1099 /*----------------------------------------------------------------------
1100 | AP4_JsonInspector::AP4_JsonInspector
1101 +---------------------------------------------------------------------*/
1102 AP4_JsonInspector::AP4_JsonInspector(AP4_ByteStream& stream) :
1103 m_Stream(&stream)
1104 {
1105 m_Stream->AddReference();
1106 m_Stream->WriteString("[\n");
1107 PushContext(Context::TOP_LEVEL);
1108 }
1109
1110 /*----------------------------------------------------------------------
1111 | AP4_JsonInspector::~AP4_JsonInspector
1112 +---------------------------------------------------------------------*/
1113 AP4_JsonInspector::~AP4_JsonInspector()
1114 {
1115 m_Stream->WriteString("\n]\n");
1116 m_Stream->Release();
1117 }
1118
1119 /*----------------------------------------------------------------------
1120 | AP4_JsonInspector::PushContext
1121 +---------------------------------------------------------------------*/
1122 void
1123 AP4_JsonInspector::PushContext(Context::Type type)
1124 {
1125 m_Contexts.Append(Context(type));
1126 AP4_MakePrefixString(m_Contexts.ItemCount() * 2, m_Prefix, sizeof(m_Prefix));
1127 }
1128
1129 /*----------------------------------------------------------------------
1130 | AP4_JsonInspector::PopContext
1131 +---------------------------------------------------------------------*/
1132 void
1133 AP4_JsonInspector::PopContext()
1134 {
1135 m_Contexts.RemoveLast();
1136 AP4_MakePrefixString(m_Contexts.ItemCount() * 2, m_Prefix, sizeof(m_Prefix));
1137 }
1138
1139 /*----------------------------------------------------------------------
1140 | AP4_JsonInspector::OnFieldAdded
1141 +---------------------------------------------------------------------*/
1142 void
1143 AP4_JsonInspector::OnFieldAdded()
1144 {
1145 if (LastContext().m_FieldCount) {
1146 m_Stream->WriteString(",\n");
1147 }
1148 ++LastContext().m_FieldCount;
1149 }
1150
1151 /*----------------------------------------------------------------------
1152 | AP4_JsonInspector::PrintFieldName
1153 +---------------------------------------------------------------------*/
1154 void
1155 AP4_JsonInspector::PrintFieldName(const char* name)
1156 {
1157 if (!name) return;
1158 m_Stream->WriteString("\"");
1159 m_Stream->WriteString(EscapeString(name).GetChars());
1160 m_Stream->WriteString("\": ");
1161 }
1162
1163 /*----------------------------------------------------------------------
1164 | Read one code point from a UTF-8 string
1165 +---------------------------------------------------------------------*/
1166 static AP4_Result
1167 ReadUTF8(const AP4_UI08* utf, AP4_Size* length, AP4_UI32* code_point) {
1168 if (*length < 1) {
1169 return AP4_ERROR_NOT_ENOUGH_DATA;
1170 }
1171
1172 AP4_UI32 c = utf[0];
1173 if ((c & 0x80) == 0) {
1174 *length = 1;
1175 *code_point = c;
1176 return AP4_SUCCESS;
1177 }
1178 if (*length < 2) {
1179 return AP4_ERROR_NOT_ENOUGH_DATA;
1180 }
1181 *code_point = 0;
1182 if ((utf[1] & 0xc0) != 0x80) {
1183 return AP4_ERROR_INVALID_FORMAT;
1184 }
1185 if ((c & 0xe0) == 0xe0) {
1186 if (*length < 3) {
1187 return AP4_ERROR_NOT_ENOUGH_DATA;
1188 }
1189 if ((utf[2] & 0xc0) != 0x80) {
1190 return AP4_ERROR_INVALID_FORMAT;
1191 }
1192 if ((c & 0xf0) == 0xf0) {
1193 if (*length < 4) {
1194 return AP4_ERROR_NOT_ENOUGH_DATA;
1195 }
1196 if ((c & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80) {
1197 return AP4_ERROR_INVALID_FORMAT;
1198 }
1199 *length = 4;
1200 c = (utf[0] & 0x07) << 18;
1201 c |= (utf[1] & 0x3f) << 12;
1202 c |= (utf[2] & 0x3f) << 6;
1203 c |= (utf[3] & 0x3f);
1204 } else {
1205 *length = 3;
1206 c = (utf[0] & 0x0f) << 12;
1207 c |= (utf[1] & 0x3f) << 6;
1208 c |= (utf[2] & 0x3f);
1209 }
1210 } else {
1211 /* 2-byte code */
1212 *length = 2;
1213 c = (utf[0] & 0x1f) << 6;
1214 c |= (utf[1] & 0x3f);
1215 }
1216
1217 *code_point = c;
1218 return AP4_SUCCESS;
1219 }
1220
1221 /*----------------------------------------------------------------------
1222 | AP4_JsonInspector::EscapeString
1223 |
1224 | Not very efficient but simple function to escape characters in a
1225 | JSON string
1226 +---------------------------------------------------------------------*/
1227 AP4_String
1228 AP4_JsonInspector::EscapeString(const char* string)
1229 {
1230 AP4_String result(string);
1231
1232 // Shortcut
1233 if (result.GetLength() == 0) {
1234 return result;
1235 }
1236
1237 // Compute the output size
1238 AP4_Size string_length = (AP4_Size)strlen(string);
1239 const AP4_UI08* input = (const AP4_UI08*)string;
1240 AP4_Size input_length = string_length;
1241 AP4_Size output_size = 0;
1242 while (input_length) {
1243 AP4_Size chars_available = input_length;
1244 AP4_UI32 code_point = 0;
1245 AP4_Result r = ReadUTF8(input, &chars_available, &code_point);
1246 if (AP4_FAILED(r)) {
1247 // stop, but don't fail
1248 break;
1249 }
1250 if (code_point == '"' || code_point == '\\') {
1251 output_size += 2;
1252 } else if (code_point <= 0x1F) {
1253 output_size += 6;
1254 } else {
1255 output_size += chars_available;
1256 }
1257 input_length -= chars_available;
1258 input += chars_available;
1259 }
1260
1261 // Shortcut
1262 if (output_size == result.GetLength()) {
1263 return result;
1264 }
1265
1266 // Compute the escaped string in a temporary buffer
1267 char* buffer = new char[output_size];
1268 char* escaped = buffer;
1269 input = (const AP4_UI08*)string;
1270 input_length = string_length;
1271 while (input_length) {
1272 AP4_Size chars_available = input_length;
1273 AP4_UI32 code_point = 0;
1274 AP4_Result r = ReadUTF8(input, &chars_available, &code_point);
1275 if (AP4_FAILED(r)) {
1276 // stop, but don't fail
1277 break;
1278 }
1279 if (code_point == '"' || code_point == '\\') {
1280 *escaped++ = '\\';
1281 *escaped++ = (char)code_point;
1282 } else if (code_point <= 0x1F) {
1283 *escaped++ = '\\';
1284 *escaped++ = 'u';
1285 *escaped++ = '0';
1286 *escaped++ = '0';
1287 *escaped++ = AP4_NibbleHex(code_point >> 4);
1288 *escaped++ = AP4_NibbleHex(code_point & 0x0F);
1289 } else {
1290 for (AP4_Size i = 0; i < chars_available; i++) {
1291 *escaped++ = (char)input[i];
1292 }
1293 }
1294 input_length -= chars_available;
1295 input += chars_available;
1296 }
1297
1298 // Copy the buffer to a final string
1299 result.Assign(buffer, output_size);
1300 delete[] buffer;
1301
1302 return result;
1303 }
1304
1305 /*----------------------------------------------------------------------
1306 | AP4_JsonInspector::StartAtom
1307 +---------------------------------------------------------------------*/
1308 void
1309 AP4_JsonInspector::StartAtom(const char* name,
1310 AP4_UI08 version,
1311 AP4_UI32 flags,
1312 AP4_Size header_size,
1313 AP4_UI64 size)
1314 {
1315 OnFieldAdded();
1316 ++LastContext().m_ChildrenCount;
1317
1318 // Starting the first atom within an atom means staring a childen array
1319 if (LastContext().m_Type == Context::ATOM && LastContext().m_ChildrenCount == 1) {
1320 m_Stream->WriteString(m_Prefix);
1321 m_Stream->WriteString("\"children\":[ \n");
1322 }
1323
1324 m_Stream->WriteString(m_Prefix);
1325 m_Stream->WriteString("{\n");
1326 PushContext(Context::ATOM);
1327
1328 OnFieldAdded();
1329 m_Stream->WriteString(m_Prefix);
1330 PrintFieldName("name");
1331 m_Stream->WriteString("\"");
1332 m_Stream->WriteString(EscapeString(name).GetChars());
1333 m_Stream->WriteString("\"");
1334
1335 OnFieldAdded();
1336 m_Stream->WriteString(m_Prefix);
1337 PrintFieldName("header_size");
1338 char val[32];
1339 AP4_FormatString(val, sizeof(val), "%d", header_size);
1340 m_Stream->WriteString(val);
1341
1342 OnFieldAdded();
1343 m_Stream->WriteString(m_Prefix);
1344 PrintFieldName("size");
1345 AP4_FormatString(val, sizeof(val), "%lld", size);
1346 m_Stream->WriteString(val);
1347
1348 if (version) {
1349 OnFieldAdded();
1350 m_Stream->WriteString(m_Prefix);
1351 PrintFieldName("version");
1352 AP4_FormatString(val, sizeof(val), "%d", version);
1353 m_Stream->WriteString(val);
1354 }
1355
1356 if (flags) {
1357 OnFieldAdded();
1358 m_Stream->WriteString(m_Prefix);
1359 PrintFieldName("flags");
1360 AP4_FormatString(val, sizeof(val), "%d", flags);
1361 m_Stream->WriteString(val);
1362 }
1363 }
1364
1365 /*----------------------------------------------------------------------
1366 | AP4_JsonInspector::EndAtom
1367 +---------------------------------------------------------------------*/
1368 void
1369 AP4_JsonInspector::EndAtom()
1370 {
1371 // Ending an atom with children means we need to close the children array
1372 if (LastContext().m_ChildrenCount) {
1373 m_Stream->WriteString("]");
1374 }
1375
1376 PopContext();
1377
1378 m_Stream->WriteString("\n");
1379 m_Stream->WriteString(m_Prefix);
1380 m_Stream->WriteString("}");
1381 }
1382
1383 /*----------------------------------------------------------------------
1384 | AP4_JsonInspector::StartDescriptor
1385 +---------------------------------------------------------------------*/
1386 void
1387 AP4_JsonInspector::StartDescriptor(const char* name,
1388 AP4_Size header_size,
1389 AP4_UI64 size)
1390 {
1391 StartAtom(name, 0, 0, header_size, size);
1392 }
1393
1394 /*----------------------------------------------------------------------
1395 | AP4_JsonInspector::EndDescriptor
1396 +---------------------------------------------------------------------*/
1397 void
1398 AP4_JsonInspector::EndDescriptor()
1399 {
1400 EndAtom();
1401 }
1402
1403 /*----------------------------------------------------------------------
1404 | AP4_JsonInspector::StartArray
1405 +---------------------------------------------------------------------*/
1406 void
1407 AP4_JsonInspector::StartArray(const char* name, unsigned int /* element_count */)
1408 {
1409 OnFieldAdded();
1410 m_Stream->WriteString(m_Prefix);
1411 if (name) {
1412 PrintFieldName(name);
1413 }
1414
1415 m_Stream->WriteString("[\n");
1416 PushContext(Context::ARRAY);
1417 }
1418
1419 /*----------------------------------------------------------------------
1420 | AP4_JsonInspector::EndArray
1421 +---------------------------------------------------------------------*/
1422 void
1423 AP4_JsonInspector::EndArray()
1424 {
1425 PopContext();
1426 m_Stream->WriteString("\n");
1427 m_Stream->WriteString(m_Prefix);
1428 m_Stream->WriteString("]");
1429 }
1430
1431 /*----------------------------------------------------------------------
1432 | AP4_JsonInspector::StartObject
1433 +---------------------------------------------------------------------*/
1434 void
1435 AP4_JsonInspector::StartObject(const char* name, unsigned int /* field_count */, bool /* compact */)
1436 {
1437 OnFieldAdded();
1438 m_Stream->WriteString(m_Prefix);
1439 if (name) {
1440 PrintFieldName(name);
1441 }
1442
1443 m_Stream->WriteString("{\n");
1444 PushContext(Context::ARRAY);
1445 }
1446
1447 /*----------------------------------------------------------------------
1448 | AP4_JsonInspector::EndObject
1449 +---------------------------------------------------------------------*/
1450 void
1451 AP4_JsonInspector::EndObject()
1452 {
1453 PopContext();
1454 m_Stream->WriteString("\n");
1455 m_Stream->WriteString(m_Prefix);
1456 m_Stream->WriteString("}");
1457 }
1458
1459 /*----------------------------------------------------------------------
1460 | AP4_JsonInspector::AddField
1461 +---------------------------------------------------------------------*/
1462 void
1463 AP4_JsonInspector::AddField(const char* name, const char* value, FormatHint)
1464 {
1465 OnFieldAdded();
1466 m_Stream->WriteString(m_Prefix);
1467 PrintFieldName(name);
1468 m_Stream->WriteString("\"");
1469 m_Stream->WriteString(EscapeString(value).GetChars());
1470 m_Stream->WriteString("\"");
1471 }
1472
1473 /*----------------------------------------------------------------------
1474 | AP4_JsonInspector::AddField
1475 +---------------------------------------------------------------------*/
1476 void
1477 AP4_JsonInspector::AddField(const char* name, AP4_UI64 value, FormatHint /* hint */)
1478 {
1479 OnFieldAdded();
1480 m_Stream->WriteString(m_Prefix);
1481 PrintFieldName(name);
1482 char str[32];
1483 AP4_FormatString(str, sizeof(str),
1484 "%lld",
1485 value);
1486 m_Stream->WriteString(str);
1487 }
1488
1489 /*----------------------------------------------------------------------
1490 | AP4_JsonInspector::AddFieldF
1491 +---------------------------------------------------------------------*/
1492 void
1493 AP4_JsonInspector::AddFieldF(const char* name, float value, FormatHint /*hint*/)
1494 {
1495 OnFieldAdded();
1496 m_Stream->WriteString(m_Prefix);
1497 PrintFieldName(name);
1498 char str[32];
1499 AP4_FormatString(str, sizeof(str),
1500 "%f",
1501 value);
1502 m_Stream->WriteString(str);
1503 }
1504
1505 /*----------------------------------------------------------------------
1506 | AP4_JsonInspector::AddField
1507 +---------------------------------------------------------------------*/
1508 void
1509 AP4_JsonInspector::AddField(const char* name,
1510 const unsigned char* bytes,
1511 AP4_Size byte_count,
1512 FormatHint /* hint */)
1513 {
1514 OnFieldAdded();
1515 m_Stream->WriteString(m_Prefix);
1516 PrintFieldName(name);
1517 m_Stream->WriteString("\"[");
1518 unsigned int offset = 1;
1519 char byte[4];
1520 for (unsigned int i = 0; i < byte_count; i++) {
1521 AP4_FormatString(byte, 4, " %02x", bytes[i]);
1522 m_Stream->Write(&byte[offset], 3 - offset);
1523 offset = 0;
1524 }
1525 m_Stream->WriteString("]\"");
1526 }
1527
1528
7878 public:
7979 // types
8080 typedef enum {
81 HINT_NONE = 0,
82 HINT_HEX = 1,
83 HINT_BOOLEAN = 2
81 HINT_NONE = 0,
82 HINT_HEX = 1,
83 HINT_BOOLEAN = 2
8484 } FormatHint;
8585
8686 // constructor and destructor
102102 AP4_Size /* header_size */,
103103 AP4_UI64 /*size */) {}
104104 virtual void EndDescriptor() {}
105 virtual void AddField(const char* /* name */,
105 virtual void StartArray(const char* /* name */, unsigned int element_count = 0) {}
106 virtual void EndArray() {}
107 virtual void StartObject(const char* /* name */, unsigned int field_count = 0, bool compact = false) {}
108 virtual void EndObject() {}
109 virtual void AddField(const char* /* name */,
106110 AP4_UI64 /* value */,
107111 FormatHint hint = HINT_NONE) {
108112 (void)hint; // gcc warning
147151 AP4_Size header_size,
148152 AP4_UI64 size);
149153 void EndDescriptor();
154 void StartArray(const char* name, unsigned int element_count);
155 void EndArray();
156 void StartObject(const char* name, unsigned int field_count, bool compact);
157 void EndObject();
150158 void AddField(const char* name, AP4_UI64 value, FormatHint hint);
151159 void AddFieldF(const char* name, float value, FormatHint hint);
152160 void AddField(const char* name, const char* value, FormatHint hint);
153161 void AddField(const char* name, const unsigned char* bytes, AP4_Size size, FormatHint hint);
154162
155163 private:
164 // types
165 struct Context {
166 typedef enum {
167 TOP_LEVEL,
168 ATOM,
169 ARRAY,
170 OBJECT,
171 COMPACT_OBJECT
172 } Type;
173
174 Context(Type type) : m_Type(type), m_ArrayIndex(0) {}
175
176 Type m_Type;
177 AP4_Cardinal m_ArrayIndex;
178 };
179
180 // methods
181 void PushContext(Context::Type type);
182 void PopContext();
183 Context& LastContext() { return m_Contexts[m_Contexts.ItemCount() - 1]; }
184 void PrintPrefix();
185 void PrintSuffix();
186
156187 // members
157 AP4_ByteStream* m_Stream;
158 AP4_Cardinal m_Indent;
188 AP4_ByteStream* m_Stream;
189 AP4_Array<Context> m_Contexts;
159190 };
160191
161192 /*----------------------------------------------------------------------
177208 AP4_Size header_size,
178209 AP4_UI64 size);
179210 void EndDescriptor();
211 void StartArray(const char* name, unsigned int element_count);
212 void EndArray();
213 void StartObject(const char* name, unsigned int field_count, bool compact);
214 void EndObject();
180215 void AddField(const char* name, AP4_UI64 value, FormatHint hint);
181216 void AddFieldF(const char* name, float value, FormatHint hint);
182217 void AddField(const char* name, const char* value, FormatHint hint);
183218 void AddField(const char* name, const unsigned char* bytes, AP4_Size size, FormatHint hint);
184219
185220 private:
221 // types
222 struct Context {
223 typedef enum {
224 TOP_LEVEL,
225 ATOM,
226 ARRAY,
227 OBJECT
228 } Type;
229
230 Context(Type type) : m_Type(type), m_FieldCount(0), m_ChildrenCount(0) {}
231
232 Type m_Type;
233 AP4_Cardinal m_FieldCount;
234 AP4_Cardinal m_ChildrenCount; // to count atoms within atoms
235 };
236
237 // methods
238 static AP4_String EscapeString(const char* string);
239 void PushContext(Context::Type type);
240 void PopContext();
241 Context& LastContext() { return m_Contexts[m_Contexts.ItemCount() - 1]; }
242 void OnFieldAdded();
243 void PrintFieldName(const char* name);
244
186245 // members
187 AP4_ByteStream* m_Stream;
188 AP4_Cardinal m_Depth;
189 AP4_Array<AP4_Cardinal> m_Items;
246 AP4_ByteStream* m_Stream;
247 AP4_Array<Context> m_Contexts;
248 char m_Prefix[256];
190249 };
191250
192251 /*----------------------------------------------------------------------
242301 // methods
243302 AP4_UI32 GetFlags() const { return m_Flags; }
244303 void SetFlags(AP4_UI32 flags) { m_Flags = flags; }
304 AP4_UI08 GetVersion() const {return m_Version;}
305 void SetVersion(AP4_UI08 version) { m_Version = version; }
245306 Type GetType() const { return m_Type; }
246307 void SetType(Type type) { m_Type = type; }
247308 virtual AP4_Size GetHeaderSize() const;
303364 // base methods
304365 virtual ~AP4_AtomParent();
305366 AP4_List<AP4_Atom>& GetChildren() { return m_Children; }
367 AP4_Result CopyChildren(AP4_AtomParent& destination) const;
306368 virtual AP4_Result AddChild(AP4_Atom* child, int position = -1);
307369 virtual AP4_Result RemoveChild(AP4_Atom* child);
308370 virtual AP4_Result DeleteChild(AP4_Atom::Type type, AP4_Ordinal index = 0);
413475 const AP4_Atom::Type AP4_ATOM_TYPE_AVC2 = AP4_ATOM_TYPE('a','v','c','2');
414476 const AP4_Atom::Type AP4_ATOM_TYPE_AVC3 = AP4_ATOM_TYPE('a','v','c','3');
415477 const AP4_Atom::Type AP4_ATOM_TYPE_AVC4 = AP4_ATOM_TYPE('a','v','c','4');
478 const AP4_Atom::Type AP4_ATOM_TYPE_DVAV = AP4_ATOM_TYPE('d','v','a','v');
479 const AP4_Atom::Type AP4_ATOM_TYPE_DVA1 = AP4_ATOM_TYPE('d','v','a','1');
416480 const AP4_Atom::Type AP4_ATOM_TYPE_HEV1 = AP4_ATOM_TYPE('h','e','v','1');
417481 const AP4_Atom::Type AP4_ATOM_TYPE_HVC1 = AP4_ATOM_TYPE('h','v','c','1');
482 const AP4_Atom::Type AP4_ATOM_TYPE_DVHE = AP4_ATOM_TYPE('d','v','h','e');
483 const AP4_Atom::Type AP4_ATOM_TYPE_DVH1 = AP4_ATOM_TYPE('d','v','h','1');
484 const AP4_Atom::Type AP4_ATOM_TYPE_VP08 = AP4_ATOM_TYPE('v','p','0','8');
485 const AP4_Atom::Type AP4_ATOM_TYPE_VP09 = AP4_ATOM_TYPE('v','p','0','9');
486 const AP4_Atom::Type AP4_ATOM_TYPE_VP10 = AP4_ATOM_TYPE('v','p','1','0');
487 const AP4_Atom::Type AP4_ATOM_TYPE_AV01 = AP4_ATOM_TYPE('a','v','0','1');
418488 const AP4_Atom::Type AP4_ATOM_TYPE_ALAC = AP4_ATOM_TYPE('a','l','a','c');
419489 const AP4_Atom::Type AP4_ATOM_TYPE_ENCA = AP4_ATOM_TYPE('e','n','c','a');
420490 const AP4_Atom::Type AP4_ATOM_TYPE_ENCV = AP4_ATOM_TYPE('e','n','c','v');
474544 const AP4_Atom::Type AP4_ATOM_TYPE_MDRI = AP4_ATOM_TYPE('m','d','r','i');
475545 const AP4_Atom::Type AP4_ATOM_TYPE_AVCC = AP4_ATOM_TYPE('a','v','c','C');
476546 const AP4_Atom::Type AP4_ATOM_TYPE_HVCC = AP4_ATOM_TYPE('h','v','c','C');
547 const AP4_Atom::Type AP4_ATOM_TYPE_DVCC = AP4_ATOM_TYPE('d','v','c','C');
548 const AP4_Atom::Type AP4_ATOM_TYPE_VPCC = AP4_ATOM_TYPE('v','p','c','C');
549 const AP4_Atom::Type AP4_ATOM_TYPE_DVVC = AP4_ATOM_TYPE('d','v','v','C');
550 const AP4_Atom::Type AP4_ATOM_TYPE_HVCE = AP4_ATOM_TYPE('h','v','c','E');
551 const AP4_Atom::Type AP4_ATOM_TYPE_AVCE = AP4_ATOM_TYPE('a','v','c','E');
552 const AP4_Atom::Type AP4_ATOM_TYPE_AV1C = AP4_ATOM_TYPE('a','v','1','C');
477553 const AP4_Atom::Type AP4_ATOM_TYPE_WAVE = AP4_ATOM_TYPE('w','a','v','e');
478554 const AP4_Atom::Type AP4_ATOM_TYPE_WIDE = AP4_ATOM_TYPE('w','i','d','e');
479555 const AP4_Atom::Type AP4_ATOM_TYPE_UUID = AP4_ATOM_TYPE('u','u','i','d');
481557 const AP4_Atom::Type AP4_ATOM_TYPE_8BDL = AP4_ATOM_TYPE('8','b','d','l');
482558 const AP4_Atom::Type AP4_ATOM_TYPE_AC_3 = AP4_ATOM_TYPE('a','c','-','3');
483559 const AP4_Atom::Type AP4_ATOM_TYPE_EC_3 = AP4_ATOM_TYPE('e','c','-','3');
560 const AP4_Atom::Type AP4_ATOM_TYPE_AC_4 = AP4_ATOM_TYPE('a','c','-','4');
484561 const AP4_Atom::Type AP4_ATOM_TYPE_DTSC = AP4_ATOM_TYPE('d','t','s','c');
485562 const AP4_Atom::Type AP4_ATOM_TYPE_DTSH = AP4_ATOM_TYPE('d','t','s','h');
486563 const AP4_Atom::Type AP4_ATOM_TYPE_DTSL = AP4_ATOM_TYPE('d','t','s','l');
487564 const AP4_Atom::Type AP4_ATOM_TYPE_DTSE = AP4_ATOM_TYPE('d','t','s','e');
565 const AP4_Atom::Type AP4_ATOM_TYPE_FLAC = AP4_ATOM_TYPE('f','L','a','C');
566 const AP4_Atom::Type AP4_ATOM_TYPE_OPUS = AP4_ATOM_TYPE('O','p','u','s');
488567 const AP4_Atom::Type AP4_ATOM_TYPE_MFRA = AP4_ATOM_TYPE('m','f','r','a');
489568 const AP4_Atom::Type AP4_ATOM_TYPE_TFRA = AP4_ATOM_TYPE('t','f','r','a');
490569 const AP4_Atom::Type AP4_ATOM_TYPE_MFRO = AP4_ATOM_TYPE('m','f','r','o');
501580 const AP4_Atom::Type AP4_ATOM_TYPE_MKID = AP4_ATOM_TYPE('m','k','i','d');
502581 const AP4_Atom::Type AP4_ATOM_TYPE_PRFT = AP4_ATOM_TYPE('p','r','f','t');
503582 const AP4_Atom::Type AP4_ATOM_TYPE_STPP = AP4_ATOM_TYPE('s','t','p','p');
583 const AP4_Atom::Type AP4_ATOM_TYPE_DAC3 = AP4_ATOM_TYPE('d','a','c','3');
504584 const AP4_Atom::Type AP4_ATOM_TYPE_DEC3 = AP4_ATOM_TYPE('d','e','c','3');
505 const AP4_Atom::Type AP4_ATOM_TYPE_DAC3 = AP4_ATOM_TYPE('d','a','c','3');
585 const AP4_Atom::Type AP4_ATOM_TYPE_DAC4 = AP4_ATOM_TYPE('d','a','c','4');
506586 const AP4_Atom::Type AP4_ATOM_TYPE_SIDX = AP4_ATOM_TYPE('s','i','d','x');
507587 const AP4_Atom::Type AP4_ATOM_TYPE_SSIX = AP4_ATOM_TYPE('s','s','i','x');
508588 const AP4_Atom::Type AP4_ATOM_TYPE_SBGP = AP4_ATOM_TYPE('s','b','g','p');
509589 const AP4_Atom::Type AP4_ATOM_TYPE_SGPD = AP4_ATOM_TYPE('s','g','p','d');
510 const AP4_Atom::Type AP4_ATOM_TYPE_VPCC = AP4_ATOM_TYPE('v','p','c','C');
511590
512591 /*----------------------------------------------------------------------
513592 | AP4_AtomListInspector
8484 #include "Ap4GrpiAtom.h"
8585 #include "Ap4AvccAtom.h"
8686 #include "Ap4HvccAtom.h"
87 #include "Ap4DvccAtom.h"
88 #include "Ap4VpccAtom.h"
89 #include "Ap4Av1cAtom.h"
8790 #include "Ap4Marlin.h"
8891 #include "Ap48bdlAtom.h"
8992 #include "Ap4Piff.h"
98101 #include "Ap4BlocAtom.h"
99102 #include "Ap4AinfAtom.h"
100103 #include "Ap4PsshAtom.h"
104 #include "Ap4Dac3Atom.h"
101105 #include "Ap4Dec3Atom.h"
102 #include "Ap4Dac3Atom.h"
106 #include "Ap4Dac4Atom.h"
103107 #include "Ap4SidxAtom.h"
104108 #include "Ap4SbgpAtom.h"
105109 #include "Ap4SgpdAtom.h"
106 #include "Ap4TrafAtom.h"
107 #include "Ap4VpcCAtom.h"
108110
109111 /*----------------------------------------------------------------------
110112 | AP4_AtomFactory::~AP4_AtomFactory
197199 stream.GetSize(stream_size);
198200 if (stream_size >= start) {
199201 size = stream_size - start;
202
203 if (size <= 0xFFFFFFFF) {
204 size_32 = (AP4_UI32)size;
205 } else {
206 size_32 = 1; // signal a large atom
207 }
200208 }
201209 } else if (size == 1) {
202210 // 64-bit size
206214 return AP4_ERROR_INVALID_FORMAT;
207215 }
208216 stream.ReadUI64(size);
217 if (size < 16) {
218 stream.Seek(start);
219 return AP4_ERROR_INVALID_FORMAT;
220 }
209221 if (size <= 0xFFFFFFFF) {
210222 force_64 = true;
211223 }
262274 AP4_Atom*& atom)
263275 {
264276 bool atom_is_large = (size_32 == 1);
265 bool force_64 = (size_32==1 && ((size_64>>32) == 0));
277 bool force_64 = (size_32 == 1 && ((size_64 >> 32) == 0));
266278
267279 // create the atom
268280 if (GetContext() == AP4_ATOM_TYPE_STSD) {
301313 case AP4_ATOM_TYPE_AVC2:
302314 case AP4_ATOM_TYPE_AVC3:
303315 case AP4_ATOM_TYPE_AVC4:
316 case AP4_ATOM_TYPE_DVAV:
317 case AP4_ATOM_TYPE_DVA1:
304318 atom = new AP4_AvcSampleEntry(type, size_32, stream, *this);
305319 break;
306320
307321 case AP4_ATOM_TYPE_HEV1:
308322 case AP4_ATOM_TYPE_HVC1:
323 case AP4_ATOM_TYPE_DVHE:
324 case AP4_ATOM_TYPE_DVH1:
309325 atom = new AP4_HevcSampleEntry(type, size_32, stream, *this);
310326 break;
311327
328 case AP4_ATOM_TYPE_AV01:
329 atom = new AP4_Av1SampleEntry(type, size_32, stream, *this);
330 break;
331
332 case AP4_ATOM_TYPE_AC_3:
333 atom = new AP4_Ac3SampleEntry(type, size_32, stream, *this);
334 break;
335
336 case AP4_ATOM_TYPE_EC_3:
337 atom = new AP4_Eac3SampleEntry(type, size_32, stream, *this);
338 break;
339
340 case AP4_ATOM_TYPE_AC_4:
341 atom = new AP4_Ac4SampleEntry(type, size_32, stream, *this);
342 break;
343
312344 case AP4_ATOM_TYPE_ALAC:
313 case AP4_ATOM_TYPE_AC_3:
314 case AP4_ATOM_TYPE_EC_3:
315345 case AP4_ATOM_TYPE_DTSC:
316346 case AP4_ATOM_TYPE_DTSH:
317347 case AP4_ATOM_TYPE_DTSL:
318348 case AP4_ATOM_TYPE_DTSE:
349 case AP4_ATOM_TYPE_FLAC:
350 case AP4_ATOM_TYPE_OPUS:
319351 atom = new AP4_AudioSampleEntry(type, size_32, stream, *this);
320352 break;
321353
354 case AP4_ATOM_TYPE_VP08:
355 case AP4_ATOM_TYPE_VP09:
356 case AP4_ATOM_TYPE_VP10:
357 atom = new AP4_VisualSampleEntry(type, size_32, stream, *this);
358 break;
359
322360 case AP4_ATOM_TYPE_RTP_:
323361 atom = new AP4_RtpHintSampleEntry(size_32, stream, *this);
324362 break;
477515 case AP4_ATOM_TYPE_HVCC:
478516 if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
479517 atom = AP4_HvccAtom::Create(size_32, stream);
518 break;
519
520 case AP4_ATOM_TYPE_DVCC:
521 case AP4_ATOM_TYPE_DVVC:
522 if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
523 atom = AP4_DvccAtom::Create(size_32, stream);
524 break;
525
526 case AP4_ATOM_TYPE_VPCC:
527 if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
528 atom = AP4_VpccAtom::Create(size_32, stream);
529 break;
530
531 case AP4_ATOM_TYPE_AV1C:
532 if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
533 atom = AP4_Av1cAtom::Create(size_32, stream);
534 break;
535
536 case AP4_ATOM_TYPE_HVCE:
537 if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
538 atom = AP4_HvccAtom::Create(size_32, stream);
539 if (atom) {
540 atom->SetType(AP4_ATOM_TYPE_HVCE);
541 }
542 break;
543
544 case AP4_ATOM_TYPE_AVCE:
545 if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
546 atom = AP4_AvccAtom::Create(size_32, stream);
547 if (atom) {
548 atom->SetType(AP4_ATOM_TYPE_AVCE);
549 }
480550 break;
481551
482552 #if !defined(AP4_CONFIG_MINI_BUILD)
678748 atom = AP4_SgpdAtom::Create(size_32, stream);
679749 break;
680750
681 case AP4_ATOM_TYPE_VPCC:
682 if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
683 atom = AP4_VpcCAtom::Create(size_32, stream);
684 break;
685
686751 case AP4_ATOM_TYPE_MKID:
687752 if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
688753 if (GetContext() == AP4_ATOM_TYPE_MARL) {
692757
693758 case AP4_ATOM_TYPE_DAC3:
694759 if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
695 if (GetContext() == AP4_ATOM_TYPE_AC_3) {
696 atom = AP4_Dac3Atom::Create(size_32, stream);
760 if (GetContext() == AP4_ATOM_TYPE_AC_3 || GetContext() == AP4_ATOM_TYPE_ENCA) {
761 atom = AP4_Dac3Atom::Create(size_32, stream);
697762 }
698763 break;
699764
700765 case AP4_ATOM_TYPE_DEC3:
701766 if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
702 if (GetContext() == AP4_ATOM_TYPE_EC_3) {
767 if (GetContext() == AP4_ATOM_TYPE_EC_3 || GetContext() == AP4_ATOM_TYPE_ENCA) {
703768 atom = AP4_Dec3Atom::Create(size_32, stream);
704769 }
705770 break;
706771
707 case AP4_ATOM_TYPE_TRAF:
708 if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
709 atom = AP4_TrafAtom::Create(type, size_64, force_64, stream, *this);
710 break;
772 case AP4_ATOM_TYPE_DAC4:
773 if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
774 if (GetContext() == AP4_ATOM_TYPE_AC_4 || GetContext() == AP4_ATOM_TYPE_ENCA) {
775 atom = AP4_Dac4Atom::Create(size_32, stream);
776 }
777 break;
711778
712779 // track ref types
713780 case AP4_ATOM_TYPE_HINT:
729796 // container atoms
730797 case AP4_ATOM_TYPE_MOOF:
731798 case AP4_ATOM_TYPE_MVEX:
799 case AP4_ATOM_TYPE_TRAF:
732800 case AP4_ATOM_TYPE_TREF:
733801 case AP4_ATOM_TYPE_MFRA:
734802 case AP4_ATOM_TYPE_HNTI:
857925 /*----------------------------------------------------------------------
858926 | AP4_DefaultAtomFactory::Instance
859927 +---------------------------------------------------------------------*/
860 AP4_DefaultAtomFactory AP4_DefaultAtomFactory::Instance;
928 AP4_DefaultAtomFactory AP4_DefaultAtomFactory::Instance_;
861929
862930 /*----------------------------------------------------------------------
863931 | AP4_DefaultAtomFactory::Instance
9898 class AP4_DefaultAtomFactory : public AP4_AtomFactory {
9999 public:
100100 // class members
101 static AP4_DefaultAtomFactory Instance;
101 static AP4_DefaultAtomFactory Instance_;
102102
103103 // constructor
104104 AP4_DefaultAtomFactory();
8686 {
8787 AP4_Result result;
8888
89 // check that we have an stsc atom
90 if (!m_StscAtom) {
91 return AP4_ERROR_INVALID_FORMAT;
92 }
93
8994 // check that we have a chunk offset table
9095 if (m_StcoAtom == NULL && m_Co64Atom == NULL) {
9196 return AP4_ERROR_INVALID_FORMAT;
134139 AP4_UI32 cts_offset = 0;
135140 AP4_UI64 dts = 0;
136141 AP4_UI32 duration = 0;
137 result = m_SttsAtom->GetDts(index, dts, &duration);
138 if (AP4_FAILED(result)) return result;
142 if (m_SttsAtom) {
143 result = m_SttsAtom->GetDts(index, dts, &duration);
144 if (AP4_FAILED(result)) return result;
145 }
139146 sample.SetDuration(duration);
140147 sample.SetDts(dts);
141148 if (m_CttsAtom == NULL) {
0 /*****************************************************************
1 |
2 | AP4 - avcC Atoms
3 |
4 | Copyright 2002-2008 Axiomatic Systems, LLC
5 |
6 |
7 | This file is part of Bento4/AP4 (MP4 Atom Processing Library).
8 |
9 | Unless you have obtained Bento4 under a difference license,
10 | this version of Bento4 is Bento4|GPL.
11 | Bento4|GPL is free software; you can redistribute it and/or modify
12 | it under the terms of the GNU General Public License as published by
13 | the Free Software Foundation; either version 2, or (at your option)
14 | any later version.
15 |
16 | Bento4|GPL is distributed in the hope that it will be useful,
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | GNU General Public License for more details.
20 |
21 | You should have received a copy of the GNU General Public License
22 | along with Bento4|GPL; see the file COPYING. If not, write to the
23 | Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
24 | 02111-1307, USA.
25 |
26 ****************************************************************/
27
28 /*----------------------------------------------------------------------
29 | includes
30 +---------------------------------------------------------------------*/
31 #include "Ap4Av1cAtom.h"
32 #include "Ap4AtomFactory.h"
33 #include "Ap4Utils.h"
34 #include "Ap4Types.h"
35
36 /*----------------------------------------------------------------------
37 | dynamic cast support
38 +---------------------------------------------------------------------*/
39 AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_Av1cAtom)
40
41 /*----------------------------------------------------------------------
42 | AP4_Av1cAtom::GetProfileName
43 +---------------------------------------------------------------------*/
44 const char*
45 AP4_Av1cAtom::GetProfileName(AP4_UI08 profile)
46 {
47 switch (profile) {
48 case AP4_AV1_PROFILE_MAIN: return "Main";
49 case AP4_AV1_PROFILE_HIGH: return "High";
50 case AP4_AV1_PROFILE_PROFESSIONAL: return "Professional";
51 default: return NULL;
52 }
53 }
54
55 /*----------------------------------------------------------------------
56 | AP4_Av1cAtom::Create
57 +---------------------------------------------------------------------*/
58 AP4_Av1cAtom*
59 AP4_Av1cAtom::Create(AP4_Size size, AP4_ByteStream& stream)
60 {
61 unsigned int payload_size = size-AP4_ATOM_HEADER_SIZE;
62 if (payload_size < 4) {
63 return NULL;
64 }
65 AP4_UI08 bits[4];
66 AP4_Result result = stream.Read(bits, 4);
67 if (AP4_FAILED(result)) {
68 return NULL;
69 }
70 AP4_UI08 version = bits[0] & 0x7F;
71 AP4_UI08 seq_profile = bits[1] >> 5;
72 AP4_UI08 seq_level_idx_0 = bits[1] & 0x1F;
73 AP4_UI08 seq_tier_0 = (bits[2] >> 7) & 1;
74 AP4_UI08 high_bitdepth = (bits[2] >> 6) & 1;
75 AP4_UI08 twelve_bit = (bits[2] >> 5) & 1;
76 AP4_UI08 monochrome = (bits[2] >> 4) & 1;
77 AP4_UI08 chroma_subsampling_x = (bits[2] >> 3) & 1;
78 AP4_UI08 chroma_subsampling_y = (bits[2] >> 2) & 1;
79 AP4_UI08 chroma_sample_position = (bits[2] ) & 3;
80 AP4_UI08 initial_presentation_delay_present = (bits[3] >> 4) & 1;
81 AP4_UI08 initial_presentation_delay_minus_one;
82 if (initial_presentation_delay_present) {
83 initial_presentation_delay_minus_one = (bits[3] >> 4) & 0x0F;
84 } else {
85 initial_presentation_delay_minus_one = 0;
86 }
87
88 AP4_DataBuffer config_obus;
89 if (payload_size > 4) {
90 config_obus.SetDataSize(payload_size - 4);
91 result = stream.Read(config_obus.UseData(), payload_size - 4);
92 if (AP4_FAILED(result)) {
93 return NULL;
94 }
95 }
96 return new AP4_Av1cAtom(version,
97 seq_profile,
98 seq_level_idx_0,
99 seq_tier_0,
100 high_bitdepth,
101 twelve_bit,
102 monochrome,
103 chroma_subsampling_x,
104 chroma_subsampling_y,
105 chroma_sample_position,
106 initial_presentation_delay_present,
107 initial_presentation_delay_minus_one,
108 config_obus.GetData(),
109 config_obus.GetDataSize());
110 }
111
112 /*----------------------------------------------------------------------
113 | AP4_Av1cAtom::AP4_Av1cAtom
114 +---------------------------------------------------------------------*/
115 AP4_Av1cAtom::AP4_Av1cAtom() :
116 AP4_Atom(AP4_ATOM_TYPE_AV1C, AP4_ATOM_HEADER_SIZE),
117 m_Version(1),
118 m_SeqProfile(0),
119 m_SeqLevelIdx0(0),
120 m_SeqTier0(0),
121 m_HighBitDepth(0),
122 m_TwelveBit(0),
123 m_Monochrome(0),
124 m_ChromaSubsamplingX(0),
125 m_ChromaSubsamplingY(0),
126 m_ChromaSamplePosition(0),
127 m_InitialPresentationDelayPresent(0),
128 m_InitialPresentationDelayMinusOne(0)
129 {
130 m_Size32 += 4;
131 }
132
133 /*----------------------------------------------------------------------
134 | AP4_Av1cAtom::AP4_Av1cAtom
135 +---------------------------------------------------------------------*/
136 AP4_Av1cAtom::AP4_Av1cAtom(AP4_UI08 version,
137 AP4_UI08 seq_profile,
138 AP4_UI08 seq_level_idx_0,
139 AP4_UI08 seq_tier_0,
140 AP4_UI08 high_bitdepth,
141 AP4_UI08 twelve_bit,
142 AP4_UI08 monochrome,
143 AP4_UI08 chroma_subsampling_x,
144 AP4_UI08 chroma_subsampling_y,
145 AP4_UI08 chroma_sample_position,
146 AP4_UI08 initial_presentation_delay_present,
147 AP4_UI08 initial_presentation_delay_minus_one,
148 const AP4_UI08* config_obus,
149 AP4_Size config_obus_size) :
150 AP4_Atom(AP4_ATOM_TYPE_AV1C, AP4_ATOM_HEADER_SIZE),
151 m_Version(version),
152 m_SeqProfile(seq_profile),
153 m_SeqLevelIdx0(seq_level_idx_0),
154 m_SeqTier0(seq_tier_0),
155 m_HighBitDepth(high_bitdepth),
156 m_TwelveBit(twelve_bit),
157 m_Monochrome(monochrome),
158 m_ChromaSubsamplingX(chroma_subsampling_x),
159 m_ChromaSubsamplingY(chroma_subsampling_y),
160 m_ChromaSamplePosition(chroma_sample_position),
161 m_InitialPresentationDelayPresent(initial_presentation_delay_present),
162 m_InitialPresentationDelayMinusOne(initial_presentation_delay_minus_one)
163 {
164 m_Size32 += 4 + config_obus_size;
165 if (config_obus && config_obus_size) {
166 m_ConfigObus.SetData(config_obus, config_obus_size);
167 }
168 }
169
170 /*----------------------------------------------------------------------
171 | AP4_Av1cAtom::WriteFields
172 +---------------------------------------------------------------------*/
173 AP4_Result
174 AP4_Av1cAtom::WriteFields(AP4_ByteStream& stream)
175 {
176 AP4_UI08 bits[4];
177 bits[0] = (1 << 7) | m_Version;
178 bits[1] = (m_SeqProfile << 5) | m_SeqLevelIdx0;
179 bits[2] = (m_SeqTier0 << 7) |
180 (m_HighBitDepth << 6) |
181 (m_TwelveBit << 5) |
182 (m_Monochrome << 4) |
183 (m_ChromaSubsamplingX << 3) |
184 (m_ChromaSubsamplingY << 2) |
185 (m_ChromaSamplePosition );
186 bits[3] = (m_InitialPresentationDelayPresent << 4) | m_InitialPresentationDelayMinusOne;
187 AP4_Result result = stream.Write(bits, 4);
188 if (AP4_FAILED(result)) return result;
189 if (m_ConfigObus.GetDataSize()) {
190 result = stream.Write(m_ConfigObus.GetData(), m_ConfigObus.GetDataSize());
191 if (AP4_FAILED(result)) return result;
192 }
193
194 return AP4_SUCCESS;
195 }
196
197 /*----------------------------------------------------------------------
198 | AP4_Av1cAtom::InspectFields
199 +---------------------------------------------------------------------*/
200 AP4_Result
201 AP4_Av1cAtom::InspectFields(AP4_AtomInspector& inspector)
202 {
203 inspector.AddField("version", m_Version);
204 inspector.AddField("seq_profile", m_SeqProfile);
205 inspector.AddField("seq_level_idx_0", m_SeqLevelIdx0);
206 inspector.AddField("seq_tier_0", m_SeqTier0);
207 inspector.AddField("high_bitdepth", m_HighBitDepth);
208 inspector.AddField("twelve_bit", m_TwelveBit);
209 inspector.AddField("monochrome", m_Monochrome);
210 inspector.AddField("chroma_subsampling_x", m_ChromaSubsamplingX);
211 inspector.AddField("chroma_subsampling_y", m_ChromaSubsamplingY);
212 inspector.AddField("chroma_sample_position", m_ChromaSamplePosition);
213 inspector.AddField("initial_presentation_delay", m_InitialPresentationDelayPresent ? m_InitialPresentationDelayMinusOne + 1 : 0);
214 return AP4_SUCCESS;
215 }
0 /*****************************************************************
1 |
2 | AP4 - av1C Atoms
3 |
4 | Copyright 2002-2008 Axiomatic Systems, LLC
5 |
6 |
7 | This file is part of Bento4/AP4 (MP4 Atom Processing Library).
8 |
9 | Unless you have obtained Bento4 under a difference license,
10 | this version of Bento4 is Bento4|GPL.
11 | Bento4|GPL is free software; you can redistribute it and/or modify
12 | it under the terms of the GNU General Public License as published by
13 | the Free Software Foundation; either version 2, or (at your option)
14 | any later version.
15 |
16 | Bento4|GPL is distributed in the hope that it will be useful,
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | GNU General Public License for more details.
20 |
21 | You should have received a copy of the GNU General Public License
22 | along with Bento4|GPL; see the file COPYING. If not, write to the
23 | Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
24 | 02111-1307, USA.
25 |
26 ****************************************************************/
27
28 #ifndef _AP4_AV1C_ATOM_H_
29 #define _AP4_AV1C_ATOM_H_
30
31 /*----------------------------------------------------------------------
32 | includes
33 +---------------------------------------------------------------------*/
34 #include "Ap4Atom.h"
35 #include "Ap4Array.h"
36
37 /*----------------------------------------------------------------------
38 | constants
39 +---------------------------------------------------------------------*/
40 const AP4_UI08 AP4_AV1_PROFILE_MAIN = 0;
41 const AP4_UI08 AP4_AV1_PROFILE_HIGH = 1;
42 const AP4_UI08 AP4_AV1_PROFILE_PROFESSIONAL = 2;
43
44 /*----------------------------------------------------------------------
45 | AP4_Av1cAtom
46 +---------------------------------------------------------------------*/
47 class AP4_Av1cAtom : public AP4_Atom
48 {
49 public:
50 AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_Av1cAtom, AP4_Atom)
51
52 // class methods
53 static AP4_Av1cAtom* Create(AP4_Size size, AP4_ByteStream& stream);
54 static const char* GetProfileName(AP4_UI08 profile);
55
56 // constructors
57 AP4_Av1cAtom(AP4_UI08 version,
58 AP4_UI08 seq_profile,
59 AP4_UI08 seq_level_idx_0,
60 AP4_UI08 seq_tier_0,
61 AP4_UI08 high_bitdepth,
62 AP4_UI08 twelve_bit,
63 AP4_UI08 monochrome,
64 AP4_UI08 chroma_subsampling_x,
65 AP4_UI08 chroma_subsampling_y,
66 AP4_UI08 chroma_sample_position,
67 AP4_UI08 initial_presentation_delay_present,
68 AP4_UI08 initial_presentation_delay_minus_one,
69 const AP4_UI08* config_obus,
70 AP4_Size config_obus_size);
71 AP4_Av1cAtom();
72
73 // methods
74 virtual AP4_Result InspectFields(AP4_AtomInspector& inspector);
75 virtual AP4_Result WriteFields(AP4_ByteStream& stream);
76
77 // accessors
78 AP4_UI08 GetSeqProfile() const { return m_SeqProfile; }
79 AP4_UI08 GetSeqLevelIdx0() const { return m_SeqLevelIdx0; }
80 AP4_UI08 GetSeqTier0() const { return m_SeqTier0; }
81 AP4_UI08 GetHighBitDepth() const { return m_HighBitDepth; }
82 AP4_UI08 GetTwelveBit() const { return m_TwelveBit; }
83 AP4_UI08 GetMonochrome() const { return m_Monochrome; }
84 AP4_UI08 GetChromaSubsamplingX() const { return m_ChromaSubsamplingX; }
85 AP4_UI08 GetChromaSubsamplingY() const { return m_ChromaSubsamplingY; }
86 AP4_UI08 GetChromaSamplePosition() const { return m_ChromaSamplePosition; }
87 AP4_UI08 GetInitialPresentationDelayPresent() const { return m_InitialPresentationDelayPresent; }
88 AP4_UI08 GetInitialPresentationDelayMinusOne() const { return m_InitialPresentationDelayMinusOne; }
89 const AP4_DataBuffer& GetConfigObus() const { return m_ConfigObus; }
90
91 private:
92 // methods
93 AP4_Av1cAtom(AP4_UI32 size, const AP4_UI08* payload);
94
95 // members
96 AP4_UI08 m_Version;
97 AP4_UI08 m_SeqProfile;
98 AP4_UI08 m_SeqLevelIdx0;
99 AP4_UI08 m_SeqTier0;
100 AP4_UI08 m_HighBitDepth;
101 AP4_UI08 m_TwelveBit;
102 AP4_UI08 m_Monochrome;
103 AP4_UI08 m_ChromaSubsamplingX;
104 AP4_UI08 m_ChromaSubsamplingY;
105 AP4_UI08 m_ChromaSamplePosition;
106 AP4_UI08 m_InitialPresentationDelayPresent;
107 AP4_UI08 m_InitialPresentationDelayMinusOne;
108 AP4_DataBuffer m_ConfigObus;
109 };
110
111 #endif // _AP4_AV1C_ATOM_H_
8484 cursor += 2+AP4_BytesToInt16BE(&payload[cursor]);
8585 if (cursor > payload_size) return NULL;
8686 }
87 if (cursor+1 > payload_size) return NULL;
8788 unsigned int num_pic_params = payload[cursor++];
88 if (cursor > payload_size) return NULL;
8989 for (unsigned int i=0; i<num_pic_params; i++) {
9090 if (cursor+2 > payload_size) return NULL;
9191 cursor += 2+AP4_BytesToInt16BE(&payload[cursor]);
103103 m_Profile(0),
104104 m_Level(0),
105105 m_ProfileCompatibility(0),
106 m_NaluLengthSize(0)
106 m_NaluLengthSize(0),
107 m_ChromaFormat(0),
108 m_BitDepthLumaMinus8(0),
109 m_BitDepthChromaMinus8(0)
107110 {
108111 UpdateRawBytes();
109112 m_Size32 += m_RawBytes.GetDataSize();
151154 m_SequenceParameters.EnsureCapacity(num_seq_params);
152155 unsigned int cursor = 6;
153156 for (unsigned int i=0; i<num_seq_params; i++) {
154 m_SequenceParameters.Append(AP4_DataBuffer());
155 AP4_UI16 param_length = AP4_BytesToInt16BE(&payload[cursor]);
156 m_SequenceParameters[i].SetData(&payload[cursor]+2, param_length);
157 cursor += 2+param_length;
157 if (cursor+2 <= payload_size) {
158 AP4_UI16 param_length = AP4_BytesToInt16BE(&payload[cursor]);
159 cursor += 2;
160 if (cursor + param_length <= payload_size) {
161 m_SequenceParameters.Append(AP4_DataBuffer());
162 m_SequenceParameters[i].SetData(&payload[cursor], param_length);
163 cursor += param_length;
164 }
165 }
158166 }
159167 AP4_UI08 num_pic_params = payload[cursor++];
160168 m_PictureParameters.EnsureCapacity(num_pic_params);
161169 for (unsigned int i=0; i<num_pic_params; i++) {
162 m_PictureParameters.Append(AP4_DataBuffer());
163 AP4_UI16 param_length = AP4_BytesToInt16BE(&payload[cursor]);
164 m_PictureParameters[i].SetData(&payload[cursor]+2, param_length);
165 cursor += 2+param_length;
170 if (cursor+2 <= payload_size) {
171 AP4_UI16 param_length = AP4_BytesToInt16BE(&payload[cursor]);
172 cursor += 2;
173 if (cursor + param_length <= payload_size) {
174 m_PictureParameters.Append(AP4_DataBuffer());
175 m_PictureParameters[i].SetData(&payload[cursor], param_length);
176 cursor += param_length;
177 }
178 }
166179 }
167180 }
168181
173186 AP4_AvccAtom::AP4_AvccAtom(AP4_UI08 profile,
174187 AP4_UI08 level,
175188 AP4_UI08 profile_compatibility,
176 AP4_UI08 length_size,
189 AP4_UI08 length_size,
190 AP4_UI08 chroma_format,
191 AP4_UI08 bit_depth_luma_minus8,
192 AP4_UI08 bit_depth_chroma_minus8,
177193 const AP4_Array<AP4_DataBuffer>& sequence_parameters,
178194 const AP4_Array<AP4_DataBuffer>& picture_parameters) :
179195 AP4_Atom(AP4_ATOM_TYPE_AVCC, AP4_ATOM_HEADER_SIZE),
181197 m_Profile(profile),
182198 m_Level(level),
183199 m_ProfileCompatibility(profile_compatibility),
184 m_NaluLengthSize(length_size)
200 m_NaluLengthSize(length_size),
201 m_ChromaFormat(chroma_format),
202 m_BitDepthLumaMinus8(bit_depth_luma_minus8),
203 m_BitDepthChromaMinus8(bit_depth_chroma_minus8)
185204 {
186205 // deep copy of the parameters
187206 unsigned int i = 0;
214233 for (unsigned int i=0; i<m_PictureParameters.ItemCount(); i++) {
215234 payload_size += 2+m_PictureParameters[i].GetDataSize();
216235 }
236
237 if ((m_Profile == AP4_AVC_PROFILE_HIGH) || (m_Profile == AP4_AVC_PROFILE_HIGH_10) ||
238 (m_Profile == AP4_AVC_PROFILE_HIGH_422) || (m_Profile == AP4_AVC_PROFILE_HIGH_444)) {
239 payload_size += 4;
240 }
241
217242 m_RawBytes.SetDataSize(payload_size);
218243 AP4_UI08* payload = m_RawBytes.UseData();
219244
239264 AP4_CopyMemory(&payload[cursor], m_PictureParameters[i].GetData(), param_length);
240265 cursor += param_length;
241266 }
267 if ((m_Profile == AP4_AVC_PROFILE_HIGH) || (m_Profile == AP4_AVC_PROFILE_HIGH_10) ||
268 (m_Profile == AP4_AVC_PROFILE_HIGH_422) || (m_Profile == AP4_AVC_PROFILE_HIGH_444)) {
269 payload[cursor++] = 0xfc | (0x03 & m_ChromaFormat);
270 payload[cursor++] = 0xf8 | (0x07 & m_BitDepthLumaMinus8);
271 payload[cursor++] = 0xf8 | (0x07 & m_BitDepthChromaMinus8);
272 payload[cursor] = 0;
273 }
242274 }
243275
244276 /*----------------------------------------------------------------------
269301 for (unsigned int i=0; i<m_SequenceParameters.ItemCount(); i++) {
270302 inspector.AddField("Sequence Parameter", m_SequenceParameters[i].GetData(), m_SequenceParameters[i].GetDataSize());
271303 }
272 for (unsigned int i=0; i<m_SequenceParameters.ItemCount(); i++) {
304 for (unsigned int i=0; i<m_PictureParameters.ItemCount(); i++) {
273305 inspector.AddField("Picture Parameter", m_PictureParameters[i].GetData(), m_PictureParameters[i].GetDataSize());
274306 }
275307 return AP4_SUCCESS;
6464 AP4_UI08 level,
6565 AP4_UI08 profile_compatibility,
6666 AP4_UI08 length_size,
67 AP4_UI08 chroma_format,
68 AP4_UI08 bit_depth_luma_minus8,
69 AP4_UI08 bit_depth_chroma_minus8,
6770 const AP4_Array<AP4_DataBuffer>& sequence_parameters,
6871 const AP4_Array<AP4_DataBuffer>& picture_parameters);
6972 AP4_AvccAtom(const AP4_AvccAtom& other); // copy construtor
8184 AP4_Array<AP4_DataBuffer>& GetSequenceParameters() { return m_SequenceParameters; }
8285 AP4_Array<AP4_DataBuffer>& GetPictureParameters() { return m_PictureParameters; }
8386 const AP4_DataBuffer& GetRawBytes() const { return m_RawBytes; }
87 AP4_UI08 GetChromaFormat() const { return m_ChromaFormat; }
88 AP4_UI08 GetBitDepthLumaMinus8() const { return m_BitDepthLumaMinus8; }
89 AP4_UI08 GetBitDepthChromaMinus8() const { return m_BitDepthChromaMinus8; }
8490
8591 private:
8692 // methods
9399 AP4_UI08 m_Level;
94100 AP4_UI08 m_ProfileCompatibility;
95101 AP4_UI08 m_NaluLengthSize;
102 AP4_UI08 m_ChromaFormat;
103 AP4_UI08 m_BitDepthLumaMinus8;
104 AP4_UI08 m_BitDepthChromaMinus8;
96105 AP4_Array<AP4_DataBuffer> m_SequenceParameters;
97106 AP4_Array<AP4_DataBuffer> m_PictureParameters;
98107 AP4_DataBuffer m_RawBytes;
4545 {
4646 AP4_UI08 version;
4747 AP4_UI32 flags;
48 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4849 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4950 if (version > 1) return NULL;
5051 return new AP4_BlocAtom(size, version, flags, stream);
3737 | constants
3838 +---------------------------------------------------------------------*/
3939 const int AP4_BYTE_STREAM_COPY_BUFFER_SIZE = 65536;
40 const int AP4_MEMORY_BYTE_STREAM_MAX_SIZE = 0x4000000; // 64 megs
4140
4241 /*----------------------------------------------------------------------
4342 | AP4_ByteStream::Read
363362 ++size;
364363 } while (c);
365364
366 string.Assign((const char*)buffer.GetData(), size);
365 AP4_ASSERT(size);
366 string.Assign((const char*)buffer.GetData(), size - 1);
367
367368 return AP4_SUCCESS;
368369 }
369370
756757 // shortcut
757758 if (bytes_to_write == 0) {
758759 return AP4_SUCCESS;
759 }
760
761 // check that we don't exceed the max
762 if (m_Position+bytes_to_write > (AP4_Position)AP4_MEMORY_BYTE_STREAM_MAX_SIZE) {
763 return AP4_ERROR_OUT_OF_RANGE;
764760 }
765761
766762 // reserve space in the buffer
4040 | class references
4141 +---------------------------------------------------------------------*/
4242 class AP4_String;
43 class AP4_ByteStream;
44
45 class AP4_ByteStreamObserver
46 {
47 public:
48 virtual AP4_Result OnFlush(AP4_ByteStream *stream) = 0;
49 };
5043
5144 /*----------------------------------------------------------------------
5245 | AP4_ByteStream
5447 class AP4_ByteStream : public AP4_Referenceable
5548 {
5649 public:
57 AP4_ByteStream() :observer_(0){};
58 void SetObserver(AP4_ByteStreamObserver *observer){ observer_ = observer; };
59 AP4_ByteStreamObserver *GetObserver(){ return observer_; };
60 // methods
50 // methods
6151 virtual AP4_Result ReadPartial(void* buffer,
6252 AP4_Size bytes_to_read,
6353 AP4_Size& bytes_read) = 0;
8575 virtual AP4_Result Tell(AP4_Position& position) = 0;
8676 virtual AP4_Result GetSize(AP4_LargeSize& size) = 0;
8777 virtual AP4_Result CopyTo(AP4_ByteStream& stream, AP4_LargeSize size);
88 virtual AP4_Result Buffer() { return AP4_SUCCESS; }
89 virtual AP4_Result Flush() { return AP4_SUCCESS; }
90 private:
91 AP4_ByteStreamObserver *observer_;
78 virtual AP4_Result Flush() { return AP4_SUCCESS; }
9279 };
9380
9481 /*----------------------------------------------------------------------
207194 AP4_UI08* UseData() { return m_Buffer->UseData(); }
208195 AP4_Size GetDataSize() { return m_Buffer->GetDataSize(); }
209196
210 //protected:
211197 virtual ~AP4_MemoryByteStream();
212198
213199 private:
4545 {
4646 AP4_UI08 version;
4747 AP4_UI32 flags;
48 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4849 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4950 if (version != 0) return NULL;
5051 return new AP4_Co64Atom(size, version, flags, stream);
166167 {
167168 inspector.AddField("entry_count", m_EntryCount);
168169 if (inspector.GetVerbosity() >= 1) {
169 char header[32];
170 inspector.StartArray("entries", m_EntryCount);
170171 for (AP4_Ordinal i=0; i<m_EntryCount; i++) {
171 AP4_FormatString(header, sizeof(header), "entry %8d", i);
172 inspector.AddField(header, m_Entries[i]);
172 inspector.AddField(NULL, m_Entries[i]);
173173 }
174 inspector.EndArray();
174175 }
175176
176177 return AP4_SUCCESS;
6363 const unsigned int AP4_CENC_NAL_UNIT_ENCRYPTION_MIN_SIZE = 112;
6464
6565 /*----------------------------------------------------------------------
66 | AP4_CencSampleEncrypter::~AP4_CencSampleEncrypter
67 +---------------------------------------------------------------------*/
68 AP4_CencSampleEncrypter::~AP4_CencSampleEncrypter()
69 {
70 delete m_Cipher;
71 }
72
73 /*----------------------------------------------------------------------
74 | AP4_CencCtrSampleEncrypter::EncryptSampleData
66 | AP4_CencSubSampleMapAppend
67 +---------------------------------------------------------------------*/
68 static void
69 AP4_CencSubSampleMapAppendEntry(AP4_Array<AP4_UI16>& bytes_of_cleartext_data,
70 AP4_Array<AP4_UI32>& bytes_of_encrypted_data,
71 unsigned int cleartext_size,
72 unsigned int encrypted_size)
73 {
74 // if there's already an entry, attempt to extend the last entry
75 if (bytes_of_cleartext_data.ItemCount() > 0) {
76 AP4_Cardinal last_index = bytes_of_cleartext_data.ItemCount() - 1;
77 if (bytes_of_encrypted_data[last_index] == 0) {
78 cleartext_size += bytes_of_cleartext_data[last_index];
79 bytes_of_cleartext_data.RemoveLast();
80 bytes_of_encrypted_data.RemoveLast();
81 }
82 }
83
84 // append chunks of cleartext size taking into account that the cleartext_size field is only 16 bits
85 while (cleartext_size > 0xFFFF) {
86 bytes_of_cleartext_data.Append(0xFFFF);
87 bytes_of_encrypted_data.Append(0);
88 cleartext_size -= 0xFFFF;
89 }
90
91 // append whatever is left
92 bytes_of_cleartext_data.Append(cleartext_size);
93 bytes_of_encrypted_data.Append(encrypted_size);
94 }
95
96 /*----------------------------------------------------------------------
97 | AP4_CencBasicSubSampleMapper::GetSubSampleMap
7598 +---------------------------------------------------------------------*/
7699 AP4_Result
77 AP4_CencCtrSampleEncrypter::EncryptSampleData(AP4_DataBuffer& data_in,
78 AP4_DataBuffer& data_out,
79 AP4_DataBuffer& /* sample_infos */)
80 {
81 // the output has the same size as the input
82 data_out.SetDataSize(data_in.GetDataSize());
83
84 // setup direct pointers to the buffers
85 const AP4_UI08* in = data_in.GetData();
86 AP4_UI08* out = data_out.UseData();
87
88 // setup the IV
89 m_Cipher->SetIV(m_Iv);
90
91 // process the sample data
92 if (data_in.GetDataSize()) {
93 AP4_Size out_size = data_out.GetDataSize();
94 AP4_Result result = m_Cipher->ProcessBuffer(in, data_in.GetDataSize(), out, &out_size, false);
95 if (AP4_FAILED(result)) return result;
96 }
97
98 // update the IV
99 if (m_IvSize == 16) {
100 unsigned int block_count = (data_in.GetDataSize()+15)/16;
101 AP4_UI64 counter = AP4_BytesToUInt64BE(&m_Iv[8]);
102 AP4_BytesFromUInt64BE(&m_Iv[8], counter+block_count);
103 } else if (m_IvSize == 8){
104 AP4_UI64 counter = AP4_BytesToUInt64BE(&m_Iv[0]);
105 AP4_BytesFromUInt64BE(&m_Iv[0], counter+1);
106 } else {
107 return AP4_ERROR_INTERNAL;
108 }
109
110 return AP4_SUCCESS;
111 }
112
113 /*----------------------------------------------------------------------
114 | AP4_CencCtrSubSampleEncrypter::GetSubSampleMap
115 +---------------------------------------------------------------------*/
116 AP4_Result
117 AP4_CencCtrSubSampleEncrypter::GetSubSampleMap(AP4_DataBuffer& sample_data,
118 AP4_Array<AP4_UI16>& bytes_of_cleartext_data,
119 AP4_Array<AP4_UI32>& bytes_of_encrypted_data)
100 AP4_CencBasicSubSampleMapper::GetSubSampleMap(AP4_DataBuffer& sample_data,
101 AP4_Array<AP4_UI16>& bytes_of_cleartext_data,
102 AP4_Array<AP4_UI32>& bytes_of_encrypted_data)
120103 {
121104 // setup direct pointers to the buffers
122105 const AP4_UI08* in = sample_data.GetData();
142125 return AP4_ERROR_INVALID_FORMAT;
143126 }
144127
145 unsigned int nalu_size = m_NaluLengthSize+nalu_length;
146 if (in+nalu_size > in_end) {
147 return AP4_ERROR_INVALID_FORMAT;
148 }
149
150 // skip encryption if the NAL unit is smaller than the threshold (DECE CFF spec)
151 // or should be left unencrypted for this specific format/type
152 bool skip = false;
153 if (nalu_size < AP4_CENC_NAL_UNIT_ENCRYPTION_MIN_SIZE) {
154 skip = true;
155 } else if (m_Format == AP4_SAMPLE_FORMAT_AVC1 ||
156 m_Format == AP4_SAMPLE_FORMAT_AVC2 ||
157 m_Format == AP4_SAMPLE_FORMAT_AVC3 ||
158 m_Format == AP4_SAMPLE_FORMAT_AVC4) {
159 unsigned int nalu_type = in[m_NaluLengthSize] & 0x1F;
160 if (nalu_type != AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_OF_NON_IDR_PICTURE &&
161 nalu_type != AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_A &&
162 nalu_type != AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_B &&
163 nalu_type != AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_C &&
164 nalu_type != AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_OF_IDR_PICTURE) {
165 // this NAL unit is not a VCL NAL unit
166 skip = true;
167 }
168 } else if (m_Format == AP4_SAMPLE_FORMAT_HEV1 ||
169 m_Format == AP4_SAMPLE_FORMAT_HVC1) {
170 unsigned int nalu_type = (in[m_NaluLengthSize] >> 1) & 0x3F;
171 if (nalu_type >= 32) {
172 // this NAL unit is not a VCL NAL unit
173 skip = true;
174 }
175 }
176
177 if (skip) {
178 // use cleartext regions to cover the entire NAL unit
179 unsigned int range = nalu_size;
180 while (range) {
181 AP4_UI16 cleartext_size = (range <= 0xFFFF) ? static_cast<AP4_UI16>(range) : 0xFFFF;
182 bytes_of_cleartext_data.Append(cleartext_size);
183 bytes_of_encrypted_data.Append(0);
184 range -= cleartext_size;
185 }
186 } else {
187 // leave some cleartext bytes at the start and encrypt the rest (multiple of blocks)
188 unsigned int encrypted_size = nalu_size-(AP4_CENC_NAL_UNIT_ENCRYPTION_MIN_SIZE-16);
189 encrypted_size -= (encrypted_size % 16);
190 unsigned int cleartext_size = nalu_size-encrypted_size;
191 AP4_ASSERT(encrypted_size >= 16);
192 AP4_ASSERT(cleartext_size >= m_NaluLengthSize);
193 bytes_of_cleartext_data.Append(static_cast<AP4_UI16>(cleartext_size));
194 bytes_of_encrypted_data.Append(encrypted_size);
128 unsigned int chunk_size = m_NaluLengthSize+nalu_length;
129 unsigned int cleartext_size = chunk_size%16;
130 unsigned int block_count = chunk_size/16;
131 if (cleartext_size < m_NaluLengthSize+1) {
132 AP4_ASSERT(block_count);
133 --block_count;
134 cleartext_size += 16;
195135 }
196136
197137 // move the pointers
198 in += nalu_size;
199 }
200
201 return AP4_SUCCESS;
202 }
203
204 /*----------------------------------------------------------------------
205 | AP4_CencCtrSubSampleEncrypter::EncryptSampleData
138 in += chunk_size;
139
140 // store the info
141 bytes_of_cleartext_data.Append((AP4_UI16)cleartext_size);
142 bytes_of_encrypted_data.Append((AP4_UI32)(block_count*16));
143 }
144
145 return AP4_SUCCESS;
146 }
147
148 /*----------------------------------------------------------------------
149 | AP4_CencAdvancedSubSampleEncrypter::GetSubSampleMap
206150 +---------------------------------------------------------------------*/
207151 AP4_Result
208 AP4_CencCtrSubSampleEncrypter::EncryptSampleData(AP4_DataBuffer& data_in,
209 AP4_DataBuffer& data_out,
210 AP4_DataBuffer& sample_infos)
211 {
212 // the output has the same size as the input
213 data_out.SetDataSize(data_in.GetDataSize());
214
215 // check some basics
216 if (data_in.GetDataSize() == 0) return AP4_SUCCESS;
217
218 // setup direct pointers to the buffers
219 const AP4_UI08* in = data_in.GetData();
220 AP4_UI08* out = data_out.UseData();
221
222 // setup the IV
223 unsigned int total_encrypted = 0;
224 m_Cipher->SetIV(m_Iv);
225
226 // get the subsample map
227 AP4_Array<AP4_UI16> bytes_of_cleartext_data;
228 AP4_Array<AP4_UI32> bytes_of_encrypted_data;
229 AP4_Result result = GetSubSampleMap(data_in, bytes_of_cleartext_data, bytes_of_encrypted_data);
230 if (AP4_FAILED(result)) return result;
231
232 // process the data
233 for (unsigned int i=0; i<bytes_of_cleartext_data.ItemCount(); i++) {
234 // copy the cleartext portion
235 AP4_CopyMemory(out, in, bytes_of_cleartext_data[i]);
236
237 // encrypt the rest
238 if (bytes_of_encrypted_data[i]) {
239 AP4_Size out_size = bytes_of_encrypted_data[i];
240 m_Cipher->ProcessBuffer(in+bytes_of_cleartext_data[i],
241 bytes_of_encrypted_data[i],
242 out+bytes_of_cleartext_data[i],
243 &out_size);
244 total_encrypted += bytes_of_encrypted_data[i];
245 }
246
247 // move the pointers
248 in += bytes_of_cleartext_data[i]+bytes_of_encrypted_data[i];
249 out += bytes_of_cleartext_data[i]+bytes_of_encrypted_data[i];
250 }
251
252 // update the IV
253 if (m_IvSize == 16) {
254 AP4_UI64 counter = AP4_BytesToUInt64BE(&m_Iv[8]);
255 AP4_BytesFromUInt64BE(&m_Iv[8], counter+(total_encrypted+15)/16);
256 } else {
257 AP4_UI64 counter = AP4_BytesToUInt64BE(&m_Iv[0]);
258 AP4_BytesFromUInt64BE(&m_Iv[0], counter+1);
259 }
260
261 // encode the sample infos
262 unsigned int sample_info_count = bytes_of_cleartext_data.ItemCount();
263 sample_infos.SetDataSize(2+sample_info_count*6);
264 AP4_UI08* infos = sample_infos.UseData();
265 AP4_BytesFromUInt16BE(infos, (AP4_UI16)sample_info_count);
266 for (unsigned int i=0; i<sample_info_count; i++) {
267 AP4_BytesFromUInt16BE(&infos[2+i*6], bytes_of_cleartext_data[i]);
268 AP4_BytesFromUInt32BE(&infos[2+i*6+2], bytes_of_encrypted_data[i]);
269 }
270
271 return AP4_SUCCESS;
272 }
273
274 /*----------------------------------------------------------------------
275 | AP4_CencCbcSubSampleEncrypter::GetSubSampleMap
276 +---------------------------------------------------------------------*/
277 AP4_Result
278 AP4_CencCbcSubSampleEncrypter::GetSubSampleMap(AP4_DataBuffer& sample_data,
279 AP4_Array<AP4_UI16>& bytes_of_cleartext_data,
280 AP4_Array<AP4_UI32>& bytes_of_encrypted_data)
152 AP4_CencAdvancedSubSampleMapper::GetSubSampleMap(AP4_DataBuffer& sample_data,
153 AP4_Array<AP4_UI16>& bytes_of_cleartext_data,
154 AP4_Array<AP4_UI32>& bytes_of_encrypted_data)
281155 {
282156 // setup direct pointers to the buffers
283157 const AP4_UI08* in = sample_data.GetData();
303177 return AP4_ERROR_INVALID_FORMAT;
304178 }
305179
306 unsigned int chunk_size = m_NaluLengthSize+nalu_length;
307 unsigned int cleartext_size = chunk_size%16;
308 unsigned int block_count = chunk_size/16;
309 if (cleartext_size < m_NaluLengthSize+1) {
310 AP4_ASSERT(block_count);
311 --block_count;
312 cleartext_size += 16;
180 unsigned int nalu_size = m_NaluLengthSize+nalu_length;
181 if (in+nalu_size > in_end) {
182 return AP4_ERROR_INVALID_FORMAT;
183 }
184
185 // skip encryption if the NAL unit is smaller than the threshold (DECE CFF spec)
186 // or should be left unencrypted for this specific format/type
187 bool skip = false;
188 if (nalu_size < AP4_CENC_NAL_UNIT_ENCRYPTION_MIN_SIZE) {
189 skip = true;
190 } else if (m_Format == AP4_SAMPLE_FORMAT_AVC1 ||
191 m_Format == AP4_SAMPLE_FORMAT_AVC2 ||
192 m_Format == AP4_SAMPLE_FORMAT_AVC3 ||
193 m_Format == AP4_SAMPLE_FORMAT_AVC4 ||
194 m_Format == AP4_SAMPLE_FORMAT_DVAV ||
195 m_Format == AP4_SAMPLE_FORMAT_DVA1) {
196 unsigned int nalu_type = in[m_NaluLengthSize] & 0x1F;
197 if (nalu_type != AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_OF_NON_IDR_PICTURE &&
198 nalu_type != AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_A &&
199 nalu_type != AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_B &&
200 nalu_type != AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_C &&
201 nalu_type != AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_OF_IDR_PICTURE) {
202 // this NAL unit is not a VCL NAL unit
203 skip = true;
204 }
205 } else if (m_Format == AP4_SAMPLE_FORMAT_HEV1 ||
206 m_Format == AP4_SAMPLE_FORMAT_HVC1 ||
207 m_Format == AP4_SAMPLE_FORMAT_DVHE ||
208 m_Format == AP4_SAMPLE_FORMAT_DVH1) {
209 unsigned int nalu_type = (in[m_NaluLengthSize] >> 1) & 0x3F;
210 if (nalu_type >= 32) {
211 // this NAL unit is not a VCL NAL unit
212 skip = true;
213 }
214 }
215
216 const char* cenc_layout = AP4_GlobalOptions::GetString("mpeg-cenc.encryption-layout");
217 if (cenc_layout && AP4_CompareStrings(cenc_layout, "nalu-length-and-type-only") == 0) {
218 unsigned int cleartext_size = m_NaluLengthSize+1;
219 unsigned int encrypted_size = nalu_size > cleartext_size ? nalu_size-cleartext_size : 0;
220 AP4_CencSubSampleMapAppendEntry(bytes_of_cleartext_data, bytes_of_encrypted_data, cleartext_size, encrypted_size);
221 } else if (skip) {
222 // use cleartext regions to cover the entire NAL unit
223 AP4_CencSubSampleMapAppendEntry(bytes_of_cleartext_data, bytes_of_encrypted_data, nalu_size, 0);
224 } else {
225 // leave some cleartext bytes at the start and encrypt the rest (multiple of blocks)
226 unsigned int encrypted_size = nalu_size-(AP4_CENC_NAL_UNIT_ENCRYPTION_MIN_SIZE-16);
227 encrypted_size -= (encrypted_size % 16);
228 unsigned int cleartext_size = nalu_size-encrypted_size;
229 AP4_ASSERT(encrypted_size >= 16);
230 AP4_ASSERT(cleartext_size >= m_NaluLengthSize);
231 AP4_CencSubSampleMapAppendEntry(bytes_of_cleartext_data, bytes_of_encrypted_data, cleartext_size, encrypted_size);
313232 }
314233
315234 // move the pointers
316 in += chunk_size;
235 in += nalu_size;
236 }
237
238 return AP4_SUCCESS;
239 }
240
241 /*----------------------------------------------------------------------
242 | AP4_CencCbcsSubSampleEncrypter::AP4_CencCbcsSubSampleEncrypter
243 +---------------------------------------------------------------------*/
244 AP4_CencCbcsSubSampleMapper::AP4_CencCbcsSubSampleMapper(AP4_Size nalu_length_size, AP4_UI32 format, AP4_TrakAtom* trak) :
245 AP4_CencSubSampleMapper(nalu_length_size, format),
246 m_AvcParser(NULL),
247 m_HevcParser(NULL)
248 {
249 if (!trak) return;
250
251 // get the sample description atom
252 AP4_StsdAtom* stsd = AP4_DYNAMIC_CAST(AP4_StsdAtom, trak->FindChild("mdia/minf/stbl/stsd"));
253 if (!stsd) return;
254
255 if (format == AP4_SAMPLE_FORMAT_AVC1 ||
256 format == AP4_SAMPLE_FORMAT_AVC2 ||
257 format == AP4_SAMPLE_FORMAT_AVC3 ||
258 format == AP4_SAMPLE_FORMAT_AVC4 ||
259 format == AP4_SAMPLE_FORMAT_DVAV ||
260 format == AP4_SAMPLE_FORMAT_DVA1) {
261 // create the parser
262 m_AvcParser = new AP4_AvcFrameParser();
317263
318 // store the info
319 bytes_of_cleartext_data.Append((AP4_UI16)cleartext_size);
320 bytes_of_encrypted_data.Append((AP4_UI32)(block_count*16));
321 }
322
323 return AP4_SUCCESS;
324 }
325
326 /*----------------------------------------------------------------------
327 | AP4_CencCbcSampleEncrypter::EncryptSampleData
264 // look for an avc sample description
265 AP4_AvccAtom* avcc = AP4_DYNAMIC_CAST(AP4_AvccAtom, stsd->FindChild("avc1/avcC"));
266 if (!avcc) avcc = AP4_DYNAMIC_CAST(AP4_AvccAtom, stsd->FindChild("avc2/avcC"));
267 if (!avcc) avcc = AP4_DYNAMIC_CAST(AP4_AvccAtom, stsd->FindChild("avc3/avcC"));
268 if (!avcc) avcc = AP4_DYNAMIC_CAST(AP4_AvccAtom, stsd->FindChild("avc4/avcC"));
269 if (!avcc) return;
270
271 // parse the sps and pps if we have them
272 AP4_Array<AP4_DataBuffer>& sps_list = avcc->GetSequenceParameters();
273 for (unsigned int i=0; i<sps_list.ItemCount(); i++) {
274 AP4_DataBuffer& sps = sps_list[i];
275 ParseAvcData(sps.GetData(), sps.GetDataSize());
276 }
277 AP4_Array<AP4_DataBuffer>& pps_list = avcc->GetPictureParameters();
278 for (unsigned int i=0; i<pps_list.ItemCount(); i++) {
279 AP4_DataBuffer& pps = pps_list[i];
280 ParseAvcData(pps.GetData(), pps.GetDataSize());
281 }
282 } else if (format == AP4_SAMPLE_FORMAT_HEV1 ||
283 format == AP4_SAMPLE_FORMAT_HVC1 ||
284 format == AP4_SAMPLE_FORMAT_DVHE ||
285 format == AP4_SAMPLE_FORMAT_DVH1) {
286 // create the parser
287 m_HevcParser = new AP4_HevcFrameParser();
288
289 // look for an hevc sample description
290 AP4_HvccAtom* hvcc = AP4_DYNAMIC_CAST(AP4_HvccAtom, stsd->FindChild("hvc1/hvcC"));
291 if (!hvcc) hvcc = AP4_DYNAMIC_CAST(AP4_HvccAtom, stsd->FindChild("hev1/hvcC"));
292 if (!hvcc) return;
293
294 // parse the vps, sps and pps if we have them
295 const AP4_Array<AP4_HvccAtom::Sequence>& sequence_list = hvcc->GetSequences();
296 for (unsigned int i=0; i<sequence_list.ItemCount(); i++) {
297 const AP4_Array<AP4_DataBuffer>& nalus = sequence_list[i].m_Nalus;
298 for (unsigned int j=0; j<nalus.ItemCount(); j++) {
299 ParseHevcData(nalus[j].GetData(), nalus[j].GetDataSize());
300 }
301 }
302 }
303 }
304
305 /*----------------------------------------------------------------------
306 | AP4_CencCbcsSubSampleEncrypter::~AP4_CencCbcsSubSampleEncrypter
307 +---------------------------------------------------------------------*/
308 AP4_CencCbcsSubSampleMapper::~AP4_CencCbcsSubSampleMapper()
309 {
310 delete m_AvcParser;
311 delete m_HevcParser;
312 }
313
314 /*----------------------------------------------------------------------
315 | AP4_CencCbcsSubSampleMapper::ParseAvcData
328316 +---------------------------------------------------------------------*/
329317 AP4_Result
330 AP4_CencCbcSampleEncrypter::EncryptSampleData(AP4_DataBuffer& data_in,
318 AP4_CencCbcsSubSampleMapper::ParseAvcData(const AP4_UI08* data, AP4_Size data_size)
319 {
320 if (!m_AvcParser) return AP4_ERROR_INVALID_PARAMETERS;
321
322 AP4_AvcFrameParser::AccessUnitInfo access_unit_info;
323 AP4_Result result = m_AvcParser->Feed(data, data_size, access_unit_info);
324 if (AP4_FAILED(result)) return result;
325
326 // cleanup
327 access_unit_info.Reset();
328
329 return AP4_SUCCESS;
330 }
331
332 /*----------------------------------------------------------------------
333 | AP4_CencCbcsSubSampleMapper::ParseHevcData
334 +---------------------------------------------------------------------*/
335 AP4_Result
336 AP4_CencCbcsSubSampleMapper::ParseHevcData(const AP4_UI08* data, AP4_Size data_size)
337 {
338 if (!m_HevcParser) return AP4_ERROR_INVALID_PARAMETERS;
339
340 AP4_HevcFrameParser::AccessUnitInfo access_unit_info;
341 AP4_Result result = m_HevcParser->Feed(data, data_size, access_unit_info);
342 if (AP4_FAILED(result)) return result;
343
344 // cleanup
345 access_unit_info.Reset();
346
347 return AP4_SUCCESS;
348 }
349
350 /*----------------------------------------------------------------------
351 | AP4_CencCbcsSubSampleMapper::GetSubSampleMap
352 +---------------------------------------------------------------------*/
353 AP4_Result
354 AP4_CencCbcsSubSampleMapper::GetSubSampleMap(AP4_DataBuffer& sample_data,
355 AP4_Array<AP4_UI16>& bytes_of_cleartext_data,
356 AP4_Array<AP4_UI32>& bytes_of_encrypted_data)
357 {
358 // setup direct pointers to the buffers
359 const AP4_UI08* in = sample_data.GetData();
360
361 // process the sample data, one NALU at a time
362 const AP4_UI08* in_end = sample_data.GetData()+sample_data.GetDataSize();
363 while ((AP4_Size)(in_end-in) > 1+m_NaluLengthSize) {
364 unsigned int nalu_length;
365 switch (m_NaluLengthSize) {
366 case 1:
367 nalu_length = *in;
368 break;
369
370 case 2:
371 nalu_length = AP4_BytesToUInt16BE(in);
372 break;
373
374 case 4:
375 nalu_length = AP4_BytesToUInt32BE(in);
376 break;
377
378 default:
379 return AP4_ERROR_INVALID_FORMAT;
380 }
381
382 unsigned int nalu_size = m_NaluLengthSize+nalu_length;
383 if (in+nalu_size > in_end) {
384 return AP4_ERROR_INVALID_FORMAT;
385 }
386
387 // skip encryption if the NAL unit should be left unencrypted for this specific format/type
388 bool skip = false;
389 if (m_Format == AP4_SAMPLE_FORMAT_AVC1 ||
390 m_Format == AP4_SAMPLE_FORMAT_AVC2 ||
391 m_Format == AP4_SAMPLE_FORMAT_AVC3 ||
392 m_Format == AP4_SAMPLE_FORMAT_AVC4 ||
393 m_Format == AP4_SAMPLE_FORMAT_DVAV ||
394 m_Format == AP4_SAMPLE_FORMAT_DVA1) {
395 const AP4_UI08* nalu_data = &in[m_NaluLengthSize];
396 unsigned int nalu_type = nalu_data[0] & 0x1F;
397
398 if (nalu_type == AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_OF_NON_IDR_PICTURE ||
399 nalu_type == AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_A ||
400 nalu_type == AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_OF_IDR_PICTURE) {
401 // parse the NAL unit to get the slice header size
402 if (m_AvcParser == NULL) return AP4_ERROR_INTERNAL;
403 AP4_AvcSliceHeader slice_header;
404 unsigned int nalu_ref_idc = (nalu_data[0]>>5)&3;
405 AP4_Result result = m_AvcParser->ParseSliceHeader(&nalu_data[1],
406 nalu_length-1,
407 nalu_type,
408 nalu_ref_idc,
409 slice_header);
410 if (AP4_FAILED(result)) {
411 return result;
412 }
413
414 // round up the slide header size to a multiple of bytes
415 unsigned int header_size = (slice_header.size+7)/8;
416
417 // account for emulation prevention bytes
418 unsigned int emulation_prevention_bytes = AP4_NalParser::CountEmulationPreventionBytes(&nalu_data[1], nalu_length-1, header_size);
419 header_size += emulation_prevention_bytes;
420
421 // leave the slice header in the clear, including the NAL type
422 unsigned int cleartext_size = m_NaluLengthSize+1+header_size;
423 unsigned int encrypted_size = nalu_size-cleartext_size;
424 AP4_CencSubSampleMapAppendEntry(bytes_of_cleartext_data, bytes_of_encrypted_data, cleartext_size, encrypted_size);
425 } else {
426 // this NAL unit does not have a slice header
427 skip = true;
428
429 // parse SPS and PPS NAL units
430 if (nalu_type == AP4_AVC_NAL_UNIT_TYPE_SPS ||
431 nalu_type == AP4_AVC_NAL_UNIT_TYPE_PPS) {
432 AP4_Result result = ParseAvcData(nalu_data, nalu_length);
433 if (AP4_FAILED(result)) {
434 return result;
435 }
436 }
437 }
438 } else if (m_Format == AP4_SAMPLE_FORMAT_HEV1 ||
439 m_Format == AP4_SAMPLE_FORMAT_HVC1 ||
440 m_Format == AP4_SAMPLE_FORMAT_DVHE ||
441 m_Format == AP4_SAMPLE_FORMAT_DVH1) {
442 const AP4_UI08* nalu_data = &in[m_NaluLengthSize];
443 unsigned int nalu_type = (nalu_data[0] >> 1) & 0x3F;
444
445 if (nalu_type < AP4_HEVC_NALU_TYPE_VPS_NUT) {
446 // this is a VCL NAL Unit
447 if (m_HevcParser == NULL) return AP4_ERROR_INTERNAL;
448 AP4_HevcSliceSegmentHeader slice_header;
449 AP4_Result result = m_HevcParser->ParseSliceSegmentHeader(&nalu_data[2], nalu_length-2, nalu_type, slice_header);
450 if (AP4_FAILED(result)) {
451 return result;
452 }
453
454 // leave the slice header in the clear, including the NAL type
455 // NOTE: the slice header is always a multiple of 8 bits because of byte_alignment()
456 unsigned int header_size = slice_header.size/8;
457
458 // account for emulation prevention bytes
459 unsigned int emulation_prevention_bytes = AP4_NalParser::CountEmulationPreventionBytes(&nalu_data[2], nalu_length-2, header_size);
460 header_size += emulation_prevention_bytes;
461
462 // set the encrypted range
463 unsigned int cleartext_size = m_NaluLengthSize+2+header_size;
464 unsigned int encrypted_size = nalu_size-cleartext_size;
465 AP4_CencSubSampleMapAppendEntry(bytes_of_cleartext_data, bytes_of_encrypted_data, cleartext_size, encrypted_size);
466 } else {
467 skip = true;
468
469 // parse VPS, SPS and PPS NAL units
470 if (nalu_type == AP4_HEVC_NALU_TYPE_VPS_NUT ||
471 nalu_type == AP4_HEVC_NALU_TYPE_SPS_NUT ||
472 nalu_type == AP4_HEVC_NALU_TYPE_PPS_NUT) {
473 AP4_Result result = ParseHevcData(nalu_data, nalu_length);
474 if (AP4_FAILED(result)) {
475 return result;
476 }
477 }
478 }
479 } else {
480 // only AVC and HEVC elementary streams are supported.
481 return AP4_ERROR_NOT_SUPPORTED;
482 }
483
484 if (skip) {
485 // use cleartext regions to cover the entire NAL unit
486 AP4_CencSubSampleMapAppendEntry(bytes_of_cleartext_data, bytes_of_encrypted_data, nalu_size, 0);
487 }
488
489 // move the pointers
490 in += nalu_size;
491 }
492
493 return AP4_SUCCESS;
494 }
495
496 /*----------------------------------------------------------------------
497 | AP4_CencSampleEncrypter::~AP4_CencSampleEncrypter
498 +---------------------------------------------------------------------*/
499 AP4_CencSampleEncrypter::~AP4_CencSampleEncrypter()
500 {
501 delete m_Cipher;
502 }
503
504 /*----------------------------------------------------------------------
505 | AP4_CencCtrSampleEncrypter::EncryptSampleData
506 +---------------------------------------------------------------------*/
507 AP4_Result
508 AP4_CencCtrSampleEncrypter::EncryptSampleData(AP4_DataBuffer& data_in,
331509 AP4_DataBuffer& data_out,
332510 AP4_DataBuffer& /* sample_infos */)
333511 {
342520 m_Cipher->SetIV(m_Iv);
343521
344522 // process the sample data
345 unsigned int block_count = data_in.GetDataSize()/16;
346 if (block_count) {
523 if (data_in.GetDataSize()) {
347524 AP4_Size out_size = data_out.GetDataSize();
348 AP4_Result result = m_Cipher->ProcessBuffer(in, block_count*16, out, &out_size, false);
525 AP4_Result result = m_Cipher->ProcessBuffer(in, data_in.GetDataSize(), out, &out_size, false);
349526 if (AP4_FAILED(result)) return result;
350 in += block_count*16;
351 out += block_count*16;
352
353 // update the IV (last cipherblock emitted)
354 AP4_CopyMemory(m_Iv, out-16, 16);
355 }
356
357 // any partial block at the end remains in the clear
358 unsigned int partial = data_in.GetDataSize()%16;
359 if (partial) {
360 AP4_CopyMemory(out, in, partial);
361 }
362
363 return AP4_SUCCESS;
364 }
365
366 /*----------------------------------------------------------------------
367 | AP4_CencCbcSubSampleEncrypter::EncryptSampleData
527 }
528
529 // update the IV
530 if (m_IvSize == 16) {
531 unsigned int block_count = (data_in.GetDataSize()+15)/16;
532 AP4_UI64 counter = AP4_BytesToUInt64BE(&m_Iv[8]);
533 AP4_BytesFromUInt64BE(&m_Iv[8], counter+block_count);
534 } else if (m_IvSize == 8){
535 AP4_UI64 counter = AP4_BytesToUInt64BE(&m_Iv[0]);
536 AP4_BytesFromUInt64BE(&m_Iv[0], counter+1);
537 } else {
538 return AP4_ERROR_INTERNAL;
539 }
540
541 return AP4_SUCCESS;
542 }
543
544 /*----------------------------------------------------------------------
545 | AP4_CencCtrSubSampleEncrypter::EncryptSampleData
368546 +---------------------------------------------------------------------*/
369547 AP4_Result
370 AP4_CencCbcSubSampleEncrypter::EncryptSampleData(AP4_DataBuffer& data_in,
548 AP4_CencCtrSubSampleEncrypter::EncryptSampleData(AP4_DataBuffer& data_in,
371549 AP4_DataBuffer& data_out,
372550 AP4_DataBuffer& sample_infos)
373 {
551 {
374552 // the output has the same size as the input
375553 data_out.SetDataSize(data_in.GetDataSize());
376554
382560 AP4_UI08* out = data_out.UseData();
383561
384562 // setup the IV
563 unsigned int total_encrypted = 0;
385564 m_Cipher->SetIV(m_Iv);
386565
387566 // get the subsample map
388567 AP4_Array<AP4_UI16> bytes_of_cleartext_data;
389568 AP4_Array<AP4_UI32> bytes_of_encrypted_data;
390 AP4_Result result = GetSubSampleMap(data_in, bytes_of_cleartext_data, bytes_of_encrypted_data);
569 AP4_Result result = m_SubSampleMapper->GetSubSampleMap(data_in, bytes_of_cleartext_data, bytes_of_encrypted_data);
391570 if (AP4_FAILED(result)) return result;
392571
572 // process the data
393573 for (unsigned int i=0; i<bytes_of_cleartext_data.ItemCount(); i++) {
394574 // copy the cleartext portion
395575 AP4_CopyMemory(out, in, bytes_of_cleartext_data[i]);
400580 m_Cipher->ProcessBuffer(in+bytes_of_cleartext_data[i],
401581 bytes_of_encrypted_data[i],
402582 out+bytes_of_cleartext_data[i],
403 &out_size, false);
404
405 // update the IV (last cipherblock emitted)
406 AP4_CopyMemory(m_Iv, out+bytes_of_cleartext_data[i]+bytes_of_encrypted_data[i]-16, 16);
583 &out_size);
584 total_encrypted += bytes_of_encrypted_data[i];
407585 }
408586
409587 // move the pointers
410588 in += bytes_of_cleartext_data[i]+bytes_of_encrypted_data[i];
411589 out += bytes_of_cleartext_data[i]+bytes_of_encrypted_data[i];
590 }
591
592 // update the IV
593 if (m_IvSize == 16) {
594 AP4_UI64 counter = AP4_BytesToUInt64BE(&m_Iv[8]);
595 AP4_BytesFromUInt64BE(&m_Iv[8], counter+(total_encrypted+15)/16);
596 } else {
597 AP4_UI64 counter = AP4_BytesToUInt64BE(&m_Iv[0]);
598 AP4_BytesFromUInt64BE(&m_Iv[0], counter+1);
412599 }
413600
414601 // encode the sample infos
420607 AP4_BytesFromUInt16BE(&infos[2+i*6], bytes_of_cleartext_data[i]);
421608 AP4_BytesFromUInt32BE(&infos[2+i*6+2], bytes_of_encrypted_data[i]);
422609 }
610
611 return AP4_SUCCESS;
612 }
613
614 /*----------------------------------------------------------------------
615 | AP4_CencCbcSampleEncrypter::EncryptSampleData
616 +---------------------------------------------------------------------*/
617 AP4_Result
618 AP4_CencCbcSampleEncrypter::EncryptSampleData(AP4_DataBuffer& data_in,
619 AP4_DataBuffer& data_out,
620 AP4_DataBuffer& /* sample_infos */)
621 {
622 // the output has the same size as the input
623 data_out.SetDataSize(data_in.GetDataSize());
624
625 // setup direct pointers to the buffers
626 const AP4_UI08* in = data_in.GetData();
627 AP4_UI08* out = data_out.UseData();
628
629 // setup the IV
630 m_Cipher->SetIV(m_Iv);
631
632 // process the sample data
633 unsigned int block_count = data_in.GetDataSize()/16;
634 if (block_count) {
635 AP4_Size out_size = data_out.GetDataSize();
636 AP4_Result result = m_Cipher->ProcessBuffer(in, block_count*16, out, &out_size, false);
637 if (AP4_FAILED(result)) return result;
638 in += block_count*16;
639 out += block_count*16;
640
641 if (!m_ConstantIv) {
642 // update the IV (last cipherblock emitted)
643 AP4_CopyMemory(m_Iv, out-16, 16);
644 }
645 }
646
647 // any partial block at the end remains in the clear
648 unsigned int partial = data_in.GetDataSize()%16;
649 if (partial) {
650 AP4_CopyMemory(out, in, partial);
651 }
652
653 return AP4_SUCCESS;
654 }
655
656 /*----------------------------------------------------------------------
657 | AP4_CencCbcSubSampleEncrypter::EncryptSampleData
658 +---------------------------------------------------------------------*/
659 AP4_Result
660 AP4_CencCbcSubSampleEncrypter::EncryptSampleData(AP4_DataBuffer& data_in,
661 AP4_DataBuffer& data_out,
662 AP4_DataBuffer& sample_infos)
663 {
664 // the output has the same size as the input
665 data_out.SetDataSize(data_in.GetDataSize());
666
667 // check some basics
668 if (data_in.GetDataSize() == 0) return AP4_SUCCESS;
669
670 // setup direct pointers to the buffers
671 const AP4_UI08* in = data_in.GetData();
672 AP4_UI08* out = data_out.UseData();
673
674 // setup the IV
675 m_Cipher->SetIV(m_Iv);
676
677 // get the subsample map
678 AP4_Array<AP4_UI16> bytes_of_cleartext_data;
679 AP4_Array<AP4_UI32> bytes_of_encrypted_data;
680 AP4_Result result = m_SubSampleMapper->GetSubSampleMap(data_in, bytes_of_cleartext_data, bytes_of_encrypted_data);
681 if (AP4_FAILED(result)) return result;
682
683 for (unsigned int i=0; i<bytes_of_cleartext_data.ItemCount(); i++) {
684 // copy the cleartext portion
685 AP4_CopyMemory(out, in, bytes_of_cleartext_data[i]);
686
687 // encrypt the rest
688 if (m_ResetIvForEachSubsample) {
689 m_Cipher->SetIV(m_Iv);
690 }
691 if (bytes_of_encrypted_data[i]) {
692 AP4_Size out_size = bytes_of_encrypted_data[i];
693 result = m_Cipher->ProcessBuffer(in+bytes_of_cleartext_data[i],
694 bytes_of_encrypted_data[i],
695 out+bytes_of_cleartext_data[i],
696 &out_size, false);
697 if (AP4_FAILED(result)) return result;
698
699 if (!m_ConstantIv) {
700 // update the IV (last cipherblock emitted)
701 AP4_CopyMemory(m_Iv, out+bytes_of_cleartext_data[i]+bytes_of_encrypted_data[i]-16, 16);
702 }
703 }
704
705 // move the pointers
706 in += bytes_of_cleartext_data[i]+bytes_of_encrypted_data[i];
707 out += bytes_of_cleartext_data[i]+bytes_of_encrypted_data[i];
708 }
709
710 // encode the sample infos
711 unsigned int sample_info_count = bytes_of_cleartext_data.ItemCount();
712 sample_infos.SetDataSize(2+sample_info_count*6);
713 AP4_UI08* infos = sample_infos.UseData();
714 AP4_BytesFromUInt16BE(infos, (AP4_UI16)sample_info_count);
715 for (unsigned int i=0; i<sample_info_count; i++) {
716 AP4_BytesFromUInt16BE(&infos[2+i*6], bytes_of_cleartext_data[i]);
717 AP4_BytesFromUInt32BE(&infos[2+i*6+2], bytes_of_encrypted_data[i]);
718 }
423719
424720 return AP4_SUCCESS;
425721 }
430726 class AP4_CencTrackEncrypter : public AP4_Processor::TrackHandler {
431727 public:
432728 // constructor
433 AP4_CencTrackEncrypter(AP4_CencVariant variant,
434 AP4_UI32 default_algorithm_id,
435 AP4_UI08 default_iv_size,
729 AP4_CencTrackEncrypter(AP4_CencVariant variant,
730 AP4_UI32 default_is_protected,
731 AP4_UI08 default_per_sample_iv_size,
436732 const AP4_UI08* default_kid,
733 AP4_UI08 default_constant_iv_size,
734 const AP4_UI08* default_constant_iv,
735 AP4_UI08 default_crypt_byte_block,
736 AP4_UI08 default_skip_byte_block,
437737 AP4_Array<AP4_SampleEntry*>& sample_entries,
438738 AP4_UI32 format);
439739
447747 AP4_CencVariant m_Variant;
448748 AP4_Array<AP4_SampleEntry*> m_SampleEntries;
449749 AP4_UI32 m_Format;
450 AP4_UI32 m_DefaultAlgorithmId;
451 AP4_UI08 m_DefaultIvSize;
750 AP4_UI32 m_DefaultIsProtected;
751 AP4_UI08 m_DefaultPerSampleIvSize;
452752 AP4_UI08 m_DefaultKid[16];
753 AP4_UI08 m_DefaultConstantIvSize;
754 AP4_UI08 m_DefaultConstantIv[16];
755 AP4_UI08 m_DefaultCryptByteBlock;
756 AP4_UI08 m_DefaultSkipByteBlock;
453757 };
454758
455759 /*----------------------------------------------------------------------
456760 | AP4_CencTrackEncrypter::AP4_CencTrackEncrypter
457761 +---------------------------------------------------------------------*/
458762 AP4_CencTrackEncrypter::AP4_CencTrackEncrypter(
459 AP4_CencVariant variant,
460 AP4_UI32 default_algorithm_id,
461 AP4_UI08 default_iv_size,
763 AP4_CencVariant variant,
764 AP4_UI32 default_is_protected,
765 AP4_UI08 default_per_sample_iv_size,
462766 const AP4_UI08* default_kid,
767 AP4_UI08 default_constant_iv_size,
768 const AP4_UI08* default_constant_iv,
769 AP4_UI08 default_crypt_byte_block,
770 AP4_UI08 default_skip_byte_block,
463771 AP4_Array<AP4_SampleEntry*>& sample_entries,
464772 AP4_UI32 format) :
465 AP4_Processor::TrackHandler(0, 0),
466 m_Variant(variant),
773 m_Variant(variant),
467774 m_Format(format),
468 m_DefaultAlgorithmId(default_algorithm_id),
469 m_DefaultIvSize(default_iv_size)
470 {
471 // copy the KID
775 m_DefaultIsProtected(default_is_protected),
776 m_DefaultPerSampleIvSize(default_per_sample_iv_size),
777 m_DefaultConstantIvSize(default_constant_iv_size),
778 m_DefaultCryptByteBlock(default_crypt_byte_block),
779 m_DefaultSkipByteBlock(default_skip_byte_block)
780 {
781 // copy the KID and IV
472782 AP4_CopyMemory(m_DefaultKid, default_kid, 16);
783 if (default_constant_iv) {
784 AP4_CopyMemory(m_DefaultConstantIv, default_constant_iv, 16);
785 }
473786
474787 // copy the sample entry list
475788 for (unsigned int i=0; i<sample_entries.ItemCount(); i++) {
495808 case AP4_CENC_VARIANT_PIFF_CTR:
496809 schm = new AP4_SchmAtom(AP4_PROTECTION_SCHEME_TYPE_PIFF,
497810 AP4_PROTECTION_SCHEME_VERSION_PIFF_11);
498 tenc = new AP4_PiffTrackEncryptionAtom(m_DefaultAlgorithmId,
499 m_DefaultIvSize,
811 tenc = new AP4_PiffTrackEncryptionAtom(m_DefaultIsProtected,
812 m_DefaultPerSampleIvSize,
500813 m_DefaultKid);
501814 break;
502815
503 case AP4_CENC_VARIANT_MPEG:
816 case AP4_CENC_VARIANT_MPEG_CENC:
504817 schm = new AP4_SchmAtom(AP4_PROTECTION_SCHEME_TYPE_CENC,
505818 AP4_PROTECTION_SCHEME_VERSION_CENC_10);
506 tenc = new AP4_TencAtom(m_DefaultAlgorithmId,
507 m_DefaultIvSize,
819 tenc = new AP4_TencAtom(m_DefaultIsProtected,
820 m_DefaultPerSampleIvSize,
508821 m_DefaultKid);
822 break;
823
824 case AP4_CENC_VARIANT_MPEG_CBC1:
825 schm = new AP4_SchmAtom(AP4_PROTECTION_SCHEME_TYPE_CBC1,
826 AP4_PROTECTION_SCHEME_VERSION_CENC_10);
827 tenc = new AP4_TencAtom(m_DefaultIsProtected,
828 m_DefaultPerSampleIvSize,
829 m_DefaultKid);
830 break;
831
832 case AP4_CENC_VARIANT_MPEG_CENS:
833 schm = new AP4_SchmAtom(AP4_PROTECTION_SCHEME_TYPE_CENS,
834 AP4_PROTECTION_SCHEME_VERSION_CENC_10);
835 tenc = new AP4_TencAtom(m_DefaultIsProtected,
836 m_DefaultPerSampleIvSize,
837 m_DefaultKid,
838 m_DefaultConstantIvSize,
839 m_DefaultConstantIv,
840 m_DefaultCryptByteBlock,
841 m_DefaultSkipByteBlock);
842 break;
843
844 case AP4_CENC_VARIANT_MPEG_CBCS:
845 schm = new AP4_SchmAtom(AP4_PROTECTION_SCHEME_TYPE_CBCS,
846 AP4_PROTECTION_SCHEME_VERSION_CENC_10);
847 tenc = new AP4_TencAtom(m_DefaultIsProtected,
848 m_DefaultPerSampleIvSize,
849 m_DefaultKid,
850 m_DefaultConstantIvSize,
851 m_DefaultConstantIv,
852 m_DefaultCryptByteBlock,
853 m_DefaultSkipByteBlock);
509854 break;
510855 }
511856
546891 public:
547892 // constructor
548893 AP4_CencFragmentEncrypter(AP4_CencVariant variant,
894 AP4_UI32 options,
549895 AP4_ContainerAtom* traf,
550896 AP4_CencEncryptingProcessor::Encrypter* encrypter,
551897 AP4_UI32 cleartext_sample_description_index);
560906 private:
561907 // members
562908 AP4_CencVariant m_Variant;
909 AP4_UI32 m_Options;
563910 AP4_ContainerAtom* m_Traf;
564911 AP4_CencSampleEncryption* m_SampleEncryptionAtom;
565912 AP4_CencSampleEncryption* m_SampleEncryptionAtomShadow;
573920 | AP4_CencFragmentEncrypter::AP4_CencFragmentEncrypter
574921 +---------------------------------------------------------------------*/
575922 AP4_CencFragmentEncrypter::AP4_CencFragmentEncrypter(AP4_CencVariant variant,
923 AP4_UI32 options,
576924 AP4_ContainerAtom* traf,
577925 AP4_CencEncryptingProcessor::Encrypter* encrypter,
578926 AP4_UI32 cleartext_sample_description_index) :
579927 m_Variant(variant),
928 m_Options(options),
580929 m_Traf(traf),
581930 m_SampleEncryptionAtom(NULL),
582931 m_SampleEncryptionAtomShadow(NULL),
627976 m_SampleEncryptionAtom = new AP4_PiffSampleEncryptionAtom(8);
628977 break;
629978
630 case AP4_CENC_VARIANT_MPEG:
631 if (AP4_GlobalOptions::GetBool("mpeg-cenc.piff-compatible")) {
979 case AP4_CENC_VARIANT_MPEG_CENC:
980 if (m_Options & AP4_CencEncryptingProcessor::OPTION_PIFF_COMPATIBILITY) {
632981 AP4_UI08 iv_size = 8;
633 if (AP4_GlobalOptions::GetBool("mpeg-cenc.iv-size-16")) {
982 if (m_Options & AP4_CencEncryptingProcessor::OPTION_PIFF_IV_SIZE_16) {
634983 iv_size = 16;
635984 }
636985 m_SampleEncryptionAtom = new AP4_SencAtom(iv_size);
637986 m_SampleEncryptionAtomShadow = new AP4_PiffSampleEncryptionAtom(iv_size);
638987 } else {
639988 AP4_UI08 iv_size = 16; // default
640 if (AP4_GlobalOptions::GetBool("mpeg-cenc.iv-size-8")) {
989 if (m_Options & AP4_CencEncryptingProcessor::OPTION_IV_SIZE_8) {
641990 iv_size = 8;
642991 }
643992 m_SampleEncryptionAtom = new AP4_SencAtom(iv_size);
644993 }
994 m_Saiz = new AP4_SaizAtom();
995 m_Saio = new AP4_SaioAtom();
996 break;
997
998 case AP4_CENC_VARIANT_MPEG_CBC1:
999 m_SampleEncryptionAtom = new AP4_SencAtom(16);
1000 m_Saiz = new AP4_SaizAtom();
1001 m_Saio = new AP4_SaioAtom();
1002 break;
1003
1004 case AP4_CENC_VARIANT_MPEG_CENS:
1005 m_SampleEncryptionAtom = new AP4_SencAtom(16, 0, NULL, 0, 0);
1006 m_Saiz = new AP4_SaizAtom();
1007 m_Saio = new AP4_SaioAtom();
1008 break;
1009
1010 case AP4_CENC_VARIANT_MPEG_CBCS:
1011 m_SampleEncryptionAtom = new AP4_SencAtom(0, 16, NULL, 0, 0);
6451012 m_Saiz = new AP4_SaizAtom();
6461013 m_Saio = new AP4_SaioAtom();
6471014 break;
6621029
6631030 // this is mostly for testing: forces the clients to parse saio/saiz instead
6641031 // on relying on 'senc'
665 if (AP4_GlobalOptions::GetBool("mpeg-cenc.no-senc")) {
1032 if (m_Options & AP4_CencEncryptingProcessor::OPTION_NO_SENC) {
6661033 m_SampleEncryptionAtom->GetOuter().SetType(AP4_ATOM_TYPE('s', 'e', 'n', 'C'));
6671034 }
6681035
6951062 }
6961063
6971064 if (!m_Encrypter->m_SampleEncrypter->UseSubSamples()) {
698 m_SampleEncryptionAtom->SetSampleInfosSize(sample_count*m_SampleEncryptionAtom->GetIvSize());
1065 m_SampleEncryptionAtom->SetSampleInfosSize(sample_count*m_SampleEncryptionAtom->GetPerSampleIvSize());
6991066 if (m_SampleEncryptionAtomShadow) {
700 m_SampleEncryptionAtomShadow->SetSampleInfosSize(sample_count*m_SampleEncryptionAtomShadow->GetIvSize());
1067 m_SampleEncryptionAtomShadow->SetSampleInfosSize(sample_count*m_SampleEncryptionAtomShadow->GetPerSampleIvSize());
7011068 }
7021069 if (m_Saiz) {
703 m_Saiz->SetDefaultSampleInfoSize(m_SampleEncryptionAtom->GetIvSize());
704 m_Saiz->SetSampleCount(sample_count);
1070 if (m_SampleEncryptionAtom->GetPerSampleIvSize()) {
1071 m_Saiz->SetDefaultSampleInfoSize(m_SampleEncryptionAtom->GetPerSampleIvSize());
1072 m_Saiz->SetSampleCount(sample_count);
1073 } else {
1074 m_Saiz->SetDefaultSampleInfoSize(0);
1075 m_Saiz->SetSampleCount(0);
1076 }
7051077 }
7061078 return AP4_SUCCESS;
7071079 }
7161088 AP4_DataBuffer sample_data;
7171089 AP4_Array<AP4_UI16> bytes_of_cleartext_data;
7181090 AP4_Array<AP4_UI32> bytes_of_encrypted_data;
719 AP4_Size sample_info_size = sample_count*(m_SampleEncryptionAtom->GetIvSize());
1091 AP4_Size sample_info_size = sample_count*(m_SampleEncryptionAtom->GetPerSampleIvSize());
7201092 for (unsigned int i=0; i<sample_count; i++) {
7211093 AP4_Result result = sample_table->GetSample(i, sample);
7221094 if (AP4_FAILED(result)) return result;
7311103 sample_info_size += 2+bytes_of_cleartext_data.ItemCount()*6;
7321104
7331105 if (m_Saiz) {
734 m_Saiz->SetSampleInfoSize(i, (AP4_UI08)(m_SampleEncryptionAtom->GetIvSize()+2+bytes_of_cleartext_data.ItemCount()*6));
1106 m_Saiz->SetSampleInfoSize(i, (AP4_UI08)(m_SampleEncryptionAtom->GetPerSampleIvSize()+2+bytes_of_cleartext_data.ItemCount()*6));
7351107 }
7361108 }
7371109 m_SampleEncryptionAtom->SetSampleInfosSize(sample_info_size);
8291201 | AP4_CencEncryptingProcessor:AP4_CencEncryptingProcessor
8301202 +---------------------------------------------------------------------*/
8311203 AP4_CencEncryptingProcessor::AP4_CencEncryptingProcessor(AP4_CencVariant variant,
1204 AP4_UI32 options,
8321205 AP4_BlockCipherFactory* block_cipher_factory) :
833 m_Variant(variant)
1206 m_Variant(variant),
1207 m_Options(options)
8341208 {
8351209 // create a block cipher factory if none is given
8361210 if (block_cipher_factory == NULL) {
8731247 if (!ftyp->HasCompatibleBrand(AP4_PIFF_BRAND)) {
8741248 compatible_brands.Append(AP4_PIFF_BRAND);
8751249 }
876 } else if (m_Variant == AP4_CENC_VARIANT_MPEG) {
1250 } else if (m_Variant == AP4_CENC_VARIANT_MPEG_CENC ||
1251 m_Variant == AP4_CENC_VARIANT_MPEG_CBC1 ||
1252 m_Variant == AP4_CENC_VARIANT_MPEG_CENS ||
1253 m_Variant == AP4_CENC_VARIANT_MPEG_CBCS) {
8771254 if (!ftyp->HasCompatibleBrand(AP4_FILE_BRAND_ISO6)) {
8781255 compatible_brands.Append(AP4_FILE_BRAND_ISO6);
8791256 }
9051282 if (moov) {
9061283 // create a 'standard EME' pssh atom
9071284 AP4_PsshAtom* eme_pssh = NULL;
908 if (m_Variant == AP4_CENC_VARIANT_MPEG && AP4_GlobalOptions::GetBool("mpeg-cenc.eme-pssh")) {
1285 if ((m_Variant == AP4_CENC_VARIANT_MPEG_CENC ||
1286 m_Variant == AP4_CENC_VARIANT_MPEG_CBC1 ||
1287 m_Variant == AP4_CENC_VARIANT_MPEG_CENS ||
1288 m_Variant == AP4_CENC_VARIANT_MPEG_CBCS) &&
1289 (m_Options & OPTION_EME_PSSH)) {
9091290 AP4_DataBuffer kids;
9101291 AP4_UI32 kid_count = 0;
9111292 const AP4_List<AP4_TrackPropertyMap::Entry>& prop_entries = m_PropertyMap.GetEntries();
9401321
9411322 // check if we need to create a Marlin 'mkid' table
9421323 AP4_PsshAtom* marlin_pssh = NULL;
943 if (m_Variant == AP4_CENC_VARIANT_MPEG) {
1324 if (m_Variant == AP4_CENC_VARIANT_MPEG_CENC) {
9441325 const AP4_List<AP4_TrackPropertyMap::Entry>& prop_entries = m_PropertyMap.GetEntries();
9451326 AP4_MkidAtom* mkid = NULL;
9461327 for (unsigned int i=0; i<prop_entries.ItemCount(); i++) {
10341415 | AP4_CencEncryptingProcessor:CreateTrackHandler
10351416 +---------------------------------------------------------------------*/
10361417 AP4_Processor::TrackHandler*
1037 AP4_CencEncryptingProcessor::CreateTrackHandler(AP4_TrakAtom* trak, AP4_TrexAtom* trex)
1418 AP4_CencEncryptingProcessor::CreateTrackHandler(AP4_TrakAtom* trak)
10381419 {
10391420 // find the stsd atom
10401421 AP4_StsdAtom* stsd = AP4_DYNAMIC_CAST(AP4_StsdAtom, trak->FindChild("mdia/minf/stbl/stsd"));
10731454 case AP4_ATOM_TYPE_AVC2:
10741455 case AP4_ATOM_TYPE_AVC3:
10751456 case AP4_ATOM_TYPE_AVC4:
1457 case AP4_ATOM_TYPE_DVAV:
1458 case AP4_ATOM_TYPE_DVA1:
10761459 case AP4_ATOM_TYPE_HEV1:
10771460 case AP4_ATOM_TYPE_HVC1:
1461 case AP4_ATOM_TYPE_DVHE:
1462 case AP4_ATOM_TYPE_DVH1:
10781463 enc_format = AP4_ATOM_TYPE_ENCV;
10791464 break;
10801465
11061491
11071492 // create the encrypter
11081493 AP4_Processor::TrackHandler* track_encrypter;
1109 AP4_UI32 algorithm_id = 0;
1110 AP4_UI08 iv_size = 16;
1494 AP4_UI08 cipher_iv_size = 16;
1495 AP4_BlockCipher::CipherMode cipher_mode;
1496 AP4_BlockCipher::CtrParams cipher_ctr_params;
1497 const void* cipher_mode_params = NULL;
1498 AP4_UI08 crypt_byte_block = 0;
1499 AP4_UI08 skip_byte_block = 0;
1500 bool constant_iv = false;
1501 bool reset_iv_at_each_subsample = false;
11111502 switch (m_Variant) {
11121503 case AP4_CENC_VARIANT_PIFF_CTR:
1113 algorithm_id = AP4_CENC_ALGORITHM_ID_CTR;
1114 iv_size = 8;
1115 break;
1116
1117 case AP4_CENC_VARIANT_PIFF_CBC:
1118 algorithm_id = AP4_CENC_ALGORITHM_ID_CBC;
1119 break;
1120
1121 case AP4_CENC_VARIANT_MPEG:
1122 if ((AP4_GlobalOptions::GetBool("mpeg-cenc.piff-compatible") ||
1123 AP4_GlobalOptions::GetBool("mpeg-cenc.iv-size-8")) &&
1124 !AP4_GlobalOptions::GetBool("mpeg-cenc.iv-size-16")) {
1125 iv_size = 8;
1126 }
1127 algorithm_id = AP4_CENC_ALGORITHM_ID_CTR;
1504 cipher_mode = AP4_BlockCipher::CTR;
1505 cipher_ctr_params.counter_size = 8;
1506 cipher_mode_params = &cipher_ctr_params;
1507 cipher_iv_size = 8;
1508 track_encrypter = new AP4_CencTrackEncrypter(m_Variant,
1509 1,
1510 cipher_iv_size,
1511 kid,
1512 0,
1513 NULL,
1514 0,
1515 0,
1516 entries,
1517 enc_format);
11281518 break;
11291519
1520 case AP4_CENC_VARIANT_PIFF_CBC:
1521 cipher_mode = AP4_BlockCipher::CBC;
1522 track_encrypter = new AP4_CencTrackEncrypter(m_Variant,
1523 2,
1524 cipher_iv_size,
1525 kid,
1526 0,
1527 NULL,
1528 0,
1529 0,
1530 entries,
1531 enc_format);
1532 break;
1533
1534 case AP4_CENC_VARIANT_MPEG_CENC:
1535 cipher_mode = AP4_BlockCipher::CTR;
1536 cipher_ctr_params.counter_size = 8;
1537 cipher_mode_params = &cipher_ctr_params;
1538 if ((m_Options & OPTION_IV_SIZE_8) ||
1539 ((m_Options & OPTION_PIFF_COMPATIBILITY) && !(m_Options & OPTION_PIFF_IV_SIZE_16))) {
1540 cipher_iv_size = 8;
1541 }
1542
1543 track_encrypter = new AP4_CencTrackEncrypter(m_Variant,
1544 1,
1545 cipher_iv_size,
1546 kid,
1547 0,
1548 NULL,
1549 0,
1550 0,
1551 entries,
1552 enc_format);
1553 break;
1554
1555 case AP4_CENC_VARIANT_MPEG_CENS:
1556 cipher_mode = AP4_BlockCipher::CTR;
1557 cipher_ctr_params.counter_size = 8;
1558 cipher_mode_params = &cipher_ctr_params;
1559 if (m_Options & OPTION_IV_SIZE_8) {
1560 cipher_iv_size = 8;
1561 }
1562 if (enc_format == AP4_ATOM_TYPE_ENCV) {
1563 crypt_byte_block = 1;
1564 skip_byte_block = 9;
1565 }
1566 track_encrypter = new AP4_CencTrackEncrypter(m_Variant,
1567 1,
1568 cipher_iv_size,
1569 kid,
1570 0,
1571 NULL,
1572 crypt_byte_block,
1573 skip_byte_block,
1574 entries,
1575 enc_format);
1576 break;
1577
1578 case AP4_CENC_VARIANT_MPEG_CBC1:
1579 cipher_mode = AP4_BlockCipher::CBC;
1580 track_encrypter = new AP4_CencTrackEncrypter(m_Variant,
1581 1,
1582 cipher_iv_size,
1583 kid,
1584 0,
1585 NULL,
1586 0,
1587 0,
1588 entries,
1589 enc_format);
1590 break;
1591
1592 case AP4_CENC_VARIANT_MPEG_CBCS:
1593 cipher_mode = AP4_BlockCipher::CBC;
1594 if (enc_format == AP4_ATOM_TYPE_ENCV) {
1595 crypt_byte_block = 1;
1596 skip_byte_block = 9;
1597 }
1598 constant_iv = true;
1599 reset_iv_at_each_subsample = true;
1600 track_encrypter = new AP4_CencTrackEncrypter(m_Variant,
1601 1,
1602 0,
1603 kid,
1604 cipher_iv_size,
1605 iv->GetData(),
1606 crypt_byte_block,
1607 skip_byte_block,
1608 entries,
1609 enc_format);
1610 break;
1611
11301612 default:
11311613 return NULL;
11321614 }
1133 track_encrypter = new AP4_CencTrackEncrypter(m_Variant,
1134 algorithm_id,
1135 iv_size,
1136 kid,
1137 entries,
1138 enc_format);
1139
1615
11401616 // create a block cipher
1141 AP4_BlockCipher* block_cipher = NULL;
1142 AP4_BlockCipher::CipherMode mode;
1143 AP4_BlockCipher::CtrParams ctr_params;
1144 const void* mode_params = NULL;
1145 switch (algorithm_id) {
1146 case AP4_CENC_ALGORITHM_ID_CBC:
1147 mode = AP4_BlockCipher::CBC;
1148 break;
1149
1150 case AP4_CENC_ALGORITHM_ID_CTR:
1151 mode = AP4_BlockCipher::CTR;
1152 ctr_params.counter_size = 8;
1153 mode_params = &ctr_params;
1154 break;
1155
1156 default: return NULL;
1157 }
1158 AP4_Result result = m_BlockCipherFactory->CreateCipher(AP4_BlockCipher::AES_128,
1617 AP4_BlockCipher* block_cipher = NULL;
1618 AP4_Result result = m_BlockCipherFactory->CreateCipher(AP4_BlockCipher::AES_128,
11591619 AP4_BlockCipher::ENCRYPT,
1160 mode,
1161 mode_params,
1620 cipher_mode,
1621 cipher_mode_params,
11621622 key->GetData(),
11631623 key->GetDataSize(),
11641624 block_cipher);
1165 if (AP4_FAILED(result)) return NULL;
1166
1625 if (AP4_FAILED(result)) {
1626 delete track_encrypter;
1627 return NULL;
1628 }
1629
1630 // compute the size of NAL units
1631 unsigned int nalu_length_size = 0;
1632 if (format == AP4_ATOM_TYPE_AVC1 ||
1633 format == AP4_ATOM_TYPE_AVC2 ||
1634 format == AP4_ATOM_TYPE_AVC3 ||
1635 format == AP4_ATOM_TYPE_AVC4 ||
1636 format == AP4_ATOM_TYPE_DVAV ||
1637 format == AP4_ATOM_TYPE_DVA1) {
1638 AP4_AvccAtom* avcc = AP4_DYNAMIC_CAST(AP4_AvccAtom, entries[0]->GetChild(AP4_ATOM_TYPE_AVCC));
1639 if (avcc) {
1640 nalu_length_size = avcc->GetNaluLengthSize();
1641 }
1642 } else if (format == AP4_ATOM_TYPE_HEV1 ||
1643 format == AP4_ATOM_TYPE_HVC1 ||
1644 format == AP4_ATOM_TYPE_DVHE ||
1645 format == AP4_ATOM_TYPE_DVH1) {
1646 AP4_HvccAtom* hvcc = AP4_DYNAMIC_CAST(AP4_HvccAtom, entries[0]->GetChild(AP4_ATOM_TYPE_HVCC));
1647 if (hvcc) {
1648 nalu_length_size = hvcc->GetNaluLengthSize();
1649 }
1650 }
1651
11671652 // add a new cipher state for this track
11681653 AP4_CencSampleEncrypter* sample_encrypter = NULL;
1169 AP4_StreamCipher* stream_cipher = NULL;
1170 switch (algorithm_id) {
1171 case AP4_CENC_ALGORITHM_ID_CBC:
1654 AP4_StreamCipher* stream_cipher = NULL;
1655 switch (cipher_mode) {
1656 case AP4_BlockCipher::CBC:
11721657 stream_cipher = new AP4_CbcStreamCipher(block_cipher);
1173 if (format == AP4_ATOM_TYPE_AVC1 ||
1174 format == AP4_ATOM_TYPE_AVC2 ||
1175 format == AP4_ATOM_TYPE_AVC3 ||
1176 format == AP4_ATOM_TYPE_AVC4) {
1177 AP4_AvccAtom* avcc = AP4_DYNAMIC_CAST(AP4_AvccAtom, entries[0]->GetChild(AP4_ATOM_TYPE_AVCC));
1178 if (avcc == NULL) return NULL;
1179 sample_encrypter = new AP4_CencCbcSubSampleEncrypter(stream_cipher, avcc->GetNaluLengthSize(), format);
1180 } else if (format == AP4_ATOM_TYPE_HEV1 ||
1181 format == AP4_ATOM_TYPE_HVC1) {
1182 AP4_HvccAtom* hvcc = AP4_DYNAMIC_CAST(AP4_HvccAtom, entries[0]->GetChild(AP4_ATOM_TYPE_HVCC));
1183 if (hvcc == NULL) return NULL;
1184 sample_encrypter = new AP4_CencCbcSubSampleEncrypter(stream_cipher, hvcc->GetNaluLengthSize(), format);
1658 if (crypt_byte_block && skip_byte_block) {
1659 stream_cipher = new AP4_PatternStreamCipher(stream_cipher, crypt_byte_block, skip_byte_block);
1660 }
1661
1662 if (nalu_length_size) {
1663 AP4_CencSubSampleMapper* subsample_mapper = NULL;
1664 if (m_Variant == AP4_CENC_VARIANT_MPEG_CBCS) {
1665 subsample_mapper = new AP4_CencCbcsSubSampleMapper(nalu_length_size, format, trak);
1666 } else {
1667 subsample_mapper = new AP4_CencBasicSubSampleMapper(nalu_length_size, format);
1668 }
1669 sample_encrypter = new AP4_CencCbcSubSampleEncrypter(stream_cipher,
1670 constant_iv,
1671 reset_iv_at_each_subsample,
1672 subsample_mapper);
11851673 } else {
1186 sample_encrypter = new AP4_CencCbcSampleEncrypter(stream_cipher);
1187 }
1674 sample_encrypter = new AP4_CencCbcSampleEncrypter(stream_cipher, constant_iv);
1675 }
1676
11881677 break;
11891678
1190 case AP4_CENC_ALGORITHM_ID_CTR:
1679 case AP4_BlockCipher::CTR:
11911680 stream_cipher = new AP4_CtrStreamCipher(block_cipher, 16);
1192 if (format == AP4_ATOM_TYPE_AVC1 ||
1193 format == AP4_ATOM_TYPE_AVC2 ||
1194 format == AP4_ATOM_TYPE_AVC3 ||
1195 format == AP4_ATOM_TYPE_AVC4) {
1196 AP4_AvccAtom* avcc = AP4_DYNAMIC_CAST(AP4_AvccAtom, entries[0]->GetChild(AP4_ATOM_TYPE_AVCC));
1197 if (avcc == NULL) return NULL;
1198 sample_encrypter = new AP4_CencCtrSubSampleEncrypter(stream_cipher, avcc->GetNaluLengthSize(), iv_size, format);
1199 } else if (format == AP4_ATOM_TYPE_HEV1 ||
1200 format == AP4_ATOM_TYPE_HVC1) {
1201 AP4_HvccAtom* hvcc = AP4_DYNAMIC_CAST(AP4_HvccAtom, entries[0]->GetChild(AP4_ATOM_TYPE_HVCC));
1202 if (hvcc == NULL) return NULL;
1203 sample_encrypter = new AP4_CencCtrSubSampleEncrypter(stream_cipher, hvcc->GetNaluLengthSize(), iv_size, format);
1681 if (crypt_byte_block && skip_byte_block) {
1682 stream_cipher = new AP4_PatternStreamCipher(stream_cipher, crypt_byte_block, skip_byte_block);
1683 }
1684 if (nalu_length_size) {
1685 AP4_CencSubSampleMapper* subsample_mapper = new AP4_CencAdvancedSubSampleMapper(nalu_length_size, format);
1686 sample_encrypter = new AP4_CencCtrSubSampleEncrypter(stream_cipher,
1687 constant_iv,
1688 reset_iv_at_each_subsample,
1689 cipher_iv_size,
1690 subsample_mapper);
12041691 } else {
1205 sample_encrypter = new AP4_CencCtrSampleEncrypter(stream_cipher, iv_size);
1692 sample_encrypter = new AP4_CencCtrSampleEncrypter(stream_cipher, constant_iv, cipher_iv_size);
12061693 }
12071694 break;
1695 }
1696 if (sample_encrypter == NULL) {
1697 delete stream_cipher;
1698 delete block_cipher;
1699 delete track_encrypter;
1700 return NULL;
12081701 }
12091702 sample_encrypter->SetIv(iv->GetData());
12101703
12691762 }
12701763 }
12711764 }
1272 return new AP4_CencFragmentEncrypter(m_Variant, traf, encrypter, clear_sample_description_index);
1765 return new AP4_CencFragmentEncrypter(m_Variant, m_Options, traf, encrypter, clear_sample_description_index);
12731766 }
12741767
12751768 /*----------------------------------------------------------------------
12761769 | AP4_CencSingleSampleDecrypter::Create
12771770 +---------------------------------------------------------------------*/
12781771 AP4_Result
1279 AP4_CencSingleSampleDecrypter::Create(AP4_UI32 algorithm_id,
1772 AP4_CencSingleSampleDecrypter::Create(AP4_UI32 cipher_type,
12801773 const AP4_UI08* key,
12811774 AP4_Size key_size,
1775 AP4_UI08 crypt_byte_block,
1776 AP4_UI08 skip_byte_block,
12821777 AP4_BlockCipherFactory* block_cipher_factory,
1778 bool reset_iv_at_each_subsample,
12831779 AP4_CencSingleSampleDecrypter*& decrypter)
12841780 {
12851781 // check the parameters
12911787 }
12921788
12931789 // create the cipher
1294 AP4_StreamCipher* stream_cipher = NULL;
1790 AP4_StreamCipher* stream_cipher = NULL;
12951791 bool full_blocks_only = false;
1296 switch (algorithm_id) {
1297 case AP4_CENC_ALGORITHM_ID_NONE:
1792 switch (cipher_type) {
1793 case AP4_CENC_CIPHER_NONE:
12981794 break;
12991795
1300 case AP4_CENC_ALGORITHM_ID_CTR: {
1796 case AP4_CENC_CIPHER_AES_128_CTR: {
13011797 // create the block cipher
13021798 AP4_BlockCipher* block_cipher = NULL;
13031799 AP4_BlockCipher::CtrParams ctr_params;
13161812 break;
13171813 }
13181814
1319 case AP4_CENC_ALGORITHM_ID_CBC: {
1815 case AP4_CENC_CIPHER_AES_128_CBC: {
13201816 // create the block cipher
13211817 AP4_BlockCipher* block_cipher = NULL;
13221818 AP4_Result result = block_cipher_factory->CreateCipher(AP4_BlockCipher::AES_128,
13401836 return AP4_ERROR_NOT_SUPPORTED;
13411837 }
13421838
1839 // wrap with a pattern processor if needed
1840 if (crypt_byte_block && skip_byte_block) {
1841 stream_cipher = new AP4_PatternStreamCipher(stream_cipher, crypt_byte_block, skip_byte_block);
1842 }
1843
13431844 // create the decrypter
1344 decrypter = new AP4_CencSingleSampleDecrypter(stream_cipher, full_blocks_only);
1845 decrypter = new AP4_CencSingleSampleDecrypter(stream_cipher, full_blocks_only, reset_iv_at_each_subsample);
13451846
13461847 return AP4_SUCCESS;
13471848 }
13571858 | AP4_CencSingleSampleDecrypter::DecryptSampleData
13581859 +---------------------------------------------------------------------*/
13591860 AP4_Result
1360 AP4_CencSingleSampleDecrypter::DecryptSampleData(AP4_UI32 poolid,
1861 AP4_CencSingleSampleDecrypter::DecryptSampleData(AP4_UI32 poolid,
13611862 AP4_DataBuffer& data_in,
13621863 AP4_DataBuffer& data_out,
13631864 const AP4_UI08* iv,
14081909
14091910 // decrypt the rest
14101911 if (encrypted_size) {
1912 if (m_ResetIvAtEachSubsample) {
1913 m_Cipher->SetIV(iv);
1914 }
1915
14111916 AP4_Result result = m_Cipher->ProcessBuffer(in+cleartext_size, encrypted_size, out+cleartext_size, &encrypted_size, false);
14121917 if (AP4_FAILED(result)) return result;
14131918 }
14141919
1415 // move the pointers
1920 // move the pointers and udate counters
14161921 in += cleartext_size+encrypted_size;
14171922 out += cleartext_size+encrypted_size;
1923 }
1924
1925 // copy any leftover partial block
1926 unsigned int partial = (unsigned int)(in_end-in);
1927 if (partial) {
1928 AP4_CopyMemory(out, in, partial);
14181929 }
14191930 } else {
14201931 if (m_FullBlocksOnly) {
14361947 } else {
14371948 // process the entire sample data at once
14381949 AP4_Size encrypted_size = data_in.GetDataSize();
1439 AP4_Result result = m_Cipher->ProcessBuffer(in, encrypted_size, out, &encrypted_size, false);
1950 AP4_Result result = m_Cipher->ProcessBuffer(in, encrypted_size, out, &encrypted_size, true);
14401951 if (AP4_FAILED(result)) return result;
14411952 }
14421953 }
14551966 const AP4_UI08* key,
14561967 AP4_Size key_size,
14571968 AP4_BlockCipherFactory* block_cipher_factory,
1458 AP4_CencSingleSampleDecrypter *singlesample_decrypter,
1969 AP4_CencSingleSampleDecrypter* singlesample_decrypter,
14591970 AP4_CencSampleDecrypter*& decrypter)
14601971 {
14611972 AP4_SaioAtom* saio = NULL;
14711982 saio,
14721983 saiz,
14731984 sample_encryption_atom,
1474 singlesample_decrypter,
1985 singlesample_decrypter,
14751986 decrypter);
14761987 }
14771988
14892000 AP4_SaioAtom*& saio,
14902001 AP4_SaizAtom*& saiz,
14912002 AP4_CencSampleEncryption*& sample_encryption_atom,
1492 AP4_CencSingleSampleDecrypter *singlesample_decrypter,
2003 AP4_CencSingleSampleDecrypter* singlesample_decrypter,
14932004 AP4_CencSampleDecrypter*& decrypter)
14942005 {
14952006 // default return values
15002011
15012012 // create the sample info table
15022013 AP4_CencSampleInfoTable* sample_info_table = NULL;
1503 AP4_UI32 algorithm_id = 0;
2014 AP4_UI32 protection_sheme = 0;
2015 bool reset_iv_at_each_subsample = false;
15042016 AP4_Result result = AP4_CencSampleInfoTable::Create(sample_description,
15052017 traf,
15062018 saio,
15072019 saiz,
15082020 sample_encryption_atom,
1509 algorithm_id,
2021 protection_sheme,
2022 reset_iv_at_each_subsample,
15102023 aux_info_data,
15112024 aux_info_data_offset,
15122025 sample_info_table);
15152028 }
15162029
15172030 // we now have all the info we need to create the decrypter
1518 return Create(sample_info_table, algorithm_id, key, key_size, block_cipher_factory, singlesample_decrypter, decrypter);
2031 return Create(sample_info_table,
2032 protection_sheme,
2033 key,
2034 key_size,
2035 block_cipher_factory,
2036 reset_iv_at_each_subsample,
2037 singlesample_decrypter,
2038 decrypter);
15192039 }
15202040
15212041 /*----------------------------------------------------------------------
15232043 +---------------------------------------------------------------------*/
15242044 AP4_Result
15252045 AP4_CencSampleDecrypter::Create(AP4_CencSampleInfoTable* sample_info_table,
1526 AP4_UI32 algorithm_id,
2046 AP4_UI32 cipher_type,
15272047 const AP4_UI08* key,
15282048 AP4_Size key_size,
15292049 AP4_BlockCipherFactory* block_cipher_factory,
1530 AP4_CencSingleSampleDecrypter *singlesample_decrypter,
2050 bool reset_iv_at_each_subsample,
2051 AP4_CencSingleSampleDecrypter* singlesample_decrypter,
15312052 AP4_CencSampleDecrypter*& decrypter)
15322053 {
15332054 // default return value
15342055 decrypter = NULL;
15352056
15362057 // check some basic paramaters
1537 unsigned int iv_size = sample_info_table->GetIvSize();
1538 switch (algorithm_id) {
1539 case AP4_CENC_ALGORITHM_ID_NONE:
2058 unsigned int iv_size = sample_info_table->GetIvSize();
2059 switch (cipher_type) {
2060 case AP4_CENC_CIPHER_NONE:
15402061 break;
15412062
1542 case AP4_CENC_ALGORITHM_ID_CTR:
2063 case AP4_CENC_CIPHER_AES_128_CTR:
15432064 if (iv_size != 8 && iv_size != 16) {
15442065 return AP4_ERROR_INVALID_FORMAT;
15452066 }
15462067 break;
15472068
1548 case AP4_CENC_ALGORITHM_ID_CBC:
2069 case AP4_CENC_CIPHER_AES_128_CBC:
15492070 if (iv_size != 16) {
15502071 return AP4_ERROR_INVALID_FORMAT;
15512072 }
15572078
15582079 // create a single-sample decrypter
15592080 AP4_CencSingleSampleDecrypter* single_sample_decrypter = NULL;
1560 if (!singlesample_decrypter)
1561 {
1562 AP4_Result result = AP4_CencSingleSampleDecrypter::Create(algorithm_id, key, key_size, block_cipher_factory, single_sample_decrypter);
1563 if (AP4_FAILED(result)) return result;
1564 }
1565 else
1566 single_sample_decrypter = singlesample_decrypter;
2081 if (!singlesample_decrypter)
2082 {
2083 AP4_Result result = AP4_CencSingleSampleDecrypter::Create(cipher_type,
2084 key,
2085 key_size,
2086 sample_info_table->GetCryptByteBlock(),
2087 sample_info_table->GetSkipByteBlock(),
2088 block_cipher_factory,
2089 reset_iv_at_each_subsample,
2090 single_sample_decrypter);
2091
2092 if (AP4_FAILED(result)) return result;
2093 }
2094 else
2095 {
2096 single_sample_decrypter = singlesample_decrypter;
2097 }
15672098
15682099 // create the decrypter
15692100 decrypter = new AP4_CencSampleDecrypter(single_sample_decrypter, sample_info_table);
15762107 +---------------------------------------------------------------------*/
15772108 AP4_CencSampleDecrypter::~AP4_CencSampleDecrypter()
15782109 {
1579 delete m_SampleInfoTable;
1580 if (m_SingleSampleDecrypter->GetParentIsOwner())
1581 delete m_SingleSampleDecrypter;
2110 delete m_SampleInfoTable;
2111 if (m_SingleSampleDecrypter->GetParentIsOwner())
2112 delete m_SingleSampleDecrypter;
15822113 }
15832114
15842115 /*----------------------------------------------------------------------
15962127 +---------------------------------------------------------------------*/
15972128 AP4_Result
15982129 AP4_CencSampleDecrypter::DecryptSampleData(AP4_UI32 poolid,
1599 AP4_DataBuffer& data_in,
1600 AP4_DataBuffer& data_out,
1601 const AP4_UI08* iv)
1602
2130 AP4_DataBuffer& data_in,
2131 AP4_DataBuffer& data_out,
2132 const AP4_UI08* iv)
16032133 {
16042134 // increment the sample cursor
16052135 unsigned int sample_cursor = m_SampleCursor++;
16142144 AP4_CopyMemory(iv_block, iv, iv_size);
16152145 if (iv_size != 16) AP4_SetMemory(&iv_block[iv_size], 0, 16-iv_size);
16162146
1617 // get the subsample info to this sample if needed
2147 // get the subsample info for this sample if needed
16182148 unsigned int subsample_count = 0;
16192149 const AP4_UI16* bytes_of_cleartext_data = NULL;
16202150 const AP4_UI32* bytes_of_encrypted_data = NULL;
16242154 }
16252155
16262156 // decrypt the sample
1627 return m_SingleSampleDecrypter->DecryptSampleData(
1628 poolid,
1629 data_in,
1630 data_out,
1631 iv_block,
1632 subsample_count,
1633 bytes_of_cleartext_data,
1634 bytes_of_encrypted_data);
2157 return m_SingleSampleDecrypter->DecryptSampleData(poolid, data_in, data_out, iv_block, subsample_count, bytes_of_cleartext_data, bytes_of_encrypted_data);
16352158 }
16362159
16372160 /*----------------------------------------------------------------------
16422165 AP4_IMPLEMENT_DYNAMIC_CAST(AP4_CencTrackDecrypter)
16432166
16442167 // constructor
1645 static AP4_Result Create(AP4_TrakAtom* trak,
1646 AP4_TrexAtom* trex,
1647 const unsigned char* key,
2168 static AP4_Result Create(const unsigned char* key,
16482169 AP4_Size key_size,
16492170 AP4_Array<AP4_ProtectedSampleDescription*>& sample_descriptions,
16502171 AP4_Array<AP4_SampleEntry*>& sample_entries,
16662187
16672188 private:
16682189 // constructor
1669 AP4_CencTrackDecrypter(AP4_TrakAtom* trak,
1670 AP4_TrexAtom* trex,
1671 AP4_Array<AP4_ProtectedSampleDescription*>& sample_descriptions,
2190 AP4_CencTrackDecrypter(AP4_Array<AP4_ProtectedSampleDescription*>& sample_descriptions,
16722191 AP4_Array<AP4_SampleEntry*>& sample_entries,
16732192 AP4_UI32 original_format);
16742193
16872206 | AP4_CencTrackDecrypter::Create
16882207 +---------------------------------------------------------------------*/
16892208 AP4_Result
1690 AP4_CencTrackDecrypter::Create(AP4_TrakAtom* trak,
1691 AP4_TrexAtom* trex,
1692 const unsigned char* key,
2209 AP4_CencTrackDecrypter::Create(const unsigned char* key,
16932210 AP4_Size /* key_size */,
16942211 AP4_Array<AP4_ProtectedSampleDescription*>& sample_descriptions,
16952212 AP4_Array<AP4_SampleEntry*>& sample_entries,
17032220 }
17042221
17052222 // instantiate the object
1706 decrypter = new AP4_CencTrackDecrypter(trak, trex, sample_descriptions,
2223 decrypter = new AP4_CencTrackDecrypter(sample_descriptions,
17072224 sample_entries,
17082225 sample_descriptions[0]->GetOriginalFormat());
17092226 return AP4_SUCCESS;
17122229 /*----------------------------------------------------------------------
17132230 | AP4_CencTrackDecrypter::AP4_CencTrackDecrypter
17142231 +---------------------------------------------------------------------*/
1715 AP4_CencTrackDecrypter::AP4_CencTrackDecrypter(AP4_TrakAtom* trak, AP4_TrexAtom* trex,
1716 AP4_Array<AP4_ProtectedSampleDescription*>& sample_descriptions,
2232 AP4_CencTrackDecrypter::AP4_CencTrackDecrypter(AP4_Array<AP4_ProtectedSampleDescription*>& sample_descriptions,
17172233 AP4_Array<AP4_SampleEntry*>& sample_entries,
17182234 AP4_UI32 original_format) :
1719 AP4_Processor::TrackHandler(trak, trex),
17202235 m_OriginalFormat(original_format)
17212236 {
17222237 for (unsigned int i=0; i<sample_descriptions.ItemCount(); i++) {
17572272 class AP4_CencFragmentDecrypter : public AP4_Processor::FragmentHandler {
17582273 public:
17592274 // constructor
1760 AP4_CencFragmentDecrypter(AP4_CencSampleDecrypter* sample_decrypter,
2275 AP4_CencFragmentDecrypter(AP4_CencSampleDecrypter* sample_decrypter, // ownership is transfered
17612276 AP4_SaioAtom* saio_atom,
17622277 AP4_SaizAtom* saiz_atom,
17632278 AP4_CencSampleEncryption* sample_encryption_atom) :
17662281 m_SaizAtom(saiz_atom),
17672282 m_SampleEncryptionAtom(sample_encryption_atom) {}
17682283
2284 ~AP4_CencFragmentDecrypter() { delete m_SampleDecrypter; }
2285
17692286 // methods
17702287 virtual AP4_Result ProcessFragment();
17712288 virtual AP4_Result FinishFragment();
18292346 +---------------------------------------------------------------------*/
18302347 AP4_CencDecryptingProcessor::AP4_CencDecryptingProcessor(const AP4_ProtectionKeyMap* key_map,
18312348 AP4_BlockCipherFactory* block_cipher_factory,
1832 AP4_CencSingleSampleDecrypter *cenc_singlesample_decrypter) :
1833 m_CencSingleSampleDecrypter(cenc_singlesample_decrypter),
1834 m_KeyMap(key_map)
2349 AP4_CencSingleSampleDecrypter *cenc_singlesample_decrypter) :
2350 m_CencSingleSampleDecrypter(cenc_singlesample_decrypter),
2351 m_KeyMap(key_map)
18352352 {
18362353 if (block_cipher_factory) {
18372354 m_BlockCipherFactory = block_cipher_factory;
18412358 }
18422359
18432360 /*----------------------------------------------------------------------
2361 | AP4_CencDecryptingProcessor:GetKeyForTrak
2362 +---------------------------------------------------------------------*/
2363 const AP4_DataBuffer*
2364 AP4_CencDecryptingProcessor::GetKeyForTrak(AP4_UI32 track_id, AP4_ProtectedSampleDescription* sample_description)
2365 {
2366 // look for the key by track ID
2367 const AP4_DataBuffer* key = m_KeyMap->GetKey(track_id);
2368 if (!key) {
2369 // no key found by track ID, look for a key by KID
2370 if (sample_description) {
2371 AP4_ProtectionSchemeInfo* scheme_info = sample_description->GetSchemeInfo();
2372 if (scheme_info) {
2373 AP4_ContainerAtom* schi = scheme_info->GetSchiAtom();
2374 if (schi) {
2375 AP4_TencAtom* tenc = AP4_DYNAMIC_CAST(AP4_TencAtom, schi->FindChild("tenc"));
2376 if (tenc) {
2377 const AP4_UI08* kid = tenc->GetDefaultKid();
2378 if (kid) {
2379 key = m_KeyMap->GetKeyByKid(kid);
2380 }
2381 }
2382 }
2383 }
2384 }
2385 }
2386
2387 return key;
2388 }
2389
2390 /*----------------------------------------------------------------------
18442391 | AP4_CencDecryptingProcessor:CreateTrackHandler
18452392 +---------------------------------------------------------------------*/
18462393 AP4_Processor::TrackHandler*
1847 AP4_CencDecryptingProcessor::CreateTrackHandler(AP4_TrakAtom* trak, AP4_TrexAtom* trex)
2394 AP4_CencDecryptingProcessor::CreateTrackHandler(AP4_TrakAtom* trak)
18482395 {
18492396 // find the stsd atom
18502397 AP4_StsdAtom* stsd = AP4_DYNAMIC_CAST(AP4_StsdAtom, trak->FindChild("mdia/minf/stbl/stsd"));
18662413 AP4_ProtectedSampleDescription* protected_desc =
18672414 static_cast<AP4_ProtectedSampleDescription*>(sample_desc);
18682415 if (protected_desc->GetSchemeType() == AP4_PROTECTION_SCHEME_TYPE_PIFF ||
1869 protected_desc->GetSchemeType() == AP4_PROTECTION_SCHEME_TYPE_CENC) {
2416 protected_desc->GetSchemeType() == AP4_PROTECTION_SCHEME_TYPE_CENC ||
2417 protected_desc->GetSchemeType() == AP4_PROTECTION_SCHEME_TYPE_CBC1 ||
2418 protected_desc->GetSchemeType() == AP4_PROTECTION_SCHEME_TYPE_CENS ||
2419 protected_desc->GetSchemeType() == AP4_PROTECTION_SCHEME_TYPE_CBCS) {
18702420 sample_descs.Append(protected_desc);
18712421 sample_entries.Append(sample_entry);
18722422 }
18732423 }
18742424 }
18752425 if (sample_entries.ItemCount() == 0) return NULL;
1876 const AP4_DataBuffer* key = m_KeyMap->GetKey(trak->GetId());
2426
2427 // get the key for this track
2428 const AP4_DataBuffer* key = GetKeyForTrak(trak->GetId(), sample_descs.ItemCount() ? sample_descs[0] : NULL);
2429
2430 // create a decrypter with this key
18772431 if (key) {
18782432 AP4_CencTrackDecrypter* handler = NULL;
1879 AP4_Result result = AP4_CencTrackDecrypter::Create(trak, trex, key->GetData(),
2433 AP4_Result result = AP4_CencTrackDecrypter::Create(key->GetData(),
18802434 key->GetDataSize(),
18812435 sample_descs,
18822436 sample_entries,
18922446 | AP4_CencDecryptingProcessor::CreateFragmentHandler
18932447 +---------------------------------------------------------------------*/
18942448 AP4_Processor::FragmentHandler*
1895 AP4_CencDecryptingProcessor::CreateFragmentHandler(AP4_TrakAtom* /*trak*/,
2449 AP4_CencDecryptingProcessor::CreateFragmentHandler(AP4_TrakAtom* trak,
18962450 AP4_TrexAtom* trex,
18972451 AP4_ContainerAtom* traf,
18982452 AP4_ByteStream& moof_data,
19012455 // find the matching track handler to get to the track sample description
19022456 const AP4_DataBuffer* key = NULL;
19032457 AP4_ProtectedSampleDescription* sample_description = NULL;
1904 for (unsigned int i=0; i<m_TrackData.ItemCount(); i++) {
2458 for (unsigned int i=0; i<m_TrackIds.ItemCount(); i++) {
19052459 AP4_TfhdAtom* tfhd = AP4_DYNAMIC_CAST(AP4_TfhdAtom, traf->GetChild(AP4_ATOM_TYPE_TFHD));
1906 if (tfhd && m_TrackData[i].new_id == tfhd->GetTrackId()) {
2460 if (tfhd && m_TrackIds[i] == tfhd->GetTrackId()) {
19072461 // look for the Track Encryption Box
19082462 AP4_CencTrackDecrypter* track_decrypter =
1909 AP4_DYNAMIC_CAST(AP4_CencTrackDecrypter, m_TrackData[i].track_handler);
2463 AP4_DYNAMIC_CAST(AP4_CencTrackDecrypter, m_TrackHandlers[i]);
19102464 if (track_decrypter) {
19112465 unsigned int index = trex->GetDefaultSampleDescriptionIndex();
19122466 unsigned int tfhd_flags = tfhd->GetFlags();
19172471 sample_description = track_decrypter->GetSampleDescription(index-1);
19182472 }
19192473 if (sample_description == NULL) return NULL;
1920 }
1921
1922 // get the matching key
1923 key = m_KeyMap->GetKey(tfhd->GetTrackId());
2474
2475 // get the key for this track
2476 key = GetKeyForTrak(tfhd->GetTrackId(), sample_description);
2477 }
19242478
19252479 break;
19262480 }
19272481 }
1928 if (sample_description == NULL) return NULL;
2482 if (sample_description == NULL || key == NULL) return NULL;
19292483
19302484 // create the sample decrypter for the fragment
19312485 AP4_CencSampleDecrypter* sample_decrypter = NULL;
19322486 AP4_SaioAtom* saio = NULL;
19332487 AP4_SaizAtom* saiz = NULL;
19342488 AP4_CencSampleEncryption* sample_encryption_atom = NULL;
1935 AP4_Result result = AP4_CencSampleDecrypter::Create(
2489 AP4_Result result = AP4_CencSampleDecrypter::Create(
19362490 sample_description,
19372491 traf,
19382492 moof_data,
19392493 moof_offset,
1940 key?key->GetData():0,
1941 key?key->GetDataSize():0,
1942 NULL,
2494 key->GetData(),
2495 key->GetDataSize(),
2496 m_BlockCipherFactory,
19432497 saio,
19442498 saiz,
19452499 sample_encryption_atom,
1946 m_CencSingleSampleDecrypter,
2500 m_CencSingleSampleDecrypter,
19472501 sample_decrypter);
19482502 if (AP4_FAILED(result)) return NULL;
19492503
19582512 /*----------------------------------------------------------------------
19592513 | AP4_CencTrackEncryption::AP4_CencTrackEncryption
19602514 +---------------------------------------------------------------------*/
1961 AP4_CencTrackEncryption::AP4_CencTrackEncryption() :
1962 m_DefaultAlgorithmId(0),
1963 m_DefaultIvSize(0)
2515 AP4_CencTrackEncryption::AP4_CencTrackEncryption(AP4_UI08 version) :
2516 m_Version_(version),
2517 m_DefaultIsProtected(0),
2518 m_DefaultPerSampleIvSize(0),
2519 m_DefaultConstantIvSize(0),
2520 m_DefaultCryptByteBlock(0),
2521 m_DefaultSkipByteBlock(0)
19642522 {
19652523 AP4_SetMemory(m_DefaultKid, 0, 16);
2524 AP4_SetMemory(m_DefaultConstantIv, 0, 16);
19662525 }
19672526
19682527 /*----------------------------------------------------------------------
19692528 | AP4_CencTrackEncryption::AP4_CencTrackEncryption
19702529 +---------------------------------------------------------------------*/
1971 AP4_CencTrackEncryption::AP4_CencTrackEncryption(AP4_UI32 default_algorithm_id,
1972 AP4_UI08 default_iv_size,
1973 const AP4_UI08* default_kid) :
1974 m_DefaultAlgorithmId(default_algorithm_id),
1975 m_DefaultIvSize(default_iv_size)
2530 AP4_CencTrackEncryption::AP4_CencTrackEncryption(AP4_UI08 version,
2531 AP4_UI08 default_is_protected,
2532 AP4_UI08 default_per_sample_iv_size,
2533 const AP4_UI08* default_kid,
2534 AP4_UI08 default_constant_iv_size,
2535 const AP4_UI08* default_constant_iv,
2536 AP4_UI08 default_crypt_byte_block,
2537 AP4_UI08 default_skip_byte_block) :
2538 m_Version_(version),
2539 m_DefaultIsProtected(default_is_protected),
2540 m_DefaultPerSampleIvSize(default_per_sample_iv_size),
2541 m_DefaultConstantIvSize(default_constant_iv_size),
2542 m_DefaultCryptByteBlock(default_crypt_byte_block),
2543 m_DefaultSkipByteBlock(default_skip_byte_block)
19762544 {
19772545 AP4_CopyMemory(m_DefaultKid, default_kid, 16);
1978 }
1979
1980 /*----------------------------------------------------------------------
1981 | AP4_CencTrackEncryption::AP4_CencTrackEncryption
1982 +---------------------------------------------------------------------*/
1983 AP4_CencTrackEncryption::AP4_CencTrackEncryption(AP4_ByteStream& stream)
1984 {
1985 stream.ReadUI24(m_DefaultAlgorithmId);
1986 stream.ReadUI08(m_DefaultIvSize);
2546 AP4_SetMemory(m_DefaultConstantIv, 0, 16);
2547 if (default_per_sample_iv_size == 0 && default_constant_iv_size && default_constant_iv) {
2548 if (default_constant_iv_size > 16) {
2549 // too large, truncate
2550 default_constant_iv_size = 16;
2551 }
2552 AP4_CopyMemory(&m_DefaultConstantIv[16-default_constant_iv_size], default_constant_iv, default_constant_iv_size);
2553 }
2554 }
2555
2556 /*----------------------------------------------------------------------
2557 | AP4_CencTrackEncryption::Parse
2558 +---------------------------------------------------------------------*/
2559 AP4_Result
2560 AP4_CencTrackEncryption::Parse(AP4_ByteStream& stream)
2561 {
2562 AP4_UI08 reserved;
2563 AP4_Result result = stream.ReadUI08(reserved);
2564 if (AP4_FAILED(result)) return result;
2565 if (m_Version_ == 0) {
2566 result = stream.ReadUI08(reserved);
2567 if (AP4_FAILED(result)) return result;
2568 } else {
2569 AP4_UI08 blocks;
2570 result = stream.ReadUI08(blocks);
2571 if (AP4_FAILED(result)) return result;
2572 m_DefaultCryptByteBlock = (blocks >> 4) & 0xF;
2573 m_DefaultSkipByteBlock = (blocks ) & 0xF;
2574 }
2575 result = stream.ReadUI08(m_DefaultIsProtected);
2576 if (AP4_FAILED(result)) return result;
2577 result = stream.ReadUI08(m_DefaultPerSampleIvSize);
2578 if (AP4_FAILED(result)) return result;
19872579 AP4_SetMemory(m_DefaultKid, 0, 16);
1988 stream.Read(m_DefaultKid, 16);
2580 result = stream.Read(m_DefaultKid, 16);
2581 if (AP4_FAILED(result)) return result;
2582 if (m_DefaultPerSampleIvSize == 0) {
2583 result = stream.ReadUI08(m_DefaultConstantIvSize);
2584 if (AP4_FAILED(result)) return result;
2585 if (m_DefaultConstantIvSize > 16) {
2586 m_DefaultConstantIvSize = 0;
2587 return AP4_ERROR_INVALID_FORMAT;
2588 }
2589 AP4_SetMemory(m_DefaultConstantIv, 0, 16);
2590 result = stream.Read(m_DefaultConstantIv, m_DefaultConstantIvSize);
2591 if (AP4_FAILED(result)) return result;
2592 }
2593
2594 return AP4_SUCCESS;
19892595 }
19902596
19912597 /*----------------------------------------------------------------------
19942600 AP4_Result
19952601 AP4_CencTrackEncryption::DoInspectFields(AP4_AtomInspector& inspector)
19962602 {
1997 inspector.AddField("default_AlgorithmID", m_DefaultAlgorithmId);
1998 inspector.AddField("default_IV_size", m_DefaultIvSize);
1999 inspector.AddField("default_KID", m_DefaultKid, 16);
2000
2603 // the spelling of these fields is inconsistent, but that's how it appears in the spec!
2604 inspector.AddField("default_isProtected", m_DefaultIsProtected);
2605 inspector.AddField("default_Per_Sample_IV_Size", m_DefaultPerSampleIvSize);
2606 inspector.AddField("default_KID", m_DefaultKid, 16);
2607 if (m_Version_ >= 1) {
2608 inspector.AddField("default_crypt_byte_block", m_DefaultCryptByteBlock);
2609 inspector.AddField("default_skip_byte_block", m_DefaultSkipByteBlock);
2610 }
2611 if (m_DefaultPerSampleIvSize == 0) {
2612 inspector.AddField("default_constant_IV_size", m_DefaultConstantIvSize);
2613 if (m_DefaultConstantIvSize <= 16) {
2614 inspector.AddField("default_constant_IV", m_DefaultConstantIv, m_DefaultConstantIvSize);
2615 }
2616 }
20012617 return AP4_SUCCESS;
20022618 }
20032619
20092625 {
20102626 AP4_Result result;
20112627
2012 // write the fields
2013 result = stream.WriteUI24(m_DefaultAlgorithmId);
2628 // write the fields
2629 result = stream.WriteUI08(0); // reserved
20142630 if (AP4_FAILED(result)) return result;
2015 result = stream.WriteUI08(m_DefaultIvSize);
2631 if (m_Version_ == 0) {
2632 result = stream.WriteUI08(0); // reserved
2633 if (AP4_FAILED(result)) return result;
2634 } else {
2635 result = stream.WriteUI08(m_DefaultCryptByteBlock<<4 | m_DefaultSkipByteBlock);
2636 if (AP4_FAILED(result)) return result;
2637 }
2638 result = stream.WriteUI08(m_DefaultIsProtected);
2639 if (AP4_FAILED(result)) return result;
2640 result = stream.WriteUI08(m_DefaultPerSampleIvSize);
20162641 if (AP4_FAILED(result)) return result;
20172642 result = stream.Write(m_DefaultKid, 16);
20182643 if (AP4_FAILED(result)) return result;
2019
2644 if (m_DefaultPerSampleIvSize == 0) {
2645 result = stream.WriteUI08(m_DefaultConstantIvSize);
2646 if (AP4_FAILED(result)) return result;
2647 result = stream.Write(m_DefaultConstantIv, m_DefaultConstantIvSize <= 16 ? m_DefaultConstantIvSize : 16);
2648 if (AP4_FAILED(result)) return result;
2649 }
2650
20202651 return AP4_SUCCESS;
20212652 }
20222653
20312662 AP4_Result
20322663 AP4_CencSampleInfoTable::Create(AP4_ProtectedSampleDescription* sample_description,
20332664 AP4_ContainerAtom* traf,
2034 AP4_UI32& algorithm_id,
2665 AP4_UI32& cipher_type,
2666 bool& reset_iv_at_each_subsample,
20352667 AP4_ByteStream& aux_info_data,
20362668 AP4_Position aux_info_data_offset,
20372669 AP4_CencSampleInfoTable*& sample_info_table)
20442676 saio,
20452677 saiz,
20462678 sample_encryption_atom,
2047 algorithm_id,
2679 cipher_type,
2680 reset_iv_at_each_subsample,
20482681 aux_info_data,
20492682 aux_info_data_offset,
20502683 sample_info_table);
20592692 AP4_SaioAtom*& saio,
20602693 AP4_SaizAtom*& saiz,
20612694 AP4_CencSampleEncryption*& sample_encryption_atom,
2062 AP4_UI32& algorithm_id,
2695 AP4_UI32& cipher_type,
2696 bool& reset_iv_at_each_subsample,
20632697 AP4_ByteStream& aux_info_data,
20642698 AP4_Position aux_info_data_offset,
20652699 AP4_CencSampleInfoTable*& sample_info_table)
20662700 {
20672701 // default return values
2068 saio = NULL;
2069 saiz = NULL;
2070 sample_encryption_atom = NULL;
2071 sample_info_table = NULL;
2072 unsigned int iv_size = 0;
2073
2074 // check the scheme
2075 if (sample_description->GetSchemeType() == AP4_PROTECTION_SCHEME_TYPE_PIFF) {
2076 // we don't support PIFF 1.0 anymore!
2077 //if (sample_description->GetSchemeVersion() != AP4_PROTECTION_SCHEME_VERSION_PIFF_11) {
2078 // return AP4_ERROR_NOT_SUPPORTED;
2079 //}
2080 } else if (sample_description->GetSchemeType() == AP4_PROTECTION_SCHEME_TYPE_CENC) {
2081 if (sample_description->GetSchemeVersion() != AP4_PROTECTION_SCHEME_VERSION_CENC_10) {
2082 return AP4_ERROR_NOT_SUPPORTED;
2083 }
2084 } else {
2085 return AP4_ERROR_NOT_SUPPORTED;
2086 }
2087
2702 saio = NULL;
2703 saiz = NULL;
2704 sample_encryption_atom = NULL;
2705 sample_info_table = NULL;
2706 cipher_type = AP4_CENC_CIPHER_NONE;
2707 reset_iv_at_each_subsample = false;
2708
20882709 // get the scheme info atom
20892710 AP4_ContainerAtom* schi = sample_description->GetSchemeInfo()->GetSchiAtom();
20902711 if (schi == NULL) return AP4_ERROR_INVALID_FORMAT;
20952716 if (track_encryption_atom == NULL) {
20962717 track_encryption_atom = AP4_DYNAMIC_CAST(AP4_CencTrackEncryption, schi->GetChild(AP4_UUID_PIFF_TRACK_ENCRYPTION_ATOM));
20972718 }
2719 if (track_encryption_atom == NULL) {
2720 return AP4_ERROR_INVALID_FORMAT;
2721 }
20982722
20992723 // look for a sample encryption atom
21002724 if (traf) {
21042728 }
21052729 }
21062730
2731 // check the scheme and compute the cipher
2732 switch (sample_description->GetSchemeType()) {
2733 case AP4_PROTECTION_SCHEME_TYPE_PIFF:
2734 switch (track_encryption_atom->GetDefaultIsProtected()) {
2735 case 0:
2736 cipher_type = AP4_CENC_CIPHER_NONE;
2737 break;
2738
2739 case 1:
2740 cipher_type = AP4_CENC_CIPHER_AES_128_CTR;
2741 break;
2742 case 2:
2743 cipher_type = AP4_CENC_CIPHER_AES_128_CBC;
2744 break;
2745
2746 default:
2747 return AP4_ERROR_NOT_SUPPORTED;
2748 }
2749 break;
2750
2751 case AP4_PROTECTION_SCHEME_TYPE_CENC:
2752 case AP4_PROTECTION_SCHEME_TYPE_CENS:
2753 cipher_type = AP4_CENC_CIPHER_AES_128_CTR;
2754 break;
2755
2756 case AP4_PROTECTION_SCHEME_TYPE_CBC1:
2757 cipher_type = AP4_CENC_CIPHER_AES_128_CBC;
2758 break;
2759
2760 case AP4_PROTECTION_SCHEME_TYPE_CBCS:
2761 cipher_type = AP4_CENC_CIPHER_AES_128_CBC;
2762 reset_iv_at_each_subsample = true;
2763 break;
2764
2765 default:
2766 // not supported
2767 return AP4_ERROR_NOT_SUPPORTED;
2768 }
2769 if (!track_encryption_atom->GetDefaultIsProtected()) {
2770 cipher_type = AP4_CENC_CIPHER_NONE;
2771 }
2772
21072773 // parse the crypto params
2774 AP4_UI08 per_sample_iv_size = 0;
2775 AP4_UI08 constant_iv_size = 0;
2776 const AP4_UI08* constant_iv = NULL;
2777 AP4_UI08 crypt_byte_block = 0;
2778 AP4_UI08 skip_byte_block = 0;
21082779 if (sample_encryption_atom &&
21092780 (sample_encryption_atom->GetOuter().GetFlags() & AP4_CENC_SAMPLE_ENCRYPTION_FLAG_OVERRIDE_TRACK_ENCRYPTION_DEFAULTS)) {
2110 algorithm_id = sample_encryption_atom->GetAlgorithmId();
2111 iv_size = sample_encryption_atom->GetIvSize();
2781
2782 switch (sample_encryption_atom->GetAlgorithmId()) {
2783 case 0:
2784 cipher_type = AP4_CENC_CIPHER_NONE;
2785 break;
2786
2787 case 1:
2788 cipher_type = AP4_CENC_CIPHER_AES_128_CTR;
2789 break;
2790
2791 case 2:
2792 cipher_type = AP4_CENC_CIPHER_AES_128_CBC;
2793 break;
2794 }
2795 per_sample_iv_size = sample_encryption_atom->GetPerSampleIvSize();
21122796 } else {
2113 if (track_encryption_atom == NULL) return AP4_ERROR_INVALID_FORMAT;
2114 algorithm_id = track_encryption_atom->GetDefaultAlgorithmId();
2115 iv_size = track_encryption_atom->GetDefaultIvSize();
2116 }
2117
2118 // try to create a sample info table from senc
2119 if (sample_info_table == NULL && sample_encryption_atom) {
2120 AP4_Result result = sample_encryption_atom->CreateSampleInfoTable(iv_size, sample_info_table);
2121 if (AP4_FAILED(result)) return result;
2797 per_sample_iv_size = track_encryption_atom->GetDefaultPerSampleIvSize();
2798 constant_iv_size = track_encryption_atom->GetDefaultConstantIvSize();
2799 crypt_byte_block = track_encryption_atom->GetDefaultCryptByteBlock();
2800 skip_byte_block = track_encryption_atom->GetDefaultSkipByteBlock();
2801 if (constant_iv_size) {
2802 constant_iv = track_encryption_atom->GetDefaultConstantIv();
2803 }
21222804 }
21232805
21242806 // try to create a sample info table from saio/saiz
2125 if (traf) {
2807 if (sample_info_table == NULL && traf) {
21262808 for (AP4_List<AP4_Atom>::Item* child = traf->GetChildren().FirstItem();
21272809 child;
21282810 child = child->GetNext()) {
21382820 }
21392821 }
21402822 }
2141 if (sample_info_table == NULL && saio && saiz) {
2142 AP4_Result result = Create(iv_size,
2823 if (saio && saiz) {
2824 AP4_Result result = Create(0,
2825 crypt_byte_block,
2826 skip_byte_block,
2827 per_sample_iv_size,
2828 constant_iv_size,
2829 constant_iv,
21432830 *traf,
21442831 *saio,
21452832 *saiz,
21502837 }
21512838 }
21522839
2840 // try to create a sample info table from senc
2841 if (sample_info_table == NULL && sample_encryption_atom) {
2842 AP4_Result result = sample_encryption_atom->CreateSampleInfoTable(0,
2843 crypt_byte_block,
2844 skip_byte_block,
2845 per_sample_iv_size,
2846 constant_iv_size,
2847 constant_iv,
2848 sample_info_table);
2849 if (AP4_FAILED(result)) return result;
2850 }
2851
21532852 if (sample_info_table == NULL) {
21542853 return AP4_ERROR_INVALID_FORMAT;
21552854 }
21612860 | AP4_CencSampleInfoTable::Create
21622861 +---------------------------------------------------------------------*/
21632862 AP4_Result
2164 AP4_CencSampleInfoTable::Create(unsigned int iv_size,
2863 AP4_CencSampleInfoTable::Create(AP4_UI08 flags,
2864 AP4_UI08 crypt_byte_block,
2865 AP4_UI08 skip_byte_block,
2866 AP4_UI08 per_sample_iv_size,
2867 AP4_UI08 constant_iv_size,
2868 const AP4_UI08* constant_iv,
21652869 AP4_ContainerAtom& traf,
21662870 AP4_SaioAtom& saio,
21672871 AP4_SaizAtom& saiz,
21892893 }
21902894
21912895 // create the table
2192 AP4_CencSampleInfoTable* table = new AP4_CencSampleInfoTable(sample_info_count, (AP4_UI08)iv_size);
2896 AP4_UI08 iv_size = per_sample_iv_size;
2897 if (iv_size == 0) {
2898 iv_size = constant_iv_size;
2899 if (iv_size == 0 || constant_iv == NULL) {
2900 return AP4_ERROR_INVALID_PARAMETERS;
2901 }
2902 }
2903 AP4_CencSampleInfoTable* table = new AP4_CencSampleInfoTable(flags,
2904 crypt_byte_block,
2905 skip_byte_block,
2906 sample_info_count,
2907 iv_size);
21932908
21942909 // process each sample's auxiliary info
21952910 AP4_Ordinal saio_index = 0;
22252940 if (AP4_FAILED(result)) goto end;
22262941
22272942 const AP4_UI08* info_data = info.GetData();
2228 table->SetIv(saiz_index, info_data);
2229 if (info_size > iv_size+2) {
2230 AP4_UI16 subsample_count = AP4_BytesToUInt16BE(info_data+iv_size);
2231 if (info_size < iv_size+2+subsample_count*6) {
2943 if (per_sample_iv_size) {
2944 table->SetIv(saiz_index, info_data);
2945 } else {
2946 table->SetIv(saiz_index, constant_iv);
2947 }
2948 if (info_size > per_sample_iv_size+2) {
2949 AP4_UI16 subsample_count = AP4_BytesToUInt16BE(info_data+per_sample_iv_size);
2950 if (info_size < per_sample_iv_size+2+subsample_count*6) {
22322951 // not enough data
22332952 goto end;
22342953 }
2235 table->AddSubSampleData(subsample_count, info_data+iv_size+2);
2954 table->AddSubSampleData(subsample_count, info_data+per_sample_iv_size+2);
22362955 }
22372956 saiz_index++;
22382957 }
22612980 {
22622981 sample_info_table = NULL;
22632982
2983 // basic size check
22642984 if (serialized_size < 4+4) {
22652985 return AP4_ERROR_INVALID_FORMAT;
22662986 }
2267 AP4_UI32 sample_count = AP4_BytesToUInt32BE(serialized); serialized += 4; serialized_size -= 4;
2268 AP4_UI32 iv_size = AP4_BytesToUInt32BE(serialized); serialized += 4; serialized_size -= 4;
2987
2988 AP4_UI32 sample_count = AP4_BytesToUInt32BE(serialized); serialized += 4; serialized_size -= 4;
2989 AP4_UI08 flags = serialized[0]; serialized += 1; serialized_size -= 1;
2990 AP4_UI08 crypt_byte_block = serialized[0]; serialized += 1; serialized_size -= 1;
2991 AP4_UI08 skip_byte_block = serialized[0]; serialized += 1; serialized_size -= 1;
2992 AP4_UI08 iv_size = serialized[0]; serialized += 1; serialized_size -= 1;
22692993
22702994 if (serialized_size < sample_count*iv_size) {
22712995 return AP4_ERROR_INVALID_FORMAT;
22722996 }
2273 AP4_CencSampleInfoTable* table = new AP4_CencSampleInfoTable(sample_count, (AP4_UI08)iv_size);
2997 AP4_CencSampleInfoTable* table = new AP4_CencSampleInfoTable(flags, crypt_byte_block, skip_byte_block, sample_count, (AP4_UI08)iv_size);
22742998 table->m_IvData.SetData(serialized, sample_count*iv_size);
22752999 serialized += sample_count*iv_size;
22763000 serialized_size -= sample_count*iv_size;
23313055 /*----------------------------------------------------------------------
23323056 | AP4_CencSampleInfoTable::AP4_CencSampleInfoTable
23333057 +---------------------------------------------------------------------*/
2334 AP4_CencSampleInfoTable::AP4_CencSampleInfoTable(AP4_UI32 sample_count,
3058 AP4_CencSampleInfoTable::AP4_CencSampleInfoTable(AP4_UI08 flags,
3059 AP4_UI08 crypt_byte_block,
3060 AP4_UI08 skip_byte_block,
3061 AP4_UI32 sample_count,
23353062 AP4_UI08 iv_size) :
23363063 m_SampleCount(sample_count),
3064 m_Flags(flags),
3065 m_CryptByteBlock(crypt_byte_block),
3066 m_SkipByteBlock(skip_byte_block),
23373067 m_IvSize(iv_size)
23383068 {
23393069 m_IvData.SetDataSize(m_IvSize*sample_count);
23713101 buffer.SetDataSize(size);
23723102 AP4_UI08* data = buffer.UseData();
23733103
2374 AP4_BytesFromUInt32BE(data, m_SampleCount); data += 4;
2375 AP4_BytesFromUInt32BE(data, m_IvSize); data += 4;
3104 AP4_BytesFromUInt32BE(data, m_SampleCount); data += 4;
3105 *data++ = m_Flags;
3106 *data++ = m_CryptByteBlock;
3107 *data++ = m_SkipByteBlock;
3108 *data++ = m_IvSize;
23763109 AP4_CopyMemory(data, m_IvData.GetData(), m_SampleCount*m_IvSize); data += m_SampleCount*m_IvSize;
23773110 AP4_BytesFromUInt32BE(data, m_BytesOfCleartextData.ItemCount()); data += 4;
23783111 for (unsigned int i=0; i<m_BytesOfCleartextData.ItemCount(); i++) {
24993232 AP4_CencSampleEncryption::AP4_CencSampleEncryption(AP4_Atom& outer,
25003233 AP4_Size size,
25013234 AP4_ByteStream& stream) :
2502 m_Outer(outer), m_SampleInfoCursor(0)
2503 {
3235 m_Outer(outer),
3236 m_ConstantIvSize(0),
3237 m_CryptByteBlock(0),
3238 m_SkipByteBlock(0),
3239 m_SampleInfoCursor(0)
3240 {
3241 AP4_SetMemory(m_ConstantIv, 0, 16);
3242
25043243 if (outer.GetFlags() & AP4_CENC_SAMPLE_ENCRYPTION_FLAG_OVERRIDE_TRACK_ENCRYPTION_DEFAULTS) {
25053244 stream.ReadUI24(m_AlgorithmId);
2506 stream.ReadUI08(m_IvSize);
3245 stream.ReadUI08(m_PerSampleIvSize);
25073246 stream.Read (m_Kid, 16);
25083247 } else {
2509 m_AlgorithmId = 0;
2510 m_IvSize = 0;
3248 m_AlgorithmId = 0;
3249 m_PerSampleIvSize = 0;
25113250 AP4_SetMemory(m_Kid, 0, 16);
25123251 }
25133252
25213260 /*----------------------------------------------------------------------
25223261 | AP4_CencSampleEncryption::AP4_CencSampleEncryption
25233262 +---------------------------------------------------------------------*/
2524 AP4_CencSampleEncryption::AP4_CencSampleEncryption(AP4_Atom& outer, AP4_UI08 iv_size) :
3263 AP4_CencSampleEncryption::AP4_CencSampleEncryption(AP4_Atom& outer,
3264 AP4_UI08 per_sample_iv_size,
3265 AP4_UI08 constant_iv_size,
3266 const AP4_UI08* constant_iv,
3267 AP4_UI08 crypt_byte_block,
3268 AP4_UI08 skip_byte_block) :
25253269 m_Outer(outer),
25263270 m_AlgorithmId(0),
2527 m_IvSize(iv_size),
3271 m_PerSampleIvSize(per_sample_iv_size),
3272 m_ConstantIvSize(constant_iv_size),
3273 m_CryptByteBlock(crypt_byte_block),
3274 m_SkipByteBlock(skip_byte_block),
25283275 m_SampleInfoCount(0),
25293276 m_SampleInfoCursor(0)
25303277 {
3278 AP4_SetMemory(m_ConstantIv, 0, 16);
3279 if (constant_iv_size <= 16 && constant_iv) {
3280 AP4_CopyMemory(m_ConstantIv, constant_iv, m_ConstantIvSize);
3281 }
25313282 AP4_SetMemory(m_Kid, 0, 16);
25323283 }
25333284
25363287 +---------------------------------------------------------------------*/
25373288 AP4_CencSampleEncryption::AP4_CencSampleEncryption(AP4_Atom& outer,
25383289 AP4_UI32 algorithm_id,
2539 AP4_UI08 iv_size,
3290 AP4_UI08 per_sample_iv_size,
25403291 const AP4_UI08* kid) :
25413292 m_Outer(outer),
25423293 m_AlgorithmId(algorithm_id),
2543 m_IvSize(iv_size),
3294 m_PerSampleIvSize(per_sample_iv_size),
3295 m_ConstantIvSize(0),
3296 m_CryptByteBlock(0),
3297 m_SkipByteBlock(0),
25443298 m_SampleInfoCount(0),
25453299 m_SampleInfoCursor(0)
25463300 {
3301 AP4_SetMemory(m_ConstantIv, 0, 16);
25473302 AP4_CopyMemory(m_Kid, kid, 16);
25483303 }
25493304
25543309 AP4_CencSampleEncryption::AddSampleInfo(const AP4_UI08* iv,
25553310 AP4_DataBuffer& subsample_info)
25563311 {
2557 unsigned int added_size = m_IvSize+subsample_info.GetDataSize();
3312 unsigned int added_size = m_PerSampleIvSize+subsample_info.GetDataSize();
25583313
25593314 if (m_SampleInfoCursor+added_size > m_SampleInfos.GetDataSize()) {
25603315 // too much data!
25613316 return AP4_ERROR_OUT_OF_RANGE;
25623317 }
25633318 AP4_UI08* info = m_SampleInfos.UseData()+m_SampleInfoCursor;
2564 AP4_CopyMemory(info, iv, m_IvSize);
3319 if (m_PerSampleIvSize) {
3320 AP4_CopyMemory(info, iv, m_PerSampleIvSize);
3321 }
25653322 if (subsample_info.GetDataSize()) {
2566 AP4_CopyMemory(info+m_IvSize, subsample_info.GetData(), subsample_info.GetDataSize());
3323 AP4_CopyMemory(info+m_PerSampleIvSize, subsample_info.GetData(), subsample_info.GetDataSize());
25673324 }
25683325 m_SampleInfoCursor += added_size;
25693326 ++m_SampleInfoCount;
25983355 | AP4_CencSampleEncryption::CreateSampleInfoTable
25993356 +---------------------------------------------------------------------*/
26003357 AP4_Result
2601 AP4_CencSampleEncryption::CreateSampleInfoTable(AP4_Size default_iv_size,
3358 AP4_CencSampleEncryption::CreateSampleInfoTable(AP4_UI08 flags,
3359 AP4_UI08 default_crypt_byte_block,
3360 AP4_UI08 default_skip_byte_block,
3361 AP4_UI08 default_per_sample_iv_size,
3362 AP4_UI08 default_constant_iv_size,
3363 const AP4_UI08* default_constant_iv,
26023364 AP4_CencSampleInfoTable*& table)
26033365 {
2604 AP4_Size iv_size = default_iv_size;
3366 // default return value
3367 table = NULL;
3368
3369 // check if some values are overridden
3370 AP4_Size per_sample_iv_size = default_per_sample_iv_size;
26053371 if (m_Outer.GetFlags() & AP4_CENC_SAMPLE_ENCRYPTION_FLAG_OVERRIDE_TRACK_ENCRYPTION_DEFAULTS) {
2606 iv_size = m_IvSize;
3372 per_sample_iv_size = m_PerSampleIvSize;
26073373 }
26083374 bool has_subsamples = false;
26093375 if (m_Outer.GetFlags() & AP4_CENC_SAMPLE_ENCRYPTION_FLAG_USE_SUB_SAMPLE_ENCRYPTION) {
26103376 has_subsamples = true;
26113377 }
3378
3379 // check some of the parameters
3380 if (per_sample_iv_size == 0) {
3381 if (default_constant_iv_size == 0 || default_constant_iv == NULL) {
3382 return AP4_ERROR_INVALID_PARAMETERS;
3383 }
3384 }
26123385
26133386 // create the table
26143387 AP4_Result result = AP4_ERROR_INVALID_FORMAT;
2615 table = new AP4_CencSampleInfoTable(m_SampleInfoCount, (AP4_UI08)iv_size);
3388 table = new AP4_CencSampleInfoTable(flags,
3389 default_crypt_byte_block,
3390 default_skip_byte_block,
3391 m_SampleInfoCount,
3392 per_sample_iv_size?per_sample_iv_size:default_constant_iv_size);
26163393 const AP4_UI08* data = m_SampleInfos.GetData();
26173394 AP4_UI32 data_size = m_SampleInfos.GetDataSize();
26183395 for (unsigned int i=0; i<m_SampleInfoCount; i++) {
2619 if (data_size < iv_size) goto end;
2620 table->SetIv(i, data);
2621 data += iv_size;
2622 data_size -= iv_size;
3396 if (per_sample_iv_size) {
3397 if (data_size < per_sample_iv_size) goto end;
3398 table->SetIv(i, data);
3399 data += per_sample_iv_size;
3400 data_size -= per_sample_iv_size;
3401 } else {
3402 table->SetIv(i, default_constant_iv);
3403 }
26233404 if (has_subsamples) {
26243405 if (data_size < 2) goto end;
26253406 AP4_UI16 subsample_count = AP4_BytesToUInt16BE(data);
26533434 {
26543435 if (m_Outer.GetFlags() & AP4_CENC_SAMPLE_ENCRYPTION_FLAG_OVERRIDE_TRACK_ENCRYPTION_DEFAULTS) {
26553436 inspector.AddField("AlgorithmID", m_AlgorithmId);
2656 inspector.AddField("IV_size", m_IvSize);
3437 inspector.AddField("IV_size", m_PerSampleIvSize);
26573438 inspector.AddField("KID", m_Kid, 16);
26583439 }
26593440
26653446
26663447 // since we don't know the IV size necessarily (we don't have the context), we
26673448 // will try to guess the IV size (we'll try 16 and 8)
2668 unsigned int iv_size = m_IvSize;
3449 unsigned int iv_size = m_PerSampleIvSize;
26693450 if (iv_size == 0) {
26703451 if (m_Outer.GetFlags() & AP4_CENC_SAMPLE_ENCRYPTION_FLAG_USE_SUB_SAMPLE_ENCRYPTION) {
26713452 bool data_ok = false;
2672 for (unsigned int k=1; k<=2 && !data_ok; k++) {
3453 for (unsigned int k=0; k<=2 && !data_ok; k++) {
26733454 data_ok = true;
26743455 iv_size = 8*k;
26753456 const AP4_UI08* info = m_SampleInfos.GetData();
27023483 }
27033484 }
27043485 inspector.AddField("IV Size (inferred)", iv_size);
2705
3486
3487 inspector.StartArray("sample info entries", m_SampleInfoCount);
27063488 const AP4_UI08* info = m_SampleInfos.GetData();
27073489 for (unsigned int i=0; i<m_SampleInfoCount; i++) {
2708 char header[64];
2709 AP4_FormatString(header, sizeof(header), "entry %04d", i);
2710 inspector.AddField(header, info, iv_size);
3490 inspector.StartObject(NULL);
3491 inspector.AddField("info", info, iv_size);
27113492 info += iv_size;
27123493 if (m_Outer.GetFlags() & AP4_CENC_SAMPLE_ENCRYPTION_FLAG_USE_SUB_SAMPLE_ENCRYPTION) {
27133494 unsigned int num_entries = AP4_BytesToInt16BE(info);
27143495 info += 2;
3496 inspector.StartArray("sub entries", num_entries);
27153497 for (unsigned int j=0; j<num_entries; j++) {
3498 inspector.StartObject(NULL, 2, true);
27163499 unsigned int bocd = AP4_BytesToUInt16BE(info);
2717 AP4_FormatString(header, sizeof(header), "sub-entry %04d.%d bytes of clear data", i, j);
2718 inspector.AddField(header, bocd);
3500 inspector.AddField("bytes_of_clear_data", bocd);
27193501 unsigned int boed = AP4_BytesToUInt32BE(info+2);
2720 AP4_FormatString(header, sizeof(header), "sub-entry %04d.%d bytes of encrypted data", i, j);
2721 inspector.AddField(header, boed);
3502 inspector.AddField("bytes_of_encrypted_data", boed);
27223503 info += 6;
2723 }
2724 }
2725 }
3504 inspector.EndObject();
3505 }
3506 inspector.EndArray();
3507 }
3508 inspector.EndObject();
3509 }
3510 inspector.EndArray();
27263511
27273512 return AP4_SUCCESS;
27283513 }
27393524 if (m_Outer.GetFlags() & AP4_CENC_SAMPLE_ENCRYPTION_FLAG_OVERRIDE_TRACK_ENCRYPTION_DEFAULTS) {
27403525 result = stream.WriteUI24(m_AlgorithmId);
27413526 if (AP4_FAILED(result)) return result;
2742 result = stream.WriteUI08(m_IvSize);
3527 result = stream.WriteUI08(m_PerSampleIvSize);
27433528 if (AP4_FAILED(result)) return result;
27443529 result = stream.Write(m_Kid, 16);
27453530 if (AP4_FAILED(result)) return result;
11 |
22 | AP4 - Common Encryption support
33 |
4 | Copyright 2002-2011 Axiomatic Systems, LLC
4 | Copyright 2002-2017 Axiomatic Systems, LLC
55 |
66 |
77 | This file is part of Bento4/AP4 (MP4 Atom Processing Library).
4545 class AP4_SaizAtom;
4646 class AP4_SaioAtom;
4747 class AP4_CencSampleInfoTable;
48 class AP4_AvcFrameParser;
49 class AP4_HevcFrameParser;
4850 class AP4_CencSingleSampleDecrypter;
4951
5052 /*----------------------------------------------------------------------
5153 | constants
5254 +---------------------------------------------------------------------*/
5355 const AP4_UI32 AP4_PROTECTION_SCHEME_TYPE_CENC = AP4_ATOM_TYPE('c','e','n','c');
56 const AP4_UI32 AP4_PROTECTION_SCHEME_TYPE_CENS = AP4_ATOM_TYPE('c','e','n','s');
57 const AP4_UI32 AP4_PROTECTION_SCHEME_TYPE_CBC1 = AP4_ATOM_TYPE('c','b','c','1');
58 const AP4_UI32 AP4_PROTECTION_SCHEME_TYPE_CBCS = AP4_ATOM_TYPE('c','b','c','s');
5459 const AP4_UI32 AP4_PROTECTION_SCHEME_VERSION_CENC_10 = 0x00010000;
5560
56 const AP4_UI32 AP4_CENC_ALGORITHM_ID_NONE = 0;
57 const AP4_UI32 AP4_CENC_ALGORITHM_ID_CTR = 1;
58 const AP4_UI32 AP4_CENC_ALGORITHM_ID_CBC = 2;
61 const AP4_UI32 AP4_CENC_CIPHER_NONE = 0;
62 const AP4_UI32 AP4_CENC_CIPHER_AES_128_CTR = 1;
63 const AP4_UI32 AP4_CENC_CIPHER_AES_128_CBC = 2;
5964
6065 const AP4_UI32 AP4_CENC_SAMPLE_ENCRYPTION_FLAG_OVERRIDE_TRACK_ENCRYPTION_DEFAULTS = 1;
6166 const AP4_UI32 AP4_CENC_SAMPLE_ENCRYPTION_FLAG_USE_SUB_SAMPLE_ENCRYPTION = 2;
6368 typedef enum {
6469 AP4_CENC_VARIANT_PIFF_CTR,
6570 AP4_CENC_VARIANT_PIFF_CBC,
66 AP4_CENC_VARIANT_MPEG
71 AP4_CENC_VARIANT_MPEG_CENC,
72 AP4_CENC_VARIANT_MPEG_CBC1,
73 AP4_CENC_VARIANT_MPEG_CENS,
74 AP4_CENC_VARIANT_MPEG_CBCS
6775 } AP4_CencVariant;
6876
6977 /*----------------------------------------------------------------------
7684 virtual ~AP4_CencTrackEncryption() {}
7785
7886 // methods
87 AP4_Result Parse(AP4_ByteStream& stream);
7988 AP4_Result DoInspectFields(AP4_AtomInspector& inspector);
8089 AP4_Result DoWriteFields(AP4_ByteStream& stream);
8190
8291 // accessors
83 AP4_UI32 GetDefaultAlgorithmId() { return m_DefaultAlgorithmId; }
84 AP4_UI08 GetDefaultIvSize() { return m_DefaultIvSize; }
85 const AP4_UI08* GetDefaultKid() { return m_DefaultKid; }
92 AP4_UI32 GetDefaultIsProtected() { return m_DefaultIsProtected; }
93 AP4_UI08 GetDefaultPerSampleIvSize() { return m_DefaultPerSampleIvSize; }
94 AP4_UI08 GetDefaultConstantIvSize() { return m_DefaultConstantIvSize; }
95 const AP4_UI08* GetDefaultConstantIv() { return m_DefaultConstantIv; }
96 const AP4_UI08* GetDefaultKid() { return m_DefaultKid; }
97 AP4_UI08 GetDefaultCryptByteBlock() { return m_DefaultCryptByteBlock; }
98 AP4_UI08 GetDefaultSkipByteBlock() { return m_DefaultSkipByteBlock; }
8699
87100 protected:
88101 // constructors
89 AP4_CencTrackEncryption();
90 AP4_CencTrackEncryption(AP4_ByteStream& stream);
91 AP4_CencTrackEncryption(AP4_UI32 default_algorithm_id,
92 AP4_UI08 default_iv_size,
93 const AP4_UI08* default_kid);
102 AP4_CencTrackEncryption(AP4_UI08 version);
103 AP4_CencTrackEncryption(AP4_UI08 version,
104 AP4_UI08 default_is_protected,
105 AP4_UI08 default_per_sample_iv_size,
106 const AP4_UI08* default_kid,
107 AP4_UI08 default_constant_iv_size = 0,
108 const AP4_UI08* default_constant_iv = NULL,
109 AP4_UI08 default_crypt_byte_block = 0,
110 AP4_UI08 default_skip_byte_block = 0);
94111
95112 private:
96113 // members
97 AP4_UI32 m_DefaultAlgorithmId;
98 AP4_UI08 m_DefaultIvSize;
99 AP4_UI08 m_DefaultKid[16];
114 AP4_UI08 m_Version_; // cannot be called m_Version because it would conflict with AP4_Atom::m_Version
115 AP4_UI08 m_DefaultIsProtected;
116 AP4_UI08 m_DefaultPerSampleIvSize;
117 AP4_UI08 m_DefaultConstantIvSize;
118 AP4_UI08 m_DefaultConstantIv[16];
119 AP4_UI08 m_DefaultKid[16];
120 AP4_UI08 m_DefaultCryptByteBlock;
121 AP4_UI08 m_DefaultSkipByteBlock;
100122 };
101123
102124 /*----------------------------------------------------------------------
115137 // accessors
116138 AP4_Atom& GetOuter() { return m_Outer; }
117139 AP4_UI32 GetAlgorithmId() { return m_AlgorithmId; }
118 AP4_UI08 GetIvSize() { return m_IvSize; }
119 AP4_Result SetIvSize(AP4_UI08 iv_size);
140 AP4_UI08 GetPerSampleIvSize() { return m_PerSampleIvSize; }
141 AP4_Result SetPerSampleIvSize(AP4_UI08 iv_size);
142 AP4_UI08 GetConstantIvSize() { return m_ConstantIvSize; }
143 AP4_Result SetConstantIvSize(AP4_UI08 iv_size);
144 AP4_UI08 GetCryptByteBlock() { return m_CryptByteBlock; }
145 AP4_UI08 GetSkipByteBlock() { return m_SkipByteBlock; }
146 const AP4_UI08* GetConstantIv() { return m_ConstantIv; }
120147 const AP4_UI08* GetKid() { return m_Kid; }
121148 AP4_Cardinal GetSampleInfoCount() { return m_SampleInfoCount; }
122149 AP4_Result AddSampleInfo(const AP4_UI08* iv, AP4_DataBuffer& subsample_info);
123150 AP4_Result SetSampleInfosSize(AP4_Size size);
124 AP4_Result CreateSampleInfoTable(AP4_Size default_iv_size,
151 AP4_Result CreateSampleInfoTable(AP4_UI08 flags,
152 AP4_UI08 default_crypt_byte_block,
153 AP4_UI08 default_skip_byte_block,
154 AP4_UI08 default_per_sample_iv_size,
155 AP4_UI08 default_constant_iv_size,
156 const AP4_UI08* default_constant_iv,
125157 AP4_CencSampleInfoTable*& table);
126158
127159 protected:
128160 // constructors
129 AP4_CencSampleEncryption(AP4_Atom& outer, AP4_UI08 iv_size);
161 AP4_CencSampleEncryption(AP4_Atom& outer,
162 AP4_UI08 per_sample_iv_size,
163 AP4_UI08 constant_iv_size = 0,
164 const AP4_UI08* constant_iv = NULL,
165 AP4_UI08 crypt_byte_block = 0,
166 AP4_UI08 skip_byte_block = 0);
130167 AP4_CencSampleEncryption(AP4_Atom& outer, AP4_Size size, AP4_ByteStream& stream);
131168 AP4_CencSampleEncryption(AP4_Atom& outer,
132169 AP4_UI32 algorithm_id,
133 AP4_UI08 iv_size,
170 AP4_UI08 per_sample_iv_size,
134171 const AP4_UI08* kid);
135172
136173 protected:
137174 // members
138175 AP4_Atom& m_Outer;
139176 AP4_UI32 m_AlgorithmId;
140 AP4_UI08 m_IvSize;
177 AP4_UI08 m_PerSampleIvSize;
178 AP4_UI08 m_ConstantIvSize;
179 AP4_UI08 m_ConstantIv[16];
180 AP4_UI08 m_CryptByteBlock;
181 AP4_UI08 m_SkipByteBlock;
141182 AP4_UI08 m_Kid[16];
142183 AP4_Cardinal m_SampleInfoCount;
143184 AP4_DataBuffer m_SampleInfos;
152193 // class methods
153194 static AP4_Result Create(AP4_ProtectedSampleDescription* sample_description,
154195 AP4_ContainerAtom* traf,
155 AP4_UI32& algorithm_id,
196 AP4_UI32& cipher_type,
197 bool& reset_iv_at_each_subsample,
156198 AP4_ByteStream& aux_info_data,
157199 AP4_Position aux_info_data_offset,
158200 AP4_CencSampleInfoTable*& sample_info_table);
162204 AP4_SaioAtom*& saio,
163205 AP4_SaizAtom*& saiz,
164206 AP4_CencSampleEncryption*& sample_encryption_atom,
165 AP4_UI32& algorithm_id,
207 AP4_UI32& cipher_type,
208 bool& reset_iv_at_each_subsample,
166209 AP4_ByteStream& aux_info_data,
167210 AP4_Position aux_info_data_offset,
168211 AP4_CencSampleInfoTable*& sample_info_table);
169212
170 static AP4_Result Create(unsigned int iv_size,
213 static AP4_Result Create(AP4_UI08 flags,
214 AP4_UI08 crypt_byte_block,
215 AP4_UI08 skip_byte_block,
216 AP4_UI08 per_sample_iv_size,
217 AP4_UI08 constant_iv_size,
218 const AP4_UI08* constant_iv,
171219 AP4_ContainerAtom& traf,
172220 AP4_SaioAtom& saio,
173221 AP4_SaizAtom& saiz,
182230 AP4_CencSampleInfoTable*& sample_info_table);
183231
184232 // constructor
185 AP4_CencSampleInfoTable(AP4_UI32 sample_count,
233 AP4_CencSampleInfoTable(AP4_UI08 flags,
234 AP4_UI08 crypt_byte_block,
235 AP4_UI08 skip_byte_block,
236 AP4_UI32 sample_count,
186237 AP4_UI08 iv_size);
187238
188239 // methods
189 AP4_UI32 GetSampleCount() { return m_SampleCount; }
190 AP4_UI08 GetIvSize() { return m_IvSize; }
240 AP4_UI08 GetFlags() { return m_Flags; }
241 AP4_UI08 GetCryptByteBlock() { return m_CryptByteBlock; }
242 AP4_UI08 GetSkipByteBlock() { return m_SkipByteBlock; }
243 AP4_UI32 GetSampleCount() { return m_SampleCount; }
244 AP4_UI08 GetIvSize() { return m_IvSize; }
191245 AP4_Result SetIv(AP4_Ordinal sample_index, const AP4_UI08* iv);
192246 const AP4_UI08* GetIv(AP4_Ordinal sample_index);
193247 AP4_Result AddSubSampleData(AP4_Cardinal subsample_count,
217271
218272 private:
219273 AP4_UI32 m_SampleCount;
274 AP4_UI08 m_Flags;
275 AP4_UI08 m_CryptByteBlock;
276 AP4_UI08 m_SkipByteBlock;
220277 AP4_UI08 m_IvSize;
221278 AP4_DataBuffer m_IvData;
222279 AP4_Array<AP4_UI16> m_BytesOfCleartextData;
237294 | +---------------+----------------+------------------------------------+
238295 | | 4 bytes | 32-bit integer | sample_count |
239296 | +---------------+----------------+------------------------------------+
240 | | 4 bytes | 32-bit integer | iv_size |
297 | | 1 byte | 8-bit integer | flags |
298 | +---------------+----------------+------------------------------------+
299 | | 1 byte | 8-bit integer | crypt_byte_block |
300 | +---------------+----------------+------------------------------------+
301 | | 1 byte | 8-bit integer | skip_byte_block |
302 | +---------------+----------------+------------------------------------+
303 | | 1 byte | 8-bit integer | iv_size |
241304 | +---------------+----------------+------------------------------------+
242305 |
243306 | repeat sample_count times:
273336 | | 4 bytes | 32-bit integer | subsample_map_length[i] |
274337 | +---------------+----------------+------------------------------------+
275338 |
276 | NOTES: subsample_map_start[i] ans subsample_map_length[i] are, respecitvely,
339 | NOTES: subsample_map_start[i] ans subsample_map_length[i] are, respectively,
277340 | the index and the length the i'th subsample map sequence in the
278341 | bytes_of_cleartext_data anb bytes_of_encrypted_data arrays.
279342 | For example, if we have:
296359 {
297360 public:
298361 // constructor and destructor
299 AP4_CencSampleEncrypter(AP4_StreamCipher* cipher) : m_Cipher(cipher) {
300 AP4_SetMemory(m_Iv, 0, 16);
362 AP4_CencSampleEncrypter(AP4_StreamCipher* cipher,
363 bool constant_iv) :
364 m_Cipher(cipher),
365 m_ConstantIv(constant_iv) {
366 AP4_SetMemory(m_Iv, 0, 16);
301367 };
302368 virtual ~AP4_CencSampleEncrypter();
303369
318384 protected:
319385 AP4_UI08 m_Iv[16];
320386 AP4_StreamCipher* m_Cipher;
387 bool m_ConstantIv;
321388 };
322389
323390 /*----------------------------------------------------------------------
327394 {
328395 public:
329396 // constructor and destructor
330 AP4_CencCtrSampleEncrypter(AP4_StreamCipher* cipher, unsigned int iv_size) :
331 AP4_CencSampleEncrypter(cipher),
397 AP4_CencCtrSampleEncrypter(AP4_StreamCipher* cipher,
398 bool constant_iv,
399 unsigned int iv_size) :
400 AP4_CencSampleEncrypter(cipher, constant_iv),
332401 m_IvSize(iv_size) {}
333402
334403 // methods
347416 {
348417 public:
349418 // constructor and destructor
350 AP4_CencCbcSampleEncrypter(AP4_StreamCipher* cipher) :
351 AP4_CencSampleEncrypter(cipher) {}
419 AP4_CencCbcSampleEncrypter(AP4_StreamCipher* cipher,
420 bool constant_iv) :
421 AP4_CencSampleEncrypter(cipher, constant_iv) {}
352422
353423 // methods
354424 virtual AP4_Result EncryptSampleData(AP4_DataBuffer& data_in,
357427 };
358428
359429 /*----------------------------------------------------------------------
360 | AP4_CencSubSampleEncrypter
361 +---------------------------------------------------------------------*/
362 class AP4_CencSubSampleEncrypter : public AP4_CencSampleEncrypter
363 {
364 public:
365 // constructor and destructor
366 AP4_CencSubSampleEncrypter(AP4_StreamCipher* cipher,
367 AP4_Size nalu_length_size,
368 AP4_UI32 format) :
369 AP4_CencSampleEncrypter(cipher),
430 | AP4_CencSubSampleMapper
431 +---------------------------------------------------------------------*/
432 class AP4_CencSubSampleMapper
433 {
434 public:
435 // constructor and destructor
436 AP4_CencSubSampleMapper(AP4_Size nalu_length_size, AP4_UI32 format) :
370437 m_NaluLengthSize(nalu_length_size),
371438 m_Format(format) {}
372
373 // methods
374 virtual bool UseSubSamples() { return true;}
375
439 virtual ~AP4_CencSubSampleMapper() {}
440
441 // methods
442 virtual AP4_Result GetSubSampleMap(AP4_DataBuffer& sample_data,
443 AP4_Array<AP4_UI16>& bytes_of_cleartext_data,
444 AP4_Array<AP4_UI32>& bytes_of_encrypted_data) = 0;
445
446 protected:
376447 // members
377448 AP4_Size m_NaluLengthSize;
378449 AP4_UI32 m_Format;
379450 };
380451
381452 /*----------------------------------------------------------------------
382 | AP4_CencCtrSubSampleEncrypter
383 +---------------------------------------------------------------------*/
384 class AP4_CencCtrSubSampleEncrypter : public AP4_CencSubSampleEncrypter
385 {
386 public:
387 // constructor and destructor
388 AP4_CencCtrSubSampleEncrypter(AP4_StreamCipher* cipher,
389 AP4_Size nalu_length_size,
390 unsigned int iv_size,
391 AP4_UI32 format) :
392 AP4_CencSubSampleEncrypter(cipher, nalu_length_size, format),
393 m_IvSize(iv_size) {}
394
395 // methods
396 virtual AP4_Result GetSubSampleMap(AP4_DataBuffer& sample_data,
453 | AP4_CencBasicSubSampleMapper
454 +---------------------------------------------------------------------*/
455 class AP4_CencBasicSubSampleMapper : public AP4_CencSubSampleMapper
456 {
457 public:
458 // constructor and destructor
459 AP4_CencBasicSubSampleMapper(AP4_Size nalu_length_size, AP4_UI32 format) :
460 AP4_CencSubSampleMapper(nalu_length_size, format) {}
461
462 // methods
463 virtual AP4_Result GetSubSampleMap(AP4_DataBuffer& sample_data,
397464 AP4_Array<AP4_UI16>& bytes_of_cleartext_data,
398465 AP4_Array<AP4_UI32>& bytes_of_encrypted_data);
466 };
467
468 /*----------------------------------------------------------------------
469 | AP4_CencAdvancedSubSampleMapper
470 +---------------------------------------------------------------------*/
471 class AP4_CencAdvancedSubSampleMapper : public AP4_CencSubSampleMapper
472 {
473 public:
474 // constructor and destructor
475 AP4_CencAdvancedSubSampleMapper(AP4_Size nalu_length_size, AP4_UI32 format) :
476 AP4_CencSubSampleMapper(nalu_length_size, format) {}
477
478 // methods
479 virtual AP4_Result GetSubSampleMap(AP4_DataBuffer& sample_data,
480 AP4_Array<AP4_UI16>& bytes_of_cleartext_data,
481 AP4_Array<AP4_UI32>& bytes_of_encrypted_data);
482 };
483
484 /*----------------------------------------------------------------------
485 | AP4_CencCbcsSubSampleMapper
486 +---------------------------------------------------------------------*/
487 class AP4_CencCbcsSubSampleMapper : public AP4_CencSubSampleMapper
488 {
489 public:
490 // constructor and destructor
491 AP4_CencCbcsSubSampleMapper(AP4_Size nalu_length_size, AP4_UI32 format, AP4_TrakAtom* trak);
492 ~AP4_CencCbcsSubSampleMapper();
493
494 // methods
495 virtual AP4_Result GetSubSampleMap(AP4_DataBuffer& sample_data,
496 AP4_Array<AP4_UI16>& bytes_of_cleartext_data,
497 AP4_Array<AP4_UI32>& bytes_of_encrypted_data);
498
499 private:
500 // members
501 AP4_AvcFrameParser* m_AvcParser;
502 AP4_HevcFrameParser* m_HevcParser;
503
504 // methods
505 AP4_Result ParseAvcData(const AP4_UI08* data, AP4_Size data_size);
506 AP4_Result ParseHevcData(const AP4_UI08* data, AP4_Size data_size);
507 };
508
509 /*----------------------------------------------------------------------
510 | AP4_CencSubSampleEncrypter
511 +---------------------------------------------------------------------*/
512 class AP4_CencSubSampleEncrypter : public AP4_CencSampleEncrypter
513 {
514 public:
515 // constructor and destructor
516 AP4_CencSubSampleEncrypter(AP4_StreamCipher* cipher,
517 bool constant_iv,
518 bool reset_iv_at_each_subsample,
519 AP4_CencSubSampleMapper* subsample_mapper) :
520 AP4_CencSampleEncrypter(cipher, constant_iv),
521 m_ResetIvForEachSubsample(reset_iv_at_each_subsample),
522 m_SubSampleMapper(subsample_mapper) {}
523 virtual ~AP4_CencSubSampleEncrypter() {
524 delete m_SubSampleMapper;
525 }
526
527 // methods
528 virtual bool UseSubSamples() { return true; }
529 virtual AP4_Result GetSubSampleMap(AP4_DataBuffer& sample_data,
530 AP4_Array<AP4_UI16>& bytes_of_cleartext_data,
531 AP4_Array<AP4_UI32>& bytes_of_encrypted_data) {
532 return m_SubSampleMapper->GetSubSampleMap(sample_data, bytes_of_cleartext_data, bytes_of_encrypted_data);
533 }
534
535 // members
536 bool m_ResetIvForEachSubsample;
537 AP4_CencSubSampleMapper* m_SubSampleMapper;
538 };
539
540 /*----------------------------------------------------------------------
541 | AP4_CencCtrSubSampleEncrypter
542 +---------------------------------------------------------------------*/
543 class AP4_CencCtrSubSampleEncrypter : public AP4_CencSubSampleEncrypter
544 {
545 public:
546 // constructor and destructor
547 AP4_CencCtrSubSampleEncrypter(AP4_StreamCipher* cipher,
548 bool constant_iv,
549 bool reset_iv_at_each_subsample,
550 unsigned int iv_size,
551 AP4_CencSubSampleMapper* subsample_mapper) :
552 AP4_CencSubSampleEncrypter(cipher,
553 constant_iv,
554 reset_iv_at_each_subsample,
555 subsample_mapper),
556 m_IvSize(iv_size) {}
557
558 // methods
399559 virtual AP4_Result EncryptSampleData(AP4_DataBuffer& data_in,
400560 AP4_DataBuffer& data_out,
401561 AP4_DataBuffer& sample_infos);
411571 {
412572 public:
413573 // constructor and destructor
414 AP4_CencCbcSubSampleEncrypter(AP4_StreamCipher* cipher,
415 AP4_Size nalu_length_size,
416 AP4_UI32 format) :
417 AP4_CencSubSampleEncrypter(cipher, nalu_length_size, format) {}
418
419 // methods
420 virtual AP4_Result GetSubSampleMap(AP4_DataBuffer& sample_data,
421 AP4_Array<AP4_UI16>& bytes_of_cleartext_data,
422 AP4_Array<AP4_UI32>& bytes_of_encrypted_data);
574 AP4_CencCbcSubSampleEncrypter(AP4_StreamCipher* cipher,
575 bool constant_iv,
576 bool reset_iv_at_each_subsample,
577 AP4_CencSubSampleMapper* subsample_mapper) :
578 AP4_CencSubSampleEncrypter(cipher,
579 constant_iv,
580 reset_iv_at_each_subsample,
581 subsample_mapper) {}
582
583 // methods
423584 virtual AP4_Result EncryptSampleData(AP4_DataBuffer& data_in,
424585 AP4_DataBuffer& data_out,
425586 AP4_DataBuffer& sample_infos);
431592 class AP4_CencEncryptingProcessor : public AP4_Processor
432593 {
433594 public:
595 // class constants
596 static const AP4_UI32 OPTION_EME_PSSH = 0x01; ///< Include a 'standard EME' pssh atom in the output
597 static const AP4_UI32 OPTION_PIFF_COMPATIBILITY = 0x02; ///< Attempt to create an output that is compatible with the PIFF format
598 static const AP4_UI32 OPTION_PIFF_IV_SIZE_16 = 0x04; ///< With the PIFF-compatibiity option, use an IV of size 16 when possible (instead of 8)
599 static const AP4_UI32 OPTION_IV_SIZE_8 = 0x08; ///< Use an IV of size 8 when possible (instead of 16 by default).
600 static const AP4_UI32 OPTION_NO_SENC = 0x10; ///< Don't output an 'senc' atom
601
434602 // types
435603 struct Encrypter {
436604 Encrypter(AP4_UI32 track_id, AP4_UI32 cleartext_fragments, AP4_CencSampleEncrypter* sample_encrypter) :
447615
448616 // constructor
449617 AP4_CencEncryptingProcessor(AP4_CencVariant variant,
618 AP4_UI32 options = 0,
450619 AP4_BlockCipherFactory* block_cipher_factory = NULL);
451620 ~AP4_CencEncryptingProcessor();
452621
459628 virtual AP4_Result Initialize(AP4_AtomParent& top_level,
460629 AP4_ByteStream& stream,
461630 AP4_Processor::ProgressListener* listener = NULL);
462 virtual AP4_Processor::TrackHandler* CreateTrackHandler(AP4_TrakAtom* trak, AP4_TrexAtom* trex);
631 virtual AP4_Processor::TrackHandler* CreateTrackHandler(AP4_TrakAtom* trak);
463632 virtual AP4_Processor::FragmentHandler* CreateFragmentHandler(AP4_TrakAtom* trak,
464633 AP4_TrexAtom* trex,
465634 AP4_ContainerAtom* traf,
469638 protected:
470639 // members
471640 AP4_CencVariant m_Variant;
641 AP4_UI32 m_Options;
472642 AP4_BlockCipherFactory* m_BlockCipherFactory;
473643 AP4_ProtectionKeyMap m_KeyMap;
474644 AP4_TrackPropertyMap m_PropertyMap;
485655 // constructor
486656 AP4_CencDecryptingProcessor(const AP4_ProtectionKeyMap* key_map,
487657 AP4_BlockCipherFactory* block_cipher_factory = NULL,
488 AP4_CencSingleSampleDecrypter *cenc_singlesample_decrypter = NULL);
658 AP4_CencSingleSampleDecrypter* cenc_singlesample_decrypter = NULL);
489659
490660 // AP4_Processor methods
491 virtual AP4_Processor::TrackHandler* CreateTrackHandler(AP4_TrakAtom* trak, AP4_TrexAtom* trex);
661 virtual AP4_Processor::TrackHandler* CreateTrackHandler(AP4_TrakAtom* trak);
492662 virtual AP4_Processor::FragmentHandler* CreateFragmentHandler(AP4_TrakAtom* trak,
493663 AP4_TrexAtom* trex,
494664 AP4_ContainerAtom* traf,
495665 AP4_ByteStream& moof_data,
496666 AP4_Position moof_offset);
497667
498 protected:
668 protected:
669 // methods
670 const AP4_DataBuffer* GetKeyForTrak(AP4_UI32 track_id, AP4_ProtectedSampleDescription* sample_description);
671
499672 // members
500673 AP4_BlockCipherFactory* m_BlockCipherFactory;
501 AP4_CencSingleSampleDecrypter* m_CencSingleSampleDecrypter;
674 AP4_CencSingleSampleDecrypter* m_CencSingleSampleDecrypter;
502675 const AP4_ProtectionKeyMap* m_KeyMap;
503676 };
504677
508681 class AP4_CencSingleSampleDecrypter
509682 {
510683 public:
511 static AP4_Result Create(AP4_UI32 algorithm_id,
684 static AP4_Result Create(AP4_UI32 cipher_type,
512685 const AP4_UI08* key,
513686 AP4_Size key_size,
687 AP4_UI08 crypt_byte_block,
688 AP4_UI08 skip_byte_block,
514689 AP4_BlockCipherFactory* block_cipher_factory,
690 bool reset_iv_at_each_subsample,
515691 AP4_CencSingleSampleDecrypter*& decrypter);
516692
517693 // methods
518 AP4_CencSingleSampleDecrypter(AP4_StreamCipher* cipher) : m_Cipher(cipher), m_FullBlocksOnly(false), m_ParentIsOwner(true){}
519 virtual ~AP4_CencSingleSampleDecrypter();
694 AP4_CencSingleSampleDecrypter(AP4_StreamCipher* cipher) :
695 m_Cipher(cipher),
696 m_FullBlocksOnly(false),
697 m_ParentIsOwner(true) {}
698 virtual ~AP4_CencSingleSampleDecrypter();
520699 virtual AP4_Result SetFragmentInfo(AP4_UI32 poolid, const AP4_UI08* keyid, const AP4_UI08 nalu_length_size,
521 AP4_DataBuffer &annexb_sps_pps, AP4_UI32 flags) { return AP4_ERROR_NOT_SUPPORTED; };
700 AP4_DataBuffer &annexb_sps_pps, AP4_UI32 flags) {
701 return AP4_ERROR_NOT_SUPPORTED;
702 };
522703 virtual AP4_UI32 AddPool() { return 0; };
523704 virtual void RemovePool(AP4_UI32 poolid) {};
524 virtual const char* GetSessionId() { return NULL; };
525
705 virtual const char* GetSessionId() { return nullptr; };
526706 virtual AP4_Result DecryptSampleData(AP4_UI32 poolid,
527707 AP4_DataBuffer& data_in,
528708 AP4_DataBuffer& data_out,
539719 // array of <subsample_count> integers. NULL if subsample_count is 0
540720 const AP4_UI32* bytes_of_encrypted_data);
541721 bool GetParentIsOwner()const { return m_ParentIsOwner; };
542 void SetParentIsOwner(bool parent_is_owner){ m_ParentIsOwner = parent_is_owner; };
543
722 void SetParentIsOwner(bool parent_is_owner) { m_ParentIsOwner = parent_is_owner; };
723
544724 private:
545725 // constructor
546 AP4_CencSingleSampleDecrypter(AP4_StreamCipher* cipher, bool full_blocks_only) :
726 AP4_CencSingleSampleDecrypter(AP4_StreamCipher* cipher,
727 bool full_blocks_only,
728 bool reset_iv_at_each_subsample) :
547729 m_Cipher(cipher),
548730 m_FullBlocksOnly(full_blocks_only),
549 m_ParentIsOwner(true){ }
731 m_ResetIvAtEachSubsample(reset_iv_at_each_subsample),
732 m_ParentIsOwner(true) {}
550733
551734 // members
552735 AP4_StreamCipher* m_Cipher;
553736 bool m_FullBlocksOnly;
554 bool m_ParentIsOwner;
737 bool m_ResetIvAtEachSubsample;
738 bool m_ParentIsOwner;
555739 };
556740
557741 /*----------------------------------------------------------------------
570754 AP4_SaioAtom*& saio_atom, // [out]
571755 AP4_SaizAtom*& saiz_atom, // [out]
572756 AP4_CencSampleEncryption*& sample_encryption_atom, // [out]
573 AP4_CencSingleSampleDecrypter *singlesample_decrypter,
574 AP4_CencSampleDecrypter*& decrypter);
757 AP4_CencSingleSampleDecrypter* singlesample_decrypter,
758 AP4_CencSampleDecrypter*& decrypter);
575759
576760 static AP4_Result Create(AP4_ProtectedSampleDescription* sample_description,
577761 AP4_ContainerAtom* traf,
580764 const AP4_UI08* key,
581765 AP4_Size key_size,
582766 AP4_BlockCipherFactory* block_cipher_factory,
583 AP4_CencSingleSampleDecrypter *singlesample_decrypter,
767 AP4_CencSingleSampleDecrypter* singlesample_decrypter,
584768 AP4_CencSampleDecrypter*& decrypter);
585769
586770 static AP4_Result Create(AP4_CencSampleInfoTable* sample_info_table,
587 AP4_UI32 algorithm_id,
771 AP4_UI32 cipher_type,
588772 const AP4_UI08* key,
589773 AP4_Size key_size,
590774 AP4_BlockCipherFactory* block_cipher_factory,
591 AP4_CencSingleSampleDecrypter *singlesample_decrypter,
592 AP4_CencSampleDecrypter*& decrypter);
775 bool reset_iv_at_each_subsample,
776 AP4_CencSingleSampleDecrypter* singlesample_decrypter,
777 AP4_CencSampleDecrypter*& decrypter);
593778
594779 // methods
595780 AP4_CencSampleDecrypter(AP4_CencSingleSampleDecrypter* single_sample_decrypter,
599784 m_SampleCursor(0) {}
600785 virtual ~AP4_CencSampleDecrypter();
601786 virtual AP4_Result SetSampleIndex(AP4_Ordinal sample_index);
602 virtual AP4_Result DecryptSampleData(AP4_UI32 poolid, AP4_DataBuffer& data_in,
603 AP4_DataBuffer& data_out,
604 const AP4_UI08* iv);
787 virtual AP4_Result DecryptSampleData(AP4_UI32 poolid,
788 AP4_DataBuffer& data_in,
789 AP4_DataBuffer& data_out,
790 const AP4_UI08* iv);
791
605792 protected:
606793 AP4_CencSingleSampleDecrypter* m_SingleSampleDecrypter;
607794 AP4_CencSampleInfoTable* m_SampleInfoTable;
5151 #if !defined(AP4_PLATFORM_BYTE_ORDER)
5252 #if defined(__ppc__)
5353 #define AP4_PLATFORM_BYTE_ORDER AP4_PLATFORM_BYTE_ORDER_BIG_ENDIAN
54 #elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__arm64__)
54 #elif defined(_MSC_VER)
55 #if defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM) || defined(_M_ARM64)
56 #define AP4_PLATFORM_BYTE_ORDER AP4_PLATFORM_BYTE_ORDER_LITTLE_ENDIAN
57 #endif
58 #elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
5559 #define AP4_PLATFORM_BYTE_ORDER AP4_PLATFORM_BYTE_ORDER_LITTLE_ENDIAN
5660 #endif
5761 #endif
9498 #define AP4_ftell ftell
9599 #endif
96100
101 /* MinGW-w64 */
102 #if defined(__MINGW32__) || defined (__MINGW64__)
103 #define AP4_CONFIG_HAVE_FOPEN_S
104 #endif
105
97106 /* Symbian */
98107 #if defined(__SYMBIAN32__)
99108 #undef APT_CONFIG_HAVE_NEW_H
110119
111120 /* Android */
112121 #if defined(ANDROID)
122 #if !defined(AP4_CONFIG_NO_RTTI)
113123 #define AP4_CONFIG_NO_RTTI
124 #endif
125 #if !defined(AP4_CONFIG_NO_EXCEPTIONS)
114126 #define AP4_CONFIG_NO_EXCEPTIONS
127 #endif
115128 #endif
116129
117130 /* Emscripten */
5353 if (is_full) {
5454 AP4_UI08 version;
5555 AP4_UI32 flags;
56 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
5657 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
5758
5859 // special case for 'meta' atoms, because Apple sometimes creates them as
9292 void ReadChildren(AP4_AtomFactory& atom_factory,
9393 AP4_ByteStream& stream,
9494 AP4_UI64 size);
95 // For temporary use, will not be serialized
96 AP4_UI64 value64;
97 AP4_UI64 value32;
9895 };
9996
10097 #endif // _AP4_CONTAINER_ATOM_H_
4545 {
4646 AP4_UI08 version;
4747 AP4_UI32 flags;
48 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4849 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4950 if (version > 1) return NULL;
5051 return new AP4_CttsAtom(size, version, flags, stream);
7273 m_LookupCache.sample = 0;
7374 m_LookupCache.entry_index = 0;
7475
76 if (size < AP4_FULL_ATOM_HEADER_SIZE + 4) {
77 return;
78 }
79
80 // read the number of entries
7581 AP4_UI32 entry_count;
7682 stream.ReadUI32(entry_count);
83
84 // check that there's enough data
85 if (((size - AP4_FULL_ATOM_HEADER_SIZE - 4) / 8) < entry_count) {
86 return;
87 }
88
89 // read the entries
7790 m_Entries.SetItemCount(entry_count);
7891 unsigned char* buffer = new unsigned char[entry_count*8];
7992 AP4_Result result = stream.Read(buffer, entry_count*8);
195208 inspector.AddField("entry_count", m_Entries.ItemCount());
196209
197210 if (inspector.GetVerbosity() >= 2) {
198 char header[32];
199 char value[64];
211 inspector.StartArray("entries", m_Entries.ItemCount());
200212 for (AP4_Ordinal i=0; i<m_Entries.ItemCount(); i++) {
201 AP4_FormatString(header, sizeof(header), "entry %8d", i);
202 AP4_FormatString(value, sizeof(value), "count=%d, offset=%d",
203 m_Entries[i].m_SampleCount,
204 m_Entries[i].m_SampleOffset);
205 inspector.AddField(header, value);
213 inspector.StartObject(NULL, 2, true);
214 inspector.AddField("count", m_Entries[i].m_SampleCount);
215 inspector.AddField("offset", m_Entries[i].m_SampleOffset);
216 inspector.EndObject();
206217 }
218 inspector.EndArray();
207219 }
208220
209221 return AP4_SUCCESS;
00 /*****************************************************************
11 |
2 | AP4 - dec3 Atoms
2 | AP4 - dac3 Atoms
33 |
4 | Copyright 2002-2008 Axiomatic Systems, LLC
4 | Copyright 2002-2019 Axiomatic Systems, LLC
55 |
66 |
77 | This file is part of Bento4/AP4 (MP4 Atom Processing Library).
4141 /*----------------------------------------------------------------------
4242 | AP4_Dac3Atom::Create
4343 +---------------------------------------------------------------------*/
44 AP4_Dac3Atom*
44 AP4_Dac3Atom*
4545 AP4_Dac3Atom::Create(AP4_Size size, AP4_ByteStream& stream)
4646 {
4747 // read the raw bytes in a buffer
5858 /*----------------------------------------------------------------------
5959 | AP4_Dac3Atom::AP4_Dac3Atom
6060 +---------------------------------------------------------------------*/
61 AP4_Dac3Atom::AP4_Dac3Atom(const AP4_Dac3Atom& other):
62 AP4_Atom(AP4_ATOM_TYPE_DAC3, other.m_Size32),
63 m_DataRate(other.m_DataRate),
64 m_StreamInfo(other.m_StreamInfo),
65 m_RawBytes(other.m_RawBytes)
66 {
67 }
68
69 /*----------------------------------------------------------------------
70 | AP4_Dac3Atom::AP4_Dac3Atom
71 +---------------------------------------------------------------------*/
72 AP4_Dac3Atom::AP4_Dac3Atom(const StreamInfo* m_StreamInfo):
73 AP4_Atom(AP4_ATOM_TYPE_DAC3, AP4_ATOM_HEADER_SIZE){
74 AP4_BitWriter bits(3);
75
76 bits.Write(m_StreamInfo->fscod, 2);
77 bits.Write(m_StreamInfo->bsid, 5);
78 bits.Write(m_StreamInfo->bsmod, 3);
79 bits.Write(m_StreamInfo->acmod, 3);
80 bits.Write(m_StreamInfo->lfeon, 1);
81 bits.Write(m_StreamInfo->bit_rate_code, 5);
82 bits.Write(0, 5); // reserved
83
84 m_RawBytes.SetData(bits.GetData(), bits.GetBitCount() / 8);
85 m_Size32 += m_RawBytes.GetDataSize();
86 }
87
88 /*----------------------------------------------------------------------
89 | AP4_Dac3Atom::AP4_Dac3Atom
90 +---------------------------------------------------------------------*/
6191 AP4_Dac3Atom::AP4_Dac3Atom(AP4_UI32 size, const AP4_UI08* payload) :
6292 AP4_Atom(AP4_ATOM_TYPE_DAC3, size),
63 m_bsmod(0),
64 m_acmod(0),
65 m_lfeon(0)
93 m_DataRate(0)
6694 {
67 // make a copy of our configuration bytes
68 unsigned int payload_size = size-AP4_ATOM_HEADER_SIZE;
69 m_RawBytes.SetData(payload, payload_size);
95 // make a copy of our configuration bytes
96 unsigned int payload_size = size-AP4_ATOM_HEADER_SIZE;
97 m_RawBytes.SetData(payload, payload_size);
7098
71 // sanity check
72 if (payload_size < 2) return;
99 // sanity check
100 if (payload_size < 3) {
101 memset(&m_StreamInfo, 0, sizeof(m_StreamInfo));
102 return;
103 }
73104
74 // parse the payload
75 m_bsmod = (payload[1] >> 6) & 0x7;
76 m_acmod = (payload[1] >> 3) & 0x7;
77 m_lfeon = (payload[1] >> 2) & 0x1;
105 // parse the payload
106 m_DataRate = (payload[0]<<5)|(payload[1]>>3);
107 m_StreamInfo.fscod = (payload[0]>>6) & 0x03;
108 m_StreamInfo.bsid = (payload[0]>>1) & 0x1F;
109 m_StreamInfo.bsmod = ((payload[0]<<2) | (payload[1]>>6)) & 0x07;
110 m_StreamInfo.acmod = (payload[1]>>3) & 0x07;
111 m_StreamInfo.lfeon = (payload[1]>>2) & 0x01;
112 m_StreamInfo.bit_rate_code = ((payload[1]<<3) | (payload[2]>>5)) & 0x1F;
113
114 const unsigned int bit_rate_table[19] = {
115 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 448, 512, 576, 640
116 };
117 if (m_StreamInfo.bit_rate_code < sizeof(bit_rate_table)/sizeof(bit_rate_table[0])) {
118 m_DataRate = bit_rate_table[m_StreamInfo.bit_rate_code];
119 }
78120 }
79121
80122 /*----------------------------------------------------------------------
92134 AP4_Result
93135 AP4_Dac3Atom::InspectFields(AP4_AtomInspector& inspector)
94136 {
95 char value[256];
96 AP4_FormatString(value, sizeof(value),
97 "bsmod=%d, acmod=%d, lfeon=%d", (int)m_bsmod, (int)m_acmod, (int)m_lfeon);
98 inspector.AddField("params", value);
99 return AP4_SUCCESS;
137 inspector.AddField("data_rate", m_DataRate);
138 inspector.AddField("fscod", m_StreamInfo.fscod);
139 inspector.AddField("bsid", m_StreamInfo.bsid);
140 inspector.AddField("bsmod", m_StreamInfo.bsmod);
141 inspector.AddField("acmod", m_StreamInfo.acmod);
142 inspector.AddField("lfeon", m_StreamInfo.lfeon);
143 return AP4_SUCCESS;
100144 }
101145
102146 AP4_UI08 AP4_Dac3Atom::GetChannels() const
103147 {
104148 static const AP4_UI08 CC[] = { 2, 1, 2, 3, 3, 4, 4, 5 };
105 return CC[m_acmod] + m_lfeon;
149 return CC[m_StreamInfo.acmod] + m_StreamInfo.lfeon;
106150 }
00 /*****************************************************************
11 |
2 | AP4 - dec3 Atoms
2 | AP4 - dac3 Atoms
33 |
4 | Copyright 2002-2008 Axiomatic Systems, LLC
4 | Copyright 2002-2019 Axiomatic Systems, LLC
55 |
66 |
77 | This file is part of Bento4/AP4 (MP4 Atom Processing Library).
3232 | includes
3333 +---------------------------------------------------------------------*/
3434 #include "Ap4Atom.h"
35 #include "Ap4Array.h"
3536
3637 /*----------------------------------------------------------------------
3738 | constants
4445 {
4546 public:
4647 AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_Dac3Atom, AP4_Atom)
47
48
49 // types
50 struct StreamInfo {
51 unsigned int fscod;
52 unsigned int bsid;
53 unsigned int bsmod;
54 unsigned int acmod;
55 unsigned int lfeon;
56 unsigned int bit_rate_code;
57 };
58
4859 // class methods
4960 static AP4_Dac3Atom* Create(AP4_Size size, AP4_ByteStream& stream);
61
62 // constructors
63 AP4_Dac3Atom(const AP4_Dac3Atom& other);
64 AP4_Dac3Atom(const StreamInfo* StreamInfo); // DSI vaiable initialize m_RawBytes (SpecificBoxInfo -> m_RawBytes)
5065
5166 // methods
5267 virtual AP4_Result InspectFields(AP4_AtomInspector& inspector);
5469 virtual AP4_Atom* Clone() { return new AP4_Dac3Atom(m_Size32, m_RawBytes.GetData()); }
5570
5671 // accessors
57 const AP4_DataBuffer& GetRawBytes() const { return m_RawBytes; }
58 AP4_UI08 GetChannels() const;
59
72 const AP4_DataBuffer& GetRawBytes() const { return m_RawBytes; }
73 unsigned int GetDataRate() const { return m_DataRate; }
74 const StreamInfo& GetStreamInfo() const { return m_StreamInfo; }
75 AP4_UI08 GetChannels() const;
76
6077 private:
6178 // methods
62 AP4_Dac3Atom(AP4_UI32 size, const AP4_UI08* payload);
79 AP4_Dac3Atom(AP4_UI32 size, const AP4_UI08* payload); // box data initialize m_Dsi (m_RawBytes -> SpecificBoxInfo)
6380
6481 // members
65 AP4_DataBuffer m_RawBytes;
66 AP4_UI08 m_bsmod, m_acmod, m_lfeon;
82 unsigned int m_DataRate;
83 StreamInfo m_StreamInfo;
84 AP4_DataBuffer m_RawBytes;
6785 };
6886
69 #endif // _AP4_DEC3_ATOM_H_
87 #endif // _AP4_DAC3_ATOM_H_
0 /*****************************************************************
1 |
2 | AP4 - dac4 Atoms
3 |
4 | Copyright 2002-2018 Axiomatic Systems, LLC
5 |
6 |
7 | This file is part of Bento4/AP4 (MP4 Atom Processing Library).
8 |
9 | Unless you have obtained Bento4 under a difference license,
10 | this version of Bento4 is Bento4|GPL.
11 | Bento4|GPL is free software; you can redistribute it and/or modify
12 | it under the terms of the GNU General Public License as published by
13 | the Free Software Foundation; either version 2, or (at your option)
14 | any later version.
15 |
16 | Bento4|GPL is distributed in the hope that it will be useful,
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | GNU General Public License for more details.
20 |
21 | You should have received a copy of the GNU General Public License
22 | along with Bento4|GPL; see the file COPYING. If not, write to the
23 | Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
24 | 02111-1307, USA.
25 |
26 ****************************************************************/
27
28 /*----------------------------------------------------------------------
29 | includes
30 +---------------------------------------------------------------------*/
31 #include "Ap4Dac4Atom.h"
32 #include "Ap4AtomFactory.h"
33 #include "Ap4Utils.h"
34 #include "Ap4Types.h"
35
36 #include <cmath>
37
38 /*----------------------------------------------------------------------
39 | dynamic cast support
40 +---------------------------------------------------------------------*/
41 AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_Dac4Atom)
42
43 /*----------------------------------------------------------------------
44 | AP4_Dac4Atom::Create
45 +---------------------------------------------------------------------*/
46 AP4_Dac4Atom*
47 AP4_Dac4Atom::Create(AP4_Size size, AP4_ByteStream& stream)
48 {
49 // read the raw bytes in a buffer
50 unsigned int payload_size = size-AP4_ATOM_HEADER_SIZE;
51 AP4_DataBuffer payload_data(payload_size);
52 AP4_Result result = stream.Read(payload_data.UseData(), payload_size);
53 if (AP4_FAILED(result)) return NULL;
54
55 // check the version
56 const AP4_UI08* payload = payload_data.GetData();
57 return new AP4_Dac4Atom(size, payload);
58 }
59
60 /*----------------------------------------------------------------------
61 | AP4_Dac4Atom::AP4_Dac4Atom
62 +---------------------------------------------------------------------*/
63 AP4_Dac4Atom::AP4_Dac4Atom(AP4_UI32 size, const Ac4Dsi* ac4Dsi):
64 AP4_Atom(AP4_ATOM_TYPE_DAC4, AP4_ATOM_HEADER_SIZE){
65 AP4_BitWriter bits(size);
66 bits.Write(ac4Dsi->ac4_dsi_version, 3);
67 bits.Write(ac4Dsi->d.v1.bitstream_version, 7);
68 bits.Write(ac4Dsi->d.v1.fs_index, 1);
69 bits.Write(ac4Dsi->d.v1.frame_rate_index, 4);
70
71 // IMS presentation shall has the legacy presentation
72 unsigned int add_n_presentations = 0;
73 for (unsigned int idx = 0; idx < ac4Dsi->d.v1.n_presentations; idx++){
74 if (ac4Dsi->d.v1.presentations[idx].presentation_version == 2) {
75 add_n_presentations++;
76 }
77 }
78
79 // Assume the total presentation numbers is less than 512 after adding legacy presentation
80 bits.Write(ac4Dsi->d.v1.n_presentations + add_n_presentations, 9);
81
82 if (ac4Dsi->d.v1.bitstream_version > 1){
83 bits.Write(ac4Dsi->d.v1.b_program_id, 1);
84 if (ac4Dsi->d.v1.b_program_id == 1){
85 bits.Write(ac4Dsi->d.v1.short_program_id, 16);
86 bits.Write(ac4Dsi->d.v1.b_uuid, 1);
87 if (ac4Dsi->d.v1.b_uuid == 1) {
88 for (unsigned int idx = 0; idx < 16; idx ++) {
89 bits.Write(ac4Dsi->d.v1.program_uuid[idx], 8);
90 }
91 }
92 }
93 }
94 // ac4_bitrate_dsi()
95 AP4_Dac4Atom::Ac4Dsi::Ac4BitrateDsi ac4_bitrate_dsi = ac4Dsi->d.v1.ac4_bitrate_dsi;
96 ac4_bitrate_dsi.WriteBitrateDsi(bits);
97
98 AP4_ByteAlign(bits);
99 for (unsigned int idx = 0; idx < ac4Dsi->d.v1.n_presentations; idx ++) {
100 unsigned int default_pres_bytes = 36; // random value
101 AP4_Dac4Atom::Ac4Dsi::PresentationV1 &presentation = ac4Dsi->d.v1.presentations[idx];
102 bits.Write(presentation.presentation_version, 8);
103 bits.Write(default_pres_bytes, 8); // pres_bytes, need to be updated later
104 //TODO: if (pres_bytes == 255), shall not happen now. Need the memory move function for bits
105 unsigned int pres_bytes_idx = bits.GetBitCount() / 8 - 1;
106 if (ac4Dsi->d.v1.n_presentations != 1 && presentation.d.v1.b_presentation_id == 0 && presentation.d.v1.b_extended_presentation_id == 0) {
107 fprintf(stderr, "WARN: Need presentation_id for multiple presnetaion signal. The presentation of Presentation Index (PI) is %d miss presentation_id.\n", idx + 1);
108 }
109 if (presentation.presentation_version == 0){
110 // TODO: support presentation version = 0
111 }else if (presentation.presentation_version == 1 || presentation.presentation_version == 2){
112 presentation.WritePresentationV1Dsi(bits);
113 Ap4_Ac4UpdatePresBytes(bits.GetData(), pres_bytes_idx, bits.GetBitCount()/8 - pres_bytes_idx - 1);
114 } else {
115 Ap4_Ac4UpdatePresBytes(bits.GetData(), pres_bytes_idx, 0);
116 }
117
118 //legacy presentation for IMS
119 if (presentation.presentation_version == 2) {
120 AP4_Dac4Atom::Ac4Dsi::PresentationV1 legacy_presentation = presentation;
121 if (legacy_presentation.d.v1.b_presentation_id == 0 && legacy_presentation.d.v1.b_extended_presentation_id == 0) {
122 fprintf(stderr, "WARN: Need presentation_id for IMS signal.\n");
123 }
124 legacy_presentation.presentation_version = 1;
125 legacy_presentation.d.v1.b_pre_virtualized = 0;
126 legacy_presentation.d.v1.dolby_atmos_indicator = 0;
127
128 bits.Write(legacy_presentation.presentation_version, 8);
129 bits.Write(default_pres_bytes, 8); // pres_bytes, need to be updated later
130 //TODO: if (pres_bytes == 255), shall not happen now
131 unsigned int pres_bytes_idx = bits.GetBitCount() / 8 - 1;
132 legacy_presentation.WritePresentationV1Dsi(bits);
133 Ap4_Ac4UpdatePresBytes(bits.GetData(), pres_bytes_idx, bits.GetBitCount()/8 - pres_bytes_idx - 1);
134 }
135 }
136 m_RawBytes.SetData(bits.GetData(), bits.GetBitCount() / 8);
137 m_Size32 += m_RawBytes.GetDataSize();
138 // clear the DSI
139 AP4_SetMemory(&m_Dsi, 0, sizeof(m_Dsi));
140 m_Dsi.ac4_dsi_version = -1;
141 }
142
143 /*----------------------------------------------------------------------
144 | AP4_Dac4Atom::AP4_Dac4Atom
145 +---------------------------------------------------------------------*/
146 AP4_Dac4Atom::AP4_Dac4Atom(AP4_UI32 size, const AP4_UI08* payload) :
147 AP4_Atom(AP4_ATOM_TYPE_DAC4, size)
148 {
149 // clear the DSI
150 AP4_SetMemory(&m_Dsi, 0, sizeof(m_Dsi));
151
152 // make a copy of our configuration bytes
153 unsigned int payload_size = size-AP4_ATOM_HEADER_SIZE;
154 m_RawBytes.SetData(payload, payload_size);
155
156 // sanity check
157 if (payload_size < 11) return;
158
159 // parse the `ac4_dsi` or `ac4_dsi_v1` bits
160 AP4_BitReader bits(payload, payload_size);
161 m_Dsi.ac4_dsi_version = bits.ReadBits(3);
162 if (m_Dsi.ac4_dsi_version == 0) {
163 m_Dsi.d.v0.bitstream_version = bits.ReadBits(7);
164 m_Dsi.d.v0.fs_index = bits.ReadBits(1);
165 m_Dsi.d.v0.frame_rate_index = bits.ReadBits(4);
166 m_Dsi.d.v0.n_presentations = bits.ReadBits(9);
167
168 // fill in computed fields
169 m_Dsi.d.v0.fs = m_Dsi.d.v0.fs_index == 0 ? 44100 : 48000;
170 } else if (m_Dsi.ac4_dsi_version == 1) {
171 m_Dsi.d.v1.bitstream_version = bits.ReadBits(7);
172 m_Dsi.d.v1.fs_index = bits.ReadBits(1);
173 m_Dsi.d.v1.frame_rate_index = bits.ReadBits(4);
174 m_Dsi.d.v1.n_presentations = bits.ReadBits(9);
175 if (m_Dsi.d.v1.bitstream_version > 1) {
176 if (bits.ReadBit()) {
177 m_Dsi.d.v1.short_program_id = bits.ReadBits(16);
178 if (bits.ReadBit()) {
179 for (unsigned int i = 0; i < 16; i ++) {
180 m_Dsi.d.v1.program_uuid[i] = bits.ReadBits(8);
181 }
182 }
183 }
184 }
185 m_Dsi.d.v1.ac4_bitrate_dsi.bit_rate_mode = bits.ReadBits(2);
186 m_Dsi.d.v1.ac4_bitrate_dsi.bit_rate = bits.ReadBits(32);
187 m_Dsi.d.v1.ac4_bitrate_dsi.bit_rate_precision = bits.ReadBits(32);
188
189 // byte align
190 if (bits.GetBitsRead() % 8) {
191 bits.SkipBits(8 - (bits.GetBitsRead() % 8));
192 }
193
194 // parse the presentations
195 m_Dsi.d.v1.presentations = new Ac4Dsi::PresentationV1[m_Dsi.d.v1.n_presentations];
196 AP4_SetMemory(m_Dsi.d.v1.presentations, 0, m_Dsi.d.v1.n_presentations * sizeof(m_Dsi.d.v1.presentations[0]));
197 for (unsigned int i = 0; i < m_Dsi.d.v1.n_presentations; i++) {
198 Ac4Dsi::PresentationV1& presentation = m_Dsi.d.v1.presentations[i];
199
200 presentation.presentation_version = bits.ReadBits(8);
201 unsigned int pres_bytes = bits.ReadBits(8);
202 if (pres_bytes == 255) {
203 pres_bytes += bits.ReadBits(16);
204 }
205 unsigned int bits_read_before_presentation = bits.GetBitsRead();
206 if (presentation.presentation_version == 0) {
207 presentation.d.v0.presentation_config = bits.ReadBits(5);
208 //bool b_add_emdf_substreams = false;
209 if (presentation.d.v0.presentation_config == 0x06) {
210 //b_add_emdf_substreams = true;
211 } else {
212 presentation.d.v0.mdcompat = bits.ReadBits(3);
213 if (bits.ReadBit()) { // b_presentation_id
214 presentation.d.v0.presentation_id = bits.ReadBits(5);
215 }
216 presentation.d.v0.dsi_frame_rate_multiply_info = bits.ReadBits(2);
217 presentation.d.v0.presentation_emdf_version = bits.ReadBits(5);
218 presentation.d.v0.presentation_key_id = bits.ReadBits(10);
219 presentation.d.v0.presentation_channel_mask = bits.ReadBits(24);
220 }
221 // some fields skipped
222 if (bits.GetBitsRead() % 8) {
223 bits.SkipBits(8 - (bits.GetBitsRead() % 8));
224 }
225 } else if (presentation.presentation_version == 1 || presentation.presentation_version == 2) {
226 presentation.d.v1.presentation_config_v1 = bits.ReadBits(5);
227 if (presentation.d.v1.presentation_config_v1 == 0x06) {
228 presentation.d.v1.b_add_emdf_substreams = 1;
229 } else {
230 presentation.d.v1.mdcompat = bits.ReadBits(3);
231 presentation.d.v1.b_presentation_id = bits.ReadBit();
232 if (presentation.d.v1.b_presentation_id) {
233 presentation.d.v1.presentation_id = bits.ReadBits(5);
234 }
235 presentation.d.v1.dsi_frame_rate_multiply_info = bits.ReadBits(2);
236 presentation.d.v1.dsi_frame_rate_fraction_info = bits.ReadBits(2);
237 presentation.d.v1.presentation_emdf_version = bits.ReadBits(5);
238 presentation.d.v1.presentation_key_id = bits.ReadBits(10);
239 presentation.d.v1.b_presentation_channel_coded = bits.ReadBit();
240 if (presentation.d.v1.b_presentation_channel_coded) {
241 presentation.d.v1.dsi_presentation_ch_mode = bits.ReadBits(5);
242 if (presentation.d.v1.dsi_presentation_ch_mode == 11 ||
243 presentation.d.v1.dsi_presentation_ch_mode == 12 ||
244 presentation.d.v1.dsi_presentation_ch_mode == 13 ||
245 presentation.d.v1.dsi_presentation_ch_mode == 14) {
246 presentation.d.v1.pres_b_4_back_channels_present = bits.ReadBit();
247 presentation.d.v1.pres_top_channel_pairs = bits.ReadBits(2);
248 }
249 presentation.d.v1.presentation_channel_mask_v1 = bits.ReadBits(24);
250 }else {
251 presentation.d.v1.presentation_channel_mask_v1 = 0x800000;
252 }
253 presentation.d.v1.b_presentation_core_differs = bits.ReadBit();
254 if (presentation.d.v1.b_presentation_core_differs) {
255 presentation.d.v1.b_presentation_core_channel_coded = bits.ReadBit();
256 if (presentation.d.v1.b_presentation_core_channel_coded) {
257 presentation.d.v1.dsi_presentation_channel_mode_core = bits.ReadBits(2);
258 }
259 }
260 presentation.d.v1.b_presentation_filter = bits.ReadBit();
261 if (presentation.d.v1.b_presentation_filter) {
262 presentation.d.v1.b_enable_presentation = bits.ReadBit();
263 presentation.d.v1.n_filter_bytes = bits.ReadBits(8);
264 for (int idx = 0; idx < presentation.d.v1.n_filter_bytes; idx ++) { bits.SkipBits(8); }
265 }
266 bool parse_substream_groups = true;
267 if (presentation.d.v1.presentation_config_v1 == 0x1f){
268 presentation.d.v1.n_substream_groups = 1;
269 } else {
270 presentation.d.v1.b_multi_pid = bits.ReadBit();
271 switch (presentation.d.v1.presentation_config_v1){
272 case 0:
273 case 1:
274 case 2:
275 presentation.d.v1.n_substream_groups = 2;
276 break;
277 case 3:
278 case 4:
279 presentation.d.v1.n_substream_groups = 3;
280 break;
281 case 5:
282 presentation.d.v1.n_substream_groups = bits.ReadBits(3) + 2;
283 break;
284 default:
285 parse_substream_groups = false;
286 presentation.d.v1.n_skip_bytes = bits.ReadBits(7);
287 for (int idx = 0; idx < presentation.d.v1.n_skip_bytes; idx ++) { bits.SkipBits(8); }
288 }
289
290 }
291 // Start to parse substream_groups
292 if (parse_substream_groups) {
293 presentation.d.v1.substream_groups = new Ac4Dsi::SubStreamGroupV1[presentation.d.v1.n_substream_groups];
294 AP4_SetMemory(presentation.d.v1.substream_groups, 0, presentation.d.v1.n_substream_groups * sizeof(presentation.d.v1.substream_groups[0]));
295 for (int cnt = 0; cnt < presentation.d.v1.n_substream_groups; cnt ++){
296 Ac4Dsi::SubStreamGroupV1& substreamgroup = presentation.d.v1.substream_groups[cnt];
297 substreamgroup.d.v1.b_substreams_present = bits.ReadBit();
298 substreamgroup.d.v1.b_hsf_ext = bits.ReadBit();
299 substreamgroup.d.v1.b_channel_coded = bits.ReadBit();
300 substreamgroup.d.v1.n_substreams = bits.ReadBits(8);
301
302 substreamgroup.d.v1.substreams = new Ac4Dsi::SubStream[substreamgroup.d.v1.n_substreams];
303 AP4_SetMemory(substreamgroup.d.v1.substreams, 0, substreamgroup.d.v1.n_substreams * sizeof(substreamgroup.d.v1.substreams[0]));
304 for (int sus = 0; sus < substreamgroup.d.v1.n_substreams; sus ++){
305 Ac4Dsi::SubStream& substream = substreamgroup.d.v1.substreams[sus];
306 substream.dsi_sf_multiplier = bits.ReadBits(2);
307 substream.b_substream_bitrate_indicator = bits.ReadBit();
308 if (substream.b_substream_bitrate_indicator) {
309 substream.substream_bitrate_indicator = bits.ReadBits(5);
310 }
311 if (substreamgroup.d.v1.b_channel_coded){
312 substream.dsi_substream_channel_mask = bits.ReadBits(24);
313 } else {
314 substream.b_ajoc = bits.ReadBit();
315 if (substream.b_ajoc) {
316 substream.b_static_dmx = bits.ReadBit();
317 if (substream.b_static_dmx == 0) {
318 substream.n_dmx_objects_minus1 = bits.ReadBits(4);
319 }
320 substream.n_umx_objects_minus1 = bits.ReadBits(6);
321 }
322 substream.b_substream_contains_bed_objects = bits.ReadBit();
323 substream.b_substream_contains_dynamic_objects = bits.ReadBit();
324 substream.b_substream_contains_ISF_objects = bits.ReadBit();
325 bits.SkipBit(); // reserved
326 }
327 }
328 substreamgroup.d.v1.b_content_type = bits.ReadBit();
329 if (substreamgroup.d.v1.b_content_type) {
330 substreamgroup.d.v1.content_classifier = bits.ReadBits(3);
331 substreamgroup.d.v1.b_language_indicator = bits.ReadBit();
332 if (substreamgroup.d.v1.b_language_indicator) {
333 substreamgroup.d.v1.n_language_tag_bytes = bits.ReadBits(6);
334 for (int l = 0; l < substreamgroup.d.v1.n_language_tag_bytes; l++) {
335 substreamgroup.d.v1.language_tag_bytes[l] = bits.ReadBits(8);
336 }
337 }
338 }
339 }
340 }
341 presentation.d.v1.b_pre_virtualized = bits.ReadBit();
342 presentation.d.v1.b_add_emdf_substreams = bits.ReadBit();
343 }
344 if (presentation.d.v1.b_add_emdf_substreams) {
345 presentation.d.v1.n_add_emdf_substreams = bits.ReadBits(7);
346 for (int j = 0; j < presentation.d.v1.n_add_emdf_substreams; j ++) {
347 presentation.d.v1.substream_emdf_version[j] = bits.ReadBits(5);
348 presentation.d.v1.substream_key_id[j] = bits.ReadBits(10);
349 }
350 }
351 presentation.d.v1.b_presentation_bitrate_info = bits.ReadBit();
352 if (presentation.d.v1.b_presentation_bitrate_info) {
353 presentation.d.v1.ac4_bitrate_dsi.bit_rate_mode = bits.ReadBits(2);
354 presentation.d.v1.ac4_bitrate_dsi.bit_rate = bits.ReadBits(32);
355 presentation.d.v1.ac4_bitrate_dsi.bit_rate_precision = bits.ReadBits(32);
356 }
357 presentation.d.v1.b_alternative = bits.ReadBit();
358 if (presentation.d.v1.b_alternative) {
359 // byte align
360 if (bits.GetBitsRead() % 8) {
361 bits.SkipBits(8 - (bits.GetBitsRead() % 8));
362 }
363
364 presentation.d.v1.alternative_info.name_len = bits.ReadBits(16);
365 for (int n = 0; n < presentation.d.v1.alternative_info.name_len; n++) {
366 presentation.d.v1.alternative_info.presentation_name[n] = bits.ReadBits(8);
367 }
368 presentation.d.v1.alternative_info.n_targets = bits.ReadBits(5);
369 for (int t = 0; t < presentation.d.v1.alternative_info.n_targets; t++ ){
370 presentation.d.v1.alternative_info.target_md_compat[t] = bits.ReadBits(3);
371 presentation.d.v1.alternative_info.target_device_category[t] = bits.ReadBits(8);
372 }
373 }
374 // byte align
375 if (bits.GetBitsRead() % 8) {
376 bits.SkipBits(8 - (bits.GetBitsRead() % 8));
377 }
378 presentation.d.v1.de_indicator = bits.ReadBit();
379 presentation.d.v1.dolby_atmos_indicator = bits.ReadBit();
380 bits.SkipBits(4);
381 presentation.d.v1.b_extended_presentation_id = bits.ReadBit();
382 if (presentation.d.v1.b_extended_presentation_id){
383 presentation.d.v1.extended_presentation_id = bits.ReadBits(9);
384 } else {
385 bits.SkipBit();
386 }
387 }
388 unsigned int bits_read_after_presentation = bits.GetBitsRead();
389 unsigned int presentation_bytes = (bits_read_after_presentation - bits_read_before_presentation) / 8;
390 if (pres_bytes < presentation_bytes) {
391 break;
392 }
393 unsigned int skip_bytes = pres_bytes - presentation_bytes;
394 for (unsigned int skip = 0; skip < skip_bytes; skip++) {
395 bits.SkipBits(8);
396 }
397 }
398
399 // fill in computed fields
400 m_Dsi.d.v1.fs = m_Dsi.d.v1.fs_index == 0 ? 44100 : 48000;
401 } else {
402 // not supported
403 return;
404 }
405 }
406
407 /*----------------------------------------------------------------------
408 | AP4_Dac4Atom::~AP4_Dac4Atom
409 +---------------------------------------------------------------------*/
410 AP4_Dac4Atom::~AP4_Dac4Atom()
411 {
412 if (m_Dsi.ac4_dsi_version == 0) {
413 //delete[] m_Dsi.d.v0.presentations;
414 } else if (m_Dsi.ac4_dsi_version == 1) {
415 for (int i = 0; i < m_Dsi.d.v1.n_presentations; i++) {
416 for (int j = 0; j < m_Dsi.d.v1.presentations[i].d.v1.n_substream_groups; j++) {
417 delete[] m_Dsi.d.v1.presentations[i].d.v1.substream_groups[j].d.v1.substreams;
418 }
419 delete[] m_Dsi.d.v1.presentations[i].d.v1.substream_groups;
420 }
421 delete[] m_Dsi.d.v1.presentations;
422 }
423 }
424
425 /*----------------------------------------------------------------------
426 | AP4_Dac4Atom::WriteFields
427 +---------------------------------------------------------------------*/
428 AP4_Result
429 AP4_Dac4Atom::WriteFields(AP4_ByteStream& stream)
430 {
431 return stream.Write(m_RawBytes.GetData(), m_RawBytes.GetDataSize());
432 }
433
434 /*----------------------------------------------------------------------
435 | AP4_Dac4Atom::GetCodecString
436 +---------------------------------------------------------------------*/
437 void
438 AP4_Dac4Atom::GetCodecString(AP4_String& codec)
439 {
440 AP4_UI08 bitstream_version = 0;
441 AP4_UI08 presentation_version = 0;
442 AP4_UI08 mdcompat = 0;
443 if (m_Dsi.ac4_dsi_version == 0) {
444 bitstream_version = m_Dsi.d.v0.bitstream_version;
445 } else if (m_Dsi.ac4_dsi_version == 1) {
446 bitstream_version = m_Dsi.d.v1.bitstream_version;
447 if (m_Dsi.d.v1.n_presentations) {
448 presentation_version = m_Dsi.d.v1.presentations[0].presentation_version;
449 if (presentation_version == 0) {
450 mdcompat = m_Dsi.d.v1.presentations[0].d.v0.mdcompat;
451 } else if (presentation_version == 1 || presentation_version == 2) {
452 mdcompat = m_Dsi.d.v1.presentations[0].d.v1.mdcompat;
453 for (int idx = 0; idx < m_Dsi.d.v1.n_presentations; idx ++){
454 if (mdcompat > m_Dsi.d.v1.presentations[idx].d.v1.mdcompat) {
455 mdcompat = m_Dsi.d.v1.presentations[idx].d.v1.mdcompat;
456 }
457 }
458 }
459 }
460 }
461 char string[64];
462 AP4_FormatString(string,
463 sizeof(string),
464 "ac-4.%02x.%02x.%02x",
465 bitstream_version,
466 presentation_version,
467 mdcompat);
468 codec = string;
469 }
470
471 /*----------------------------------------------------------------------
472 | AP4_Dac4Atom::InspectFields
473 +---------------------------------------------------------------------*/
474 AP4_Result
475 AP4_Dac4Atom::InspectFields(AP4_AtomInspector& inspector)
476 {
477 inspector.AddField("ac4_dsi_version", m_Dsi.ac4_dsi_version);
478 if (m_Dsi.ac4_dsi_version == 0) {
479 inspector.AddField("bitstream_version", m_Dsi.d.v0.bitstream_version);
480 inspector.AddField("fs_index", m_Dsi.d.v0.fs_index);
481 inspector.AddField("fs", m_Dsi.d.v0.fs);
482 inspector.AddField("frame_rate_index", m_Dsi.d.v0.frame_rate_index);
483 } else if (m_Dsi.ac4_dsi_version == 1) {
484 inspector.AddField("bitstream_version", m_Dsi.d.v1.bitstream_version);
485 inspector.AddField("fs_index", m_Dsi.d.v1.fs_index);
486 inspector.AddField("fs", m_Dsi.d.v1.fs);
487 inspector.AddField("frame_rate_index", m_Dsi.d.v1.frame_rate_index);
488 if (m_Dsi.d.v1.bitstream_version > 1) {
489 inspector.AddField("short_program_id", m_Dsi.d.v1.short_program_id);
490 inspector.AddField("program_uuid", m_Dsi.d.v1.program_uuid, 16, AP4_AtomInspector::HINT_HEX);
491 }
492 inspector.AddField("bit_rate_mode", m_Dsi.d.v1.ac4_bitrate_dsi.bit_rate_mode);
493 inspector.AddField("bit_rate", m_Dsi.d.v1.ac4_bitrate_dsi.bit_rate);
494 inspector.AddField("bit_rate_precision", m_Dsi.d.v1.ac4_bitrate_dsi.bit_rate_precision);
495
496 for (unsigned int i = 0; i < m_Dsi.d.v1.n_presentations; i++) {
497 Ac4Dsi::PresentationV1& presentation = m_Dsi.d.v1.presentations[i];
498 char field_name[64];
499 AP4_FormatString(field_name, sizeof(field_name), "[%02d].presentation_version", i);
500 inspector.AddField(field_name, presentation.presentation_version);
501 if (presentation.presentation_version == 0) {
502 AP4_FormatString(field_name, sizeof(field_name), "[%02d].presentation_config", i);
503 inspector.AddField(field_name, presentation.d.v0.presentation_config);
504 AP4_FormatString(field_name, sizeof(field_name), "[%02d].mdcompat", i);
505 inspector.AddField(field_name, presentation.d.v0.mdcompat);
506 AP4_FormatString(field_name, sizeof(field_name), "[%02d].presentation_id", i);
507 inspector.AddField(field_name, presentation.d.v0.presentation_id);
508 AP4_FormatString(field_name, sizeof(field_name), "[%02d].dsi_frame_rate_multiply_info", i);
509 inspector.AddField(field_name, presentation.d.v0.dsi_frame_rate_multiply_info);
510 AP4_FormatString(field_name, sizeof(field_name), "[%02d].presentation_emdf_version", i);
511 inspector.AddField(field_name, presentation.d.v0.presentation_emdf_version);
512 AP4_FormatString(field_name, sizeof(field_name), "[%02d].presentation_key_id", i);
513 inspector.AddField(field_name, presentation.d.v0.presentation_key_id);
514 AP4_FormatString(field_name, sizeof(field_name), "[%02d].presentation_channel_mask", i);
515 inspector.AddField(field_name, presentation.d.v0.presentation_channel_mask, AP4_AtomInspector::HINT_HEX);
516 } else if (presentation.presentation_version == 1 || presentation.presentation_version == 2) {
517 AP4_FormatString(field_name, sizeof(field_name), "[%02d].presentation_config_v1", i);
518 inspector.AddField(field_name, presentation.d.v1.presentation_config_v1);
519 AP4_FormatString(field_name, sizeof(field_name), "[%02d].mdcompat", i);
520 inspector.AddField(field_name, presentation.d.v1.mdcompat);
521 AP4_FormatString(field_name, sizeof(field_name), "[%02d].presentation_id", i);
522 inspector.AddField(field_name, presentation.d.v1.presentation_id);
523 AP4_FormatString(field_name, sizeof(field_name), "[%02d].dsi_frame_rate_multiply_info", i);
524 inspector.AddField(field_name, presentation.d.v1.dsi_frame_rate_multiply_info);
525 AP4_FormatString(field_name, sizeof(field_name), "[%02d].dsi_frame_rate_fraction_info", i);
526 inspector.AddField(field_name, presentation.d.v1.dsi_frame_rate_fraction_info);
527 AP4_FormatString(field_name, sizeof(field_name), "[%02d].presentation_emdf_version", i);
528 inspector.AddField(field_name, presentation.d.v1.presentation_emdf_version);
529 AP4_FormatString(field_name, sizeof(field_name), "[%02d].presentation_key_id", i);
530 inspector.AddField(field_name, presentation.d.v1.presentation_key_id);
531 AP4_FormatString(field_name, sizeof(field_name), "[%02d].b_presentation_channel_coded", i);
532 inspector.AddField(field_name, presentation.d.v1.b_presentation_channel_coded);
533 AP4_FormatString(field_name, sizeof(field_name), "[%02d].dsi_presentation_ch_mode", i);
534 inspector.AddField(field_name, presentation.d.v1.dsi_presentation_ch_mode);
535 AP4_FormatString(field_name, sizeof(field_name), "[%02d].pres_b_4_back_channels_present", i);
536 inspector.AddField(field_name, presentation.d.v1.pres_b_4_back_channels_present);
537 AP4_FormatString(field_name, sizeof(field_name), "[%02d].pres_top_channel_pairs", i);
538 inspector.AddField(field_name, presentation.d.v1.pres_top_channel_pairs);
539 AP4_FormatString(field_name, sizeof(field_name), "[%02d].presentation_channel_mask_v1", i);
540 inspector.AddField(field_name, presentation.d.v1.presentation_channel_mask_v1, AP4_AtomInspector::HINT_HEX);
541 }
542 }
543 }
544 return AP4_SUCCESS;
545 }
546
547 /*----------------------------------------------------------------------
548 | AP4_Dac4Atom::Ac4Dsi::Ac4BitrateDsi::WriteBitrateDsi
549 +---------------------------------------------------------------------*/
550 AP4_Result
551 AP4_Dac4Atom::Ac4Dsi::Ac4BitrateDsi::WriteBitrateDsi(AP4_BitWriter &bits)
552 {
553 bits.Write(bit_rate_mode, 2);
554 bits.Write(bit_rate, 32);
555 bits.Write(bit_rate_precision, 32);
556 return AP4_SUCCESS;
557 }
558
559 /*----------------------------------------------------------------------
560 | AP4_Dac4Atom::Ac4Dsi::Ac4AlternativeInfo::WriteAlternativeInfo
561 +---------------------------------------------------------------------*/
562 AP4_Result
563 AP4_Dac4Atom::Ac4Dsi::Ac4AlternativeInfo::WriteAlternativeInfo(AP4_BitWriter &bits)
564 {
565 bits.Write(name_len, 16);
566 for (unsigned int l = 0; l < name_len; l ++) {
567 bits.Write(presentation_name[l], 8);
568 }
569 bits.Write(n_targets, 5);
570 for (unsigned int t = 0; t < n_targets; t ++) {
571 bits.Write(target_md_compat[t], 3);
572 bits.Write(target_device_category[t], 8);
573 }
574 return AP4_SUCCESS;
575 }
576
577 /*----------------------------------------------------------------------
578 | AP4_Dac4Atom::Ac4Dsi::SubStream::ParseSubstreamInfoChan
579 +---------------------------------------------------------------------*/
580 AP4_Result
581 AP4_Dac4Atom::Ac4Dsi::SubStream::ParseSubstreamInfoChan(AP4_BitReader &bits,
582 unsigned int presentation_version,
583 unsigned char defalut_presentation_flag,
584 unsigned int fs_idx,
585 unsigned int &speaker_index_mask,
586 unsigned int frame_rate_factor,
587 unsigned int b_substreams_present,
588 unsigned char &dolby_atmos_indicator)
589 {
590 ch_mode = ParseChMode(bits, presentation_version, dolby_atmos_indicator);
591 int substreamSpeakerGroupIndexMask = AC4_SPEAKER_GROUP_INDEX_MASK_BY_CH_MODE[ch_mode];
592 if ((ch_mode >= CH_MODE_7_0_4) && (ch_mode <= CH_MODE_9_1_4)) {
593 if (!(b_4_back_channels_present = bits.ReadBit())) { // b_4_back_channels_present false
594 substreamSpeakerGroupIndexMask &= ~0x8; // Remove back channels (Lb,Rb) from mask
595 }
596 if (!(b_centre_present = bits.ReadBit())) { // b_centre_present false
597 substreamSpeakerGroupIndexMask &= ~0x2; // Remove centre channel (C) from mask
598 }
599 switch (top_channels_present = bits.ReadBits(2)) { // top_channels_present
600 case 0:
601 substreamSpeakerGroupIndexMask &= ~0x30; // Remove top channels (Tfl,Tfr,Tbl,Tbr) from mask
602 break;
603 case 1:
604 case 2:
605 substreamSpeakerGroupIndexMask &= ~0x30; // Remove top channels (Tfl,Tfr,Tbl,Tbr) from mask
606 substreamSpeakerGroupIndexMask |= 0x80; // Add top channels (Tl, Tr) from mask;
607 break;
608 }
609 }
610 dsi_substream_channel_mask = substreamSpeakerGroupIndexMask;
611 // Only combine channel masks of substream groups that are part of the first/default presentation
612 if (defalut_presentation_flag) {
613 speaker_index_mask |= substreamSpeakerGroupIndexMask;
614 }
615
616 ParseDsiSfMutiplier(bits, fs_idx);
617
618 b_substream_bitrate_indicator = bits.ReadBit();
619 if (b_substream_bitrate_indicator) { // b_bitrate_info
620 // bitrate_indicator()
621 ParseBitrateIndicator(bits);
622 }
623
624 if (ch_mode >= CH_MODE_70_52 && ch_mode <= CH_MODE_71_322) {
625 bits.ReadBit(); // add_ch_base
626 }
627 for (unsigned int i = 0; i < frame_rate_factor; i++) {
628 bits.ReadBit(); // b_audio_ndot
629 }
630
631 ParseSubstreamIdxInfo(bits, b_substreams_present);
632
633 return AP4_SUCCESS;
634 }
635
636 /*----------------------------------------------------------------------
637 | AP4_Dac4Atom::Ac4Dsi::SubStream::ParseSubStreamInfoAjoc
638 +---------------------------------------------------------------------*/
639 AP4_Result
640 AP4_Dac4Atom::Ac4Dsi::SubStream::ParseSubStreamInfoAjoc(AP4_BitReader &bits,
641 unsigned int &channel_count,
642 unsigned char defalut_presentation_flag,
643 unsigned int fs_idx,
644 unsigned int frame_rate_factor,
645 unsigned int b_substreams_present)
646 {
647 b_lfe = bits.ReadBit(); // b_lfe
648 b_static_dmx = bits.ReadBit();
649 if (b_static_dmx) { // b_static_dmx
650 if (defalut_presentation_flag) {
651 channel_count += 5;
652 }
653 } else {
654 n_dmx_objects_minus1 = bits.ReadBits(4);
655 unsigned int nFullbandDmxSignals = n_dmx_objects_minus1 + 1;
656 BedDynObjAssignment(bits, nFullbandDmxSignals, false);
657 if (defalut_presentation_flag) {
658 channel_count += nFullbandDmxSignals;
659 }
660 }
661 if (bits.ReadBit()) { // b_oamd_common_data_present
662 // oamd_common_data()
663 ParseOamdCommonData(bits);
664 }
665 n_umx_objects_minus1 = bits.ReadBits(4);
666 int nFullbandUpmixSignals = n_umx_objects_minus1 + 1;
667 if (nFullbandUpmixSignals == 16) {
668 nFullbandUpmixSignals += AP4_Ac4VariableBits(bits, 3);
669 }
670
671 BedDynObjAssignment(bits, nFullbandUpmixSignals, true);
672 ParseDsiSfMutiplier(bits, fs_idx);
673
674 b_substream_bitrate_indicator = bits.ReadBit();
675 if (b_substream_bitrate_indicator) { // b_bitrate_info
676 ParseBitrateIndicator(bits);
677 }
678 for (unsigned int i = 0; i< frame_rate_factor; i++) {
679 bits.ReadBit(); // b_audio_ndot
680 }
681 ParseSubstreamIdxInfo(bits, b_substreams_present);
682 return AP4_SUCCESS;
683 }
684
685 /*----------------------------------------------------------------------
686 | AP4_Dac4Atom::Ac4Dsi::SubStream::ParseSubstreamInfoObj
687 +---------------------------------------------------------------------*/
688 AP4_Result
689 AP4_Dac4Atom::Ac4Dsi::SubStream::ParseSubstreamInfoObj(AP4_BitReader &bits,
690 unsigned int &channel_count,
691 unsigned char defalut_presentation_flag,
692 unsigned int fs_idx,
693 unsigned int frame_rate_factor,
694 unsigned int b_substreams_present)
695 {
696 int nObjectsCode = bits.ReadBits(3);
697 if (defalut_presentation_flag) {
698 switch (nObjectsCode) {
699 case 0:
700 case 1:
701 case 2:
702 case 3:
703 channel_count += nObjectsCode;
704 break;
705 case 4:
706 channel_count += 5;
707 break;
708 default:
709 break;
710 //TODO: Error
711 }
712 }
713 if (bits.ReadBit()) { // b_dynamic_objects
714 b_substream_contains_dynamic_objects = 1;
715 unsigned int b_lfe = bits.ReadBit(); // b_lfe
716 if (defalut_presentation_flag && b_lfe) { channel_count += 1; }
717 }else {
718 if (bits.ReadBit()) { // b_bed_objects
719 b_substream_contains_bed_objects = 1;
720 if (bits.ReadBit()) { // b_bed_start
721 if (bits.ReadBit()) { // b_ch_assign_code
722 bits.ReadBits(3); // bed_chan_assign_code
723 }
724 else {
725 if (bits.ReadBit()) { // b_nonstd_bed_channel_assignment
726 bits.ReadBits(17); // nonstd_bed_channel_assignment_mask
727 }
728 else {
729 bits.ReadBits(10); // std_bed_channel_assignment_mask
730 }
731 }
732 }
733 }else {
734 if (bits.ReadBit()) { // b_isf
735 b_substream_contains_ISF_objects = 1;
736 if (bits.ReadBit()) { // b_isf_start
737 bits.ReadBits(3); // isf_config
738 }
739 }else {
740 int resBytes = bits.ReadBits(4);
741 bits.ReadBits(resBytes * 8);
742 }
743 }
744 }
745
746 ParseDsiSfMutiplier(bits, fs_idx);
747
748 b_substream_bitrate_indicator = bits.ReadBit();
749 if (b_substream_bitrate_indicator) { // b_bitrate_info
750 ParseBitrateIndicator(bits);
751 }
752 for (unsigned int i = 0; i< frame_rate_factor; i++) {
753 bits.ReadBit(); // b_audio_ndot
754 }
755 ParseSubstreamIdxInfo(bits, b_substreams_present);
756 return AP4_SUCCESS;
757 }
758
759 /*----------------------------------------------------------------------
760 | AP4_Dac4Atom::Ac4Dsi::SubStream::WriteSubstreamDsi
761 +---------------------------------------------------------------------*/
762 AP4_Result
763 AP4_Dac4Atom::Ac4Dsi::SubStream::WriteSubstreamDsi(AP4_BitWriter &bits, unsigned char b_channel_coded)
764 {
765 bits.Write(dsi_sf_multiplier, 2);
766 bits.Write(b_substream_bitrate_indicator, 1);
767 if (b_substream_bitrate_indicator == 1) {
768 bits.Write(substream_bitrate_indicator, 5);
769 }
770 if (b_channel_coded == 1) {
771 bits.Write(dsi_substream_channel_mask, 24);
772 }else {
773 bits.Write(b_ajoc, 1);
774 if (b_ajoc == 1) {
775 bits.Write(b_static_dmx, 1);
776 if (b_static_dmx == 0) {
777 bits.Write(n_dmx_objects_minus1, 4);
778 }
779 bits.Write(n_umx_objects_minus1, 6);
780 }
781 // substream composition information
782 bits.Write(b_substream_contains_bed_objects, 1);
783 bits.Write(b_substream_contains_dynamic_objects, 1);
784 bits.Write(b_substream_contains_ISF_objects, 1);
785 bits.Write(0, 1); //reserved bit
786 }
787 return AP4_SUCCESS;
788 }
789
790 /*----------------------------------------------------------------------
791 | AP4_Dac4Atom::Ac4Dsi::SubStream::ParseChMode
792 +---------------------------------------------------------------------*/
793 AP4_Result
794 AP4_Dac4Atom::Ac4Dsi::SubStream::ParseChMode(AP4_BitReader &bits, int presentationVersion, unsigned char &dolby_atmos_indicator)
795 {
796 int channel_mode_code = 0;
797
798 channel_mode_code = bits.ReadBit();
799 if (channel_mode_code == 0) { // Mono 0b0
800 return CH_MODE_MONO;
801 }
802 channel_mode_code = (channel_mode_code << 1) | bits.ReadBit();
803 if (channel_mode_code == 2) { // Stereo 0b10
804 return CH_MODE_STEREO;
805 }
806 channel_mode_code = (channel_mode_code << 2) | bits.ReadBits(2);
807 switch (channel_mode_code) {
808 case 12: // 3.0 0b1100
809 return CH_MODE_3_0;
810 case 13: // 5.0 0b1101
811 return CH_MODE_5_0;
812 case 14: // 5.1 0b1110
813 return CH_MODE_5_1;
814 }
815 channel_mode_code = (channel_mode_code << 3) | bits.ReadBits(3);
816 switch (channel_mode_code) {
817 case 120: // 0b1111000
818 if (presentationVersion == 2) { // IMS (all content)
819 return CH_MODE_STEREO;
820 }
821 else { // 7.0: 3/4/0
822 return CH_MODE_70_34;
823 }
824 case 121: // 0b1111001
825 if (presentationVersion == 2) { // IMS (Atmos content)
826 dolby_atmos_indicator |= 1;
827 return CH_MODE_STEREO;
828 }
829 else { // 7.1: 3/4/0.1
830 return CH_MODE_71_34;
831 }
832 case 122: // 7.0: 5/2/0 0b1111010
833 return CH_MODE_70_52;
834 case 123: // 7.1: 5/2/0.1 0b1111011
835 return CH_MODE_71_52;
836 case 124: // 7.0: 3/2/2 0b1111100
837 return CH_MODE_70_322;
838 case 125: // 7.1: 3/2/2.1 0b1111101
839 return CH_MODE_71_322;
840 }
841 channel_mode_code = (channel_mode_code << 1) | bits.ReadBit();
842 switch (channel_mode_code) {
843 case 252: // 7.0.4 0b11111100
844 return CH_MODE_7_0_4;
845 case 253: // 7.1.4 0b11111101
846 return CH_MODE_7_1_4;
847 }
848 channel_mode_code = (channel_mode_code << 1) | bits.ReadBit();
849 switch (channel_mode_code) {
850 case 508: // 9.0.4 0b111111100
851 return CH_MODE_9_0_4;
852 case 509: // 9.1.4 0b111111101
853 return CH_MODE_9_1_4;
854 case 510: // 22.2 0b111111110
855 return CH_MODE_22_2;
856 case 511: // Reserved, escape value 0b111111111
857 default:
858 AP4_Ac4VariableBits(bits, 2);
859 return CH_MODE_RESERVED;
860 }
861 }
862
863 /*----------------------------------------------------------------------
864 | AP4_Dac4Atom::Ac4Dsi::SubStream::ParseDsiSfMutiplier
865 +---------------------------------------------------------------------*/
866 AP4_Result
867 AP4_Dac4Atom::Ac4Dsi::SubStream::ParseDsiSfMutiplier(AP4_BitReader &bits,
868 unsigned int fs_idx)
869 {
870 if (fs_idx == 1) {
871 if (bits.ReadBit()) { // b_sf_miultiplier
872 // 96 kHz or 192 kHz
873 dsi_sf_multiplier = bits.ReadBit() + 1; // sf_multiplier
874 }else{
875 // 48 kHz
876 dsi_sf_multiplier = 0;
877 }
878 }
879 return AP4_SUCCESS;
880 }
881
882 /*----------------------------------------------------------------------
883 | AP4_Dac4Atom::Ac4Dsi::SubStream::BedDynObjAssignment
884 +---------------------------------------------------------------------*/
885 AP4_Result
886 AP4_Dac4Atom::Ac4Dsi::SubStream::BedDynObjAssignment(AP4_BitReader &bits,
887 unsigned int nSignals,
888 bool is_upmix)
889 {
890 if (!bits.ReadBit()) { // b_dyn_objects_only
891 if (bits.ReadBit()) { // b_isf
892 unsigned char isf_config = bits.ReadBits(3);
893 if (is_upmix) {
894 b_substream_contains_ISF_objects |= 1;
895 if (nSignals > ObjNumFromIsfConfig(isf_config)) {
896 b_substream_contains_dynamic_objects |= 1;
897 }
898 }
899 }else {
900 if (bits.ReadBit()) { // b_ch_assign_code
901 unsigned char bed_chan_assign_code = bits.ReadBits(3);
902 if (is_upmix) {
903 b_substream_contains_bed_objects |= 1;
904 if (nSignals > BedNumFromAssignCode(bed_chan_assign_code)) {
905 b_substream_contains_dynamic_objects |= 1;
906 }
907 }
908 }else {
909 if (bits.ReadBit()) { // b_chan_assign_mask
910 if (bits.ReadBit()) { // b_nonstd_bed_channel_assignment
911 unsigned int nonstd_bed_channel_assignment_mask = bits.ReadBits(17);
912 if (is_upmix) {
913 unsigned int bed_num = BedNumFromNonStdMask(nonstd_bed_channel_assignment_mask);
914 if (bed_num > 0) { b_substream_contains_bed_objects |= 1; }
915 if (nSignals > bed_num) {
916 b_substream_contains_dynamic_objects |= 1;
917 }
918 }
919 }
920 else {
921 unsigned int std_bed_channel_assignment_mask = bits.ReadBits(10);
922 if (is_upmix) {
923 unsigned int bed_num = BedNumFromStdMask(std_bed_channel_assignment_mask);
924 if (bed_num > 0) { b_substream_contains_bed_objects |= 1; }
925 if (nSignals > bed_num) {
926 b_substream_contains_dynamic_objects |= 1;
927 }
928 }
929 }
930 }else {
931 unsigned int nBedSignals = 0;
932 if (nSignals > 1) {
933 int bedChBits = (int) ceil(log((float)nSignals)/log((float)2));
934 nBedSignals = bits.ReadBits(bedChBits) + 1;
935 }
936 else {
937 nBedSignals = 1;
938 }
939 for (unsigned int b = 0; b < nBedSignals; b++) {
940 bits.ReadBits(4); // nonstd_bed_channel_assignment
941 }
942 if (is_upmix) {
943 b_substream_contains_bed_objects |= 1;
944 if (nSignals > nBedSignals){ b_substream_contains_dynamic_objects |= 1; }
945 }
946 }
947 }
948 }
949 }else {
950 if (is_upmix) {
951 b_substream_contains_dynamic_objects |= 1;
952 b_substream_contains_bed_objects |= 0;
953 b_substream_contains_ISF_objects |= 0;
954 }
955 }
956 return AP4_SUCCESS;
957 }
958
959 /*----------------------------------------------------------------------
960 | AP4_Dac4Atom::Ac4Dsi::SubStream::ParseSubstreamIdxInfo
961 +---------------------------------------------------------------------*/
962 AP4_Result
963 AP4_Dac4Atom::Ac4Dsi::SubStream::ParseSubstreamIdxInfo(AP4_BitReader &bits, unsigned int b_substreams_present)
964 {
965 if (b_substreams_present == 1) {
966 if (bits.ReadBits(2) == 3) { // substream_index
967 AP4_Ac4VariableBits(bits, 2);
968 }
969 }
970 return AP4_SUCCESS;
971 }
972
973 /*----------------------------------------------------------------------
974 | AP4_Dac4Atom::Ac4Dsi::SubStream::ParseBitrateIndicator
975 +---------------------------------------------------------------------*/
976 AP4_Result
977 AP4_Dac4Atom::Ac4Dsi::SubStream::ParseBitrateIndicator(AP4_BitReader &bits)
978 {
979 substream_bitrate_indicator = bits.ReadBits(3);
980 if ((substream_bitrate_indicator & 0x1) == 1) { // bitrate_indicator
981 substream_bitrate_indicator = (substream_bitrate_indicator << 2) + bits.ReadBits(2);
982 }
983 return AP4_SUCCESS;
984 }
985
986 /*----------------------------------------------------------------------
987 | AP4_Dac4Atom::Ac4Dsi::SubStream::ParseOamdCommonData
988 +---------------------------------------------------------------------*/
989 AP4_Result
990 AP4_Dac4Atom::Ac4Dsi::SubStream::ParseOamdCommonData(AP4_BitReader &bits)
991 {
992 if (bits.ReadBit() == 0) { // b_default_screen_size_ratio
993 bits.ReadBits(5); // master_screen_size_ratio_code
994 }
995 bits.ReadBit(); // b_bed_object_chan_distribute
996 if (bits.ReadBit()) { // b_additional_data
997 int addDataBytes = bits.ReadBit() + 1;
998 if (addDataBytes == 2) {
999 addDataBytes += AP4_Ac4VariableBits(bits, 2);
1000 }
1001 unsigned int bits_used = Trim(bits);
1002 bits_used += BedRendeInfo(bits);
1003 bits.ReadBits(addDataBytes * 8 - bits_used);
1004 }
1005 return AP4_SUCCESS;
1006 }
1007
1008 /*----------------------------------------------------------------------
1009 | AP4_Dac4Atom::Ac4Dsi::SubStream::Trim
1010 +---------------------------------------------------------------------*/
1011 AP4_Result
1012 AP4_Dac4Atom::Ac4Dsi::SubStream::Trim(AP4_BitReader &bits)
1013 {
1014 return AP4_SUCCESS;
1015 }
1016
1017 /*----------------------------------------------------------------------
1018 | AP4_Dac4Atom::Ac4Dsi::SubStream::BedRendeInfo
1019 +---------------------------------------------------------------------*/
1020 AP4_Result
1021 AP4_Dac4Atom::Ac4Dsi::SubStream::BedRendeInfo(AP4_BitReader &bits)
1022 {
1023 return AP4_SUCCESS;
1024 }
1025
1026 /*----------------------------------------------------------------------
1027 | AP4_Dac4Atom::Ac4Dsi::SubStream::ObjNumFromIsfConfig
1028 +---------------------------------------------------------------------*/
1029 AP4_UI32
1030 AP4_Dac4Atom::Ac4Dsi::SubStream::ObjNumFromIsfConfig(unsigned char isf_config)
1031 {
1032 unsigned int obj_num = 0;
1033 switch (isf_config){
1034 case 0: obj_num = 4 ; break;
1035 case 1: obj_num = 8 ; break;
1036 case 2: obj_num = 10; break;
1037 case 3: obj_num = 14; break;
1038 case 4: obj_num = 15; break;
1039 case 5: obj_num = 30; break;
1040 default: obj_num = 0;
1041 }
1042 return obj_num;
1043 }
1044
1045 /*----------------------------------------------------------------------
1046 | AP4_Dac4Atom::Ac4Dsi::SubStream::BedNumFromAssignCode
1047 +---------------------------------------------------------------------*/
1048 AP4_UI32
1049 AP4_Dac4Atom::Ac4Dsi::SubStream::BedNumFromAssignCode(unsigned char assign_code)
1050 {
1051 unsigned int bed_num = 0;
1052 switch (assign_code){
1053 case 0: bed_num = 2 ; break;
1054 case 1: bed_num = 3 ; break;
1055 case 2: bed_num = 6 ; break;
1056 case 3: bed_num = 8 ; break;
1057 case 4: bed_num = 10; break;
1058 case 5: bed_num = 8 ; break;
1059 case 6: bed_num = 10; break;
1060 case 7: bed_num = 12; break;
1061 default: bed_num = 0;
1062 }
1063 return bed_num;
1064 }
1065
1066 /*----------------------------------------------------------------------
1067 | AP4_Dac4Atom::Ac4Dsi::SubStream::BedNumFromNonStdMask
1068 +---------------------------------------------------------------------*/
1069 AP4_UI32
1070 AP4_Dac4Atom::Ac4Dsi::SubStream::BedNumFromNonStdMask(unsigned int non_std_mask)
1071 {
1072 unsigned int bed_num = 0;
1073 // Table 85: nonstd_bed_channel_assignment AC-4 part-2 v1.2.1
1074 for (unsigned int idx = 0; idx < 17; idx ++) {
1075 if ((non_std_mask >> idx) & 0x1){
1076 bed_num ++;
1077 }
1078 }
1079 return bed_num;
1080 }
1081
1082 /*----------------------------------------------------------------------
1083 | AP4_Dac4Atom::Ac4Dsi::SubStream::BedNumFromStdMask
1084 +---------------------------------------------------------------------*/
1085 AP4_UI32
1086 AP4_Dac4Atom::Ac4Dsi::SubStream::BedNumFromStdMask(unsigned int std_mask)
1087 {
1088 unsigned int bed_num = 0;
1089 // Table 86 std_bed_channel_assignment_flag[] AC-4 part-2 v1.2.1
1090 for (unsigned int idx = 0; idx < 10; idx ++) {
1091 if ((std_mask >> idx) & 0x1){
1092 if ((idx == 1) || (idx == 2) || (idx == 9)) { bed_num ++;}
1093 else { bed_num += 2; }
1094 }
1095 }
1096 return bed_num;
1097 }
1098
1099 /*----------------------------------------------------------------------
1100 | AP4_Dac4Atom::Ac4Dsi::SubStream::GetChModeCore
1101 +---------------------------------------------------------------------*/
1102 AP4_Result
1103 AP4_Dac4Atom::Ac4Dsi::SubStream::GetChModeCore(unsigned char b_channel_coded)
1104 {
1105 int ch_mode_core = -1;
1106 if (b_channel_coded == 0 &&
1107 b_ajoc == 1 &&
1108 b_static_dmx == 1 &&
1109 b_lfe == 0){
1110 ch_mode_core = 3 ;
1111 }else if (b_channel_coded == 0 &&
1112 b_ajoc == 1 &&
1113 b_static_dmx == 1 &&
1114 b_lfe == 1){
1115 ch_mode_core = 4 ;
1116 }else if ((b_channel_coded == 1) &&
1117 (ch_mode == 11 || ch_mode == 13)){
1118 ch_mode_core = 5 ;
1119 }else if ((b_channel_coded == 1) &&
1120 (ch_mode == 12 || ch_mode == 14)){
1121 ch_mode_core = 6 ;
1122 }
1123 return ch_mode_core;
1124 }
1125
1126 /*----------------------------------------------------------------------
1127 | AP4_Dac4Atom::Ac4Dsi::SubStreamGroupV1::ParseSubstreamGroupInfo
1128 +---------------------------------------------------------------------*/
1129 AP4_Result
1130 AP4_Dac4Atom::Ac4Dsi::SubStreamGroupV1::ParseSubstreamGroupInfo(AP4_BitReader& bits,
1131 unsigned int bitstream_version,
1132 unsigned int presentation_version,
1133 unsigned char defalut_presentation_flag,
1134 unsigned int frame_rate_factor,
1135 unsigned int fs_idx,
1136 unsigned int& channel_count,
1137 unsigned int& speaker_index_mask,
1138 unsigned int& b_obj_or_Ajoc)
1139 {
1140 d.v1.b_substreams_present = bits.ReadBit();
1141 d.v1.b_hsf_ext = bits.ReadBit();
1142 if (bits.ReadBit()) {
1143 d.v1.n_substreams = 1;
1144 } else{
1145 d.v1.n_substreams = bits.ReadBits(2) + 2;
1146 if (d.v1.n_substreams == 5) {
1147 d.v1.n_substreams += AP4_Ac4VariableBits(bits, 2);
1148 }
1149 }
1150 d.v1.substreams = new AP4_Dac4Atom::Ac4Dsi::SubStream[d.v1.n_substreams];
1151 AP4_SetMemory(d.v1.substreams, 0, d.v1.n_substreams * sizeof(d.v1.substreams[0]));
1152 d.v1.b_channel_coded = bits.ReadBit();
1153 if (d.v1.b_channel_coded) {
1154 for (unsigned int sus = 0; sus < d.v1.n_substreams; sus++) {
1155 AP4_Dac4Atom::Ac4Dsi::SubStream& substream = d.v1.substreams[sus];
1156 if (bitstream_version == 1) {
1157 bits.ReadBit(); // sus_ver
1158 }
1159
1160 // ac4_substream_info_chan()
1161 substream.ParseSubstreamInfoChan(bits,
1162 presentation_version,
1163 defalut_presentation_flag,
1164 fs_idx,
1165 speaker_index_mask,
1166 frame_rate_factor,
1167 d.v1.b_substreams_present,
1168 d.v1.dolby_atmos_indicator);
1169
1170 if (d.v1.b_hsf_ext) {
1171 // ac4_hsf_ext_substream_info()
1172 ParseHsfExtSubstreamInfo(bits);
1173 }
1174 }
1175 } else { // b_channel_coded == 0
1176 b_obj_or_Ajoc = 1;
1177 if (bits.ReadBit()) { // b_oamd_substream
1178 //oamd_substream_info()
1179 ParseOamdSubstreamInfo(bits);
1180 }
1181 for (int sus = 0; sus < d.v1.n_substreams; sus++) {
1182 AP4_Dac4Atom::Ac4Dsi::SubStream& substream = d.v1.substreams[sus];
1183 substream.b_ajoc = bits.ReadBit();
1184 unsigned int local_channel_count = 0;
1185 if (substream.b_ajoc) { // b_ajoc
1186 // ac4_substream_info_ajoc()
1187 substream.ParseSubStreamInfoAjoc(bits,
1188 local_channel_count,
1189 defalut_presentation_flag,
1190 fs_idx,
1191 frame_rate_factor,
1192 d.v1.b_substreams_present);
1193
1194 if (d.v1.b_hsf_ext) {
1195 // ac4_hsf_ext_substream_info()
1196 ParseHsfExtSubstreamInfo(bits);
1197 }
1198 }else {
1199 // ac4_substream_info_obj()
1200 substream.ParseSubstreamInfoObj(bits,
1201 local_channel_count,
1202 defalut_presentation_flag,
1203 fs_idx,
1204 frame_rate_factor,
1205 d.v1.b_substreams_present);
1206
1207 if (d.v1.b_hsf_ext) {
1208 // ac4_hsf_ext_substream_info()
1209 ParseHsfExtSubstreamInfo(bits);
1210 }
1211 }
1212 if (channel_count < local_channel_count) { channel_count = local_channel_count;}
1213 }
1214 }
1215
1216 d.v1.b_content_type = bits.ReadBit();
1217 if (d.v1.b_content_type) {
1218 // content_type()
1219 ParseContentType(bits);
1220 }
1221 return AP4_SUCCESS;
1222 }
1223
1224 /*----------------------------------------------------------------------
1225 | AP4_Dac4Atom::Ac4Dsi::SubStreamGroupV1::WriteSubstreamGroupDsi
1226 +---------------------------------------------------------------------*/
1227 AP4_Result
1228 AP4_Dac4Atom::Ac4Dsi::SubStreamGroupV1::WriteSubstreamGroupDsi(AP4_BitWriter &bits)
1229 {
1230 bits.Write(d.v1.b_substreams_present, 1);
1231 bits.Write(d.v1.b_hsf_ext, 1);
1232 bits.Write(d.v1.b_channel_coded, 1);
1233 bits.Write(d.v1.n_substreams, 8);
1234 for (unsigned int sg = 0; sg < d.v1.n_substreams; sg++ ){
1235 d.v1.substreams[sg].WriteSubstreamDsi(bits, d.v1.b_channel_coded);
1236 }
1237 WriteContentType(bits);
1238 return AP4_SUCCESS;
1239 }
1240
1241 /*----------------------------------------------------------------------
1242 | AP4_Dac4Atom::Ac4Dsi::SubStreamGroupV1::ParseOamdSubstreamInfo
1243 +---------------------------------------------------------------------*/
1244 AP4_Result
1245 AP4_Dac4Atom::Ac4Dsi::SubStreamGroupV1::ParseOamdSubstreamInfo(AP4_BitReader &bits)
1246 {
1247 bits.ReadBit(); // b_oamd_ndot
1248 if (d.v1.b_substreams_present == 1) {
1249 if (bits.ReadBits(2) == 3) { // substream_index
1250 AP4_Ac4VariableBits(bits, 2);
1251 }
1252 }
1253 return AP4_SUCCESS;
1254 }
1255
1256 /*----------------------------------------------------------------------
1257 | AP4_Dac4Atom::Ac4Dsi::SubStreamGroupV1::ParseHsfExtSubstreamInfo
1258 +---------------------------------------------------------------------*/
1259 AP4_Result
1260 AP4_Dac4Atom::Ac4Dsi::SubStreamGroupV1::ParseHsfExtSubstreamInfo(AP4_BitReader &bits)
1261 {
1262 if (d.v1.b_substreams_present == 1) {
1263 if (bits.ReadBits(2) == 3) { // substream_index
1264 AP4_Ac4VariableBits(bits, 2);
1265 }
1266 }
1267 return AP4_SUCCESS;
1268 }
1269
1270 /*----------------------------------------------------------------------
1271 | AP4_Dac4Atom::Ac4Dsi::SubStreamGroupV1::ParseContentType
1272 +---------------------------------------------------------------------*/
1273 AP4_Result
1274 AP4_Dac4Atom::Ac4Dsi::SubStreamGroupV1::ParseContentType(AP4_BitReader &bits)
1275 {
1276 d.v1.content_classifier = bits.ReadBits(3); // content_classifier
1277 d.v1.b_language_indicator = bits.ReadBit();
1278 if (d.v1.b_language_indicator == 1) { // b_language_indicator
1279 if (bits.ReadBit()) { // b_serialized_language_tag
1280 bits.ReadBits(17); // b_start_tag, language_tag_chunk
1281 }
1282 else {
1283 d.v1.n_language_tag_bytes= bits.ReadBits(6);
1284 for (unsigned int l = 0; l < d.v1.n_language_tag_bytes; l++){
1285 d.v1.language_tag_bytes[l] = bits.ReadBits(8);
1286 }
1287 }
1288 }
1289 return AP4_SUCCESS;
1290 }
1291
1292 /*----------------------------------------------------------------------
1293 | AP4_Dac4Atom::Ac4Dsi::SubStreamGroupV1::WriteContentType
1294 +---------------------------------------------------------------------*/
1295 AP4_Result
1296 AP4_Dac4Atom::Ac4Dsi::SubStreamGroupV1::WriteContentType(AP4_BitWriter &bits)
1297 {
1298 bits.Write(d.v1.b_content_type, 1);
1299 if (d.v1.b_content_type == 1){
1300 bits.Write(d.v1.content_classifier, 3);
1301 bits.Write(d.v1.b_language_indicator, 1);
1302 if (d.v1.b_language_indicator == 1){
1303 bits.Write(d.v1.n_language_tag_bytes, 6);
1304 for (unsigned int idx = 0; idx < d.v1.n_language_tag_bytes; idx++ ){
1305 bits.Write(d.v1.language_tag_bytes[idx], 8);
1306 }
1307 }
1308 }
1309 return AP4_SUCCESS;
1310 }
1311
1312 /*----------------------------------------------------------------------
1313 | AP4_Dac4Atom::Ac4Dsi::PresentationV1::Parse
1314 +---------------------------------------------------------------------*/
1315 AP4_Result
1316 AP4_Dac4Atom::Ac4Dsi::PresentationV1::ParsePresentationV1Info(AP4_BitReader &bits,
1317 unsigned int bitstream_version,
1318 unsigned int frame_rate_idx,
1319 unsigned int pres_idx,
1320 unsigned int &max_group_index,
1321 unsigned int **first_pres_sg_index,
1322 unsigned int &first_pres_sg_num)
1323 {
1324 unsigned int *substreamGroupIndexes = new unsigned int[AP4_AC4_SUBSTREAM_GROUP_NUM];
1325 unsigned int b_single_substream_group = bits.ReadBit();
1326 if (b_single_substream_group != 1){
1327 d.v1.presentation_config_v1 = bits.ReadBits(3);
1328 if (d.v1.presentation_config_v1 == 7) {
1329 d.v1.presentation_config_v1 += AP4_Ac4VariableBits(bits, 2);
1330 }
1331 }else {
1332 d.v1.presentation_config_v1 = 0x1f;
1333 }
1334
1335 // presentation_version()
1336 ParsePresentationVersion(bits, bitstream_version);
1337
1338 AP4_Ac4EmdfInfo tmp_emdf_info;
1339 if (b_single_substream_group != 1 && d.v1.presentation_config_v1 == 6){
1340 d.v1.b_add_emdf_substreams = 1;
1341 }else{
1342 if (bitstream_version != 1){
1343 d.v1.mdcompat = bits.ReadBits(3);
1344 }
1345 d.v1.b_presentation_id = bits.ReadBit();
1346 if (d.v1.b_presentation_id) {
1347 d.v1.presentation_id = AP4_Ac4VariableBits(bits, 2);
1348 }
1349 // frame_rate_multiply_info()
1350 ParseDSIFrameRateMultiplyInfo(bits, frame_rate_idx);
1351
1352 // frame_rate_fractions_info()
1353 ParseDSIFrameRateFractionsInfo(bits, frame_rate_idx);
1354
1355 // emdf_info()
1356 ParseEmdInfo(bits, tmp_emdf_info);
1357 d.v1.presentation_emdf_version = tmp_emdf_info.emdf_version;
1358 d.v1.presentation_key_id = tmp_emdf_info.key_id;
1359
1360 // b_presentation_filter
1361 d.v1.b_presentation_filter = bits.ReadBit();
1362 if (d.v1.b_presentation_filter == 1){
1363 d.v1.b_enable_presentation = bits.ReadBit();
1364 }
1365 if (b_single_substream_group == 1){
1366 substreamGroupIndexes[0] = ParseAc4SgiSpecifier(bits, bitstream_version);
1367 max_group_index = AP4_SetMaxGroupIndex(substreamGroupIndexes[0], max_group_index);
1368 d.v1.n_substream_groups = 1;
1369 d.v1.substream_group_indexs = substreamGroupIndexes;
1370 }else {
1371 d.v1.b_multi_pid = bits.ReadBit();
1372 switch (d.v1.presentation_config_v1){
1373 case 0: // M&E + D
1374 case 2: // Main + Assoc
1375 substreamGroupIndexes[0] = ParseAc4SgiSpecifier(bits, bitstream_version);
1376 substreamGroupIndexes[1] = ParseAc4SgiSpecifier(bits, bitstream_version);
1377 max_group_index = AP4_SetMaxGroupIndex(substreamGroupIndexes[0], max_group_index);
1378 max_group_index = AP4_SetMaxGroupIndex(substreamGroupIndexes[1], max_group_index);
1379 d.v1.n_substream_groups = 2;
1380 d.v1.substream_group_indexs = substreamGroupIndexes;
1381 break;
1382 case 1: // Main + DE
1383 // shall return same substream group index, need stream to verify
1384 substreamGroupIndexes[0] = ParseAc4SgiSpecifier(bits, bitstream_version);
1385 substreamGroupIndexes[1] = ParseAc4SgiSpecifier(bits, bitstream_version);
1386 max_group_index = AP4_SetMaxGroupIndex(substreamGroupIndexes[0], max_group_index);
1387 max_group_index = AP4_SetMaxGroupIndex(substreamGroupIndexes[1], max_group_index);
1388 d.v1.n_substream_groups = 2;
1389 d.v1.substream_group_indexs = substreamGroupIndexes;
1390 break;
1391 case 3: // M&E + D + Assoc
1392 substreamGroupIndexes[0] = ParseAc4SgiSpecifier(bits, bitstream_version);
1393 substreamGroupIndexes[1] = ParseAc4SgiSpecifier(bits, bitstream_version);
1394 substreamGroupIndexes[2] = ParseAc4SgiSpecifier(bits, bitstream_version);
1395 max_group_index = AP4_SetMaxGroupIndex(substreamGroupIndexes[0], max_group_index);
1396 max_group_index = AP4_SetMaxGroupIndex(substreamGroupIndexes[1], max_group_index);
1397 max_group_index = AP4_SetMaxGroupIndex(substreamGroupIndexes[2], max_group_index);
1398 d.v1.n_substream_groups = 3;
1399 d.v1.substream_group_indexs = substreamGroupIndexes;
1400 break;
1401 case 4: // Main + DE + Assoc
1402 // shall return only two substream group index, need stream to verify
1403 substreamGroupIndexes[0] = ParseAc4SgiSpecifier(bits, bitstream_version);
1404 substreamGroupIndexes[1] = ParseAc4SgiSpecifier(bits, bitstream_version);
1405 substreamGroupIndexes[2] = ParseAc4SgiSpecifier(bits, bitstream_version);
1406 max_group_index = AP4_SetMaxGroupIndex(substreamGroupIndexes[0], max_group_index);
1407 max_group_index = AP4_SetMaxGroupIndex(substreamGroupIndexes[1], max_group_index);
1408 max_group_index = AP4_SetMaxGroupIndex(substreamGroupIndexes[2], max_group_index);
1409 d.v1.n_substream_groups = 3;
1410 d.v1.substream_group_indexs = substreamGroupIndexes;
1411 break;
1412 case 5:
1413 d.v1.n_substream_groups = bits.ReadBits(2) + 2;
1414 if (d.v1.n_substream_groups == 5) {
1415 d.v1.n_substream_groups += AP4_Ac4VariableBits(bits, 2);
1416 }
1417 delete[] substreamGroupIndexes;
1418 substreamGroupIndexes = new unsigned int[d.v1.n_substream_groups];
1419 for (unsigned int sg = 0; sg < d.v1.n_substream_groups; sg ++){
1420 substreamGroupIndexes[sg] = ParseAc4SgiSpecifier(bits, bitstream_version);
1421 max_group_index = AP4_SetMaxGroupIndex(substreamGroupIndexes[sg], max_group_index);
1422 }
1423 d.v1.substream_group_indexs = substreamGroupIndexes;
1424 break;
1425 default:
1426 // presentation_config_ext_info()
1427 ParsePresentationConfigExtInfo(bits, bitstream_version);
1428 break;
1429 }
1430 }
1431 // b_pre_virtualized
1432 d.v1.b_pre_virtualized = bits.ReadBit();
1433 d.v1.b_add_emdf_substreams = bits.ReadBit();
1434 // ac4_presentation_substream_info()
1435 ParsePresentationSubstreamInfo(bits);
1436 }
1437
1438 if (d.v1.b_add_emdf_substreams){
1439 d.v1.n_add_emdf_substreams = bits.ReadBits(2);
1440 if (d.v1.n_add_emdf_substreams == 0){
1441 d.v1.n_add_emdf_substreams = AP4_Ac4VariableBits(bits, 2) + 4;
1442 }
1443 for (unsigned int cnt = 0; cnt < d.v1.n_add_emdf_substreams; cnt ++){
1444 ParseEmdInfo(bits, tmp_emdf_info);
1445 d.v1.substream_emdf_version[cnt] = tmp_emdf_info.emdf_version;
1446 d.v1.substream_key_id[cnt] = tmp_emdf_info.key_id;
1447 }
1448 }
1449 if (pres_idx == 0){
1450 *first_pres_sg_index = substreamGroupIndexes;
1451 first_pres_sg_num = d.v1.n_substream_groups;
1452 }
1453 return AP4_SUCCESS;
1454 }
1455
1456 /*----------------------------------------------------------------------
1457 | AP4_Dac4Atom::Ac4Dsi::PresentationV1::WritePresentationV1Dsi
1458 +---------------------------------------------------------------------*/
1459 AP4_Result
1460 AP4_Dac4Atom::Ac4Dsi::PresentationV1::WritePresentationV1Dsi(AP4_BitWriter &bits)
1461 {
1462 bits.Write(d.v1.presentation_config_v1, 5);
1463 if (d.v1.presentation_config_v1 == 0x06) {
1464 d.v1.b_add_emdf_substreams = 1;
1465 }else {
1466 bits.Write(d.v1.mdcompat, 3);
1467 bits.Write(d.v1.b_presentation_id, 1);
1468 if (d.v1.b_presentation_id == 1){
1469 bits.Write(d.v1.presentation_id, 5);
1470 }
1471 bits.Write(d.v1.dsi_frame_rate_multiply_info, 2);
1472 bits.Write(d.v1.dsi_frame_rate_fraction_info, 2);
1473 bits.Write(d.v1.presentation_emdf_version, 5);
1474 bits.Write(d.v1.presentation_key_id, 10);
1475 d.v1.b_presentation_channel_coded = ((GetPresentationChMode() == -1) ? 0: 1);
1476 bits.Write(d.v1.b_presentation_channel_coded, 1);
1477 if (d.v1.b_presentation_channel_coded == 1) {
1478 d.v1.dsi_presentation_ch_mode = GetPresentationChMode();
1479 bits.Write(d.v1.dsi_presentation_ch_mode, 5);
1480 if (d.v1.dsi_presentation_ch_mode >= 11 && d.v1.dsi_presentation_ch_mode <= 14){
1481 GetPresB4BackChannelsPresent();
1482 GetPresTopChannelPairs();
1483 bits.Write(d.v1.pres_b_4_back_channels_present, 1);
1484 bits.Write(d.v1.pres_top_channel_pairs, 2);
1485 if (d.v1.pres_top_channel_pairs) {
1486 d.v1.dolby_atmos_indicator = 1;
1487 }
1488 }
1489 d.v1.presentation_channel_mask_v1 = GetPresentationChannelMask();
1490 bits.Write(d.v1.presentation_channel_mask_v1, 24);
1491 }
1492 int pres_ch_mode_core = GetBPresentationCoreDiffers();
1493 bits.Write(d.v1.b_presentation_core_differs = ((pres_ch_mode_core == -1) ? 0: 1), 1);
1494 if (d.v1.b_presentation_core_differs == 1) {
1495 bits.Write(d.v1.b_presentation_core_channel_coded = ((pres_ch_mode_core == -1) ? 0: 1), 1);
1496 if (d.v1.b_presentation_core_channel_coded == 1) {
1497 bits.Write(d.v1.dsi_presentation_channel_mode_core = (pres_ch_mode_core - 3), 2);
1498 }
1499 }
1500 bits.Write(d.v1.b_presentation_filter, 1);
1501 if (d.v1.b_presentation_filter == 1) {
1502 bits.Write(d.v1.b_enable_presentation, 1);
1503 // Encoders implemented according to the present document shall write the value 0
1504 d.v1.n_filter_bytes = 0;
1505 bits.Write(d.v1.n_filter_bytes, 8);
1506 //TODO: filter_data if n_filter_bytes > 0
1507 }
1508
1509 if (d.v1.presentation_config_v1 == 0x1f){
1510 d.v1.substream_groups[0].WriteSubstreamGroupDsi(bits);
1511 }else {
1512 bits.Write(d.v1.b_multi_pid, 1);
1513 if (d.v1.presentation_config_v1 <= 2){
1514 d.v1.substream_groups[0].WriteSubstreamGroupDsi(bits);
1515 d.v1.substream_groups[1].WriteSubstreamGroupDsi(bits);
1516 }
1517 if (d.v1.presentation_config_v1 >= 3 && d.v1.presentation_config_v1 <= 4){
1518 d.v1.substream_groups[0].WriteSubstreamGroupDsi(bits);
1519 d.v1.substream_groups[1].WriteSubstreamGroupDsi(bits);
1520 d.v1.substream_groups[2].WriteSubstreamGroupDsi(bits);
1521 }
1522 if (d.v1.presentation_config_v1 == 5) {
1523 bits.Write(d.v1.n_substream_groups - 2, 3);
1524 for (unsigned int sg = 0; sg < d.v1.n_substream_groups; sg ++) {
1525 d.v1.substream_groups[sg].WriteSubstreamGroupDsi(bits);
1526 }
1527 }
1528 if (d.v1.presentation_config_v1 > 5) {
1529 d.v1.n_skip_bytes = 0;
1530 bits.Write(d.v1.n_skip_bytes, 7);
1531 //TODO: skip_data if n_skip_bytes > 0
1532 }
1533 }
1534
1535 // IMS shall set the b_pre_virtualized = 1
1536 if (presentation_version == 2) {
1537 d.v1.b_pre_virtualized = 1;
1538 }
1539 bits.Write(d.v1.b_pre_virtualized, 1);
1540 bits.Write(d.v1.b_add_emdf_substreams, 1);
1541 }
1542 if (d.v1.b_add_emdf_substreams == 1){
1543 bits.Write(d.v1.n_add_emdf_substreams, 7);
1544 for (unsigned int j = 0; j < d.v1.n_add_emdf_substreams; j++){
1545 bits.Write(d.v1.substream_emdf_version[j], 5);
1546 bits.Write(d.v1.substream_key_id[j], 10);
1547 }
1548 }
1549 // TODO: Not implement, can't get the informaiton from TOC, need calcuate by the muxer
1550 bits.Write(d.v1.b_presentation_bitrate_info, 1);
1551 if (d.v1.b_presentation_bitrate_info == 1) {
1552 d.v1.ac4_bitrate_dsi.WriteBitrateDsi(bits);
1553 }
1554
1555 bits.Write(d.v1.b_alternative, 1);
1556 if (d.v1.b_alternative == 1) {
1557 AP4_ByteAlign(bits);
1558 // TODO: Not implement, need the information from ac4_presentation_substream
1559 d.v1.alternative_info.WriteAlternativeInfo(bits);
1560 }
1561 AP4_ByteAlign(bits);
1562
1563 /*
1564 * TODO: Not implement, need the information from ac4_substream.
1565 * Currently just set the value to 1 according to Dolby's internal discussion.
1566 */
1567 d.v1.de_indicator = 1;
1568 bits.Write(d.v1.de_indicator, 1);
1569
1570 bits.Write(d.v1.dolby_atmos_indicator, 1);
1571 bits.Write(0, 4); //reserved bits
1572
1573 if (d.v1.presentation_id > 31) {
1574 d.v1.b_extended_presentation_id = 1;
1575 d.v1.extended_presentation_id = d.v1.presentation_id;
1576 }
1577 bits.Write(d.v1.b_extended_presentation_id, 1);
1578 if (d.v1.b_extended_presentation_id == 1) {
1579 bits.Write(d.v1.extended_presentation_id, 9);
1580 }else {
1581 bits.Write(0, 1); //reserved bit
1582 }
1583 return AP4_SUCCESS;
1584 }
1585
1586 /*----------------------------------------------------------------------
1587 | AP4_Dac4Atom::Ac4Dsi::PresentationV1::ParsePresentationVersion
1588 +---------------------------------------------------------------------*/
1589 AP4_Result
1590 AP4_Dac4Atom::Ac4Dsi::PresentationV1::ParsePresentationVersion(AP4_BitReader& bits, unsigned int bitstream_version)
1591 {
1592 presentation_version = 0;
1593 if (bitstream_version != 1){
1594 while(bits.ReadBit() == 1){
1595 presentation_version ++;
1596 }
1597 }
1598 return AP4_SUCCESS;
1599 }
1600
1601 /*----------------------------------------------------------------------
1602 | AP4_Dac4Atom::Ac4Dsi::PresentationV1::ParsePresentationConfigExtInfo
1603 +---------------------------------------------------------------------*/
1604 AP4_Result
1605 AP4_Dac4Atom::Ac4Dsi::PresentationV1::ParsePresentationConfigExtInfo(AP4_BitReader &bits, unsigned int bitstream_version)
1606 {
1607 unsigned int nSkipBytes = bits.ReadBits(5);
1608 if (bits.ReadBit()) { // b_more_skip_bytes
1609 nSkipBytes += (AP4_Ac4VariableBits(bits, 2) << 5);
1610 }
1611 if (bitstream_version == 1 && d.v1.presentation_config_v1 == 7) {
1612 // TODO: refer to chapte 6.2.1.5 - TS 103 190-2
1613 }
1614 bits.ReadBits(nSkipBytes * 8);
1615 return AP4_SUCCESS;
1616 }
1617
1618 /*----------------------------------------------------------------------
1619 | AP4_Dac4Atom::Ac4Dsi::PresentationV1::ParseAc4SgiSpecifier
1620 +---------------------------------------------------------------------*/
1621 AP4_UI32
1622 AP4_Dac4Atom::Ac4Dsi::PresentationV1::ParseAc4SgiSpecifier(AP4_BitReader &bits, unsigned int bitstream_version)
1623 {
1624 if (bitstream_version == 1) {
1625 // Error
1626 return 0;
1627 } else{
1628 unsigned int groupIndex = bits.ReadBits(3);
1629 if (groupIndex == 7) {
1630 groupIndex += AP4_Ac4VariableBits(bits, 2);
1631 }
1632 return groupIndex;
1633 }
1634 }
1635
1636 /*----------------------------------------------------------------------
1637 | AP4_Dac4Atom::Ac4Dsi::PresentationV1::ParseDSIFrameRateMultiplyInfo
1638 +---------------------------------------------------------------------*/
1639 AP4_Result
1640 AP4_Dac4Atom::Ac4Dsi::PresentationV1::ParseDSIFrameRateMultiplyInfo(AP4_BitReader &bits, unsigned int frame_rate_idx)
1641 {
1642 switch (frame_rate_idx) {
1643 case 2:
1644 case 3:
1645 case 4:
1646 if (bits.ReadBit()) { // b_multiplier
1647 unsigned int multiplier_bit = bits.ReadBit(); //multiplier_bit
1648 d.v1.dsi_frame_rate_multiply_info = (multiplier_bit == 0)? 1: 2;
1649 }
1650 else {
1651 d.v1.dsi_frame_rate_multiply_info = 0;
1652 }
1653 break;
1654 case 0:
1655 case 1:
1656 case 7:
1657 case 8:
1658 case 9:
1659 if (bits.ReadBit()) {
1660 d.v1.dsi_frame_rate_multiply_info = 1;
1661 }else {
1662 d.v1.dsi_frame_rate_multiply_info = 0;
1663 }
1664 break;
1665 default:
1666 d.v1.dsi_frame_rate_multiply_info = 0;
1667 break;
1668 }
1669 return AP4_SUCCESS;
1670 }
1671
1672
1673 /*----------------------------------------------------------------------
1674 | AP4_Dac4Atom::Ac4Dsi::PresentationV1::ParseDSIFrameRateFractionsInfo
1675 +---------------------------------------------------------------------*/
1676 AP4_Result
1677 AP4_Dac4Atom::Ac4Dsi::PresentationV1::ParseDSIFrameRateFractionsInfo(AP4_BitReader &bits, unsigned int frame_rate_idx)
1678 {
1679 if (frame_rate_idx >= 5 && frame_rate_idx <= 9) {
1680 if (bits.ReadBit() == 1) { // b_frame_rate_fraction
1681 d.v1.dsi_frame_rate_fraction_info = 1;
1682 }else{
1683 d.v1.dsi_frame_rate_fraction_info = 0;
1684 }
1685 }else if (frame_rate_idx >= 10 && frame_rate_idx <= 12){
1686 if (bits.ReadBit() == 1) { // b_frame_rate_fraction
1687 if (bits.ReadBit() == 1) { // b_frame_rate_fraction_is_4
1688 d.v1.dsi_frame_rate_fraction_info = 2;
1689 } else {
1690 d.v1.dsi_frame_rate_fraction_info = 1;
1691 }
1692
1693 }else{
1694 d.v1.dsi_frame_rate_fraction_info = 0;
1695 }
1696 }
1697 return AP4_SUCCESS;
1698 }
1699
1700 /*----------------------------------------------------------------------
1701 | AP4_Dac4Atom::Ac4Dsi::PresentationV1::ParseEmdInfo
1702 +---------------------------------------------------------------------*/
1703 AP4_Result
1704 AP4_Dac4Atom::Ac4Dsi::PresentationV1::ParseEmdInfo(AP4_BitReader &bits, AP4_Ac4EmdfInfo &emdf_info)
1705 {
1706 emdf_info.emdf_version = bits.ReadBits(2);
1707 if (emdf_info.emdf_version == 3) {
1708 emdf_info.emdf_version += AP4_Ac4VariableBits(bits, 2);
1709 }
1710 emdf_info.key_id = bits.ReadBits(3);
1711 if (emdf_info.key_id == 7) {
1712 emdf_info.key_id += AP4_Ac4VariableBits(bits, 3);
1713 }
1714 emdf_info.b_emdf_payloads_substream_info = bits.ReadBit();
1715 if (emdf_info.b_emdf_payloads_substream_info == 1) {
1716 // emdf_payloads_substream_info ()
1717 if (bits.ReadBits(2) == 3) { // substream_index
1718 AP4_Ac4VariableBits(bits, 2);
1719 }
1720 }
1721 emdf_info.protectionLengthPrimary = bits.ReadBits(2);
1722 emdf_info.protectionLengthSecondary = bits.ReadBits(2);
1723 // protection_bits_primary
1724 switch (emdf_info.protectionLengthPrimary) {
1725 case 1:
1726 emdf_info.protection_bits_primary[0] = bits.ReadBits(8);
1727 break;
1728 case 2:
1729 for (unsigned idx = 0; idx < 4; idx ++) { emdf_info.protection_bits_primary[idx] = bits.ReadBits(8); }
1730 break;
1731 case 3:
1732 for (unsigned idx = 0; idx < 16; idx ++) { emdf_info.protection_bits_primary[idx] = bits.ReadBits(8); }
1733 break;
1734 default:
1735 // Error
1736 break;
1737 }
1738 // protection_bits_secondary
1739 switch (emdf_info.protectionLengthSecondary) {
1740 case 0:
1741 break;
1742 case 1:
1743 emdf_info.protection_bits_Secondary[0] = bits.ReadBits(8);
1744 break;
1745 case 2:
1746 for (unsigned idx = 0; idx < 4; idx ++) { emdf_info.protection_bits_Secondary[idx] = bits.ReadBits(8); }
1747 break;
1748 case 3:
1749 for (unsigned idx = 0; idx < 16; idx ++) { emdf_info.protection_bits_Secondary[idx] = bits.ReadBits(8); }
1750 break;
1751 default:
1752 // TODO: Error
1753 break;
1754 }
1755 return AP4_SUCCESS;
1756 }
1757
1758 /*----------------------------------------------------------------------
1759 | AP4_Dac4Atom::Ac4Dsi::PresentationV1::ParsePresentationSubstreamInfo
1760 +---------------------------------------------------------------------*/
1761 AP4_Result
1762 AP4_Dac4Atom::Ac4Dsi::PresentationV1::ParsePresentationSubstreamInfo(AP4_BitReader &bits)
1763 {
1764 d.v1.b_alternative = bits.ReadBit();
1765 /* unsigned int b_pres_ndot = */ bits.ReadBit(); // b_pres_ndot;
1766 unsigned int substream_index = bits.ReadBits(2); //substream_index
1767 if (substream_index == 3){
1768 AP4_Ac4VariableBits(bits, 2);
1769 }
1770 return AP4_SUCCESS;
1771 }
1772
1773 /*----------------------------------------------------------------------
1774 | AP4_Dac4Atom::Ac4Dsi::PresentationV1::GetPresentationChMode
1775 +---------------------------------------------------------------------*/
1776 AP4_Result
1777 AP4_Dac4Atom::Ac4Dsi::PresentationV1::GetPresentationChMode()
1778 {
1779 int pres_ch_mode = -1;
1780 char b_obj_or_ajoc = 0;
1781 // TODO: n_substream_groups
1782 for (unsigned int sg = 0; sg < d.v1.n_substream_groups; sg++){
1783 AP4_Dac4Atom::Ac4Dsi::SubStreamGroupV1 &substream_group = d.v1.substream_groups[sg];
1784 unsigned int n_substreams = d.v1.substream_groups[sg].d.v1.n_substreams;
1785 for (unsigned int sus = 0; sus < n_substreams; sus++){
1786 AP4_Dac4Atom::Ac4Dsi::SubStream &substream = substream_group.d.v1.substreams[sus];
1787 if (substream_group.d.v1.b_channel_coded){
1788 pres_ch_mode = AP4_Ac4SuperSet(pres_ch_mode, substream.ch_mode);
1789 }else {
1790 b_obj_or_ajoc = 1;
1791 }
1792 }
1793 }
1794 if (b_obj_or_ajoc == 1) { pres_ch_mode = -1; }
1795 return pres_ch_mode;
1796 }
1797
1798 /*----------------------------------------------------------------------
1799 | AP4_Dac4Atom::Ac4Dsi::PresentationV1::GetPresentationChannelMask
1800 +---------------------------------------------------------------------*/
1801 AP4_Result
1802 AP4_Dac4Atom::Ac4Dsi::PresentationV1::GetPresentationChannelMask()
1803 {
1804 unsigned int channel_mask = 0;
1805 char b_obj_or_ajoc = 0;
1806 // TODO: n_substream_groups
1807 for (unsigned int sg = 0; sg < d.v1.n_substream_groups; sg ++){
1808 AP4_Dac4Atom::Ac4Dsi::SubStreamGroupV1 &substream_group = d.v1.substream_groups[sg];
1809 unsigned int n_substreams = d.v1.substream_groups[sg].d.v1.n_substreams;
1810 for (unsigned int sus = 0; sus < n_substreams; sus ++){
1811 AP4_Dac4Atom::Ac4Dsi::SubStream &substream = substream_group.d.v1.substreams[sus];
1812 if (substream_group.d.v1.b_channel_coded){
1813 channel_mask |= substream.dsi_substream_channel_mask;
1814 }else {
1815 b_obj_or_ajoc = 1;
1816 }
1817 }
1818 }
1819 //Modify the mask for headphone presentation with b_pre_virtualized = 1
1820 /*
1821 if (presentation_version == 2 || d.v1.b_pre_virtualized == 1){
1822 if (channel_mask == 0x03) { channel_mask = 0x01;}
1823 }
1824 */
1825 // TODO: temporary solution according to Dolby's internal discussion
1826 if (channel_mask == 0x03) { channel_mask = 0x01;}
1827
1828 // If one substream contains Tfl, Tfr, Tbl, Tbr, Tl and Tr shall be removed.
1829 if ((channel_mask & 0x30) && (channel_mask & 0x80)) { channel_mask &= ~0x80;}
1830
1831 // objective channel mask
1832 if (b_obj_or_ajoc == 1) { channel_mask = 0x800000; }
1833 return channel_mask;
1834 }
1835
1836 /*----------------------------------------------------------------------
1837 | AP4_Dac4Atom::Ac4Dsi::PresentationV1::GetPresB4BackChannelsPresent
1838 +---------------------------------------------------------------------*/
1839 AP4_Result
1840 AP4_Dac4Atom::Ac4Dsi::PresentationV1::GetPresB4BackChannelsPresent()
1841 {
1842 for (unsigned int sg = 0; sg < d.v1.n_substream_groups; sg ++){
1843 AP4_Dac4Atom::Ac4Dsi::SubStreamGroupV1 &substream_group = d.v1.substream_groups[sg];
1844 for (unsigned int sus = 0; sus < substream_group.d.v1.n_substreams; sus ++){
1845 d.v1.pres_b_4_back_channels_present |= substream_group.d.v1.substreams[sus].b_4_back_channels_present;
1846 }
1847 }
1848 return AP4_SUCCESS;
1849 }
1850
1851 /*----------------------------------------------------------------------
1852 | AP4_Dac4Atom::Ac4Dsi::PresentationV1::GetPresTopChannelPairs
1853 +---------------------------------------------------------------------*/
1854 AP4_Result
1855 AP4_Dac4Atom::Ac4Dsi::PresentationV1::GetPresTopChannelPairs()
1856 {
1857 unsigned char tmp_pres_top_channel_pairs = 0;
1858 for (unsigned int sg = 0; sg < d.v1.n_substream_groups; sg ++){
1859 AP4_Dac4Atom::Ac4Dsi::SubStreamGroupV1 &substream_group = d.v1.substream_groups[sg];
1860 for (unsigned int sus = 0; sus < substream_group.d.v1.n_substreams; sus ++){
1861 if (tmp_pres_top_channel_pairs < substream_group.d.v1.substreams[sus].top_channels_present) {
1862 tmp_pres_top_channel_pairs = substream_group.d.v1.substreams[sus].top_channels_present;
1863 }
1864 }
1865 }
1866 switch (tmp_pres_top_channel_pairs){
1867 case 0:
1868 d.v1.pres_top_channel_pairs = 0; break;
1869 case 1:
1870 case 2:
1871 d.v1.pres_top_channel_pairs = 1; break;
1872 case 3:
1873 d.v1.pres_top_channel_pairs = 2; break;
1874 default:
1875 d.v1.pres_top_channel_pairs = 0; break;
1876 }
1877 return AP4_SUCCESS;
1878 }
1879
1880
1881 /*----------------------------------------------------------------------
1882 | AP4_Dac4Atom::Ac4Dsi::PresentationV1::GetBPresentationCoreDiffers
1883 +---------------------------------------------------------------------*/
1884 AP4_Result
1885 AP4_Dac4Atom::Ac4Dsi::PresentationV1::GetBPresentationCoreDiffers()
1886 {
1887 int pres_ch_mode_core = -1;
1888 char b_obj_or_ajoc_adaptive = 0;
1889 for (unsigned int sg = 0; sg < d.v1.n_substream_groups; sg ++){
1890 AP4_Dac4Atom::Ac4Dsi::SubStreamGroupV1 &substream_group = d.v1.substream_groups[sg];
1891 unsigned int n_substreams = d.v1.substream_groups[sg].d.v1.n_substreams;
1892 for (unsigned int sus = 0; sus < n_substreams; sus ++){
1893 AP4_Dac4Atom::Ac4Dsi::SubStream &substream = substream_group.d.v1.substreams[sus];
1894 if (substream_group.d.v1.b_channel_coded){
1895 pres_ch_mode_core = AP4_Ac4SuperSet(pres_ch_mode_core, substream.GetChModeCore(substream_group.d.v1.b_channel_coded));
1896 }else {
1897 if (substream.b_ajoc){
1898 if (substream.b_static_dmx){
1899 pres_ch_mode_core = AP4_Ac4SuperSet(pres_ch_mode_core, substream.GetChModeCore(substream_group.d.v1.b_channel_coded));
1900 }else{
1901 b_obj_or_ajoc_adaptive = 1;
1902 }
1903 }else{
1904 b_obj_or_ajoc_adaptive = 1;
1905 }
1906 }
1907 }
1908 }
1909 if (b_obj_or_ajoc_adaptive) {
1910 pres_ch_mode_core = -1;
1911 }
1912 if (pres_ch_mode_core == GetPresentationChMode()) {
1913 pres_ch_mode_core = -1;
1914 }
1915 return pres_ch_mode_core;
1916 }
0 /*****************************************************************
1 |
2 | AP4 - dac4 Atoms
3 |
4 | Copyright 2002-2018 Axiomatic Systems, LLC
5 |
6 |
7 | This file is part of Bento4/AP4 (MP4 Atom Processing Library).
8 |
9 | Unless you have obtained Bento4 under a difference license,
10 | this version of Bento4 is Bento4|GPL.
11 | Bento4|GPL is free software; you can redistribute it and/or modify
12 | it under the terms of the GNU General Public License as published by
13 | the Free Software Foundation; either version 2, or (at your option)
14 | any later version.
15 |
16 | Bento4|GPL is distributed in the hope that it will be useful,
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | GNU General Public License for more details.
20 |
21 | You should have received a copy of the GNU General Public License
22 | along with Bento4|GPL; see the file COPYING. If not, write to the
23 | Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
24 | 02111-1307, USA.
25 |
26 ****************************************************************/
27
28 #ifndef _AP4_DEC4_ATOM_H_
29 #define _AP4_DEC4_ATOM_H_
30
31 /*----------------------------------------------------------------------
32 | includes
33 +---------------------------------------------------------------------*/
34 #include "Ap4Atom.h"
35 #include "Ap4Utils.h"
36 #include "Ap4Ac4Utils.h"
37
38 /*----------------------------------------------------------------------
39 | AP4_Dac4Atom
40 +---------------------------------------------------------------------*/
41 class AP4_Dac4Atom : public AP4_Atom
42 {
43 public:
44 AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_Dac4Atom, AP4_Atom)
45
46 // inner classes
47 struct Ac4Dsi {
48 struct Ac4BitrateDsi{
49 AP4_UI08 bit_rate_mode;
50 AP4_UI32 bit_rate;
51 AP4_UI32 bit_rate_precision;
52
53 // methods
54 AP4_Result WriteBitrateDsi(AP4_BitWriter &bits);
55 };
56 struct Ac4AlternativeInfo{
57 AP4_UI16 name_len;
58 AP4_UI08 presentation_name[256]; // restrict to 256 char
59 AP4_UI08 n_targets;
60 AP4_UI08 target_md_compat[32];
61 AP4_UI08 target_device_category[32];
62
63 // methods
64 AP4_Result WriteAlternativeInfo(AP4_BitWriter &bits);
65 };
66 struct SubStream{
67 AP4_UI08 b_4_back_channels_present;
68 AP4_UI08 b_centre_present;
69 AP4_UI08 top_channels_present;
70 AP4_UI08 b_lfe;
71 AP4_UI08 dsi_sf_multiplier;
72 AP4_UI08 b_substream_bitrate_indicator;
73 AP4_UI08 substream_bitrate_indicator;
74 AP4_UI08 ch_mode; // auxiliary information, used to calcuate pres_ch_mode
75 AP4_UI32 dsi_substream_channel_mask;
76 AP4_UI08 b_ajoc;
77 AP4_UI08 b_static_dmx;
78 AP4_UI08 n_dmx_objects_minus1;
79 AP4_UI08 n_umx_objects_minus1;
80 AP4_UI08 b_substream_contains_bed_objects;
81 AP4_UI08 b_substream_contains_dynamic_objects;
82 AP4_UI08 b_substream_contains_ISF_objects;
83
84 // methods
85 AP4_Result ParseSubstreamInfoChan(AP4_BitReader &bits,
86 unsigned int presentation_version,
87 unsigned char defalut_presentation_flag,
88 unsigned int fs_idx,
89 unsigned int &speaker_index_mask,
90 unsigned int frame_rate_factor,
91 unsigned int b_substreams_present,
92 unsigned char &dolby_atmos_indicator);
93
94 AP4_Result ParseSubStreamInfoAjoc(AP4_BitReader &bits,
95 unsigned int &channel_count,
96 unsigned char defalut_presentation_flag,
97 unsigned int fs_idx,
98 unsigned int frame_rate_factor,
99 unsigned int b_substreams_present);
100
101 AP4_Result ParseSubstreamInfoObj(AP4_BitReader &bits,
102 unsigned int &channel_count,
103 unsigned char defalut_presentation_flag,
104 unsigned int fs_idx,
105 unsigned int frame_rate_factor,
106 unsigned int b_substreams_present);
107 AP4_Result WriteSubstreamDsi (AP4_BitWriter &bits, unsigned char b_channel_coded);
108 AP4_Result GetChModeCore (unsigned char b_channel_coded);
109 private:
110 AP4_Result ParseChMode (AP4_BitReader &bits, int presentationVersion, unsigned char &dolby_atmos_indicator);
111 AP4_Result ParseDsiSfMutiplier (AP4_BitReader &bits, unsigned int fs_idx );
112 AP4_Result BedDynObjAssignment (AP4_BitReader &bits, unsigned int nSignals, bool is_upmix);
113 AP4_Result ParseSubstreamIdxInfo(AP4_BitReader &bits, unsigned int b_substreams_present);
114
115 AP4_Result ParseBitrateIndicator(AP4_BitReader &bits);
116 AP4_Result ParseOamdCommonData (AP4_BitReader &bits);
117 AP4_Result Trim (AP4_BitReader &bits);
118 AP4_Result BedRendeInfo (AP4_BitReader &bits);
119 AP4_UI32 ObjNumFromIsfConfig (unsigned char isf_config);
120 AP4_UI32 BedNumFromAssignCode (unsigned char assign_code);
121 AP4_UI32 BedNumFromNonStdMask (unsigned int non_std_mask);
122 AP4_UI32 BedNumFromStdMask (unsigned int std_mask);
123 };
124 struct SubStreamGroupV1 {
125 union {
126 struct
127 {
128 AP4_UI08 channel_mode;
129 AP4_UI08 dsi_sf_multiplier;
130 AP4_UI08 b_substream_bitrate_indicator;
131 AP4_UI08 substream_bitrate_indicator;
132 AP4_UI08 add_ch_base;
133 AP4_UI08 b_content_type;
134 AP4_UI08 content_classifier;
135 AP4_UI08 b_language_indicator;
136 AP4_UI08 n_language_tag_bytes;
137 AP4_UI08 language_tag_bytes[64];
138 }v0;
139 struct
140 {
141 AP4_UI08 b_substreams_present;
142 AP4_UI08 b_hsf_ext;
143 AP4_UI08 b_channel_coded;
144 AP4_UI08 n_substreams;
145 SubStream* substreams;
146 AP4_UI08 b_content_type;
147 AP4_UI08 content_classifier;
148 AP4_UI08 b_language_indicator;
149 AP4_UI08 n_language_tag_bytes;
150 AP4_UI08 language_tag_bytes[64]; // n_language_tag_bytes is 6 bits
151 AP4_UI08 dolby_atmos_indicator;
152 }v1;
153 }d;
154 AP4_Result ParseSubstreamGroupInfo(AP4_BitReader &bits,
155 unsigned int bitstream_version,
156 unsigned int presentation_version,
157 unsigned char defalut_presentation_flag,
158 unsigned int frame_rate_factor,
159 unsigned int fs_idx,
160 unsigned int &channel_count,
161 unsigned int &speaker_index_mask,
162 unsigned int &b_obj_or_Ajoc);
163 AP4_Result WriteSubstreamGroupDsi(AP4_BitWriter &bits);
164 private:
165 AP4_Result ParseOamdSubstreamInfo (AP4_BitReader &bits);
166 AP4_Result ParseHsfExtSubstreamInfo(AP4_BitReader &bits);
167 AP4_Result ParseContentType (AP4_BitReader &bits);
168 AP4_Result WriteContentType (AP4_BitWriter &bits);
169 };
170 struct PresentationV1 {
171 AP4_UI08 presentation_version;
172 union {
173 struct {
174 AP4_UI08 presentation_config;
175 AP4_UI08 mdcompat;
176 AP4_UI08 presentation_id;
177 AP4_UI08 dsi_frame_rate_multiply_info;
178 AP4_UI08 presentation_emdf_version;
179 AP4_UI16 presentation_key_id;
180 AP4_UI32 presentation_channel_mask;
181 // more fields omitted, v0 is deprecated.
182 } v0;
183 struct {
184 AP4_UI08 presentation_config_v1;
185 AP4_UI08 mdcompat;
186 AP4_UI08 b_presentation_id;
187 AP4_UI08 presentation_id;
188 AP4_UI08 dsi_frame_rate_multiply_info;
189 AP4_UI08 dsi_frame_rate_fraction_info;
190 AP4_UI08 presentation_emdf_version;
191 AP4_UI16 presentation_key_id;
192 AP4_UI08 b_presentation_channel_coded;
193 AP4_UI08 dsi_presentation_ch_mode;
194 AP4_UI08 pres_b_4_back_channels_present;
195 AP4_UI08 pres_top_channel_pairs;
196 AP4_UI32 presentation_channel_mask_v1;
197 AP4_UI08 b_presentation_core_differs;
198 AP4_UI08 b_presentation_core_channel_coded;
199 AP4_UI08 dsi_presentation_channel_mode_core;
200 AP4_UI08 b_presentation_filter;
201 AP4_UI08 b_enable_presentation;
202 AP4_UI08 n_filter_bytes;
203
204 AP4_UI08 b_multi_pid;
205 AP4_UI08 n_substream_groups;
206 SubStreamGroupV1* substream_groups;
207 AP4_UI32* substream_group_indexs; // auxiliary information, not exist in DSI
208 AP4_UI08 n_skip_bytes;
209
210 AP4_UI08 b_pre_virtualized;
211 AP4_UI08 b_add_emdf_substreams;
212 AP4_UI08 n_add_emdf_substreams;
213 AP4_UI08 substream_emdf_version[128]; // n_add_emdf_substreams - 7 bits
214 AP4_UI16 substream_key_id[128];
215
216 AP4_UI08 b_presentation_bitrate_info;
217 Ac4BitrateDsi ac4_bitrate_dsi;
218 AP4_UI08 b_alternative;
219 Ac4AlternativeInfo alternative_info;
220 AP4_UI08 de_indicator;
221 AP4_UI08 dolby_atmos_indicator;
222 AP4_UI08 b_extended_presentation_id;
223 AP4_UI16 extended_presentation_id;
224 } v1;
225 } d;
226 AP4_Result ParsePresentationV1Info(AP4_BitReader &bits,
227 unsigned int bitstream_version,
228 unsigned int frame_rate_idx,
229 unsigned int pres_idx,
230 unsigned int &max_group_index,
231 unsigned int **first_pres_sg_index,
232 unsigned int &first_pres_sg_num);
233 AP4_Result WritePresentationV1Dsi(AP4_BitWriter &bits);
234 private:
235 AP4_Result ParsePresentationVersion (AP4_BitReader &bits, unsigned int bitstream_version);
236 AP4_Result ParsePresentationConfigExtInfo(AP4_BitReader &bits, unsigned int bitstream_version);
237 AP4_UI32 ParseAc4SgiSpecifier (AP4_BitReader &bits, unsigned int bitstream_version) ;
238 AP4_Result ParseDSIFrameRateMultiplyInfo (AP4_BitReader &bits, unsigned int frame_rate_idx);
239 AP4_Result ParseDSIFrameRateFractionsInfo(AP4_BitReader &bits, unsigned int frame_rate_idx);
240 AP4_Result ParseEmdInfo (AP4_BitReader &bits, AP4_Ac4EmdfInfo &emdf_info);
241 AP4_Result ParsePresentationSubstreamInfo(AP4_BitReader &bits);
242 AP4_Result GetPresentationChMode();
243 AP4_Result GetPresentationChannelMask();
244 AP4_Result GetPresB4BackChannelsPresent();
245 AP4_Result GetPresTopChannelPairs();
246 AP4_Result GetBPresentationCoreDiffers();
247 };
248
249 AP4_UI08 ac4_dsi_version;
250 union {
251 struct {
252 AP4_UI08 bitstream_version;
253 AP4_UI08 fs_index;
254 AP4_UI32 fs;
255 AP4_UI08 frame_rate_index;
256 AP4_UI16 n_presentations;
257 // more fields from `ac4_dsi` are not included here, v0 is deprecated.
258 } v0;
259 struct {
260 AP4_UI08 bitstream_version;
261 AP4_UI08 fs_index;
262 AP4_UI32 fs;
263 AP4_UI08 frame_rate_index;
264 AP4_UI08 b_program_id;
265 AP4_UI16 short_program_id;
266 AP4_UI08 b_uuid;
267 AP4_UI08 program_uuid[16];
268 Ac4BitrateDsi ac4_bitrate_dsi;
269 AP4_UI16 n_presentations;
270 PresentationV1* presentations;
271 } v1;
272 } d;
273 };
274
275 // class methods
276 static AP4_Dac4Atom* Create(AP4_Size size, AP4_ByteStream& stream);
277
278 // constructors
279 AP4_Dac4Atom(AP4_UI32 size, const Ac4Dsi* ac4Dsi); // DSI vaiable initialize m_RawBytes (m_Dsi -> m_RawBytes)
280
281 // destructor
282 ~AP4_Dac4Atom();
283
284 // methods
285 virtual AP4_Result InspectFields(AP4_AtomInspector& inspector);
286 virtual AP4_Result WriteFields(AP4_ByteStream& stream);
287 virtual AP4_Atom* Clone() { return new AP4_Dac4Atom(m_Size32, m_RawBytes.GetData()); }
288 virtual AP4_Dac4Atom* CloneConst() const { return new AP4_Dac4Atom(m_Size32, m_RawBytes.GetData()); }
289
290 // accessors
291 const AP4_DataBuffer& GetRawBytes() const { return m_RawBytes; }
292 const Ac4Dsi& GetDsi() const { return m_Dsi; }
293
294 // helpers
295 void GetCodecString(AP4_String& codec);
296
297 private:
298 // methods
299 AP4_Dac4Atom(const AP4_Dac4Atom& other);
300 AP4_Dac4Atom(AP4_UI32 size, const AP4_UI08* payload); // box data initialize m_Dsi (m_RawBytes -> m_Dsi)
301
302 // members
303 AP4_DataBuffer m_RawBytes;
304 Ac4Dsi m_Dsi;
305 };
306
307 #endif // _AP4_DAC4_ATOM_H_
5858 /*----------------------------------------------------------------------
5959 | AP4_Dec3Atom::AP4_Dec3Atom
6060 +---------------------------------------------------------------------*/
61 AP4_Dec3Atom::AP4_Dec3Atom(const AP4_Dec3Atom& other):
62 AP4_Atom(AP4_ATOM_TYPE_DEC3, other.m_Size32),
63 m_DataRate(other.m_DataRate),
64 m_FlagEC3ExtensionTypeA(other.m_FlagEC3ExtensionTypeA),
65 m_ComplexityIndexTypeA(other.m_ComplexityIndexTypeA),
66 m_SubStreams(other.m_SubStreams),
67 m_RawBytes(other.m_RawBytes)
68 {
69 }
70
71 /*----------------------------------------------------------------------
72 | AP4_Dec3Atom::AP4_Dec3Atom
73 +---------------------------------------------------------------------*/
74 AP4_Dec3Atom::AP4_Dec3Atom():
75 AP4_Atom(AP4_ATOM_TYPE_DEC3, AP4_ATOM_HEADER_SIZE),
76 m_DataRate(0),
77 m_FlagEC3ExtensionTypeA(0),
78 m_ComplexityIndexTypeA(0)
79 {
80 m_SubStreams.Append(SubStream());
81 }
82
83 /*----------------------------------------------------------------------
84 | AP4_Dec3Atom::AP4_Dec3Atom
85 +---------------------------------------------------------------------*/
86 AP4_Dec3Atom::AP4_Dec3Atom(AP4_UI32 au_size, const SubStream* substream, const unsigned int complexity_index_type_a):
87 AP4_Atom(AP4_ATOM_TYPE_DEC3, AP4_ATOM_HEADER_SIZE)
88 {
89 AP4_BitWriter bits(7); // I0 + D0 or 5.1 DD+ JOC is the most complicated stream
90
91 unsigned int date_rate = au_size / 4;
92 unsigned int num_ind_sub = 0; // num_ind_sub is set to 0 which is ensured by E-AC-3 parser.
93
94 bits.Write(date_rate, 13);
95 bits.Write(num_ind_sub, 3);
96 for (unsigned int idx = 0; idx < num_ind_sub + 1; idx ++) {
97 bits.Write(substream->fscod, 2);
98 bits.Write(substream->bsid , 5);
99 bits.Write(0, 1); // reserved
100 bits.Write(0, 1); // asvc is always 0
101 bits.Write(substream->bsmod, 3);
102 bits.Write(substream->acmod, 3);
103 bits.Write(substream->lfeon, 1);
104 bits.Write(0, 3); // reserved
105 bits.Write(substream->num_dep_sub, 4);
106 if (substream->num_dep_sub > 0) {
107 bits.Write(substream->chan_loc, 9);
108 }else{
109 bits.Write(0, 1); // reserved
110 }
111 }
112 if (complexity_index_type_a) {
113 bits.Write(1, 8);
114 bits.Write(complexity_index_type_a, 8);
115 }
116 m_RawBytes.SetData(bits.GetData(), bits.GetBitCount() / 8);
117 m_Size32 += m_RawBytes.GetDataSize();
118 }
119
120 /*----------------------------------------------------------------------
121 | AP4_Dec3Atom::AP4_Dec3Atom
122 +---------------------------------------------------------------------*/
61123 AP4_Dec3Atom::AP4_Dec3Atom(AP4_UI32 size, const AP4_UI08* payload) :
62124 AP4_Atom(AP4_ATOM_TYPE_DEC3, size),
63 m_DataRate(0)
125 m_DataRate(0),
126 m_FlagEC3ExtensionTypeA(0),
127 m_ComplexityIndexTypeA(0)
64128 {
65129 // make a copy of our configuration bytes
66130 unsigned int payload_size = size-AP4_ATOM_HEADER_SIZE;
102166 payload_size -= 3;
103167 }
104168 }
169 // DD+/Atmos
170 if (payload_size >= 2) {
171 m_FlagEC3ExtensionTypeA = payload[0] & 0x1;
172 m_ComplexityIndexTypeA = payload[1];
173 payload += 2;
174 payload_size -= 2;
175 }
105176 }
106177
107178 /*----------------------------------------------------------------------
120191 AP4_Dec3Atom::InspectFields(AP4_AtomInspector& inspector)
121192 {
122193 inspector.AddField("data_rate", m_DataRate);
194 inspector.AddField("complexity_index_type_a", m_ComplexityIndexTypeA);
123195 for (unsigned int i=0; i<m_SubStreams.ItemCount(); i++) {
124196 char name[16];
125197 char value[256];
6161 // class methods
6262 static AP4_Dec3Atom* Create(AP4_Size size, AP4_ByteStream& stream);
6363
64 // constructors
65 AP4_Dec3Atom();
66 AP4_Dec3Atom(const AP4_Dec3Atom& other);
67 AP4_Dec3Atom(AP4_UI32 au_size, const SubStream* substream, const unsigned int complexity_index_type_a); // DSI vaiable initialize m_RawBytes (substream -> m_RawBytes)
68
6469 // methods
6570 virtual AP4_Result InspectFields(AP4_AtomInspector& inspector);
6671 virtual AP4_Result WriteFields(AP4_ByteStream& stream);
7075 const AP4_DataBuffer& GetRawBytes() const { return m_RawBytes; }
7176 unsigned int GetDataRate() const { return m_DataRate; }
7277 const AP4_Array<SubStream>& GetSubStreams() const { return m_SubStreams; }
78 unsigned int GetFlagEC3ExtensionTypeA() const { return m_FlagEC3ExtensionTypeA; }
79 unsigned int GetComplexityIndexTypeA() const { return m_ComplexityIndexTypeA; }
7380
7481 private:
7582 // methods
76 AP4_Dec3Atom(AP4_UI32 size, const AP4_UI08* payload);
83 AP4_Dec3Atom(AP4_UI32 size, const AP4_UI08* payload); // box data initialize m_Dsi (m_RawBytes -> substream)
7784
7885 // members
7986 unsigned int m_DataRate;
87 unsigned int m_FlagEC3ExtensionTypeA;
88 unsigned int m_ComplexityIndexTypeA;
8089 AP4_Array<SubStream> m_SubStreams;
8190 AP4_DataBuffer m_RawBytes;
8291 };
7373 header_size,
7474 payload_size)
7575 {
76 // record the start position
77 AP4_Position start;
78 stream.Tell(start);
79
8076 // read descriptor fields
77 if (payload_size < 13) return;
8178 stream.ReadUI08(m_ObjectTypeIndication);
8279 unsigned char bits;
8380 stream.ReadUI08(bits);
8683 stream.ReadUI24(m_BufferSize);
8784 stream.ReadUI32(m_MaxBitrate);
8885 stream.ReadUI32(m_AverageBitrate);
89
86 payload_size -= 13;
87
9088 // read other descriptors
91 AP4_SubStream* substream = new AP4_SubStream(stream, start+13, payload_size-13);
89 AP4_Position offset;
90 stream.Tell(offset);
91 AP4_SubStream* substream = new AP4_SubStream(stream, offset, payload_size);
9292 AP4_Descriptor* descriptor = NULL;
9393 while (AP4_DescriptorFactory::CreateDescriptorFromStream(*substream,
9494 descriptor)
7777 } while (--max && (ext&0x80));
7878
7979 // create the descriptor
80 switch (tag) {
81 case AP4_DESCRIPTOR_TAG_OD:
82 case AP4_DESCRIPTOR_TAG_MP4_OD:
83 descriptor = new AP4_ObjectDescriptor(stream, tag, header_size, payload_size);
84 break;
80 if (payload_size) {
81 switch (tag) {
82 case AP4_DESCRIPTOR_TAG_OD:
83 case AP4_DESCRIPTOR_TAG_MP4_OD:
84 descriptor = new AP4_ObjectDescriptor(stream, tag, header_size, payload_size);
85 break;
8586
86 case AP4_DESCRIPTOR_TAG_IOD:
87 case AP4_DESCRIPTOR_TAG_MP4_IOD:
88 descriptor = new AP4_InitialObjectDescriptor(stream, tag, header_size, payload_size);
89 break;
87 case AP4_DESCRIPTOR_TAG_IOD:
88 case AP4_DESCRIPTOR_TAG_MP4_IOD:
89 descriptor = new AP4_InitialObjectDescriptor(stream, tag, header_size, payload_size);
90 break;
9091
91 case AP4_DESCRIPTOR_TAG_ES_ID_INC:
92 descriptor = new AP4_EsIdIncDescriptor(stream, header_size, payload_size);
93 break;
92 case AP4_DESCRIPTOR_TAG_ES_ID_INC:
93 descriptor = new AP4_EsIdIncDescriptor(stream, header_size, payload_size);
94 break;
9495
95 case AP4_DESCRIPTOR_TAG_ES_ID_REF:
96 descriptor = new AP4_EsIdRefDescriptor(stream, header_size, payload_size);
97 break;
98
99 case AP4_DESCRIPTOR_TAG_ES:
100 descriptor = new AP4_EsDescriptor(stream, header_size, payload_size);
101 break;
96 case AP4_DESCRIPTOR_TAG_ES_ID_REF:
97 descriptor = new AP4_EsIdRefDescriptor(stream, header_size, payload_size);
98 break;
10299
103 case AP4_DESCRIPTOR_TAG_DECODER_CONFIG:
104 descriptor = new AP4_DecoderConfigDescriptor(stream, header_size, payload_size);
105 break;
100 case AP4_DESCRIPTOR_TAG_ES:
101 descriptor = new AP4_EsDescriptor(stream, header_size, payload_size);
102 break;
106103
107 case AP4_DESCRIPTOR_TAG_DECODER_SPECIFIC_INFO:
108 descriptor = new AP4_DecoderSpecificInfoDescriptor(stream, header_size, payload_size);
109 break;
110
111 case AP4_DESCRIPTOR_TAG_SL_CONFIG:
112 if (payload_size != 1) return AP4_ERROR_INVALID_FORMAT;
113 descriptor = new AP4_SLConfigDescriptor(header_size);
114 break;
104 case AP4_DESCRIPTOR_TAG_DECODER_CONFIG:
105 descriptor = new AP4_DecoderConfigDescriptor(stream, header_size, payload_size);
106 break;
115107
116 case AP4_DESCRIPTOR_TAG_IPMP_DESCRIPTOR_POINTER:
117 descriptor = new AP4_IpmpDescriptorPointer(stream, header_size, payload_size);
118 break;
119
120 case AP4_DESCRIPTOR_TAG_IPMP_DESCRIPTOR:
121 descriptor = new AP4_IpmpDescriptor(stream, header_size, payload_size);
122 break;
108 case AP4_DESCRIPTOR_TAG_DECODER_SPECIFIC_INFO:
109 descriptor = new AP4_DecoderSpecificInfoDescriptor(stream, header_size, payload_size);
110 break;
123111
124 default:
125 descriptor = new AP4_UnknownDescriptor(stream, tag, header_size, payload_size);
126 break;
112 case AP4_DESCRIPTOR_TAG_SL_CONFIG:
113 if (payload_size != 1) return AP4_ERROR_INVALID_FORMAT;
114 descriptor = new AP4_SLConfigDescriptor(header_size);
115 break;
116
117 case AP4_DESCRIPTOR_TAG_IPMP_DESCRIPTOR_POINTER:
118 descriptor = new AP4_IpmpDescriptorPointer(stream, header_size, payload_size);
119 break;
120
121 case AP4_DESCRIPTOR_TAG_IPMP_DESCRIPTOR:
122 descriptor = new AP4_IpmpDescriptor(stream, header_size, payload_size);
123 break;
124
125 default:
126 descriptor = new AP4_UnknownDescriptor(stream, tag, header_size, payload_size);
127 break;
128 }
127129 }
128
130
129131 // skip to the end of the descriptor
130132 stream.Seek(offset+header_size+payload_size);
131133
4343 {
4444 AP4_UI08 version;
4545 AP4_UI32 flags;
46 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4647 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4748 if (version != 0) return NULL;
4849 return new AP4_DrefAtom(size, version, flags, stream, atom_factory);
0 /*****************************************************************
1 |
2 | AP4 - dvcC Atoms
3 |
4 | Copyright 2002-2016 Axiomatic Systems, LLC
5 |
6 |
7 | This file is part of Bento4/AP4 (MP4 Atom Processing Library).
8 |
9 | Unless you have obtained Bento4 under a difference license,
10 | this version of Bento4 is Bento4|GPL.
11 | Bento4|GPL is free software; you can redistribute it and/or modify
12 | it under the terms of the GNU General Public License as published by
13 | the Free Software Foundation; either version 2, or (at your option)
14 | any later version.
15 |
16 | Bento4|GPL is distributed in the hope that it will be useful,
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | GNU General Public License for more details.
20 |
21 | You should have received a copy of the GNU General Public License
22 | along with Bento4|GPL; see the file COPYING. If not, write to the
23 | Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
24 | 02111-1307, USA.
25 |
26 ****************************************************************/
27
28 /*----------------------------------------------------------------------
29 | includes
30 +---------------------------------------------------------------------*/
31 #include "Ap4DvccAtom.h"
32 #include "Ap4AtomFactory.h"
33 #include "Ap4Utils.h"
34 #include "Ap4Types.h"
35 #include "Ap4SampleDescription.h"
36
37 /*----------------------------------------------------------------------
38 | dynamic cast support
39 +---------------------------------------------------------------------*/
40 AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_DvccAtom)
41
42 /*----------------------------------------------------------------------
43 | AP4_DvccAtom::GetProfileName
44 +---------------------------------------------------------------------*/
45 const char*
46 AP4_DvccAtom::GetProfileName(AP4_UI08 profile)
47 {
48 switch (profile) {
49 case AP4_DV_PROFILE_DVAV_PER: return "dvav.per";
50 case AP4_DV_PROFILE_DVAV_PEN: return "dvav.pen";
51 case AP4_DV_PROFILE_DVHE_DER: return "dvhe.der";
52 case AP4_DV_PROFILE_DVHE_DEN: return "dvhe.den";
53 case AP4_DV_PROFILE_DVHE_DTR: return "dvhe.dtr";
54 case AP4_DV_PROFILE_DVHE_STN: return "dvhe.stn";
55 case AP4_DV_PROFILE_DVHE_DTH: return "dvhe.dth";
56 case AP4_DV_PROFILE_DVHE_DTB: return "dvhr.dtb";
57 case AP4_DV_PROFILE_DVHE_ST : return "dvhe.st";
58 case AP4_DV_PROFILE_DVHE_SE : return "dvav.se";
59 }
60
61 return NULL;
62 }
63
64 /*----------------------------------------------------------------------
65 | AP4_DvccAtom::Create
66 +---------------------------------------------------------------------*/
67 AP4_DvccAtom*
68 AP4_DvccAtom::Create(AP4_Size size, AP4_ByteStream& stream)
69 {
70 if (size < AP4_ATOM_HEADER_SIZE+24) return NULL;
71
72 AP4_UI08 payload[24];
73 AP4_Result result = stream.Read(payload, 24);
74 if (AP4_FAILED(result)) return NULL;
75
76 return new AP4_DvccAtom(payload[0],
77 payload[1],
78 payload[2]>>1,
79 ((payload[2]&1)<<5) | (payload[3]>>3),
80 (payload[3]&4) != 0,
81 (payload[3]&2) != 0,
82 (payload[3]&1) != 0,
83 payload[4]>>4);
84 }
85
86 /*----------------------------------------------------------------------
87 | AP4_DvccAtom::AP4_DvccAtom
88 +---------------------------------------------------------------------*/
89 AP4_DvccAtom::AP4_DvccAtom() :
90 AP4_Atom(AP4_ATOM_TYPE_DVCC, AP4_ATOM_HEADER_SIZE+24),
91 m_DvVersionMajor(0),
92 m_DvVersionMinor(0),
93 m_DvProfile(0),
94 m_DvLevel(0),
95 m_RpuPresentFlag(false),
96 m_ElPresentFlag(false),
97 m_BlPresentFlag(false),
98 m_DvBlSignalCompatibilityID(0)
99 {
100 }
101
102 /*----------------------------------------------------------------------
103 | AP4_DvccAtom::AP4_DvccAtom
104 +---------------------------------------------------------------------*/
105 AP4_DvccAtom::AP4_DvccAtom(AP4_UI08 dv_version_major,
106 AP4_UI08 dv_version_minor,
107 AP4_UI08 dv_profile,
108 AP4_UI08 dv_level,
109 bool rpu_present_flag,
110 bool el_present_flag,
111 bool bl_present_flag,
112 AP4_UI08 dv_bl_signal_compatibility_id) :
113 AP4_Atom((dv_profile>7) ? AP4_ATOM_TYPE_DVVC : AP4_ATOM_TYPE_DVCC, AP4_ATOM_HEADER_SIZE+24),
114 m_DvVersionMajor(dv_version_major),
115 m_DvVersionMinor(dv_version_minor),
116 m_DvProfile(dv_profile),
117 m_DvLevel(dv_level),
118 m_RpuPresentFlag(rpu_present_flag),
119 m_ElPresentFlag(el_present_flag),
120 m_BlPresentFlag(bl_present_flag),
121 m_DvBlSignalCompatibilityID(dv_bl_signal_compatibility_id)
122 {
123 }
124
125 /*----------------------------------------------------------------------
126 | AP4_DvccAtom::GetCodecString
127 +---------------------------------------------------------------------*/
128 AP4_Result
129 AP4_DvccAtom::GetCodecString(AP4_SampleDescription* parent, AP4_String& codec)
130 {
131 char workspace[64];
132
133 AP4_UI32 format = parent->GetFormat();
134 if (format == AP4_ATOM_TYPE_DVAV ||
135 format == AP4_ATOM_TYPE_DVA1 ||
136 format == AP4_ATOM_TYPE_DVHE ||
137 format == AP4_ATOM_TYPE_DVH1) {
138 /* Non backward-compatible */
139 char coding[5];
140 AP4_FormatFourChars(coding, format);
141 AP4_FormatString(workspace,
142 sizeof(workspace),
143 "%s.%02d.%02d",
144 coding,
145 GetDvProfile(),
146 GetDvLevel());
147 codec = workspace;
148 } else {
149 /* Backward-compatible */
150 switch (format) {
151 case AP4_ATOM_TYPE_AVC1:
152 format = AP4_ATOM_TYPE_DVA1;
153 break;
154
155 case AP4_ATOM_TYPE_AVC3:
156 format = AP4_ATOM_TYPE_DVAV;
157 break;
158
159 case AP4_ATOM_TYPE_HEV1:
160 format = AP4_ATOM_TYPE_DVHE;
161 break;
162
163 case AP4_ATOM_TYPE_HVC1:
164 format = AP4_ATOM_TYPE_DVH1;
165 break;
166 }
167 char coding[5];
168 AP4_FormatFourChars(coding, format);
169 AP4_String parent_codec;
170 parent->GetCodecString(parent_codec);
171 AP4_FormatString(workspace,
172 sizeof(workspace),
173 "%s,%s.%02d.%02d",
174 parent_codec.GetChars(),
175 coding,
176 GetDvProfile(),
177 GetDvLevel());
178 codec = workspace;
179 }
180
181 return AP4_SUCCESS;
182 }
183
184 /*----------------------------------------------------------------------
185 | AP4_DvccAtom::WriteFields
186 +---------------------------------------------------------------------*/
187 AP4_Result
188 AP4_DvccAtom::WriteFields(AP4_ByteStream& stream)
189 {
190 AP4_UI08 payload[24];
191 AP4_SetMemory(payload, 0, 24);
192
193 payload[0] = m_DvVersionMajor;
194 payload[1] = m_DvVersionMinor;
195 payload[2] = (m_DvProfile<<1) | ((m_DvLevel&0x20)>>5);
196 payload[3] = (m_DvLevel<<3) | (m_RpuPresentFlag?4:0) | (m_ElPresentFlag?2:0) | (m_BlPresentFlag?1:0);
197 payload[4] = m_DvBlSignalCompatibilityID<<4;
198
199 return stream.Write(payload, 24);
200 }
201
202 /*----------------------------------------------------------------------
203 | AP4_DvccAtom::InspectFields
204 +---------------------------------------------------------------------*/
205 AP4_Result
206 AP4_DvccAtom::InspectFields(AP4_AtomInspector& inspector)
207 {
208 inspector.AddField("dv_version_major", m_DvVersionMajor);
209 inspector.AddField("dv_version_minor", m_DvVersionMinor);
210 inspector.AddField("dv_profile", m_DvProfile);
211 const char* profile_name = GetProfileName(m_DvProfile);
212 if (profile_name) {
213 inspector.AddField("dv_profile_name", profile_name);
214 } else {
215 inspector.AddField("dv_profile_name", "unknown");
216 }
217 inspector.AddField("dv_level", m_DvLevel);
218 inspector.AddField("rpu_present_flag", m_RpuPresentFlag);
219 inspector.AddField("el_present_flag", m_ElPresentFlag);
220 inspector.AddField("bl_present_flag", m_BlPresentFlag);
221 inspector.AddField("dv_bl_signal_compatibility_id", m_DvBlSignalCompatibilityID);
222 return AP4_SUCCESS;
223 }
0 /*****************************************************************
1 |
2 | AP4 - dvcC Atoms
3 |
4 | Copyright 2002-2016 Axiomatic Systems, LLC
5 |
6 |
7 | This file is part of Bento4/AP4 (MP4 Atom Processing Library).
8 |
9 | Unless you have obtained Bento4 under a difference license,
10 | this version of Bento4 is Bento4|GPL.
11 | Bento4|GPL is free software; you can redistribute it and/or modify
12 | it under the terms of the GNU General Public License as published by
13 | the Free Software Foundation; either version 2, or (at your option)
14 | any later version.
15 |
16 | Bento4|GPL is distributed in the hope that it will be useful,
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | GNU General Public License for more details.
20 |
21 | You should have received a copy of the GNU General Public License
22 | along with Bento4|GPL; see the file COPYING. If not, write to the
23 | Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
24 | 02111-1307, USA.
25 |
26 ****************************************************************/
27
28 #ifndef _AP4_DVCC_ATOM_H_
29 #define _AP4_DVCC_ATOM_H_
30
31 /*----------------------------------------------------------------------
32 | includes
33 +---------------------------------------------------------------------*/
34 #include "Ap4Atom.h"
35 #include "Ap4Array.h"
36
37 /*----------------------------------------------------------------------
38 | class references
39 +---------------------------------------------------------------------*/
40 class AP4_SampleDescription;
41
42 /*----------------------------------------------------------------------
43 | constants
44 +---------------------------------------------------------------------*/
45 const AP4_UI08 AP4_DV_PROFILE_DVAV_PER = 0;
46 const AP4_UI08 AP4_DV_PROFILE_DVAV_PEN = 1;
47 const AP4_UI08 AP4_DV_PROFILE_DVHE_DER = 2;
48 const AP4_UI08 AP4_DV_PROFILE_DVHE_DEN = 3;
49 const AP4_UI08 AP4_DV_PROFILE_DVHE_DTR = 4;
50 const AP4_UI08 AP4_DV_PROFILE_DVHE_STN = 5;
51 const AP4_UI08 AP4_DV_PROFILE_DVHE_DTH = 6;
52 const AP4_UI08 AP4_DV_PROFILE_DVHE_DTB = 7;
53 const AP4_UI08 AP4_DV_PROFILE_DVHE_ST = 8;
54 const AP4_UI08 AP4_DV_PROFILE_DVHE_SE = 9;
55
56 /*----------------------------------------------------------------------
57 | AP4_DvccAtom
58 +---------------------------------------------------------------------*/
59 class AP4_DvccAtom : public AP4_Atom
60 {
61 public:
62 AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_DvccAtom, AP4_Atom)
63
64 // class methods
65 static AP4_DvccAtom* Create(AP4_Size size, AP4_ByteStream& stream);
66 static const char* GetProfileName(AP4_UI08 profile);
67
68 // constructors
69 AP4_DvccAtom();
70 AP4_DvccAtom(AP4_UI08 dv_version_major,
71 AP4_UI08 dv_version_minor,
72 AP4_UI08 dv_profile,
73 AP4_UI08 dv_level,
74 bool rpu_present_flag,
75 bool el_present_flag,
76 bool bl_present_flag,
77 AP4_UI08 dv_bl_signal_compatibility_id);
78
79 // methods
80 virtual AP4_Result InspectFields(AP4_AtomInspector& inspector);
81 virtual AP4_Result WriteFields(AP4_ByteStream& stream);
82
83 // accessors
84 AP4_UI08 GetDvVersionMajor() { return m_DvVersionMajor; }
85 AP4_UI08 GetDvVersionMinor() { return m_DvVersionMinor; }
86 AP4_UI08 GetDvProfile() { return m_DvProfile; }
87 AP4_UI08 GetDvLevel() { return m_DvLevel; }
88 bool GetRpuPresentFlag() { return m_RpuPresentFlag != 0; }
89 bool GetElPresentFlag() { return m_ElPresentFlag != 0; }
90 bool GetBlPresentFlag() { return m_BlPresentFlag != 0; }
91 AP4_UI08 GetDvBlSignalCompatibilityID() { return m_DvBlSignalCompatibilityID; }
92
93 // helpers
94 AP4_Result GetCodecString(AP4_SampleDescription* parent, AP4_String& codec);
95
96 private:
97 // members
98 AP4_UI08 m_DvVersionMajor;
99 AP4_UI08 m_DvVersionMinor;
100 AP4_UI08 m_DvProfile;
101 AP4_UI08 m_DvLevel;
102 AP4_UI08 m_RpuPresentFlag;
103 AP4_UI08 m_ElPresentFlag;
104 AP4_UI08 m_BlPresentFlag;
105 AP4_UI08 m_DvBlSignalCompatibilityID;
106 };
107
108 #endif // _AP4_DVCC_ATOM_H_
3232 #include "Ap4Utils.h"
3333
3434 /*----------------------------------------------------------------------
35 | dynamic cast support
36 +---------------------------------------------------------------------*/
37 AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_ElstAtom)
38
39 /*----------------------------------------------------------------------
3540 | AP4_ElstAtom::Create
3641 +---------------------------------------------------------------------*/
3742 AP4_ElstAtom*
3944 {
4045 AP4_UI08 version;
4146 AP4_UI32 flags;
47 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4248 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4349 if (version > 1) return NULL;
4450 return new AP4_ElstAtom(size, version, flags, stream);
51 }
52
53 /*----------------------------------------------------------------------
54 | AP4_ElstAtom::AP4_ElstAtom
55 +---------------------------------------------------------------------*/
56 AP4_ElstAtom::AP4_ElstAtom() :
57 AP4_Atom(AP4_ATOM_TYPE_ELST, AP4_FULL_ATOM_HEADER_SIZE+4, 0, 0)
58 {
4559 }
4660
4761 /*----------------------------------------------------------------------
5367 AP4_ByteStream& stream) :
5468 AP4_Atom(AP4_ATOM_TYPE_ELST, size, version, flags)
5569 {
70 // read the number of entries
5671 AP4_UI32 entry_count;
5772 stream.ReadUI32(entry_count);
73
74 // compute bounds
75 AP4_UI32 max_entries;
76 if (version == 0) {
77 max_entries = (size - (AP4_FULL_ATOM_HEADER_SIZE + 4)) / 12;
78 } else {
79 max_entries = (size - (AP4_FULL_ATOM_HEADER_SIZE + 4)) / 20;
80 }
81 if (entry_count > max_entries) {
82 entry_count = max_entries;
83 }
84
85 // read the entries
5886 m_Entries.EnsureCapacity(entry_count);
59 for (AP4_UI32 i=0; i<entry_count; i++) {
87 for (AP4_UI32 i=0; i < entry_count; i++) {
6088 AP4_UI16 media_rate;
6189 AP4_UI16 zero;
6290 if (version == 0) {
6694 stream.ReadUI32(media_time);
6795 stream.ReadUI16(media_rate);
6896 stream.ReadUI16(zero);
69 m_Entries.Append(AP4_ElstEntry(segment_duration, media_time, media_rate));
97 m_Entries.Append(AP4_ElstEntry(segment_duration, (AP4_SI32)media_time, media_rate));
7098 } else {
7199 AP4_UI64 segment_duration;
72100 AP4_UI64 media_time;
74102 stream.ReadUI64(media_time);
75103 stream.ReadUI16(media_rate);
76104 stream.ReadUI16(zero);
77 m_Entries.Append(AP4_ElstEntry(segment_duration, media_time, media_rate));
105 m_Entries.Append(AP4_ElstEntry(segment_duration, (AP4_SI64)media_time, media_rate));
78106 }
79107 }
80108 }
116144 AP4_Result
117145 AP4_ElstAtom::InspectFields(AP4_AtomInspector& inspector)
118146 {
119 inspector.AddField("entry count", m_Entries.ItemCount());
147 inspector.AddField("entry_count", m_Entries.ItemCount());
120148 for (AP4_Ordinal i=0; i<m_Entries.ItemCount(); i++) {
121149 inspector.AddField("entry/segment duration", (AP4_UI32)m_Entries[i].m_SegmentDuration);
122150 inspector.AddField("entry/media time", (AP4_SI32)m_Entries[i].m_MediaTime);
125153
126154 return AP4_SUCCESS;
127155 }
156
157 /*----------------------------------------------------------------------
158 | AP4_ElstAtom::AddEntry
159 +---------------------------------------------------------------------*/
160 AP4_Result
161 AP4_ElstAtom::AddEntry(const AP4_ElstEntry& entry)
162 {
163 // check if this requires 64-bit fields
164 if (entry.m_SegmentDuration > 0xFFFFFFFFUL) {
165 m_Version = 1;
166 }
167 if (entry.m_MediaTime > 0 && (AP4_UI64)entry.m_MediaTime > 0xFFFFFFFFUL) {
168 m_Version = 1;
169 }
170
171 // add the entry
172 m_Entries.Append(entry);
173
174 // recompute the atom size
175 SetSize(AP4_FULL_ATOM_HEADER_SIZE+4+m_Entries.ItemCount()*(m_Version==0?12:20));
176
177 return AP4_SUCCESS;
178 }
5858 class AP4_ElstAtom : public AP4_Atom
5959 {
6060 public:
61 AP4_IMPLEMENT_DYNAMIC_CAST(AP4_ElstAtom)
62
6163 // class methods
6264 static AP4_ElstAtom* Create(AP4_Size size, AP4_ByteStream& stream);
6365
66 // constructor
67 AP4_ElstAtom();
68
6469 // methods
6570 virtual AP4_Result InspectFields(AP4_AtomInspector& inspector);
6671 virtual AP4_Result WriteFields(AP4_ByteStream& stream);
72
73 // accessors
74 AP4_Array<AP4_ElstEntry>& GetEntries() {
75 return m_Entries;
76 }
77
78 // methods
79 AP4_Result AddEntry(const AP4_ElstEntry& entry);
6780
6881 private:
6982 // methods
6262 AP4_Size payload_size) :
6363 AP4_Descriptor(AP4_DESCRIPTOR_TAG_ES, header_size, payload_size)
6464 {
65 AP4_Position start;
66 stream.Tell(start);
67
6865 // read descriptor fields
66 if (payload_size < 3) return;
6967 stream.ReadUI16(m_EsId);
7068 unsigned char bits;
7169 stream.ReadUI08(bits);
70 payload_size -= 3;
7271 m_Flags = (bits>>5)&7;
7372 m_StreamPriority = bits&0x1F;
7473 if (m_Flags & AP4_ES_DESCRIPTOR_FLAG_STREAM_DEPENDENCY) {
74 if (payload_size < 2) return;
7575 stream.ReadUI16(m_DependsOn);
76 payload_size -= 2;
7677 } else {
7778 m_DependsOn = 0;
7879 }
7980 if (m_Flags & AP4_ES_DESCRIPTOR_FLAG_URL) {
8081 unsigned char url_length;
82 if (payload_size < 1) return;
8183 stream.ReadUI08(url_length);
84 --payload_size;
8285 if (url_length) {
86 if (payload_size < url_length) return;
8387 char* url = new char[url_length+1];
8488 if (url) {
8589 stream.Read(url, url_length);
8791 m_Url = url;
8892 delete[] url;
8993 }
94 payload_size -= url_length;
9095 }
9196 }
9297 if (m_Flags & AP4_ES_DESCRIPTOR_FLAG_URL) {
98 if (payload_size < 2) return;
9399 stream.ReadUI16(m_OcrEsId);
100 payload_size -= 2;
94101 } else {
95102 m_OcrEsId = 0;
96103 }
98105 // read other descriptors
99106 AP4_Position offset;
100107 stream.Tell(offset);
101 AP4_SubStream* substream = new AP4_SubStream(stream, offset,
102 payload_size-AP4_Size(offset-start));
108 AP4_SubStream* substream = new AP4_SubStream(stream, offset, payload_size);
103109 AP4_Descriptor* descriptor = NULL;
104110 while (AP4_DescriptorFactory::CreateDescriptorFromStream(*substream,
105111 descriptor)
4545 {
4646 AP4_UI08 version;
4747 AP4_UI32 flags;
48 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4849 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4950 if (version != 0) return NULL;
5051 return new AP4_EsdsAtom(size, version, flags, stream);
3939 AP4_Size
4040 AP4_Expandable::MinHeaderSize(AP4_Size payload_size)
4141 {
42 // compute how many bytes are needed to encode the payload size
43 // plus tag
44 return 2+(payload_size/128);
42 // compute how many bytes are needed to encode the payload size plus tag
43 AP4_Size min_header_size = 2;
44 while (payload_size > 128) {
45 ++min_header_size;
46 payload_size /= 128;
47 }
48 return min_header_size;
4549 }
4650
4751 /*----------------------------------------------------------------------
5555 AP4_File::AP4_File(AP4_ByteStream& stream,
5656 AP4_AtomFactory& atom_factory,
5757 bool moov_only,
58 AP4_Movie* movie) :
58 AP4_Movie* movie) :
5959 m_Movie(movie),
6060 m_FileType(NULL),
6161 m_MetaData(NULL),
6262 m_MoovIsBeforeMdat(true)
63 {
64 ParseStream(stream, atom_factory, moov_only, movie);
65 }
66
67 /*----------------------------------------------------------------------
68 | AP4_File::AP4_File
69 +---------------------------------------------------------------------*/
70 AP4_File::AP4_File(AP4_ByteStream& stream,
71 bool moov_only) :
72 m_Movie(NULL),
73 m_FileType(NULL),
74 m_MetaData(NULL),
75 m_MoovIsBeforeMdat(true)
76 {
77 AP4_DefaultAtomFactory atom_factory;
78 ParseStream(stream, atom_factory, moov_only, m_Movie);
79 }
80
81 /*----------------------------------------------------------------------
82 | AP4_File::~AP4_File
83 +---------------------------------------------------------------------*/
84 AP4_File::~AP4_File()
85 {
86 delete m_Movie;
87 delete m_MetaData;
88 }
89
90 /*----------------------------------------------------------------------
91 | AP4_File::ParseStream
92 +---------------------------------------------------------------------*/
93 void
94 AP4_File::ParseStream(AP4_ByteStream& stream,
95 AP4_AtomFactory& atom_factory,
96 bool moov_only,
97 AP4_Movie* movie)
6398 {
6499 // parse top-level atoms
65100 AP4_Atom* atom;
85120 break;
86121 }
87122 }
88 }
89
90 /*----------------------------------------------------------------------
91 | AP4_File::~AP4_File
92 +---------------------------------------------------------------------*/
93 AP4_File::~AP4_File()
94 {
95 delete m_Movie;
96 delete m_MetaData;
97123 }
98124
99125 /*----------------------------------------------------------------------
7070 const AP4_UI32 AP4_FILE_BRAND_ODCF = AP4_ATOM_TYPE('o','d','c','f');
7171 const AP4_UI32 AP4_FILE_BRAND_OPF2 = AP4_ATOM_TYPE('o','p','f','2');
7272 const AP4_UI32 AP4_FILE_BRAND_AVC1 = AP4_ATOM_TYPE('a','v','c','1');
73 const AP4_UI32 AP4_FILE_BRAND_HVC1 = AP4_ATOM_TYPE('h','v','c','1');
74 const AP4_UI32 AP4_FILE_BRAND_DBY1 = AP4_ATOM_TYPE('d','b','y','1');
7375
7476 /*----------------------------------------------------------------------
7577 | AP4_File
9193 /**
9294 * Constructs an AP4_File from a stream
9395 * @param stream the stream containing the data of the file
94 * @param factory the atom factory that will be used to parse the stream
96 * @param atom_factory the atom factory that will be used to parse the stream
9597 * @param moov_only indicates whether parsing of the atoms should stop
9698 * when the moov atom is found or if all atoms should be parsed until the
9799 * end of the file.
98100 */
99101 AP4_File(AP4_ByteStream& stream,
100 AP4_AtomFactory& atom_factory = AP4_DefaultAtomFactory::Instance,
101 bool moov_only = false,
102 AP4_Movie* movie = NULL);
102 AP4_AtomFactory& atom_factory,
103 bool moov_only,
104 AP4_Movie* movie = NULL);
105
106 /**
107 * Constructs an AP4_File from a stream using the default atom factory
108 * @param stream the stream containing the data of the file
109 * @param moov_only indicates whether parsing of the atoms should stop
110 * when the moov atom is found or if all atoms should be parsed until the
111 * end of the file.
112 */
113 AP4_File(AP4_ByteStream& stream, bool moov_only = false);
103114
104115 /**
105116 * Destroys the AP4_File instance
147158 virtual AP4_Result Inspect(AP4_AtomInspector& inspector);
148159
149160 private:
161 // methods
162 void ParseStream(AP4_ByteStream& stream,
163 AP4_AtomFactory& atom_factory,
164 bool moov_only,
165 AP4_Movie* movie);
166
150167 // members
151168 AP4_Movie* m_Movie;
152169 AP4_FtypAtom* m_FileType;
00 /*****************************************************************
11 |
2 | AP4 - FileByteStream
2 | AP4 - FileByteStream
33 |
44 | Copyright 2002-2008 Axiomatic Systems, LLC
55 |
5151 /**
5252 * Create a stream from a file (opened or created).
5353 *
54 * @param name Name of the file open or create
54 * @param name Name of the file to open or create
5555 * @param mode Mode to use for the file
56 * @param stream Refrence to a pointer where the stream object will
56 * @param stream Reference to a pointer where the stream object will
5757 * be returned
5858 * @return AP4_SUCCESS if the file can be opened or created, or an error code if
5959 * it cannot
6060 */
6161 static AP4_Result Create(const char* name, Mode mode, AP4_ByteStream*& stream);
62
62
6363 // constructors
6464 AP4_FileByteStream(AP4_ByteStream* delegate) : m_Delegate(delegate) {}
65
65
6666 #if !defined(AP4_CONFIG_NO_EXCEPTIONS)
6767 /**
6868 * @deprecated
7171 #endif
7272
7373 // AP4_ByteStream methods
74 AP4_Result ReadPartial(void* buffer,
75 AP4_Size bytesToRead,
74 AP4_Result ReadPartial(void* buffer,
75 AP4_Size bytesToRead,
7676 AP4_Size& bytesRead) {
7777 return m_Delegate->ReadPartial(buffer, bytesToRead, bytesRead);
7878 }
79 AP4_Result WritePartial(const void* buffer,
80 AP4_Size bytesToWrite,
79 AP4_Result WritePartial(const void* buffer,
80 AP4_Size bytesToWrite,
8181 AP4_Size& bytesWritten) {
8282 return m_Delegate->WritePartial(buffer, bytesToWrite, bytesWritten);
8383 }
8484 AP4_Result Seek(AP4_Position position) { return m_Delegate->Seek(position); }
8585 AP4_Result Tell(AP4_Position& position) { return m_Delegate->Tell(position); }
8686 AP4_Result GetSize(AP4_LargeSize& size) { return m_Delegate->GetSize(size); }
87 AP4_Result Flush() { return m_Delegate->Flush(); }
87 AP4_Result Flush() { return m_Delegate->Flush(); }
88
8889 // AP4_Referenceable methods
8990 void AddReference() { m_Delegate->AddReference(); }
9091 void Release() { m_Delegate->Release(); }
7979 AP4_Array<AP4_Array<AP4_UI64>*> trak_chunk_offsets_backup;
8080 AP4_Array<AP4_UI64> chunk_offsets;
8181 for (AP4_List<AP4_Track>::Item* track_item = movie->GetTracks().FirstItem();
82 track_item;
83 track_item = track_item->GetNext()) {
82 track_item;
83 track_item = track_item->GetNext()) {
8484 AP4_Track* track = track_item->GetData();
8585 AP4_TrakAtom* trak = track->UseTrakAtom();
8686
116116 movie->GetMoovAtom()->Write(stream);
117117
118118 // create and write the media data (mdat)
119 // FIXME: this only supports 32-bit mdat size
119 // TODO: this only supports 32-bit mdat size
120120 stream.WriteUI32((AP4_UI32)mdat_size);
121121 stream.WriteUI32(AP4_ATOM_TYPE_MDAT);
122122
4242 | AP4_FragmentSampleTable::AP4_FragmentSampleTable
4343 +---------------------------------------------------------------------*/
4444 AP4_FragmentSampleTable::AP4_FragmentSampleTable(AP4_ContainerAtom* traf,
45 AP4_TrexAtom* trex,
46 AP4_Cardinal internal_track_id,
47 AP4_ByteStream* sample_stream,
48 AP4_Position moof_offset,
49 AP4_Position mdat_payload_offset,
50 AP4_UI64 mdat_payload_size,
51 AP4_UI64 dts_origin)
52 : m_Duration(0)
53 , m_InternalTrackId(internal_track_id)
45 AP4_TrexAtom* trex,
46 AP4_ByteStream* sample_stream,
47 AP4_Position moof_offset,
48 AP4_Position mdat_payload_offset,
49 AP4_UI64 mdat_payload_size,
50 AP4_UI64 dts_origin) :
51 m_Duration(0)
5452 {
5553 AP4_TfhdAtom* tfhd = AP4_DYNAMIC_CAST(AP4_TfhdAtom, traf->GetChild(AP4_ATOM_TYPE_TFHD));
5654 if (tfhd == NULL) return;
9795 }
9896 // Hack if we have a single sample and default sample size is wrong (hbo ttml)
9997 if (m_Samples.ItemCount() == 1 && (trun_flags & AP4_TRUN_FLAG_SAMPLE_SIZE_PRESENT) == 0)
100 m_Samples[0].SetSize(mdat_payload_size);
98 m_Samples[0].SetSize(mdat_payload_size);
10199 }
102100
103101 /*----------------------------------------------------------------------
177175
178176 // parse all trun entries to setup the samples
179177 AP4_UI64 dts = dts_origin;
180 m_Duration = 0;
181178 for (unsigned int i=0; i<trun->GetEntries().ItemCount(); i++) {
182179 const AP4_TrunAtom::Entry& entry = trun->GetEntries()[i];
183180 AP4_Sample& sample = m_Samples[start+i];
224221
225222 // dts and cts
226223 sample.SetDts(dts);
227 if (trun_flags & AP4_TRUN_FLAG_SAMPLE_COMPOSITION_TIME_OFFSET_PRESENT) {
224 if (trun_flags & AP4_TRUN_FLAG_SAMPLE_COMPOSITION_TIME_OFFSET_PRESENT)
225 {
228226 sample.SetCtsDelta(entry.sample_composition_time_offset);
229227 }
230228
269267 AP4_SampleDescription*
270268 AP4_FragmentSampleTable::GetSampleDescription(AP4_Ordinal /*index*/)
271269 {
272 return NULL; // FIXME
270 return NULL; // TODO
273271 }
274272
275273 /*----------------------------------------------------------------------
278276 AP4_Cardinal
279277 AP4_FragmentSampleTable::GetSampleDescriptionCount()
280278 {
281 return 1; // FIXME
279 return 1; // TODO
282280 }
283281
284282 /*----------------------------------------------------------------------
299297 | AP4_FragmentSampleTable::GetSampleIndexForTimeStamp
300298 +---------------------------------------------------------------------*/
301299 AP4_Result
302 AP4_FragmentSampleTable::GetSampleIndexForTimeStamp(AP4_UI64 ts,
300 AP4_FragmentSampleTable::GetSampleIndexForTimeStamp(AP4_UI64 ts,
303301 AP4_Ordinal& sample_index)
304302 {
305 if (!m_Samples.ItemCount())
306 return AP4_ERROR_NOT_ENOUGH_DATA;
307
308 sample_index = 0;
309 while (sample_index < m_Samples.ItemCount() && m_Samples[sample_index].GetCts() + m_Samples[sample_index].GetDuration() < ts)
310 ++sample_index;
311
312 if (sample_index == m_Samples.ItemCount())
313 return AP4_ERROR_NOT_ENOUGH_DATA;
314
315 return AP4_SUCCESS;
303 if (!m_Samples.ItemCount())
304 return AP4_ERROR_NOT_ENOUGH_DATA;
305
306 sample_index = 0;
307 while (sample_index < m_Samples.ItemCount() && m_Samples[sample_index].GetCts() + m_Samples[sample_index].GetDuration() < ts)
308 ++sample_index;
309
310 if (sample_index == m_Samples.ItemCount())
311 return AP4_ERROR_NOT_ENOUGH_DATA;
312
313 return AP4_SUCCESS;
316314 }
317315
318316 /*----------------------------------------------------------------------
321319 AP4_Ordinal
322320 AP4_FragmentSampleTable::GetNearestSyncSampleIndex(AP4_Ordinal sample_index, bool before)
323321 {
324 if (sample_index >= m_Samples.ItemCount())
322 if (sample_index >= m_Samples.ItemCount())
323 return sample_index;
324
325 AP4_Ordinal end(before ? 0 : m_Samples.ItemCount());
326
327 while (sample_index != end && !m_Samples[sample_index].IsSync())
328 sample_index = sample_index + (before ? -1 : 1);
329
325330 return sample_index;
326
327 AP4_Ordinal end(before ? 0 : m_Samples.ItemCount());
328
329 while (sample_index != end && !m_Samples[sample_index].IsSync())
330 sample_index = sample_index + (before ? -1 : 1);
331
332 return sample_index;
333 }
334
331 }
332
5151 {
5252 public:
5353 // methods
54 AP4_FragmentSampleTable(AP4_ContainerAtom* traf,
55 AP4_TrexAtom* trex,
56 AP4_Cardinal internal_track_id,
57 AP4_ByteStream* sample_stream,
58 AP4_Position moof_offset,
59 AP4_Position mdat_payload_offset, // hack because MS doesn't implement the spec correctly
60 AP4_UI64 mdat_payload_size,
61 AP4_UI64 dts_origin=0);
54 AP4_FragmentSampleTable(AP4_ContainerAtom* traf,
55 AP4_TrexAtom* trex,
56 AP4_ByteStream* sample_stream,
57 AP4_Position moof_offset,
58 AP4_Position mdat_payload_offset, // hack because MS doesn't implement the spec correctly
59 AP4_UI64 mdat_payload_size,
60 AP4_UI64 dts_origin=0);
6261 virtual ~AP4_FragmentSampleTable();
6362
6463 // AP4_SampleTable methods
7473
7574 // methods
7675 AP4_UI64 GetDuration() { return m_Duration; }
77 AP4_Cardinal GetInteralTrackId() { return m_InternalTrackId; }
78
76
7977 private:
8078 // members
8179 AP4_Array<AP4_Sample> m_Samples;
8280 AP4_UI64 m_Duration;
83 AP4_Cardinal m_InternalTrackId;
8481
8582 // methods
86 AP4_Result AddTrun(AP4_TrunAtom* trun,
87 AP4_TfhdAtom* tfhd,
88 AP4_TrexAtom* trex,
89 AP4_ByteStream* sample_stream,
90 AP4_Position moof_offset,
91 AP4_Position& payload_offset,
92 AP4_UI64& dts_origin);
83 AP4_Result AddTrun(AP4_TrunAtom* trun,
84 AP4_TfhdAtom* tfhd,
85 AP4_TrexAtom* trex,
86 AP4_ByteStream* sample_stream,
87 AP4_Position moof_offset,
88 AP4_Position& payload_offset,
89 AP4_UI64& dts_origin);
9390
9491 };
9592
4141 | AP4_FtypAtom::AP4_FtypAtom
4242 +---------------------------------------------------------------------*/
4343 AP4_FtypAtom::AP4_FtypAtom(AP4_UI32 size, AP4_ByteStream& stream) :
44 AP4_Atom(AP4_ATOM_TYPE_FTYP, size)
44 AP4_Atom(AP4_ATOM_TYPE_FTYP, size),
45 m_MajorBrand(0),
46 m_MinorVersion(0)
4547 {
48 if (size < AP4_ATOM_HEADER_SIZE + 8) return;
4649 stream.ReadUI32(m_MajorBrand);
4750 stream.ReadUI32(m_MinorVersion);
4851 size -= 16;
49 while (size) {
52 while (size >= 4) {
5053 AP4_UI32 compatible_brand;
51 stream.ReadUI32(compatible_brand);
54 AP4_Result result = stream.ReadUI32(compatible_brand);
55 if (AP4_FAILED(result)) return;
5256 m_CompatibleBrands.Append(compatible_brand);
5357 size -= 4;
5458 }
4444 {
4545 AP4_UI08 version;
4646 AP4_UI32 flags;
47 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4748 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4849 if (version != 0) return NULL;
4950 return new AP4_GrpiAtom(size, version, flags, stream);
4545 {
4646 AP4_UI08 version;
4747 AP4_UI32 flags;
48 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4849 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4950 if (version != 0) return NULL;
5051 return new AP4_HdlrAtom(size, version, flags, stream);
5556 +---------------------------------------------------------------------*/
5657 AP4_HdlrAtom::AP4_HdlrAtom(AP4_Atom::Type hdlr_type, const char* hdlr_name) :
5758 AP4_Atom(AP4_ATOM_TYPE_HDLR, AP4_FULL_ATOM_HEADER_SIZE, 0, 0),
59 m_Predefined(0),
5860 m_HandlerType(hdlr_type),
59 m_HandlerName(hdlr_name)
61 m_HandlerName(hdlr_name),
62 m_QuickTimeMode(false)
6063 {
6164 m_Size32 += 20+m_HandlerName.GetLength()+1;
6265 m_Reserved[0] = m_Reserved[1] = m_Reserved[2] = 0;
6972 AP4_UI08 version,
7073 AP4_UI32 flags,
7174 AP4_ByteStream& stream) :
72 AP4_Atom(AP4_ATOM_TYPE_HDLR, size, version, flags)
75 AP4_Atom(AP4_ATOM_TYPE_HDLR, size, version, flags),
76 m_QuickTimeMode(false)
7377 {
74 AP4_UI32 predefined;
75 stream.ReadUI32(predefined);
78 stream.ReadUI32(m_Predefined);
7679 stream.ReadUI32(m_HandlerType);
7780 stream.ReadUI32(m_Reserved[0]);
7881 stream.ReadUI32(m_Reserved[1]);
7982 stream.ReadUI32(m_Reserved[2]);
8083
8184 // read the name unless it is empty
82 int name_size = size-(AP4_FULL_ATOM_HEADER_SIZE+20);
83 if (name_size == 0) return;
85 if (size < AP4_FULL_ATOM_HEADER_SIZE+20) return;
86 AP4_UI32 name_size = size-(AP4_FULL_ATOM_HEADER_SIZE+20);
8487 char* name = new char[name_size+1];
88 if (name == NULL) return;
8589 stream.Read(name, name_size);
8690 name[name_size] = '\0'; // force a null termination
8791 // handle a special case: the Quicktime files have a pascal
8892 // string here, but ISO MP4 files have a C string.
8993 // we try to detect a pascal encoding and correct it.
90 if (name[0] == name_size-1) {
94 if ((AP4_UI08)name[0] == (AP4_UI08)(name_size-1)) {
9195 m_HandlerName = name+1;
96 m_QuickTimeMode = true;
9297 } else {
9398 m_HandlerName = name;
9499 }
104109 AP4_Result result;
105110
106111 // write the data
107 result = stream.WriteUI32(0); // predefined
112 result = stream.WriteUI32(m_Predefined);
108113 if (AP4_FAILED(result)) return result;
109114 result = stream.WriteUI32(m_HandlerType);
110115 if (AP4_FAILED(result)) return result;
115120 result = stream.WriteUI32(m_Reserved[2]);
116121 if (AP4_FAILED(result)) return result;
117122 AP4_UI08 name_size = (AP4_UI08)m_HandlerName.GetLength();
118 if (AP4_FULL_ATOM_HEADER_SIZE+20+name_size > m_Size32) {
119 name_size = (AP4_UI08)(m_Size32-AP4_FULL_ATOM_HEADER_SIZE+20);
120 }
121 if (name_size) {
122 result = stream.Write(m_HandlerName.GetChars(), name_size);
123 if (AP4_FAILED(result)) return result;
123 if (m_QuickTimeMode) {
124 name_size += 1;
125 if (AP4_FULL_ATOM_HEADER_SIZE + 20 + name_size > m_Size32) {
126 name_size = (AP4_UI08)(m_Size32 - (AP4_FULL_ATOM_HEADER_SIZE + 20));
127 }
128 if (name_size) {
129 result = stream.WriteUI08(name_size - 1);
130 if (AP4_FAILED(result)) return result;
131
132 result = stream.Write(m_HandlerName.GetChars(), name_size - 1);
133 if (AP4_FAILED(result)) return result;
134 }
135 } else {
136 if (AP4_FULL_ATOM_HEADER_SIZE + 20 + name_size > m_Size32) {
137 name_size = (AP4_UI08)(m_Size32 - (AP4_FULL_ATOM_HEADER_SIZE + 20));
138 }
139 if (name_size) {
140 result = stream.Write(m_HandlerName.GetChars(), name_size);
141 if (AP4_FAILED(result)) return result;
142 }
124143 }
125144
126145 // pad with zeros if necessary
127 AP4_Size padding = m_Size32-(AP4_FULL_ATOM_HEADER_SIZE+20+name_size);
146 AP4_Size padding = m_Size32 - (AP4_FULL_ATOM_HEADER_SIZE + 20 + name_size);
128147 while (padding--) stream.WriteUI08(0);
129148
130149 return AP4_SUCCESS;
8181 AP4_ByteStream& stream);
8282
8383 // members
84 AP4_UI32 m_Predefined; // even if this is supposed to be predefined == 0,
85 // we allow keeping a non-zero value for compatitibilty
86 // with QuickTime
8487 AP4_UI32 m_HandlerType;
8588 AP4_UI32 m_Reserved[3];
8689 AP4_String m_HandlerName;
90 bool m_QuickTimeMode; // set to true when in QuickTime-compatible mode
8791 };
8892
8993 #endif // _AP4_HDLR_ATOM_H_
4040 {
4141 AP4_UI08 version;
4242 AP4_UI32 flags;
43 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4344 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4445 if (version != 0) return NULL;
4546 return new AP4_HmhdAtom(size, version, flags, stream);
11 |
22 | AP4 - hvcC Atoms
33 |
4 | Copyright 2002-2014 Axiomatic Systems, LLC
4 | Copyright 2002-2016 Axiomatic Systems, LLC
55 |
66 |
77 | This file is part of Bento4/AP4 (MP4 Atom Processing Library).
3232 #include "Ap4AtomFactory.h"
3333 #include "Ap4Utils.h"
3434 #include "Ap4Types.h"
35 #include "Ap4HevcParser.h"
3536
3637 /*----------------------------------------------------------------------
3738 | dynamic cast support
7475 }
7576
7677 /*----------------------------------------------------------------------
77 | AP4_AvccAtom::Create
78 | AP4_HvccAtom::Create
7879 +---------------------------------------------------------------------*/
7980 AP4_HvccAtom*
8081 AP4_HvccAtom::Create(AP4_Size size, AP4_ByteStream& stream)
107108 m_Reserved3(0),
108109 m_ChromaFormat(0),
109110 m_Reserved4(0),
110 m_LumaBitDepth(0),
111 m_LumaBitDepth(8),
111112 m_Reserved5(0),
112 m_ChromaBitDepth(0),
113 m_ChromaBitDepth(8),
113114 m_AverageFrameRate(0),
114115 m_ConstantFrameRate(0),
115116 m_NumTemporalLayers(0),
116117 m_TemporalIdNested(0),
117 m_NaluLengthSize(0)
118 m_NaluLengthSize(4)
118119 {
119120 UpdateRawBytes();
120121 m_Size32 += m_RawBytes.GetDataSize();
159160 /*----------------------------------------------------------------------
160161 | AP4_HvccAtom::AP4_HvccAtom
161162 +---------------------------------------------------------------------*/
163 AP4_HvccAtom::AP4_HvccAtom(AP4_UI08 general_profile_space,
164 AP4_UI08 general_tier_flag,
165 AP4_UI08 general_profile,
166 AP4_UI32 general_profile_compatibility_flags,
167 AP4_UI64 general_constraint_indicator_flags,
168 AP4_UI08 general_level,
169 AP4_UI32 min_spatial_segmentation,
170 AP4_UI08 parallelism_type,
171 AP4_UI08 chroma_format,
172 AP4_UI08 luma_bit_depth,
173 AP4_UI08 chroma_bit_depth,
174 AP4_UI16 average_frame_rate,
175 AP4_UI08 constant_frame_rate,
176 AP4_UI08 num_temporal_layers,
177 AP4_UI08 temporal_id_nested,
178 AP4_UI08 nalu_length_size,
179 const AP4_Array<AP4_DataBuffer>& video_parameters,
180 AP4_UI08 video_parameters_completeness,
181 const AP4_Array<AP4_DataBuffer>& sequence_parameters,
182 AP4_UI08 sequence_parameters_completeness,
183 const AP4_Array<AP4_DataBuffer>& picture_parameters,
184 AP4_UI08 picture_parameters_completeness) :
185 AP4_Atom(AP4_ATOM_TYPE_HVCC, AP4_ATOM_HEADER_SIZE),
186 m_ConfigurationVersion(1),
187 m_GeneralProfileSpace(general_profile_space),
188 m_GeneralTierFlag(general_tier_flag),
189 m_GeneralProfile(general_profile),
190 m_GeneralProfileCompatibilityFlags(general_profile_compatibility_flags),
191 m_GeneralConstraintIndicatorFlags(general_constraint_indicator_flags),
192 m_GeneralLevel(general_level),
193 m_Reserved1(0),
194 m_MinSpatialSegmentation(min_spatial_segmentation),
195 m_Reserved2(0),
196 m_ParallelismType(parallelism_type),
197 m_Reserved3(0),
198 m_ChromaFormat(chroma_format),
199 m_Reserved4(0),
200 m_LumaBitDepth(luma_bit_depth),
201 m_Reserved5(0),
202 m_ChromaBitDepth(chroma_bit_depth),
203 m_AverageFrameRate(average_frame_rate),
204 m_ConstantFrameRate(constant_frame_rate),
205 m_NumTemporalLayers(num_temporal_layers),
206 m_TemporalIdNested(temporal_id_nested),
207 m_NaluLengthSize(nalu_length_size)
208 {
209 // deep copy of the parameters
210 AP4_HvccAtom::Sequence vps_sequence;
211 vps_sequence.m_NaluType = AP4_HEVC_NALU_TYPE_VPS_NUT;
212 vps_sequence.m_ArrayCompleteness = video_parameters_completeness;
213 for (unsigned int i=0; i<video_parameters.ItemCount(); i++) {
214 vps_sequence.m_Nalus.Append(video_parameters[i]);
215 }
216 if (vps_sequence.m_Nalus.ItemCount()) {
217 m_Sequences.Append(vps_sequence);
218 }
219
220 AP4_HvccAtom::Sequence sps_sequence;
221 sps_sequence.m_NaluType = AP4_HEVC_NALU_TYPE_SPS_NUT;
222 sps_sequence.m_ArrayCompleteness = sequence_parameters_completeness;
223 for (unsigned int i=0; i<sequence_parameters.ItemCount(); i++) {
224 sps_sequence.m_Nalus.Append(sequence_parameters[i]);
225 }
226 if (sps_sequence.m_Nalus.ItemCount()) {
227 m_Sequences.Append(sps_sequence);
228 }
229
230 AP4_HvccAtom::Sequence pps_sequence;
231 pps_sequence.m_NaluType = AP4_HEVC_NALU_TYPE_PPS_NUT;
232 pps_sequence.m_ArrayCompleteness = picture_parameters_completeness;
233 for (unsigned int i=0; i<picture_parameters.ItemCount(); i++) {
234 pps_sequence.m_Nalus.Append(picture_parameters[i]);
235 }
236 if (pps_sequence.m_Nalus.ItemCount()) {
237 m_Sequences.Append(pps_sequence);
238 }
239
240 UpdateRawBytes();
241 m_Size32 += m_RawBytes.GetDataSize();
242 }
243
244 /*----------------------------------------------------------------------
245 | AP4_HvccAtom::AP4_HvccAtom
246 +---------------------------------------------------------------------*/
162247 AP4_HvccAtom::AP4_HvccAtom(AP4_UI32 size, const AP4_UI08* payload) :
163248 AP4_Atom(AP4_ATOM_TYPE_HVCC, size)
164249 {
165250 // make a copy of our configuration bytes
166251 unsigned int payload_size = size-AP4_ATOM_HEADER_SIZE;
252
253 // keep a raw copy
254 if (payload_size < 22) return;
167255 m_RawBytes.SetData(payload, payload_size);
168256
169257 // parse the payload
224312 void
225313 AP4_HvccAtom::UpdateRawBytes()
226314 {
227 // FIXME: not implemented yet
315 AP4_BitWriter bits(23);
316 bits.Write(m_ConfigurationVersion, 8);
317 bits.Write(m_GeneralProfileSpace, 2);
318 bits.Write(m_GeneralTierFlag, 1);
319 bits.Write(m_GeneralProfile, 5);
320 bits.Write(m_GeneralProfileCompatibilityFlags, 32);
321 bits.Write((AP4_UI32)(m_GeneralConstraintIndicatorFlags>>32), 16);
322 bits.Write((AP4_UI32)(m_GeneralConstraintIndicatorFlags), 32);
323 bits.Write(m_GeneralLevel, 8);
324 bits.Write(0xFF, 4);
325 bits.Write(m_MinSpatialSegmentation, 12);
326 bits.Write(0xFF, 6);
327 bits.Write(m_ParallelismType, 2);
328 bits.Write(0xFF, 6);
329 bits.Write(m_ChromaFormat, 2);
330 bits.Write(0xFF, 5);
331 bits.Write(m_LumaBitDepth >= 8 ? m_LumaBitDepth - 8 : 0, 3);
332 bits.Write(0xFF, 5);
333 bits.Write(m_ChromaBitDepth >= 8 ? m_ChromaBitDepth - 8 : 0, 3);
334 bits.Write(m_AverageFrameRate, 16);
335 bits.Write(m_ConstantFrameRate, 2);
336 bits.Write(m_NumTemporalLayers, 3);
337 bits.Write(m_TemporalIdNested, 1);
338 bits.Write(m_NaluLengthSize > 0 ? m_NaluLengthSize - 1 : 0, 2);
339 bits.Write(m_Sequences.ItemCount(), 8);
340
341 m_RawBytes.SetData(bits.GetData(), 23);
342
343 for (unsigned int i=0; i<m_Sequences.ItemCount(); i++) {
344 AP4_UI08 bytes[3];
345 bytes[0] = (m_Sequences[i].m_ArrayCompleteness ? (1<<7) : 0) | m_Sequences[i].m_NaluType;
346 AP4_BytesFromUInt16BE(&bytes[1], m_Sequences[i].m_Nalus.ItemCount());
347 m_RawBytes.AppendData(bytes, 3);
348
349 for (unsigned int j=0; j<m_Sequences[i].m_Nalus.ItemCount(); j++) {
350 AP4_UI08 size[2];
351 AP4_BytesFromUInt16BE(&size[0], (AP4_UI16)m_Sequences[i].m_Nalus[j].GetDataSize());
352 m_RawBytes.AppendData(size, 2);
353 m_RawBytes.AppendData(m_Sequences[i].m_Nalus[j].GetData(), m_Sequences[i].m_Nalus[j].GetDataSize());
354 }
355 }
228356 }
229357
230358 /*----------------------------------------------------------------------
00 /*****************************************************************
11 |
2 | AP4 - avcC Atoms
2 | AP4 - hvcC Atoms
33 |
44 | Copyright 2002-2014 Axiomatic Systems, LLC
55 |
7272 // constructors
7373 AP4_HvccAtom();
7474 AP4_HvccAtom(const AP4_HvccAtom& other); // copy construtor
75
75 AP4_HvccAtom(AP4_UI08 general_profile_space,
76 AP4_UI08 general_tier_flag,
77 AP4_UI08 general_profile,
78 AP4_UI32 general_profile_compatibility_flags,
79 AP4_UI64 general_constraint_indicator_flags,
80 AP4_UI08 general_level,
81 AP4_UI32 min_spatial_segmentation,
82 AP4_UI08 parallelism_type,
83 AP4_UI08 chroma_format,
84 AP4_UI08 luma_bit_depth,
85 AP4_UI08 chroma_bit_depth,
86 AP4_UI16 average_frame_rate,
87 AP4_UI08 constant_frame_rate,
88 AP4_UI08 num_temporal_layers,
89 AP4_UI08 temporal_id_nested,
90 AP4_UI08 nalu_length_size,
91 const AP4_Array<AP4_DataBuffer>& video_parameters,
92 AP4_UI08 video_parameters_completeness,
93 const AP4_Array<AP4_DataBuffer>& sequence_parameters,
94 AP4_UI08 sequence_parameters_completeness,
95 const AP4_Array<AP4_DataBuffer>& picture_parameters,
96 AP4_UI08 picture_parameters_completeness);
97
7698 // methods
7799 virtual AP4_Result InspectFields(AP4_AtomInspector& inspector);
78100 virtual AP4_Result WriteFields(AP4_ByteStream& stream);
4444 {
4545 AP4_UI08 version;
4646 AP4_UI32 flags;
47 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4748 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4849 if (version > 1) return NULL;
4950 return new AP4_IkmsAtom(size, version, flags, stream);
4545 {
4646 AP4_UI08 version;
4747 AP4_UI32 flags;
48 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4849 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4950 if (version != 0) return NULL;
5051 return new AP4_IodsAtom(size, version, flags, stream);
4545 {
4646 AP4_UI08 version;
4747 AP4_UI32 flags;
48 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4849 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4950 if (version != 0) return NULL;
5051 return new AP4_IproAtom(size, version, flags, stream, atom_factory);
4444 {
4545 AP4_UI08 version;
4646 AP4_UI32 flags;
47 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4748 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4849 if (version != 0) return NULL;
4950 return new AP4_IsfmAtom(size, version, flags, stream);
141141 | AP4_IsmaCipher::DecryptSampleData
142142 +---------------------------------------------------------------------*/
143143 AP4_Result
144 AP4_IsmaCipher::DecryptSampleData(AP4_UI32 pool_id, AP4_DataBuffer& data_in,
144 AP4_IsmaCipher::DecryptSampleData(AP4_UI32 poolid,
145 AP4_DataBuffer& data_in,
145146 AP4_DataBuffer& data_out,
146147 const AP4_UI08* /*iv*/)
147148 {
261262 | AP4_IsmaTrackDecrypter::Create
262263 +---------------------------------------------------------------------*/
263264 AP4_Result
264 AP4_IsmaTrackDecrypter::Create(AP4_TrakAtom* trak,
265 AP4_TrexAtom* trex,
266 const AP4_UI08* key,
265 AP4_IsmaTrackDecrypter::Create(const AP4_UI08* key,
267266 AP4_Size key_size,
268267 AP4_ProtectedSampleDescription* sample_description,
269268 AP4_SampleEntry* sample_entry,
281280 if (AP4_FAILED(result)) return result;
282281
283282 // instanciate the object
284 decrypter = new AP4_IsmaTrackDecrypter(trak, trex, cipher,
283 decrypter = new AP4_IsmaTrackDecrypter(cipher,
285284 sample_entry,
286285 sample_description->GetOriginalFormat());
287286 return AP4_SUCCESS;
290289 /*----------------------------------------------------------------------
291290 | AP4_IsmaTrackDecrypter::AP4_IsmaTrackDecrypter
292291 +---------------------------------------------------------------------*/
293 AP4_IsmaTrackDecrypter::AP4_IsmaTrackDecrypter(AP4_TrakAtom* trak,
294 AP4_TrexAtom* trex,
295 AP4_IsmaCipher* cipher,
292 AP4_IsmaTrackDecrypter::AP4_IsmaTrackDecrypter(AP4_IsmaCipher* cipher,
296293 AP4_SampleEntry* sample_entry,
297294 AP4_UI32 original_format) :
298 AP4_Processor::TrackHandler(trak, trex),
299 m_Cipher(cipher),
295 m_Cipher(cipher),
300296 m_SampleEntry(sample_entry),
301297 m_OriginalFormat(original_format)
302298 {
377373 const AP4_UI08* salt,
378374 AP4_SampleEntry* sample_entry,
379375 AP4_UI32 format) :
380 AP4_Processor::TrackHandler(0,0),
381376 m_KmsUri(kms_uri),
382377 m_SampleEntry(sample_entry),
383378 m_Format(format),
7373 AP4_Result EncryptSampleData(AP4_DataBuffer& data_in,
7474 AP4_DataBuffer& data_out,
7575 AP4_UI32 block_counter);
76 AP4_Result DecryptSampleData(AP4_UI32 pool_id, AP4_DataBuffer& data_in,
76 AP4_Result DecryptSampleData(AP4_UI32 poolid,
77 AP4_DataBuffer& data_in,
7778 AP4_DataBuffer& data_out,
7879 const AP4_UI08* iv = NULL);
7980 AP4_Size GetDecryptedSampleSize(AP4_Sample& sample);
9899 class AP4_IsmaTrackDecrypter : public AP4_Processor::TrackHandler {
99100 public:
100101 // construction
101 static AP4_Result Create(AP4_TrakAtom* trak,
102 AP4_TrexAtom* trex,
103 const AP4_UI08* key,
102 static AP4_Result Create(const AP4_UI08* key,
104103 AP4_Size key_size,
105104 AP4_ProtectedSampleDescription* sample_description,
106105 AP4_SampleEntry* sample_entry,
117116
118117 private:
119118 // constructor
120 AP4_IsmaTrackDecrypter(AP4_TrakAtom* trak,
121 AP4_TrexAtom* trex,
122 AP4_IsmaCipher* cipher,
119 AP4_IsmaTrackDecrypter(AP4_IsmaCipher* cipher,
123120 AP4_SampleEntry* sample_entry,
124121 AP4_UI32 original_format);
125122
4040 | AP4_LinearReader::AP4_LinearReader
4141 +---------------------------------------------------------------------*/
4242 AP4_LinearReader::AP4_LinearReader(AP4_Movie& movie,
43 AP4_ByteStream* fragment_stream,
44 AP4_Size max_buffer) :
43 AP4_ByteStream* fragment_stream) :
4544 m_Movie(movie),
4645 m_Fragment(NULL),
4746 m_FragmentStream(fragment_stream),
47 m_CurrentFragmentPosition(0),
4848 m_NextFragmentPosition(0),
4949 m_BufferFullness(0),
5050 m_BufferFullnessPeak(0),
51 m_MaxBufferFullness(max_buffer),
5251 m_Mfra(NULL)
5352 {
5453 m_HasFragments = movie.HasFragments();
5554 if (fragment_stream) {
5655 fragment_stream->AddReference();
57 //fragment_stream->Tell(m_NextFragmentPosition);
56 //fragment_stream->Tell(m_CurrentFragmentPosition);
57 //m_NextFragmentPosition = m_CurrentFragmentPosition;
5858 }
5959 }
6060
126126 FlushQueues();
127127
128128 // reset tracker states
129 for (unsigned int i = 0; i<m_Trackers.ItemCount(); i++) {
129 for (unsigned int i = 0; i < m_Trackers.ItemCount(); i++) {
130130 if (m_Trackers[i]->m_SampleTableIsOwned) {
131131 delete m_Trackers[i]->m_SampleTable;
132132 }
205205 if (AP4_SUCCEEDED(result)) {
206206 AP4_Atom* mfra = NULL;
207207 AP4_LargeSize available = mfra_size;
208 AP4_DefaultAtomFactory::Instance.CreateAtomFromStream(*m_FragmentStream, available, mfra);
208 AP4_DefaultAtomFactory atom_factory;
209 atom_factory.CreateAtomFromStream(*m_FragmentStream, available, mfra);
209210 m_Mfra = AP4_DYNAMIC_CAST(AP4_ContainerAtom, mfra);
210211 }
211212 }
258259 }
259260
260261 // update our position
261 if (best_entry >= 0) {
262 if (actual_time_ms) {
263 // report the actual time we found (in milliseconds)
264 *actual_time_ms = (AP4_UI32)AP4_ConvertTime(entries[best_entry].m_Time, m_Trackers[t]->m_Track->GetMediaTimeScale(), 1000);
265 }
266 m_NextFragmentPosition = entries[best_entry].m_MoofOffset;
267 }
262 if (actual_time_ms) {
263 // report the actual time we found (in milliseconds)
264 *actual_time_ms = (AP4_UI32)AP4_ConvertTime(entries[best_entry].m_Time, m_Trackers[t]->m_Track->GetMediaTimeScale(), 1000);
265 }
266 m_NextFragmentPosition = entries[best_entry].m_MoofOffset;
268267 }
269268 }
270269
273272 return AP4_FAILURE;
274273 }
275274
276 Reset();
275 // flush any queued samples
276 FlushQueues();
277
278 // reset tracker states
279 for (unsigned int i=0; i<m_Trackers.ItemCount(); i++) {
280 if (m_Trackers[i]->m_SampleTableIsOwned) {
281 delete m_Trackers[i]->m_SampleTable;
282 }
283 delete m_Trackers[i]->m_NextSample;
284 m_Trackers[i]->m_SampleTable = NULL;
285 m_Trackers[i]->m_NextSample = NULL;
286 m_Trackers[i]->m_NextSampleIndex = 0;
287 m_Trackers[i]->m_Eos = false;
288 }
277289
278290 return AP4_SUCCESS;
279291 }
294306 | AP4_LinearReader::ProcessMoof
295307 +---------------------------------------------------------------------*/
296308 AP4_Result
297 AP4_LinearReader::ProcessMoof(AP4_ContainerAtom* moof,
298 AP4_Position moof_offset,
299 AP4_Position mdat_payload_offset,
300 AP4_UI64 mdat_payload_size)
309 AP4_LinearReader::ProcessMoof(AP4_ContainerAtom* moof,
310 AP4_Position moof_offset,
311 AP4_Position mdat_payload_offset,
312 AP4_UI64 mdat_payload_size)
301313 {
302314 AP4_Result result;
303315
316328 tracker->m_SampleTable = NULL;
317329 tracker->m_NextSampleIndex = 0;
318330 for (unsigned int j=0; j<ids.ItemCount(); j++) {
319 if (ids.ItemCount()==1 || ids[j] == tracker->m_Track->GetId()) {
331 if (ids[j] == tracker->m_Track->GetId()) {
320332 AP4_FragmentSampleTable* sample_table = NULL;
321 result = m_Fragment->CreateSampleTable(&m_Movie,
322 ids[j],
323 m_FragmentStream,
324 moof_offset,
325 mdat_payload_offset,
326 mdat_payload_size,
327 tracker->m_NextDts,
328 sample_table);
333 result = m_Fragment->CreateSampleTable(&m_Movie,
334 ids[j],
335 m_FragmentStream,
336 moof_offset,
337 mdat_payload_offset,
338 mdat_payload_size,
339 tracker->m_NextDts,
340 sample_table);
329341 if (AP4_FAILED(result)) return result;
330342 tracker->m_SampleTable = sample_table;
331343 tracker->m_SampleTableIsOwned = true;
347359 AP4_Result result;
348360
349361 // go the the start of the next fragment
350 if (m_NextFragmentPosition)
351 {
352 result = m_FragmentStream->Seek(m_NextFragmentPosition);
353 if (AP4_FAILED(result)) return result;
354 }
355
362 if (m_NextFragmentPosition) {
363 result = m_FragmentStream->Seek(m_NextFragmentPosition);
364 if (AP4_FAILED(result)) return result;
365 m_CurrentFragmentPosition = m_NextFragmentPosition;
366 }
356367
357368 // read atoms until we find a moof
358369 assert(m_HasFragments);
359370 if (!m_FragmentStream) return AP4_ERROR_INVALID_STATE;
371 AP4_DefaultAtomFactory atom_factory;
360372 do {
361373 AP4_Atom* atom = NULL;
362 result = AP4_DefaultAtomFactory::Instance.CreateAtomFromStream(*m_FragmentStream, atom);
374 AP4_Position last_position = 0;
375 m_FragmentStream->Tell(last_position);
376 result = atom_factory.CreateAtomFromStream(*m_FragmentStream, atom);
363377 if (AP4_SUCCEEDED(result)) {
364378 if (atom->GetType() == AP4_ATOM_TYPE_MOOF) {
365379 AP4_ContainerAtom* moof = AP4_DYNAMIC_CAST(AP4_ContainerAtom, atom);
366380 if (moof) {
381 // remember where the moof started
382 m_CurrentFragmentPosition = last_position;
383
367384 // remember where we are in the stream
368385 AP4_Position position = 0;
369386 m_FragmentStream->Tell(position);
413430 AP4_Result
414431 AP4_LinearReader::Advance(bool read_data)
415432 {
416 // first, check if we have space to advance
417 if (m_BufferFullness >= m_MaxBufferFullness) {
418 return AP4_ERROR_NOT_ENOUGH_SPACE;
419 }
420
433
421434 AP4_UI64 min_offset = (AP4_UI64)(-1);
422435 Tracker* next_tracker = NULL;
423436 for (;;) {
430443 if (tracker->m_NextSample == NULL) {
431444 if (tracker->m_NextSampleIndex >= tracker->m_SampleTable->GetSampleCount()) {
432445 if (!m_HasFragments) tracker->m_Eos = true;
433 if (tracker->m_SampleTableIsOwned)
446 if (tracker->m_SampleTableIsOwned) {
434447 delete tracker->m_SampleTable;
435 tracker->m_SampleTable = NULL;
448 tracker->m_SampleTable = NULL;
449 }
436450 continue;
437451 }
438452 tracker->m_NextSample = new AP4_Sample();
549563 }
550564
551565 // unreachable - return AP4_ERROR_EOS;
552 }
553
554 /*----------------------------------------------------------------------
555 | AP4_LinearReader::GetSample
556 +---------------------------------------------------------------------*/
557 AP4_Result AP4_LinearReader::GetSample(AP4_UI32 track_id, AP4_Sample &sample, AP4_Ordinal sample_index)
558 {
559 // look for a sample from a specific track
560 Tracker* tracker = FindTracker(track_id);
561 if (tracker == NULL)
562 return AP4_ERROR_INVALID_PARAMETERS;
563
564 // don't continue if we've reached the end of that tracker
565 if (tracker->m_Eos)
566 return AP4_ERROR_EOS;
567
568 return tracker->m_SampleTable->GetSample(sample_index, sample);
569 }
570
571 /*----------------------------------------------------------------------
572 | AP4_LinearReader::SeekSample
573 +---------------------------------------------------------------------*/
574 AP4_Result
575 AP4_LinearReader::SeekSample(AP4_UI32 track_id, AP4_UI64 ts, AP4_Ordinal &sample_index, bool preceedingSync)
576 {
577 // we only support fragmented sources for now
578 if (!m_HasFragments)
579 return AP4_ERROR_NOT_SUPPORTED;
580
581 if (m_Trackers.ItemCount() == 0) {
582 return AP4_ERROR_NO_SUCH_ITEM;
583 }
584
585 // look for a sample from a specific track
586 Tracker* tracker = FindTracker(track_id);
587 if (tracker == NULL)
588 return AP4_ERROR_INVALID_PARAMETERS;
589
590 // don't continue if we've reached the end of that tracker
591 if (tracker->m_Eos)
592 return AP4_ERROR_EOS;
593
594 AP4_Result result;
595
596 if (!tracker->m_SampleTable && AP4_FAILED(result = Advance()))
597 return result;
598
599 while (AP4_FAILED(result = tracker->m_SampleTable->GetSampleIndexForTimeStamp(ts, sample_index)))
600 {
601 if (result == AP4_ERROR_NOT_ENOUGH_DATA)
602 {
603 tracker->m_NextSampleIndex = tracker->m_SampleTable->GetSampleCount();
604 if (AP4_FAILED(result = Advance()))
605 return result;
606 continue;
607 }
608 return result;
609 }
610
611 sample_index = tracker->m_SampleTable->GetNearestSyncSampleIndex(sample_index, preceedingSync);
612 //we have reached the end -> go for the first sample of the next segment
613 if (sample_index == tracker->m_SampleTable->GetSampleCount())
614 {
615 tracker->m_NextSampleIndex = tracker->m_SampleTable->GetSampleCount();
616 if (AP4_FAILED(result = Advance()))
617 return result;
618 sample_index = 0;
619 }
620 return SetSampleIndex(tracker->m_Track->GetId(), sample_index);
621566 }
622567
623568 /*----------------------------------------------------------------------
678623 }
679624
680625 /*----------------------------------------------------------------------
626 | AP4_LinearReader::GetSample
627 +---------------------------------------------------------------------*/
628 AP4_Result AP4_LinearReader::GetSample(AP4_UI32 track_id, AP4_Sample &sample, AP4_Ordinal sample_index)
629 {
630 // look for a sample from a specific track
631 Tracker* tracker = FindTracker(track_id);
632 if (tracker == NULL)
633 return AP4_ERROR_INVALID_PARAMETERS;
634
635 // don't continue if we've reached the end of that tracker
636 if (tracker->m_Eos)
637 return AP4_ERROR_EOS;
638
639 return tracker->m_SampleTable->GetSample(sample_index, sample);
640 }
641
642 /*----------------------------------------------------------------------
643 | AP4_LinearReader::SeekSample
644 +---------------------------------------------------------------------*/
645 AP4_Result
646 AP4_LinearReader::SeekSample(AP4_UI32 track_id, AP4_UI64 ts, AP4_Ordinal &sample_index, bool preceedingSync)
647 {
648 // we only support fragmented sources for now
649 if (!m_HasFragments)
650 return AP4_ERROR_NOT_SUPPORTED;
651
652 if (m_Trackers.ItemCount() == 0) {
653 return AP4_ERROR_NO_SUCH_ITEM;
654 }
655
656 // look for a sample from a specific track
657 Tracker* tracker = FindTracker(track_id);
658 if (tracker == NULL)
659 return AP4_ERROR_INVALID_PARAMETERS;
660
661 // don't continue if we've reached the end of that tracker
662 if (tracker->m_Eos)
663 return AP4_ERROR_EOS;
664
665 AP4_Result result;
666
667 if (!tracker->m_SampleTable && AP4_FAILED(result = Advance()))
668 return result;
669
670 while (AP4_FAILED(result = tracker->m_SampleTable->GetSampleIndexForTimeStamp(ts, sample_index)))
671 {
672 if (result == AP4_ERROR_NOT_ENOUGH_DATA)
673 {
674 tracker->m_NextSampleIndex = tracker->m_SampleTable->GetSampleCount();
675 if (AP4_FAILED(result = Advance()))
676 return result;
677 continue;
678 }
679 return result;
680 }
681
682 sample_index = tracker->m_SampleTable->GetNearestSyncSampleIndex(sample_index, preceedingSync);
683 //we have reached the end -> go for the first sample of the next segment
684 if (sample_index == tracker->m_SampleTable->GetSampleCount())
685 {
686 tracker->m_NextSampleIndex = tracker->m_SampleTable->GetSampleCount();
687 if (AP4_FAILED(result = Advance()))
688 return result;
689 sample_index = 0;
690 }
691 return SetSampleIndex(tracker->m_Track->GetId(), sample_index);
692 }
693
694 /*----------------------------------------------------------------------
681695 | AP4_LinearReader::GetNextSample
682696 +---------------------------------------------------------------------*/
683697 AP4_Result
4949 const unsigned int AP4_LINEAR_READER_INITIALIZED = 1;
5050 const unsigned int AP4_LINEAR_READER_FLAG_EOS = 2;
5151
52 const unsigned int AP4_LINEAR_READER_DEFAULT_BUFFER_SIZE = 16*1024*1024;
53
5452 /*----------------------------------------------------------------------
5553 | AP4_LinearReader
5654 +---------------------------------------------------------------------*/
5755 class AP4_LinearReader {
5856 public:
59 AP4_LinearReader(AP4_Movie& movie, AP4_ByteStream* fragment_stream = NULL, AP4_Size max_buffer=AP4_LINEAR_READER_DEFAULT_BUFFER_SIZE);
57 AP4_LinearReader(AP4_Movie& movie, AP4_ByteStream* fragment_stream = NULL);
6058 virtual ~AP4_LinearReader();
6159
6260 AP4_Result EnableTrack(AP4_UI32 track_id);
8684 AP4_Result SetSampleIndex(AP4_UI32 track_id, AP4_UI32 sample_index);
8785
8886 AP4_Result SeekTo(AP4_UI32 time_ms, AP4_UI32* actual_time_ms = 0);
89
87
9088 AP4_Result SeekSample(AP4_UI32 track_id, AP4_UI64 ts, AP4_Ordinal &sample_index, bool preceedingSync);
91
92
89
9390 // accessors
9491 AP4_Size GetBufferFullness() { return m_BufferFullness; }
92 AP4_Position GetCurrentFragmentPosition() { return m_CurrentFragmentPosition; }
9593
9694 // classes
9795 class SampleReader {
160158
161159 // methods that can be overridden
162160 virtual AP4_Result ProcessTrack(AP4_Track* track);
163 virtual AP4_Result ProcessMoof(AP4_ContainerAtom* moof,
164 AP4_Position moof_offset,
165 AP4_Position mdat_payload_offset,
166 AP4_UI64 mdat_payload_size);
161 virtual AP4_Result ProcessMoof(AP4_ContainerAtom* moof,
162 AP4_Position moof_offset,
163 AP4_Position mdat_payload_offset,
164 AP4_UI64 mdat_payload_size);
167165
168166 // methods
169167 Tracker* FindTracker(AP4_UI32 track_id);
174172 AP4_DataBuffer* sample_data,
175173 AP4_UI32& track_id);
176174 AP4_Result GetSample(AP4_UI32 track_id, AP4_Sample &sample, AP4_Ordinal sample_index);
177
178175 void FlushQueue(Tracker* tracker);
179176 void FlushQueues();
180177 void Reset();
184181 bool m_HasFragments;
185182 AP4_MovieFragment* m_Fragment;
186183 AP4_ByteStream* m_FragmentStream;
184 AP4_Position m_CurrentFragmentPosition;
187185 AP4_Position m_NextFragmentPosition;
188186 AP4_Array<Tracker*> m_Trackers;
189187 AP4_Size m_BufferFullness;
190188 AP4_Size m_BufferFullnessPeak;
191 AP4_Size m_MaxBufferFullness;
192189 AP4_ContainerAtom* m_Mfra;
193190 };
194191
8989 virtual ~AP4_List<T>();
9090 AP4_Result Clear();
9191 AP4_Result Add(T* data);
92 AP4_Result Add(AP4_List<T> &data);
9392 AP4_Result Add(Item* item);
9493 AP4_Result Remove(Item* item);
9594 AP4_Result Remove(T* data);
160159 return Add(new Item(data));
161160 }
162161
163 template <typename T>
164 inline
165 AP4_Result
166 AP4_List<T>::Add(AP4_List<T> &data)
167 {
168 Item* item = data.m_Head;
169 while (item) {
170 Add(new Item(item->GetData()));
171 item->m_Data = NULL;
172 item = item->m_Next;
173 }
174 return AP4_SUCCESS;
175 }
176
177162 /*----------------------------------------------------------------------
178163 | AP4_List<T>::Add
179164 +---------------------------------------------------------------------*/
352352 AP4_BlockCipherFactory* block_cipher_factory,
353353 AP4_MarlinIpmpSampleDecrypter*& sample_decrypter)
354354 {
355 // FIXME: need to parse group key info
355 // TODO: need to parse group key info
356356 return Create(key, key_size, block_cipher_factory, sample_decrypter);
357357 }
358358
430430 | AP4_MarlinIpmpSampleDecrypter::DecryptSampleData
431431 +---------------------------------------------------------------------*/
432432 AP4_Result
433 AP4_MarlinIpmpSampleDecrypter::DecryptSampleData(AP4_UI32 pool_id, AP4_DataBuffer& data_in,
433 AP4_MarlinIpmpSampleDecrypter::DecryptSampleData(AP4_UI32 poolid,
434 AP4_DataBuffer& data_in,
434435 AP4_DataBuffer& data_out,
435436 const AP4_UI08* /*iv*/)
436437 {
520521 | AP4_MarlinIpmpDecryptingProcessor:CreateTrackHandler
521522 +---------------------------------------------------------------------*/
522523 AP4_Processor::TrackHandler*
523 AP4_MarlinIpmpDecryptingProcessor::CreateTrackHandler(AP4_TrakAtom* trak, AP4_TrexAtom* trex)
524 AP4_MarlinIpmpDecryptingProcessor::CreateTrackHandler(AP4_TrakAtom* trak)
524525 {
525526 // look for this track in the list of entries
526527 AP4_MarlinIpmpParser::SinfEntry* sinf_entry = NULL;
574575
575576 // create the decrypter
576577 AP4_MarlinIpmpTrackDecrypter* decrypter = NULL;
577 AP4_Result result = AP4_MarlinIpmpTrackDecrypter::Create(trak, trex,*m_BlockCipherFactory,
578 AP4_Result result = AP4_MarlinIpmpTrackDecrypter::Create(*m_BlockCipherFactory,
578579 key->GetData(),
579580 key->GetDataSize(),
580581 decrypter);
587588 | AP4_MarlinIpmpTrackDecrypter::Create
588589 +---------------------------------------------------------------------*/
589590 AP4_Result
590 AP4_MarlinIpmpTrackDecrypter::Create(AP4_TrakAtom* trak, AP4_TrexAtom* trex,
591 AP4_BlockCipherFactory& cipher_factory,
591 AP4_MarlinIpmpTrackDecrypter::Create(AP4_BlockCipherFactory& cipher_factory,
592592 const AP4_UI08* key,
593593 AP4_Size key_size,
594594 AP4_MarlinIpmpTrackDecrypter*& decrypter)
601601 if (AP4_FAILED(result)) return result;
602602
603603 // create the track decrypter
604 decrypter = new AP4_MarlinIpmpTrackDecrypter(trak, trex, sample_decrypter);
604 decrypter = new AP4_MarlinIpmpTrackDecrypter(sample_decrypter);
605605
606606 return AP4_SUCCESS;
607607 }
730730
731731 // create an initial object descriptor
732732 AP4_InitialObjectDescriptor* iod =
733 // FIXME: get real values from the property map
733 // TODO: get real values from the property map
734734 new AP4_InitialObjectDescriptor(AP4_DESCRIPTOR_TAG_MP4_IOD,
735735 1022, // object descriptor id
736736 false,
881881 // parse all the atoms encoded in the data and add them to the 'schi' container
882882 AP4_MemoryByteStream* mbs = new AP4_MemoryByteStream(attributes_atoms.GetData(),
883883 attributes_atoms.GetDataSize());
884 AP4_DefaultAtomFactory atom_factory;
884885 do {
885886 AP4_Atom* atom = NULL;
886 result = AP4_DefaultAtomFactory::Instance.CreateAtomFromStream(*mbs, atom);
887 result = atom_factory.CreateAtomFromStream(*mbs, atom);
887888 if (AP4_SUCCEEDED(result) && atom) {
888889 satr->AddChild(atom);
889890 }
10211022 +---------------------------------------------------------------------*/
10221023 AP4_MarlinIpmpTrackEncrypter::AP4_MarlinIpmpTrackEncrypter(AP4_StreamCipher* cipher,
10231024 const AP4_UI08* iv) :
1024 AP4_Processor::TrackHandler(NULL, NULL),
1025 m_Cipher(cipher)
1025 m_Cipher(cipher)
10261026 {
10271027 // copy the IV
10281028 AP4_CopyMemory(m_IV, iv, AP4_AES_BLOCK_SIZE);
11011101 {
11021102 AP4_UI08 version;
11031103 AP4_UI32 flags;
1104 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
11041105 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
11051106 if (version > 0) return NULL;
11061107 return new AP4_MkidAtom(size, version, flags, stream);
117117
118118 // AP4_SampleDecrypter methods
119119 AP4_Size GetDecryptedSampleSize(AP4_Sample& sample);
120 AP4_Result DecryptSampleData(AP4_UI32 pool_id, AP4_DataBuffer& data_in,
120 AP4_Result DecryptSampleData(AP4_UI32 poolid,
121 AP4_DataBuffer& data_in,
121122 AP4_DataBuffer& data_out,
122123 const AP4_UI08* iv = NULL);
123124
145146 virtual AP4_Result Initialize(AP4_AtomParent& top_level,
146147 AP4_ByteStream& stream,
147148 ProgressListener* listener);
148 virtual AP4_Processor::TrackHandler* CreateTrackHandler(AP4_TrakAtom* trak, AP4_TrexAtom* trex);
149 virtual AP4_Processor::TrackHandler* CreateTrackHandler(AP4_TrakAtom* trak);
149150
150151 private:
151152
162163 {
163164 public:
164165 // class methods
165 static AP4_Result Create(AP4_TrakAtom *trak, AP4_TrexAtom *trex,
166 AP4_BlockCipherFactory& cipher_factory,
166 static AP4_Result Create(AP4_BlockCipherFactory& cipher_factory,
167167 const AP4_UI08* key,
168168 AP4_Size key_size,
169169 AP4_MarlinIpmpTrackDecrypter*& decrypter);
170170
171171 // constructor and destructor
172 AP4_MarlinIpmpTrackDecrypter(AP4_TrakAtom *trak, AP4_TrexAtom *trex) : AP4_Processor::TrackHandler(trak, trex), m_SampleDecrypter(NULL) {};
172 AP4_MarlinIpmpTrackDecrypter() : m_SampleDecrypter(NULL) {};
173173 ~AP4_MarlinIpmpTrackDecrypter();
174174
175175 // AP4_Processor::TrackHandler methods
180180
181181 private:
182182 // constructor
183 AP4_MarlinIpmpTrackDecrypter(AP4_TrakAtom *trak, AP4_TrexAtom *trex, AP4_SampleDecrypter* sample_decrypter) :
184 AP4_Processor::TrackHandler(trak, trex), m_SampleDecrypter(sample_decrypter) {}
183 AP4_MarlinIpmpTrackDecrypter(AP4_SampleDecrypter* sample_decrypter) :
184 m_SampleDecrypter(sample_decrypter) {}
185185
186186 // members
187187 AP4_SampleDecrypter* m_SampleDecrypter;
4545 {
4646 AP4_UI08 version;
4747 AP4_UI32 flags;
48 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4849 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4950 if (version > 1) return NULL;
5051 return new AP4_MdhdAtom(size, version, flags, stream);
5354 /*----------------------------------------------------------------------
5455 | AP4_MdhdAtom::AP4_MdhdAtom
5556 +---------------------------------------------------------------------*/
56 AP4_MdhdAtom::AP4_MdhdAtom(AP4_UI32 creation_time,
57 AP4_UI32 modification_time,
57 AP4_MdhdAtom::AP4_MdhdAtom(AP4_UI64 creation_time,
58 AP4_UI64 modification_time,
5859 AP4_UI32 time_scale,
5960 AP4_UI64 duration,
6061 const char* language) :
6465 m_TimeScale(time_scale),
6566 m_Duration(duration)
6667 {
67 m_Language.Assign(language, 3);
68
69 if (duration > 0xFFFFFFFF) {
68 if (strlen(language) == 3) {
69 m_Language.Assign(language, 3);
70 } else {
71 m_Language = "und";
72 }
73 if (duration > 0xFFFFFFFFULL ||
74 creation_time > 0xFFFFFFFFULL ||
75 modification_time > 0xFFFFFFFFULL) {
7076 m_Version = 1;
7177 m_Size32 += 12;
7278 }
104110 char l0 = ((lang[0]>>2)&0x1F);
105111 char l1 = (((lang[0]&0x3)<<3) | ((lang[1]>>5)&0x7));
106112 char l2 = ((lang[1]&0x1F));
107 if (l0 && l1 && l2) {
113 if (lang[0] == 0x7F && lang[1] == 0xFF) {
114 // undefined (Quicktime)
115 m_Language.Assign("und", 3);
116 } else if (l0 && l1 && l2) {
108117 char lang_str[3] = {(char)(l0+0x60), (char)(l1+0x60), (char)(l2+0x60)};
109118 m_Language.Assign(lang_str, 3);
110119 } else {
141150 }
142151
143152 // write the language
144 AP4_UI08 l0 = m_Language[0]-0x60;
145 AP4_UI08 l1 = m_Language[1]-0x60;
146 AP4_UI08 l2 = m_Language[2]-0x60;
147 result = stream.WriteUI08((l0<<2 | l1>>3)&0xFF);
148 if (AP4_FAILED(result)) return result;
149 result = stream.WriteUI08((l1<<5 | l2)&0xFF);
150 if (AP4_FAILED(result)) return result;
153 if (m_Language.GetLength() == 3) {
154 AP4_UI08 l0 = m_Language[0]-0x60;
155 AP4_UI08 l1 = m_Language[1]-0x60;
156 AP4_UI08 l2 = m_Language[2]-0x60;
157 result = stream.WriteUI08((l0<<2 | l1>>3)&0xFF);
158 if (AP4_FAILED(result)) return result;
159 result = stream.WriteUI08((l1<<5 | l2)&0xFF);
160 if (AP4_FAILED(result)) return result;
161 } else {
162 result = stream.WriteUI16(0);
163 if (AP4_FAILED(result)) return result;
164 }
151165
152166 // pre-defined
153167 return stream.WriteUI16(0);
160174 AP4_MdhdAtom::GetDurationMs()
161175 {
162176 return AP4_DurationMsFromUnits(m_Duration, m_TimeScale);
177 }
178
179 /*----------------------------------------------------------------------
180 | AP4_MdhdAtom::SetLanguage
181 +---------------------------------------------------------------------*/
182 AP4_Result
183 AP4_MdhdAtom::SetLanguage(const char* language)
184 {
185 if (strlen(language) != 3) {
186 return AP4_ERROR_INVALID_PARAMETERS;
187 }
188 m_Language = language;
189
190 return AP4_SUCCESS;
163191 }
164192
165193 /*----------------------------------------------------------------------
5252 static AP4_MdhdAtom* Create(AP4_Size size, AP4_ByteStream& stream);
5353
5454 // methods
55 AP4_MdhdAtom(AP4_UI32 creation_time,
56 AP4_UI32 modification_time,
55 AP4_MdhdAtom(AP4_UI64 creation_time,
56 AP4_UI64 modification_time,
5757 AP4_UI32 time_scale,
5858 AP4_UI64 duration,
5959 const char* language);
6666 AP4_UI32 GetTimeScale() { return m_TimeScale; }
6767 void SetTimeScale(AP4_UI32 timescale) { m_TimeScale = timescale; }
6868 const AP4_String& GetLanguage() { return m_Language; }
69 AP4_Result SetLanguage(const char* language);
6970
7071 private:
7172 // methods
4545 {
4646 AP4_UI08 version;
4747 AP4_UI32 flags;
48 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4849 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4950 if (version > 1) return NULL;
5051 return new AP4_MehdAtom(size, version, flags, stream);
4545 {
4646 AP4_UI08 version;
4747 AP4_UI32 flags;
48 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4849 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4950 if (version > 0) return NULL;
5051 return new AP4_MfhdAtom(size, version, flags, stream);
4040 {
4141 AP4_UI08 version = 0;
4242 AP4_UI32 flags = 0;
43 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4344 AP4_Result result = ReadFullHeader(stream, version, flags);
4445 if (AP4_FAILED(result)) return NULL;
4546 if (version != 0) return NULL;
3939 AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_MoovAtom)
4040
4141 /*----------------------------------------------------------------------
42 | AP4_AtomCollector
42 | AP4_TrakAtomCollector
4343 +---------------------------------------------------------------------*/
44 class AP4_AtomCollector : public AP4_List<AP4_Atom>::Item::Operator
44 class AP4_TrakAtomCollector : public AP4_List<AP4_Atom>::Item::Operator
4545 {
4646 public:
47 AP4_AtomCollector(AP4_List<AP4_TrakAtom>* track_atoms, AP4_List<AP4_PsshAtom>* pssh_atoms) :
48 m_TrakAtoms(track_atoms), m_PsshAtoms(pssh_atoms) {}
47 AP4_TrakAtomCollector(AP4_List<AP4_TrakAtom>* track_atoms) :
48 m_TrakAtoms(track_atoms) {}
4949
5050 AP4_Result Action(AP4_Atom* atom) const {
5151 if (atom->GetType() == AP4_ATOM_TYPE_TRAK) {
5454 m_TrakAtoms->Add(trak);
5555 }
5656 }
57 else if (atom->GetType() == AP4_ATOM_TYPE_PSSH) {
58 AP4_PsshAtom* pssh = AP4_DYNAMIC_CAST(AP4_PsshAtom, atom);
59 if (pssh) {
60 m_PsshAtoms->Add(pssh);
61 }
62 }
63 return AP4_SUCCESS;
57 return AP4_SUCCESS;
6458 }
6559
6660 private:
6761 AP4_List<AP4_TrakAtom>* m_TrakAtoms;
68 AP4_List<AP4_PsshAtom>* m_PsshAtoms;
62 };
63
64 /*----------------------------------------------------------------------
65 | AP4_PsshAtomCollector
66 +---------------------------------------------------------------------*/
67 class AP4_PsshAtomCollector : public AP4_List<AP4_Atom>::Item::Operator
68 {
69 public:
70 AP4_PsshAtomCollector(AP4_List<AP4_PsshAtom>* pssh_atoms) :
71 m_PsshAtoms(pssh_atoms) {}
72
73 AP4_Result Action(AP4_Atom* atom) const {
74 if (atom->GetType() == AP4_ATOM_TYPE_PSSH) {
75 AP4_PsshAtom* pssh = AP4_DYNAMIC_CAST(AP4_PsshAtom, atom);
76 if (pssh) {
77 m_PsshAtoms->Add(pssh);
78 }
79 }
80 return AP4_SUCCESS;
81 }
82
83 private:
84 AP4_List<AP4_PsshAtom>* m_PsshAtoms;
6985 };
7086
7187 /*----------------------------------------------------------------------
87103 m_TimeScale(0)
88104 {
89105 // collect all trak atoms
90 m_Children.Apply(AP4_AtomCollector(&m_TrakAtoms, &m_PsshAtoms));
106 m_Children.Apply(AP4_TrakAtomCollector(&m_TrakAtoms));
107 // collect all pssh atoms
108 m_Children.Apply(AP4_PsshAtomCollector(&m_PsshAtoms));
91109 }
92110
93111 /*----------------------------------------------------------------------
107125 }
108126
109127 /*----------------------------------------------------------------------
110 | AP4_MoovAtom::AddTrakAtoms
111 +---------------------------------------------------------------------*/
112 AP4_Result
113 AP4_MoovAtom::AddTrakAtoms(AP4_List<AP4_TrakAtom>& atoms, AP4_List<AP4_TrakAtom>::Item* &first_item)
114 {
115 //find the insert position (behind last existing track)
116 int current=0, insertPos = GetChildren().ItemCount();
117 for (AP4_List<AP4_Atom>::Item* item = GetChildren().FirstItem(); item; item = item->GetNext(), ++current)
118 if (item->GetData()->GetType() == AP4_ATOM_TYPE_TRAK)
119 insertPos = current + 1;
120 current = m_TrakAtoms.ItemCount();
121 for (AP4_List<AP4_TrakAtom>::Item *item(atoms.FirstItem()); item; item = item->GetNext())
122 AddChild(AP4_DYNAMIC_CAST(AP4_Atom, item->GetData())->Clone(),insertPos++);
123
124 for (first_item = m_TrakAtoms.FirstItem(); current; first_item = first_item->GetNext(), --current);
125
126 return AP4_SUCCESS;
127 }
128
129 /*----------------------------------------------------------------------
130128 | AP4_MoovAtom::OnChildAdded
131129 +---------------------------------------------------------------------*/
132130 void
140138 }
141139 }
142140
143 // keep the atom in the list of pssh atoms
144 if (atom->GetType() == AP4_ATOM_TYPE_PSSH) {
145 AP4_PsshAtom* pssh = AP4_DYNAMIC_CAST(AP4_PsshAtom, atom);
146 if (pssh) {
147 m_PsshAtoms.Add(pssh);
148 }
149 }
150 // call the base class implementation
141 // call the base class implementation
151142 AP4_ContainerAtom::OnChildAdded(atom);
152143 }
153144
165156 }
166157 }
167158
168 // remove the atom from the list of pssh atoms
169 if (atom->GetType() == AP4_ATOM_TYPE_PSSH) {
170 AP4_PsshAtom* pssh = AP4_DYNAMIC_CAST(AP4_PsshAtom, atom);
171 if (pssh) {
172 m_PsshAtoms.Remove(pssh);
173 }
174 }
175
176159 // call the base class implementation
177160 AP4_ContainerAtom::OnChildRemoved(atom);
178161 }
6161 AP4_List<AP4_TrakAtom>& GetTrakAtoms() {
6262 return m_TrakAtoms;
6363 }
64 AP4_Result AddTrakAtoms(AP4_List<AP4_TrakAtom>& atoms, AP4_List<AP4_TrakAtom>::Item* &first_item);
65
66 AP4_List<AP4_PsshAtom>& GetPsshAtoms() {
67 return m_PsshAtoms;
68 }
69 AP4_UI32 GetTimeScale() {
64 AP4_List<AP4_PsshAtom>& GetPsshAtoms() {
65 return m_PsshAtoms;
66 }
67 AP4_UI32 GetTimeScale() {
7068 return m_TimeScale;
7169 }
7270 AP4_Result AdjustChunkOffsets(AP4_SI64 offset);
8280 AP4_AtomFactory& atom_factory);
8381
8482 // members
85 AP4_List<AP4_TrakAtom> m_TrakAtoms;
86 AP4_List<AP4_PsshAtom> m_PsshAtoms;
83 AP4_List<AP4_PsshAtom> m_PsshAtoms;
84 AP4_List<AP4_TrakAtom> m_TrakAtoms;
8785 AP4_UI32 m_TimeScale;
8886 };
8987
7575 /*----------------------------------------------------------------------
7676 | AP4_Movie::AP4_Movie
7777 +---------------------------------------------------------------------*/
78 AP4_Movie::AP4_Movie(AP4_UI32 time_scale, AP4_UI64 duration) :
78 AP4_Movie::AP4_Movie(AP4_UI32 time_scale,
79 AP4_UI64 duration,
80 AP4_UI64 creation_time,
81 AP4_UI64 modification_time) :
7982 m_MoovAtomIsOwned(true)
8083 {
8184 m_MoovAtom = new AP4_MoovAtom();
82 m_MvhdAtom = new AP4_MvhdAtom(0, 0,
85 m_MvhdAtom = new AP4_MvhdAtom(creation_time,
86 modification_time,
8387 time_scale,
8488 duration,
8589 0x00010000,
106110 time_scale = 0;
107111 }
108112
109 // get the pssh atoms
110 AP4_List<AP4_PsshAtom>* pssh_atoms;
111 pssh_atoms = &moov->GetPsshAtoms();
112 AP4_List<AP4_PsshAtom>::Item* pssh_item = pssh_atoms->FirstItem();
113 while (pssh_item) {
114 m_PsshAtoms.Append(new AP4_PsshAtom(*pssh_item->GetData()));
115 pssh_item = pssh_item->GetNext();
116 }
117
118 // get all tracks
113 // get the pssh atoms
114 AP4_List<AP4_PsshAtom>* pssh_atoms;
115 pssh_atoms = &moov->GetPsshAtoms();
116 AP4_List<AP4_PsshAtom>::Item* pssh_item = pssh_atoms->FirstItem();
117 while (pssh_item) {
118 m_PsshAtoms.Append(*pssh_item->GetData());
119 pssh_item = pssh_item->GetNext();
120 }
121
122 // get all tracks
119123 AP4_List<AP4_TrakAtom>* trak_atoms;
120124 trak_atoms = &moov->GetTrakAtoms();
121 AP4_List<AP4_TrakAtom>::Item* trak_item = trak_atoms->FirstItem();
122 while (trak_item) {
123 AP4_Track* track = new AP4_Track(*trak_item->GetData(),
125 AP4_List<AP4_TrakAtom>::Item* item = trak_atoms->FirstItem();
126 while (item) {
127 AP4_Track* track = new AP4_Track(*item->GetData(),
124128 sample_stream,
125129 time_scale);
126130 m_Tracks.Add(track);
127 trak_item = trak_item->GetNext();
131 item = item->GetNext();
128132 }
129133 }
130134
5151 class AP4_Movie {
5252 public:
5353 // methods
54 AP4_Movie(AP4_UI32 time_scale = 0, AP4_UI64 duration = 0);
54 AP4_Movie(AP4_UI32 time_scale = 0,
55 AP4_UI64 duration = 0,
56 AP4_UI64 creation_time = 0,
57 AP4_UI64 modification_time = 0);
5558 AP4_Movie(AP4_MoovAtom* moov, AP4_ByteStream& sample_stream, bool transfer_moov_ownership = true);
5659 virtual ~AP4_Movie();
5760 AP4_Result Inspect(AP4_AtomInspector& inspector);
5861
5962 AP4_MoovAtom* GetMoovAtom() { return m_MoovAtom;}
6063 void SetMoovAtom(AP4_MoovAtom* atom) { m_MoovAtom = atom; }
64 AP4_Array<AP4_PsshAtom>& GetPsshAtoms() { return m_PsshAtoms; }
6165 AP4_MvhdAtom* GetMvhdAtom() { return m_MvhdAtom;}
62 AP4_Array<AP4_PsshAtom*>& GetPsshAtoms() { return m_PsshAtoms; }
63
64 AP4_List<AP4_Track>& GetTracks() { return m_Tracks; }
66 AP4_List<AP4_Track>& GetTracks() { return m_Tracks; }
6567 AP4_Track* GetTrack(AP4_UI32 track_id);
6668 AP4_Track* GetTrack(AP4_Track::Type type, AP4_Ordinal index = 0);
6769 AP4_Result AddTrack(AP4_Track* track);
7577 AP4_MoovAtom* m_MoovAtom;
7678 bool m_MoovAtomIsOwned;
7779 AP4_MvhdAtom* m_MvhdAtom;
78 AP4_Array<AP4_PsshAtom*> m_PsshAtoms;
79
80 AP4_List<AP4_Track> m_Tracks;
80 AP4_Array<AP4_PsshAtom> m_PsshAtoms;
81 AP4_List<AP4_Track> m_Tracks;
8182 };
8283
8384 #endif // _AP4_MOVIE_H_
121121 | AP4_MovieFragment::CreateSampleTable
122122 +---------------------------------------------------------------------*/
123123 AP4_Result
124 AP4_MovieFragment::CreateSampleTable(AP4_MoovAtom* moov,
125 AP4_UI32 track_id,
126 AP4_ByteStream* sample_stream,
127 AP4_Position moof_offset,
128 AP4_Position mdat_payload_offset,
129 AP4_UI64 mdat_payload_size,
130 AP4_UI64 dts_origin,
131 AP4_FragmentSampleTable*& sample_table)
124 AP4_MovieFragment::CreateSampleTable(AP4_MoovAtom* moov,
125 AP4_UI32 track_id,
126 AP4_ByteStream* sample_stream,
127 AP4_Position moof_offset,
128 AP4_Position mdat_payload_offset,
129 AP4_UI64 mdat_payload_size,
130 AP4_UI64 dts_origin,
131 AP4_FragmentSampleTable*& sample_table)
132132 {
133133 // default value
134134 sample_table = NULL;
153153 }
154154 AP4_ContainerAtom* traf = NULL;
155155 if (AP4_SUCCEEDED(GetTrafAtom(track_id, traf))) {
156 sample_table = new AP4_FragmentSampleTable(traf,
157 trex,
158 track_id,
159 sample_stream,
160 moof_offset,
161 mdat_payload_offset,
162 mdat_payload_size,
163 dts_origin);
156 sample_table = new AP4_FragmentSampleTable(traf,
157 trex,
158 sample_stream,
159 moof_offset,
160 mdat_payload_offset,
161 mdat_payload_size,
162 dts_origin);
164163 return AP4_SUCCESS;
165164 }
166165
171170 | AP4_MovieFragment::CreateSampleTable
172171 +---------------------------------------------------------------------*/
173172 AP4_Result
174 AP4_MovieFragment::CreateSampleTable(AP4_Movie* movie,
175 AP4_UI32 track_id,
176 AP4_ByteStream* sample_stream,
177 AP4_Position moof_offset,
178 AP4_Position mdat_payload_offset,
179 AP4_UI64 mdat_payload_size,
180 AP4_UI64 dts_origin,
181 AP4_FragmentSampleTable*& sample_table)
173 AP4_MovieFragment::CreateSampleTable(AP4_Movie* movie,
174 AP4_UI32 track_id,
175 AP4_ByteStream* sample_stream,
176 AP4_Position moof_offset,
177 AP4_Position mdat_payload_offset,
178 AP4_UI64 mdat_payload_size,
179 AP4_UI64 dts_origin,
180 AP4_FragmentSampleTable*& sample_table)
182181 {
183182 AP4_MoovAtom* moov = movie?movie->GetMoovAtom():NULL;
184183 return CreateSampleTable(moov, track_id, sample_stream, moof_offset, mdat_payload_offset, mdat_payload_size, dts_origin, sample_table);
6464 AP4_UI32 GetSequenceNumber();
6565 AP4_Result GetTrackIds(AP4_Array<AP4_UI32>& ids);
6666 AP4_Result GetTrafAtom(AP4_UI32 track_id, AP4_ContainerAtom*& traf);
67 AP4_Result CreateSampleTable(AP4_MoovAtom* moov,
68 AP4_UI32 track_id,
69 AP4_ByteStream* sample_stream,
70 AP4_Position moof_offset,
71 AP4_Position mdat_payload_offset, // hack because MS doesn't implement the spec properly
72 AP4_UI64 mdat_payload_size,
73 AP4_UI64 dts_origin,
74 AP4_FragmentSampleTable*& sample_table);
75 AP4_Result CreateSampleTable(AP4_Movie* movie,
76 AP4_UI32 track_id,
77 AP4_ByteStream* sample_stream,
78 AP4_Position moof_offset,
79 AP4_Position mdat_payload_offset, // hack because MS doesn't implement the spec properly
80 AP4_UI64 mdat_payload_size,
81 AP4_UI64 dts_origin,
82 AP4_FragmentSampleTable*& sample_table);
67 AP4_Result CreateSampleTable(AP4_MoovAtom* moov,
68 AP4_UI32 track_id,
69 AP4_ByteStream* sample_stream,
70 AP4_Position moof_offset,
71 AP4_Position mdat_payload_offset, // hack because MS doesn't implement the spec properly
72 AP4_UI64 mdat_payload_size,
73 AP4_UI64 dts_origin,
74 AP4_FragmentSampleTable*& sample_table);
75 AP4_Result CreateSampleTable(AP4_Movie* movie,
76 AP4_UI32 track_id,
77 AP4_ByteStream* sample_stream,
78 AP4_Position moof_offset,
79 AP4_Position mdat_payload_offset, // hack because MS doesn't implement the spec properly
80 AP4_UI64 mdat_payload_size,
81 AP4_UI64 dts_origin,
82 AP4_FragmentSampleTable*& sample_table);
8383
8484 private:
8585 // members
281281 bool with_pcr,
282282 AP4_ByteStream& output)
283283 {
284 // ISO/IEC 13818-1 section 2.7.5 says a DTS shall appear only if the
285 // decoding time differs from the presentation time.
286 if (with_dts && (dts == pts)) {
287 with_dts = false;
288 }
289
284290 unsigned int pes_header_size = 14+(with_dts?5:0);
285291 AP4_BitWriter pes_header(pes_header_size);
286292
287 // adjust the base timestamp so we don't start at 0
288 // dts += 10000;
289 // pts += 10000;
293 // adjust the base timestamp, offset from the PCR
294 dts += m_PcrOffset;
295 pts += m_PcrOffset;
290296
291297 pes_header.Write(0x000001, 24); // packet_start_code_prefix
292298 pes_header.Write(m_StreamId, 8); // stream_id
331337 if (payload_size > AP4_MPEG2TS_PACKET_PAYLOAD_SIZE) payload_size = AP4_MPEG2TS_PACKET_PAYLOAD_SIZE;
332338
333339 if (first_packet) {
334 WritePacketHeader(first_packet, payload_size, with_pcr, (with_dts?dts:pts)*300, output);
340 WritePacketHeader(first_packet, payload_size, with_pcr, ((with_dts?dts:pts)-m_PcrOffset)*300, output);
335341 first_packet = false;
336342 output.Write(pes_header.GetData(), pes_header_size);
337343 output.Write(data, payload_size-pes_header_size);
359365 AP4_UI16 stream_id,
360366 AP4_Mpeg2TsWriter::SampleStream*& stream,
361367 const AP4_UI08* descriptor,
362 AP4_Size descriptor_length);
368 AP4_Size descriptor_length,
369 AP4_UI64 pcr_offset);
363370 AP4_Result WriteSample(AP4_Sample& sample,
364371 AP4_DataBuffer& sample_data,
365372 AP4_SampleDescription* sample_description,
372379 AP4_UI08 stream_type,
373380 AP4_UI16 stream_id,
374381 const AP4_UI08* descriptor,
375 AP4_Size descriptor_length) :
382 AP4_Size descriptor_length,
383 AP4_UI64 pcr_offset) :
376384 AP4_Mpeg2TsWriter::SampleStream(pid,
377385 stream_type,
378386 stream_id,
379387 timescale,
380388 descriptor,
381 descriptor_length) {}
389 descriptor_length,
390 pcr_offset) {}
382391 };
383392
384393 /*----------------------------------------------------------------------
391400 AP4_UI16 stream_id,
392401 AP4_Mpeg2TsWriter::SampleStream*& stream,
393402 const AP4_UI08* descriptor,
394 AP4_Size descriptor_length)
395 {
396 stream = new AP4_Mpeg2TsAudioSampleStream(pid, timescale, stream_type, stream_id, descriptor, descriptor_length);
403 AP4_Size descriptor_length,
404 AP4_UI64 pcr_offset)
405 {
406 stream = new AP4_Mpeg2TsAudioSampleStream(pid, timescale, stream_type, stream_id, descriptor, descriptor_length, pcr_offset);
397407 return AP4_SUCCESS;
398408 }
399409
407417 bool with_pcr,
408418 AP4_ByteStream& output)
409419 {
420 if (!sample_description) {
421 return AP4_ERROR_INVALID_PARAMETERS;
422 }
423
410424 // check the sample description
411425 if (sample_description->GetFormat() == AP4_SAMPLE_FORMAT_MP4A) {
412426 AP4_MpegAudioSampleDescription* audio_desc = AP4_DYNAMIC_CAST(AP4_MpegAudioSampleDescription, sample_description);
427
413428 if (audio_desc == NULL) return AP4_ERROR_NOT_SUPPORTED;
414429 if (audio_desc->GetMpeg4AudioObjectType() != AP4_MPEG4_AUDIO_OBJECT_TYPE_AAC_LC &&
415430 audio_desc->GetMpeg4AudioObjectType() != AP4_MPEG4_AUDIO_OBJECT_TYPE_AAC_MAIN &&
418433 return AP4_ERROR_NOT_SUPPORTED;
419434 }
420435
421 unsigned int sample_rate = audio_desc->GetSampleRate();
436 unsigned int sample_rate = audio_desc->GetSampleRate();
422437 unsigned int channel_count = audio_desc->GetChannelCount();
423 const AP4_DataBuffer& dsi = audio_desc->GetDecoderInfo();
438 const AP4_DataBuffer& dsi = audio_desc->GetDecoderInfo();
424439 if (dsi.GetDataSize()) {
425440 AP4_Mp4AudioDecoderConfig dec_config;
426441 AP4_Result result = dec_config.Parse(dsi.GetData(), dsi.GetDataSize());
430445 }
431446 }
432447 unsigned int sampling_frequency_index = GetSamplingFrequencyIndex(sample_rate);
433 unsigned int channel_configuration = channel_count;
448 unsigned int channel_configuration = channel_count;
434449
435450 unsigned char* buffer = new unsigned char[7+sample_data.GetDataSize()];
436451 MakeAdtsHeader(buffer, sample_data.GetDataSize(), sampling_frequency_index, channel_configuration);
439454 WritePES(buffer, 7+sample.GetSize(), ts, false, ts, with_pcr, output);
440455 delete[] buffer;
441456 } else if (sample_description->GetFormat() == AP4_SAMPLE_FORMAT_AC_3 ||
442 sample_description->GetFormat() == AP4_SAMPLE_FORMAT_EC_3) {
457 sample_description->GetFormat() == AP4_SAMPLE_FORMAT_EC_3 ||
458 sample_description->GetFormat() == AP4_SAMPLE_FORMAT_AC_4) {
443459 AP4_UI64 ts = AP4_ConvertTime(sample.GetDts(), m_TimeScale, 90000);
444460 WritePES(sample_data.GetData(), sample_data.GetDataSize(), ts, false, ts, with_pcr, output);
445461 } else {
462478 AP4_UI16 stream_id,
463479 AP4_Mpeg2TsWriter::SampleStream*& stream,
464480 const AP4_UI08* descriptor,
465 AP4_Size descriptor_length);
481 AP4_Size descriptor_length,
482 AP4_UI64 pcr_offset = AP4_MPEG2_TS_DEFAULT_PCR_OFFSET);
466483 AP4_Result WriteSample(AP4_Sample& sample,
467484 AP4_DataBuffer& sample_data,
468485 AP4_SampleDescription* sample_description,
475492 AP4_UI08 stream_type,
476493 AP4_UI16 stream_id,
477494 const AP4_UI08* descriptor,
478 AP4_Size descriptor_size) :
495 AP4_Size descriptor_length,
496 AP4_UI64 pcr_offset) :
479497 AP4_Mpeg2TsWriter::SampleStream(pid,
480498 stream_type,
481499 stream_id,
482500 timescale,
483501 descriptor,
484 descriptor_size),
502 descriptor_length,
503 pcr_offset),
485504 m_SampleDescriptionIndex(-1),
486505 m_NaluLengthSize(0),
487506 m_SamplesWritten(0) {}
502521 AP4_UI16 stream_id,
503522 AP4_Mpeg2TsWriter::SampleStream*& stream,
504523 const AP4_UI08* descriptor,
505 AP4_Size descriptor_length)
524 AP4_Size descriptor_length,
525 AP4_UI64 pcr_offset)
506526 {
507527 // create the stream object
508 stream = new AP4_Mpeg2TsVideoSampleStream(pid, timescale, stream_type, stream_id, descriptor, descriptor_length);
528 stream = new AP4_Mpeg2TsVideoSampleStream(pid, timescale, stream_type, stream_id, descriptor, descriptor_length, pcr_offset);
509529 return AP4_SUCCESS;
510530 }
511531
519539 bool with_pcr,
520540 AP4_ByteStream& output)
521541 {
542 if (!sample_description) {
543 return AP4_ERROR_INVALID_PARAMETERS;
544 }
545
522546 if (sample_description->GetType() == AP4_SampleDescription::TYPE_AVC) {
523547 // check the sample description
524548 AP4_AvcSampleDescription* avc_desc = AP4_DYNAMIC_CAST(AP4_AvcSampleDescription, sample_description);
658682
659683 // check if we need to add a delimiter before the NALU
660684 if (nalu_count == 0 && sample_description->GetType() == AP4_SampleDescription::TYPE_AVC) {
661 if (nalu_size != 2 || (data[0] & 0x1F) != AP4_AVC_NAL_UNIT_TYPE_ACCESS_UNIT_DELIMITER) {
685 if (data_size < 1) break;
686 if (/* nalu_size != 2 || */ (data[0] & 0x1F) != AP4_AVC_NAL_UNIT_TYPE_ACCESS_UNIT_DELIMITER) {
662687 // the first NAL unit is not an Access Unit Delimiter, we need to add one
663688 unsigned char delimiter[6];
664689 delimiter[0] = 0;
855880 SampleStream*& stream,
856881 AP4_UI16 pid,
857882 const AP4_UI08* descriptor,
858 AP4_Size descriptor_length)
883 AP4_Size descriptor_length,
884 AP4_UI64 pcr_offset)
859885 {
860886 // default
861887 stream = NULL;
866892 stream_id,
867893 m_Audio,
868894 descriptor,
869 descriptor_length);
895 descriptor_length,
896 pcr_offset);
870897 if (AP4_FAILED(result)) return result;
871898 stream = m_Audio;
872899 return AP4_SUCCESS;
882909 SampleStream*& stream,
883910 AP4_UI16 pid,
884911 const AP4_UI08* descriptor,
885 AP4_Size descriptor_length)
912 AP4_Size descriptor_length,
913 AP4_UI64 pcr_offset)
886914 {
887915 // default
888916 stream = NULL;
893921 stream_id,
894922 m_Video,
895923 descriptor,
896 descriptor_length);
924 descriptor_length,
925 pcr_offset);
897926 if (AP4_FAILED(result)) return result;
898927 stream = m_Video;
899928 return AP4_SUCCESS;
5656 const AP4_UI08 AP4_MPEG2_STREAM_TYPE_AVC = 0x1B;
5757 const AP4_UI08 AP4_MPEG2_STREAM_TYPE_HEVC = 0x24;
5858 const AP4_UI08 AP4_MPEG2_STREAM_TYPE_ATSC_AC3 = 0x81;
59 const AP4_UI08 AP4_MPEG2_STREAM_TYPE_ATSC_EAC3 = 0x87;
60
61 const AP4_UI64 AP4_MPEG2_TS_DEFAULT_PCR_OFFSET = 10000;
5962
6063 /*----------------------------------------------------------------------
6164 | AP4_Mpeg2TsWriter
9093
9194 class SampleStream : public Stream {
9295 public:
93 SampleStream(AP4_UI16 pid, AP4_UI08 stream_type, AP4_UI16 stream_id, AP4_UI32 timescale, const AP4_UI08* descriptor, AP4_Size descriptor_length) :
96 SampleStream(AP4_UI16 pid,
97 AP4_UI08 stream_type,
98 AP4_UI16 stream_id,
99 AP4_UI32 timescale,
100 const AP4_UI08* descriptor,
101 AP4_Size descriptor_length,
102 AP4_UI64 pcr_offset = AP4_MPEG2_TS_DEFAULT_PCR_OFFSET) :
94103 Stream(pid),
95104 m_StreamType(stream_type),
96105 m_StreamId(stream_id),
97 m_TimeScale(timescale) {
106 m_TimeScale(timescale),
107 m_PcrOffset(pcr_offset) {
98108 if (descriptor && descriptor_length) {
99109 m_Descriptor.SetData(descriptor, descriptor_length);
100110 }
120130 AP4_ByteStream& output);
121131
122132 void SetType(AP4_UI08 type) {m_StreamType = type;}
133 void SetDescriptor(const AP4_UI08* descriptor, AP4_Size descriptor_length) {
134 if (descriptor && descriptor_length) {
135 m_Descriptor.SetData(descriptor, descriptor_length);
136 }
137 }
123138
124139 AP4_UI08 m_StreamType;
125140 AP4_UI16 m_StreamId;
126141 AP4_UI32 m_TimeScale;
127142 AP4_DataBuffer m_Descriptor;
143 AP4_UI64 m_PcrOffset;
128144 };
129145
130146 // constructor
141157 SampleStream*& stream,
142158 AP4_UI16 pid = AP4_MPEG2_TS_DEFAULT_PID_AUDIO,
143159 const AP4_UI08* descriptor = NULL,
144 AP4_Size descriptor_length = 0);
160 AP4_Size descriptor_length = 0,
161 AP4_UI64 pcr_offset = AP4_MPEG2_TS_DEFAULT_PCR_OFFSET);
145162 AP4_Result SetVideoStream(AP4_UI32 timescale,
146163 AP4_UI08 stream_type,
147164 AP4_UI16 stream_id,
148165 SampleStream*& stream,
149166 AP4_UI16 pid = AP4_MPEG2_TS_DEFAULT_PID_VIDEO,
150167 const AP4_UI08* descriptor = NULL,
151 AP4_Size descriptor_length = 0);
168 AP4_Size descriptor_length = 0,
169 AP4_UI64 pcr_offset = AP4_MPEG2_TS_DEFAULT_PCR_OFFSET);
152170
153171 private:
154172 Stream* m_PAT;
4545 {
4646 AP4_UI08 version;
4747 AP4_UI32 flags;
48 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4849 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4950 if (version > 1) return NULL;
5051 return new AP4_MvhdAtom(size, version, flags, stream);
5354 /*----------------------------------------------------------------------
5455 | AP4_MvhdAtom::AP4_MvhdAtom
5556 +---------------------------------------------------------------------*/
56 AP4_MvhdAtom::AP4_MvhdAtom(AP4_UI32 creation_time,
57 AP4_UI32 modification_time,
57 AP4_MvhdAtom::AP4_MvhdAtom(AP4_UI64 creation_time,
58 AP4_UI64 modification_time,
5859 AP4_UI32 time_scale,
5960 AP4_UI64 duration,
6061 AP4_UI32 rate,
6162 AP4_UI16 volume) :
62 AP4_Atom(AP4_ATOM_TYPE_MVHD, AP4_FULL_ATOM_HEADER_SIZE+96, 0, 0),
63 AP4_Atom(AP4_ATOM_TYPE_MVHD, AP4_FULL_ATOM_HEADER_SIZE + 96, 0, 0),
6364 m_CreationTime(creation_time),
6465 m_ModificationTime(modification_time),
6566 m_TimeScale(time_scale),
8283 AP4_SetMemory(m_Reserved2, 0, sizeof(m_Reserved2));
8384 AP4_SetMemory(m_Predefined, 0, sizeof(m_Predefined));
8485
85 if (duration > 0xFFFFFFFF) {
86 if (duration > 0xFFFFFFFFULL ||
87 creation_time > 0xFFFFFFFFULL ||
88 modification_time > 0xFFFFFFFFULL) {
8689 m_Version = 1;
8790 m_Size32 += 12;
8891 }
4646 static AP4_MvhdAtom* Create(AP4_Size size, AP4_ByteStream& stream);
4747
4848 // methods
49 AP4_MvhdAtom(AP4_UI32 creation_time,
50 AP4_UI32 modification_time,
49 AP4_MvhdAtom(AP4_UI64 creation_time,
50 AP4_UI64 modification_time,
5151 AP4_UI32 time_scale,
5252 AP4_UI64 duration,
5353 AP4_UI32 rate,
6060 AP4_UI32 GetTimeScale() { return m_TimeScale; }
6161 AP4_Result SetTimeScale(AP4_UI32 time_scale) {
6262 m_TimeScale = time_scale;
63 return AP4_SUCCESS;
64 }
65 AP4_Result SetNextTrackId(AP4_UI32 next_track_id){
66 m_NextTrackId = next_track_id;
6367 return AP4_SUCCESS;
6468 }
6569
4040 {
4141 AP4_UI08 version;
4242 AP4_UI32 flags;
43 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4344 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4445 if (version != 0) return NULL;
4546 return new AP4_NmhdAtom(size, version, flags, stream);
7070 AP4_Size payload_size) :
7171 AP4_Descriptor(tag, header_size, payload_size)
7272 {
73 AP4_Position start;
74 stream.Tell(start);
75
7673 // read descriptor fields
7774 unsigned short bits;
75 if (payload_size < 2) return;
7876 stream.ReadUI16(bits);
77 payload_size -= 2;
7978 m_ObjectDescriptorId = (bits>>6);
8079 m_UrlFlag = ((bits&(1<<5))!=0);
8180
8281 if (m_UrlFlag) {
8382 unsigned char url_length;
83 if (payload_size < 1) return;
8484 stream.ReadUI08(url_length);
85 --payload_size;
8586 char url[256];
87 if (payload_size < url_length) return;
8688 stream.Read(url, url_length);
89 payload_size -= url_length;
8790 url[url_length] = '\0';
8891 m_Url = url;
8992 }
9194 // read other descriptors
9295 AP4_Position offset;
9396 stream.Tell(offset);
94 AP4_SubStream* substream = new AP4_SubStream(stream, offset,
95 payload_size-AP4_Size(offset-start));
97 AP4_SubStream* substream = new AP4_SubStream(stream, offset, payload_size);
9698 AP4_Descriptor* descriptor = NULL;
9799 while (AP4_DescriptorFactory::CreateDescriptorFromStream(*substream,
98100 descriptor)
222224 m_VisualProfileLevelIndication(0),
223225 m_GraphicsProfileLevelIndication(0)
224226 {
225 AP4_Position start;
226 stream.Tell(start);
227
228227 // read descriptor fields
229228 unsigned short bits;
229 if (payload_size < 2) return;
230230 stream.ReadUI16(bits);
231 payload_size -= 2;
231232 m_ObjectDescriptorId = (bits>>6);
232233 m_UrlFlag = ((bits&(1<<5))!=0);
233234 m_IncludeInlineProfileLevelFlag = ((bits&(1<<4))!=0);
234
235
235236 if (m_UrlFlag) {
236237 unsigned char url_length;
238 if (payload_size < 1) return;
237239 stream.ReadUI08(url_length);
240 --payload_size;
238241 char url[256];
242 if (payload_size < url_length) return;
239243 stream.Read(url, url_length);
244 payload_size -= url_length;
240245 url[url_length] = '\0';
241246 m_Url = url;
242247 } else {
248 if (payload_size < 5) return;
243249 stream.ReadUI08(m_OdProfileLevelIndication);
244250 stream.ReadUI08(m_SceneProfileLevelIndication);
245251 stream.ReadUI08(m_AudioProfileLevelIndication);
246252 stream.ReadUI08(m_VisualProfileLevelIndication);
247 stream.ReadUI08(m_GraphicsProfileLevelIndication);
253 stream.ReadUI08(m_GraphicsProfileLevelIndication);
254 payload_size -= 5;
248255 }
249256
250257 // read other descriptors
251258 AP4_Position offset;
252259 stream.Tell(offset);
253 AP4_SubStream* substream = new AP4_SubStream(stream, offset,
254 payload_size-AP4_Size(offset-start));
260 AP4_SubStream* substream = new AP4_SubStream(stream, offset, payload_size);
255261 AP4_Descriptor* descriptor = NULL;
256262 while (AP4_DescriptorFactory::CreateDescriptorFromStream(*substream,
257263 descriptor)
4444 {
4545 AP4_UI08 version;
4646 AP4_UI32 flags;
47 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4748 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4849 if (version != 0) return NULL;
4950 return new AP4_OdafAtom(size, version, flags, stream);
4545 {
4646 AP4_UI08 version;
4747 AP4_UI32 flags;
48 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4849 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4950 if (version != 0) return NULL;
5051 return new AP4_OddaAtom(size, version, flags, stream);
4747 {
4848 AP4_UI08 version;
4949 AP4_UI32 flags;
50 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
5051 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
5152 if (version != 0) return NULL;
5253 return new AP4_OdheAtom(size, version, flags, stream, atom_factory);
5656
5757 // constructor
5858 /**
59 * @param: ohdr ohdr atom passed with transfer of ownership semantics
59 * @param ohdr ohdr atom passed with transfer of ownership semantics
6060 */
6161 AP4_OdheAtom(const char* content_type, AP4_OhdrAtom* ohdr);
6262
4646 {
4747 AP4_UI08 version;
4848 AP4_UI32 flags;
49 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4950 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
5051 if (version != 0) return NULL;
5152 return new AP4_OhdrAtom(size, version, flags, stream, atom_factory);
350350 if (odaf) {
351351 if (odaf->GetIvLength() > AP4_CIPHER_BLOCK_SIZE) return AP4_ERROR_INVALID_FORMAT;
352352 if (odaf->GetKeyIndicatorLength() != 0) return AP4_ERROR_INVALID_FORMAT;
353 } else {
354 return AP4_ERROR_INVALID_FORMAT;
353355 }
354356
355357 // check the scheme details and create the cipher
433435 | AP4_OmaDcfCtrSampleDecrypter::DecryptSampleData
434436 +---------------------------------------------------------------------*/
435437 AP4_Result
436 AP4_OmaDcfCtrSampleDecrypter::DecryptSampleData(AP4_UI32 pool_id, AP4_DataBuffer& data_in,
438 AP4_OmaDcfCtrSampleDecrypter::DecryptSampleData(AP4_UI32 poolid,
439 AP4_DataBuffer& data_in,
437440 AP4_DataBuffer& data_out,
438441 const AP4_UI08* /*iv*/)
439442 {
528531 | AP4_OmaDbcCbcSampleDecrypter::DecryptSampleData
529532 +---------------------------------------------------------------------*/
530533 AP4_Result
531 AP4_OmaDcfCbcSampleDecrypter::DecryptSampleData(AP4_UI32 pool_id, AP4_DataBuffer& data_in,
534 AP4_OmaDcfCbcSampleDecrypter::DecryptSampleData(AP4_UI32 poolid,
535 AP4_DataBuffer& data_in,
532536 AP4_DataBuffer& data_out,
533537 const AP4_UI08* /*iv*/)
534538 {
770774 +---------------------------------------------------------------------*/
771775 AP4_Result
772776 AP4_OmaDcfTrackDecrypter::Create(
773 AP4_TrakAtom* trak,
774 AP4_TrexAtom* trex,
775777 const AP4_UI08* key,
776778 AP4_Size key_size,
777779 AP4_ProtectedSampleDescription* sample_description,
798800 if (AP4_FAILED(result)) return result;
799801
800802 // instantiate the object
801 decrypter = new AP4_OmaDcfTrackDecrypter(trak, trex, cipher,
803 decrypter = new AP4_OmaDcfTrackDecrypter(cipher,
802804 sample_entry,
803805 sample_description->GetOriginalFormat());
804806 return AP4_SUCCESS;
807809 /*----------------------------------------------------------------------
808810 | AP4_OmaDcfTrackDecrypter::AP4_OmaDcfTrackDecrypter
809811 +---------------------------------------------------------------------*/
810 AP4_OmaDcfTrackDecrypter::AP4_OmaDcfTrackDecrypter(AP4_TrakAtom* trak,
811 AP4_TrexAtom* trex,
812 AP4_OmaDcfSampleDecrypter* cipher,
812 AP4_OmaDcfTrackDecrypter::AP4_OmaDcfTrackDecrypter(AP4_OmaDcfSampleDecrypter* cipher,
813813 AP4_SampleEntry* sample_entry,
814814 AP4_UI32 original_format) :
815 AP4_Processor::TrackHandler(trak, trex),
816 m_Cipher(cipher),
815 m_Cipher(cipher),
817816 m_SampleEntry(sample_entry),
818817 m_OriginalFormat(original_format)
819818 {
898897 | AP4_OmaDcfTrackEncrypter::AP4_OmaDcfTrackEncrypter
899898 +---------------------------------------------------------------------*/
900899 AP4_OmaDcfTrackEncrypter::AP4_OmaDcfTrackEncrypter(
901 AP4_OmaDcfCipherMode cipher_mode,
902 AP4_BlockCipher* block_cipher,
903 const AP4_UI08* salt,
904 AP4_SampleEntry* sample_entry,
905 AP4_UI32 format,
906 const char* content_id,
907 const char* rights_issuer_url,
908 const AP4_Byte* textual_headers,
909 AP4_Size textual_headers_size) :
910 AP4_Processor::TrackHandler(0, 0),
900 AP4_OmaDcfCipherMode cipher_mode,
901 AP4_BlockCipher* block_cipher,
902 const AP4_UI08* salt,
903 AP4_SampleEntry* sample_entry,
904 AP4_UI32 format,
905 const char* content_id,
906 const char* rights_issuer_url,
907 const AP4_Byte* textual_headers,
908 AP4_Size textual_headers_size) :
911909 m_SampleEntry(sample_entry),
912910 m_Format(format),
913911 m_ContentId(content_id),
4444 | class references
4545 +---------------------------------------------------------------------*/
4646 class AP4_OdafAtom;
47 class AP4_TrakAtom;
4847 class AP4_StreamCipher;
4948 class AP4_CbcStreamCipher;
5049 class AP4_CtrStreamCipher;
133132 ~AP4_OmaDcfCtrSampleDecrypter();
134133
135134 // methods
136 virtual AP4_Result DecryptSampleData(AP4_UI32 pool_id, AP4_DataBuffer& data_in,
135 virtual AP4_Result DecryptSampleData(AP4_UI32 poolid,
136 AP4_DataBuffer& data_in,
137137 AP4_DataBuffer& data_out,
138138 const AP4_UI08* iv = NULL);
139139 virtual AP4_Size GetDecryptedSampleSize(AP4_Sample& sample);
155155 ~AP4_OmaDcfCbcSampleDecrypter();
156156
157157 // methods
158 virtual AP4_Result DecryptSampleData(AP4_UI32 pool_id, AP4_DataBuffer& data_in,
158 virtual AP4_Result DecryptSampleData(AP4_UI32 poolid,
159 AP4_DataBuffer& data_in,
159160 AP4_DataBuffer& data_out,
160161 const AP4_UI08* iv = NULL);
161162 virtual AP4_Size GetDecryptedSampleSize(AP4_Sample& sample);
171172 class AP4_OmaDcfTrackDecrypter : public AP4_Processor::TrackHandler {
172173 public:
173174 // constructor
174 static AP4_Result Create(AP4_TrakAtom* trak,
175 AP4_TrexAtom* trex,
176 const AP4_UI08* key,
175 static AP4_Result Create(const AP4_UI08* key,
177176 AP4_Size key_size,
178177 AP4_ProtectedSampleDescription* sample_description,
179178 AP4_SampleEntry* sample_entry,
189188
190189 private:
191190 // constructor
192 AP4_OmaDcfTrackDecrypter(AP4_TrakAtom* trak,
193 AP4_TrexAtom* trex,
194 AP4_OmaDcfSampleDecrypter* cipher,
191 AP4_OmaDcfTrackDecrypter(AP4_OmaDcfSampleDecrypter* cipher,
195192 AP4_SampleEntry* sample_entry,
196193 AP4_UI32 original_format);
197194
3939 {
4040 AP4_UI08 version;
4141 AP4_UI32 flags;
42 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4243 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4344 if (version > 1) return NULL;
4445 return new AP4_PdinAtom(size, version, flags, stream);
5454 {
5555 AP4_UI08 version = 0;
5656 AP4_UI32 flags = 0;
57 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
5758 AP4_Result result = ReadFullHeader(stream, version, flags);
5859 if (AP4_FAILED(result)) return NULL;
5960 if (version != 0) return NULL;
60 return new AP4_PiffTrackEncryptionAtom(size, version, flags, stream);
61 AP4_PiffTrackEncryptionAtom* piff = new AP4_PiffTrackEncryptionAtom(size, version, flags);
62 if (piff == NULL) {
63 return NULL;
64 }
65 result = piff->Parse(stream);
66 if (AP4_FAILED(result)) {
67 delete piff;
68 return NULL;
69 }
70 return piff;
6171 }
6272
6373 /*----------------------------------------------------------------------
6575 +---------------------------------------------------------------------*/
6676 AP4_PiffTrackEncryptionAtom::AP4_PiffTrackEncryptionAtom(AP4_UI32 size,
6777 AP4_UI08 version,
68 AP4_UI32 flags,
69 AP4_ByteStream& stream) :
78 AP4_UI32 flags) :
7079 AP4_UuidAtom(size, AP4_UUID_PIFF_TRACK_ENCRYPTION_ATOM, version, flags),
71 AP4_CencTrackEncryption(stream)
80 AP4_CencTrackEncryption(version)
7281 {
7382 }
7483
7988 AP4_UI08 default_iv_size,
8089 const AP4_UI08* default_kid) :
8190 AP4_UuidAtom(AP4_FULL_UUID_ATOM_HEADER_SIZE+20, AP4_UUID_PIFF_TRACK_ENCRYPTION_ATOM, 0, 0),
82 AP4_CencTrackEncryption(default_algorithm_id,
91 AP4_CencTrackEncryption(0,
92 default_algorithm_id,
8393 default_iv_size,
8494 default_kid)
8595 {
116126 {
117127 AP4_UI08 version = 0;
118128 AP4_UI32 flags = 0;
129 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
119130 AP4_Result result = ReadFullHeader(stream, version, flags);
120131 if (AP4_FAILED(result)) return NULL;
121132 if (version != 0) return NULL;
8989
9090 private:
9191 // methods
92 AP4_PiffTrackEncryptionAtom(AP4_UI32 size,
93 AP4_UI08 version,
94 AP4_UI32 flags,
95 AP4_ByteStream& stream);
92 AP4_PiffTrackEncryptionAtom(AP4_UI32 size,
93 AP4_UI08 version,
94 AP4_UI32 flags);
9695 };
9796
9897 /*----------------------------------------------------------------------
4343 #include "Ap4TrexAtom.h"
4444 #include "Ap4TkhdAtom.h"
4545 #include "Ap4SidxAtom.h"
46 #include "Ap4MehdAtom.h"
47 #include "Ap4MdhdAtom.h"
48 #include "Ap4TrafAtom.h"
4946 #include "Ap4DataBuffer.h"
5047 #include "Ap4Debug.h"
5148
7269 };
7370
7471 struct AP4_AtomLocator {
75 AP4_AtomLocator(AP4_Atom* atom, AP4_UI64 offset) :
72 AP4_AtomLocator(AP4_Atom* atom, AP4_UI64 offset) :
7673 m_Atom(atom),
77 m_Offset(offset){}
78 AP4_Atom* m_Atom;
79 AP4_UI64 m_Offset;
74 m_Offset(offset) {}
75 AP4_Atom* m_Atom;
76 AP4_UI64 m_Offset;
8077 };
8178
8279 /*----------------------------------------------------------------------
107104 }
108105
109106 /*----------------------------------------------------------------------
110 | AP4_Processor::~AP4_Processor
111 +---------------------------------------------------------------------*/
112 AP4_Processor::~AP4_Processor() {
113 m_ExternalTrackData.DeleteReferences();
114 delete m_MoovAtom;
115 m_MoovAtom = 0;
116 }
107 | FragmentMapEntry
108 +---------------------------------------------------------------------*/
109 typedef struct {
110 AP4_UI64 before;
111 AP4_UI64 after;
112 } FragmentMapEntry;
117113
118114 /*----------------------------------------------------------------------
119115 | FindFragmentMapEntry
120116 +---------------------------------------------------------------------*/
121 AP4_UI64 AP4_Processor::FindFragmentMapEntry(AP4_UI64 fragment_offset) {
117 static const FragmentMapEntry*
118 FindFragmentMapEntry(AP4_Array<FragmentMapEntry>& fragment_map, AP4_UI64 fragment_offset) {
122119 int first = 0;
123 int last = fragment_map_.ItemCount();
120 int last = fragment_map.ItemCount();
124121 while (first < last) {
125122 int middle = (last+first)/2;
126 AP4_UI64 middle_value = fragment_map_[middle].before;
123 AP4_UI64 middle_value = fragment_map[middle].before;
127124 if (fragment_offset < middle_value) {
128125 last = middle;
129126 } else if (fragment_offset > middle_value) {
130127 first = middle+1;
131128 } else {
132 return fragment_map_[middle].after;
133 }
134 }
135
136 return fragment_offset;
129 return &fragment_map[middle];
130 }
131 }
132
133 return NULL;
137134 }
138135
139136 /*----------------------------------------------------------------------
140137 | AP4_Processor::ProcessFragments
141138 +---------------------------------------------------------------------*/
142139 AP4_Result
143 AP4_Processor::ProcessFragment( AP4_ContainerAtom* moof,
144 AP4_SidxAtom* sidx,
145 AP4_Position sidx_position,
146 AP4_ByteStream& output,
147 AP4_Array<AP4_Position>& moof_positions,
148 AP4_Array<AP4_Position>& mdat_positions)
140 AP4_Processor::ProcessFragments(AP4_MoovAtom* moov,
141 AP4_List<AP4_AtomLocator>& atoms,
142 AP4_ContainerAtom* mfra,
143 AP4_SidxAtom* sidx,
144 AP4_Position sidx_position,
145 AP4_ByteStream& input,
146 AP4_ByteStream& output)
149147 {
150 unsigned int fragment_index = 0;
151
152 //AP4_UI64 mdat_payload_offset = atom_offset+atom->GetSize()+AP4_ATOM_HEADER_SIZE;
153 AP4_Sample sample;
154 AP4_DataBuffer sample_data_in;
155 AP4_DataBuffer sample_data_out;
156 AP4_Result result = AP4_SUCCESS;
157
158 // parse the moof
159 //AP4_MovieFragment* fragment = new AP4_MovieFragment(moof);
160
161 // process all the traf atoms
162 AP4_Array<AP4_Processor::FragmentHandler*> handlers;
163 AP4_Array<AP4_FragmentSampleTable*> sample_tables;
164
165 for (; AP4_Atom* child = moof->GetChild(AP4_ATOM_TYPE_TRAF, handlers.ItemCount());) {
166 AP4_TrafAtom* traf = AP4_DYNAMIC_CAST(AP4_TrafAtom, child);
167
168 PERTRACK &track_data(m_TrackData[traf->GetInternalTrackId()]);
169 AP4_TrakAtom* trak = track_data.track_handler->GetTrakAtom();
170 AP4_TrexAtom* trex = track_data.track_handler->GetTrexAtom();
171
172 // create the handler for this traf
173 AP4_Processor::FragmentHandler* handler = CreateFragmentHandler(trak, trex, traf,
174 *(m_StreamData[track_data.streamId].stream),
175 moof_positions[track_data.streamId]);
176 if (handler) {
177 result = handler->ProcessFragment();
178 if (AP4_FAILED(result)) return result;
179 }
180 handlers.Append(handler);
181
182 // create a sample table object so we can read the sample data
183 AP4_FragmentSampleTable* sample_table = new AP4_FragmentSampleTable(
184 traf,
185 trex,
186 traf->GetInternalTrackId(),
187 m_StreamData[track_data.streamId].stream,
188 moof_positions[traf->GetInternalTrackId()],
189 mdat_positions[traf->GetInternalTrackId()],
190 0);
191 sample_tables.Append(sample_table);
192
193 // let the handler look at the samples before we process them
194 if (handler)
195 result = handler->PrepareForSamples(sample_table);
196 if (AP4_FAILED(result))
197 return result;
198 }
148 unsigned int fragment_index = 0;
149 AP4_Array<FragmentMapEntry> fragment_map;
150
151 for (AP4_List<AP4_AtomLocator>::Item* item = atoms.FirstItem();
152 item;
153 item = item->GetNext(), ++fragment_index) {
154 AP4_AtomLocator* locator = item->GetData();
155 AP4_Atom* atom = locator->m_Atom;
156 AP4_UI64 atom_offset = locator->m_Offset;
157 AP4_UI64 mdat_payload_offset = atom_offset+atom->GetSize()+AP4_ATOM_HEADER_SIZE;
158 AP4_UI64 mdat_payload_size = atom->GetSize();
159 AP4_Sample sample;
160 AP4_DataBuffer sample_data_in;
161 AP4_DataBuffer sample_data_out;
162 AP4_Result result;
163
164 // if this is not a moof atom, just write it back and continue
165 if (atom->GetType() != AP4_ATOM_TYPE_MOOF) {
166 result = atom->Write(output);
167 if (AP4_FAILED(result)) return result;
168 continue;
169 }
170
171 // parse the moof
172 AP4_ContainerAtom* moof = AP4_DYNAMIC_CAST(AP4_ContainerAtom, atom);
173 AP4_MovieFragment* fragment = new AP4_MovieFragment(moof);
174
175 // process all the traf atoms
176 AP4_Array<AP4_Processor::FragmentHandler*> handlers;
177 AP4_Array<AP4_FragmentSampleTable*> sample_tables;
178 for (;AP4_Atom* child = moof->GetChild(AP4_ATOM_TYPE_TRAF, handlers.ItemCount());) {
179 AP4_ContainerAtom* traf = AP4_DYNAMIC_CAST(AP4_ContainerAtom, child);
180 AP4_TfhdAtom* tfhd = AP4_DYNAMIC_CAST(AP4_TfhdAtom, traf->GetChild(AP4_ATOM_TYPE_TFHD));
181
182 // find the 'trak' for this track
183 AP4_TrakAtom* trak = NULL;
184 for (AP4_List<AP4_Atom>::Item* child_item = moov->GetChildren().FirstItem();
185 child_item;
186 child_item = child_item->GetNext()) {
187 AP4_Atom* child_atom = child_item->GetData();
188 if (child_atom->GetType() == AP4_ATOM_TYPE_TRAK) {
189 trak = AP4_DYNAMIC_CAST(AP4_TrakAtom, child_atom);
190 if (trak) {
191 AP4_TkhdAtom* tkhd = AP4_DYNAMIC_CAST(AP4_TkhdAtom, trak->GetChild(AP4_ATOM_TYPE_TKHD));
192 if (tkhd && tkhd->GetTrackId() == tfhd->GetTrackId()) {
193 break;
194 }
195 }
196 trak = NULL;
197 }
198 }
199
200 // find the 'trex' for this track
201 AP4_ContainerAtom* mvex = NULL;
202 AP4_TrexAtom* trex = NULL;
203 mvex = AP4_DYNAMIC_CAST(AP4_ContainerAtom, moov->GetChild(AP4_ATOM_TYPE_MVEX));
204 if (mvex) {
205 for (AP4_List<AP4_Atom>::Item* child_item = mvex->GetChildren().FirstItem();
206 child_item;
207 child_item = child_item->GetNext()) {
208 AP4_Atom* child_atom = child_item->GetData();
209 if (child_atom->GetType() == AP4_ATOM_TYPE_TREX) {
210 trex = AP4_DYNAMIC_CAST(AP4_TrexAtom, child_atom);
211 if (trex && trex->GetTrackId() == tfhd->GetTrackId()) {
212 break;
213 }
214 trex = NULL;
215 }
216 }
217 }
218
219 // create the handler for this traf
220 AP4_Processor::FragmentHandler* handler = CreateFragmentHandler(trak, trex, traf, input, atom_offset);
221 if (handler) {
222 result = handler->ProcessFragment();
223 if (AP4_FAILED(result)) return result;
224 }
225 handlers.Append(handler);
226
227 // create a sample table object so we can read the sample data
228 AP4_FragmentSampleTable* sample_table = NULL;
229 result = fragment->CreateSampleTable(moov, tfhd->GetTrackId(), &input, atom_offset, mdat_payload_offset, mdat_payload_size, 0, sample_table);
230 if (AP4_FAILED(result)) return result;
231 sample_tables.Append(sample_table);
232
233 // let the handler look at the samples before we process them
234 if (handler) result = handler->PrepareForSamples(sample_table);
235 if (AP4_FAILED(result)) return result;
236 }
199237
200 output.Buffer();
201
202 // write the moof
203 AP4_UI64 moof_out_start = 0;
204 output.Tell(moof_out_start);
205 moof->Write(output);
206
207 // remember the location of this fragment
208 FragmentMapEntry map_entry = { moof_positions[0], moof_out_start };
209 fragment_map_.Append(map_entry);
210
211 // write an mdat header
212 AP4_Position mdat_out_start;
213 AP4_UI64 mdat_size = AP4_ATOM_HEADER_SIZE;
214 output.Tell(mdat_out_start);
215 output.WriteUI32(0);
216 output.WriteUI32(AP4_ATOM_TYPE_MDAT);
217
218 // process all track runs
219 for (unsigned int i=0; i<handlers.ItemCount(); i++) {
220 AP4_Processor::FragmentHandler* handler = handlers[i];
221
222 // get the track ID
223 AP4_ContainerAtom* traf = AP4_DYNAMIC_CAST(AP4_ContainerAtom, moof->GetChild(AP4_ATOM_TYPE_TRAF, i));
224 if (traf == NULL) continue;
225 AP4_TfhdAtom* tfhd = AP4_DYNAMIC_CAST(AP4_TfhdAtom, traf->GetChild(AP4_ATOM_TYPE_TFHD));
238 // write the moof
239 AP4_UI64 moof_out_start = 0;
240 output.Tell(moof_out_start);
241 moof->Write(output);
242
243 // remember the location of this fragment
244 FragmentMapEntry map_entry = {atom_offset, moof_out_start};
245 fragment_map.Append(map_entry);
246
247 // write an mdat header
248 AP4_Position mdat_out_start;
249 AP4_UI64 mdat_size = AP4_ATOM_HEADER_SIZE;
250 output.Tell(mdat_out_start);
251 output.WriteUI32(0);
252 output.WriteUI32(AP4_ATOM_TYPE_MDAT);
253
254 // process all track runs
255 for (unsigned int i=0; i<handlers.ItemCount(); i++) {
256 AP4_Processor::FragmentHandler* handler = handlers[i];
257
258 // get the track ID
259 AP4_ContainerAtom* traf = AP4_DYNAMIC_CAST(AP4_ContainerAtom, moof->GetChild(AP4_ATOM_TYPE_TRAF, i));
260 if (traf == NULL) continue;
261 AP4_TfhdAtom* tfhd = AP4_DYNAMIC_CAST(AP4_TfhdAtom, traf->GetChild(AP4_ATOM_TYPE_TFHD));
226262
227 // compute the base data offset
228 AP4_UI64 base_data_offset;
229 if (tfhd->GetFlags() & AP4_TFHD_FLAG_BASE_DATA_OFFSET_PRESENT) {
230 base_data_offset = mdat_out_start+AP4_ATOM_HEADER_SIZE;
231 } else {
232 base_data_offset = moof_out_start;
233 }
263 // compute the base data offset
264 AP4_UI64 base_data_offset;
265 if (tfhd->GetFlags() & AP4_TFHD_FLAG_BASE_DATA_OFFSET_PRESENT) {
266 base_data_offset = mdat_out_start+AP4_ATOM_HEADER_SIZE;
267 } else {
268 base_data_offset = moof_out_start;
269 }
234270
235 // build a list of all trun atoms
236 AP4_Array<AP4_TrunAtom*> truns;
237 for (AP4_List<AP4_Atom>::Item* child_item = traf->GetChildren().FirstItem();
238 child_item;
239 child_item = child_item->GetNext()) {
240 AP4_Atom* child_atom = child_item->GetData();
241 if (child_atom->GetType() == AP4_ATOM_TYPE_TRUN) {
242 AP4_TrunAtom* trun = AP4_DYNAMIC_CAST(AP4_TrunAtom, child_atom);
243 truns.Append(trun);
244 }
245 }
246 AP4_Ordinal trun_index = 0;
247 AP4_Ordinal trun_sample_index = 0;
248 AP4_TrunAtom* trun = truns[0];
249 trun->SetDataOffset((AP4_SI32)((mdat_out_start+mdat_size)-base_data_offset));
271 // build a list of all trun atoms
272 AP4_Array<AP4_TrunAtom*> truns;
273 for (AP4_List<AP4_Atom>::Item* child_item = traf->GetChildren().FirstItem();
274 child_item;
275 child_item = child_item->GetNext()) {
276 AP4_Atom* child_atom = child_item->GetData();
277 if (child_atom->GetType() == AP4_ATOM_TYPE_TRUN) {
278 AP4_TrunAtom* trun = AP4_DYNAMIC_CAST(AP4_TrunAtom, child_atom);
279 truns.Append(trun);
280 }
281 }
282 AP4_Ordinal trun_index = 0;
283 AP4_Ordinal trun_sample_index = 0;
284 AP4_TrunAtom* trun = truns[0];
285 trun->SetDataOffset((AP4_SI32)((mdat_out_start+mdat_size)-base_data_offset));
250286
251 // write the mdat
252 for (unsigned int j=0; j<sample_tables[i]->GetSampleCount(); j++, trun_sample_index++) {
253 // advance the trun index if necessary
254 if (trun_sample_index >= trun->GetEntries().ItemCount()) {
255 trun = truns[++trun_index];
256 trun->SetDataOffset((AP4_SI32)((mdat_out_start+mdat_size)-base_data_offset));
257 trun_sample_index = 0;
258 }
287 // write the mdat
288 AP4_UI32 default_sample_size = 0;
289 for (unsigned int j=0; j<sample_tables[i]->GetSampleCount(); j++, trun_sample_index++) {
290 // advance the trun index if necessary
291 if (trun_sample_index >= trun->GetEntries().ItemCount()) {
292 trun = truns[++trun_index];
293 trun->SetDataOffset((AP4_SI32)((mdat_out_start+mdat_size)-base_data_offset));
294 trun_sample_index = 0;
295 }
259296
260 // get the next sample
261 result = sample_tables[i]->GetSample(j, sample);
262 if (AP4_FAILED(result)) return result;
263 sample.ReadData(sample_data_in);
297 // get the next sample
298 result = sample_tables[i]->GetSample(j, sample);
299 if (AP4_FAILED(result)) return result;
300 sample.ReadData(sample_data_in);
264301
265 m_TrackData[sample_tables[i]->GetInteralTrackId()].dts = sample.GetDts();
266
267 // process the sample data
302 // process the sample data
303 if (handler) {
304 result = handler->ProcessSample(sample_data_in, sample_data_out);
305 if (AP4_FAILED(result)) return result;
306
307 // write the sample data
308 result = output.Write(sample_data_out.GetData(), sample_data_out.GetDataSize());
309 if (AP4_FAILED(result)) return result;
310
311 // update the mdat size
312 mdat_size += sample_data_out.GetDataSize();
313
314 // update the trun entry
315 trun->UseEntries()[trun_sample_index].sample_size = sample_data_out.GetDataSize();
316
317 // if this entry uses the default sample size, adjust the default accordingly
318 // (NOTE: there's only one default, so this assumes, of course, that all sample
319 // sizes change the same way, if they change at all)
320 if (default_sample_size == 0 && (trun->GetFlags() & AP4_TRUN_FLAG_SAMPLE_SIZE_PRESENT) == 0) {
321 default_sample_size = sample_data_out.GetDataSize();
322 }
323 } else {
324 // write the sample data (unmodified)
325 result = output.Write(sample_data_in.GetData(), sample_data_in.GetDataSize());
326 if (AP4_FAILED(result)) return result;
327
328 // update the mdat size
329 mdat_size += sample_data_in.GetDataSize();
330 }
331 }
332
268333 if (handler) {
269 result = handler->ProcessSample(sample_data_in, sample_data_out);
270 if (AP4_FAILED(result)) return result;
271
272 // write the sample data
273 result = output.Write(sample_data_out.GetData(), sample_data_out.GetDataSize());
274 if (AP4_FAILED(result)) return result;
275
276 // update the mdat size
277 mdat_size += sample_data_out.GetDataSize();
278
279 // update the trun entry
280 trun->UseEntries()[trun_sample_index].sample_size = sample_data_out.GetDataSize();
281 } else {
282 // write the sample data (unmodified)
283 result = output.Write(sample_data_in.GetData(), sample_data_in.GetDataSize());
284 if (AP4_FAILED(result)) return result;
285
286 // update the mdat size
287 mdat_size += sample_data_in.GetDataSize();
288 }
289 }
290
291 if (handler) {
292 // update the tfhd header
293 if (tfhd->GetFlags() & AP4_TFHD_FLAG_BASE_DATA_OFFSET_PRESENT) {
294 tfhd->SetBaseDataOffset(mdat_out_start+AP4_ATOM_HEADER_SIZE);
295 }
296 if (tfhd->GetFlags() & AP4_TFHD_FLAG_DEFAULT_SAMPLE_SIZE_PRESENT) {
297 tfhd->SetDefaultSampleSize(trun->GetEntries()[0].sample_size);
298 }
334 // update the tfhd header
335 if (tfhd->GetFlags() & AP4_TFHD_FLAG_BASE_DATA_OFFSET_PRESENT) {
336 tfhd->SetBaseDataOffset(mdat_out_start+AP4_ATOM_HEADER_SIZE);
337 }
338 if (tfhd->GetFlags() & AP4_TFHD_FLAG_DEFAULT_SAMPLE_SIZE_PRESENT) {
339 if (default_sample_size) {
340 tfhd->SetDefaultSampleSize(default_sample_size);
341 }
342 }
299343
300 // give the handler a chance to update the atoms
301 handler->FinishFragment();
302 }
303 }
304
305 // update the mdat header
306 AP4_Position mdat_out_end;
307 output.Tell(mdat_out_end);
344 // give the handler a chance to update the atoms
345 handler->FinishFragment();
346 }
347 }
348
349 // update the mdat header
350 AP4_Position mdat_out_end;
351 output.Tell(mdat_out_end);
308352 #if defined(AP4_DEBUG)
309 AP4_ASSERT(mdat_out_end-mdat_out_start == mdat_size);
353 AP4_ASSERT(mdat_out_end-mdat_out_start == mdat_size);
310354 #endif
311 if (AP4_FAILED(result = output.Seek(mdat_out_start)))
312 return result;
313 output.WriteUI32((AP4_UI32)mdat_size);
314 output.Seek(mdat_out_end);
315
316 // update the moof if needed
317 if (AP4_FAILED(result = output.Seek(moof_out_start)))
318 return result;
319 moof->Write(output);
320 output.Seek(mdat_out_end);
321
322 // update the sidx if we have one
323 if (sidx && fragment_index < sidx->GetReferences().ItemCount()) {
324 if (fragment_index == 0) {
325 sidx->SetFirstOffset(moof_out_start-(sidx_position+sidx->GetSize()));
326 }
327 AP4_LargeSize fragment_size = mdat_out_end-moof_out_start;
328 AP4_SidxAtom::Reference& sidx_ref = sidx->UseReferences()[fragment_index];
329 sidx_ref.m_ReferencedSize = (AP4_UI32)fragment_size;
330 }
331
332 // cleanup
333 //delete fragment;
334
335 for (unsigned int i=0; i<handlers.ItemCount(); i++) {
336 delete handlers[i];
337 }
338 for (unsigned int i=0; i<sample_tables.ItemCount(); i++) {
339 delete sample_tables[i];
340 }
341 if (AP4_FAILED(result = output.Flush()))
342 return result;
355 output.Seek(mdat_out_start);
356 output.WriteUI32((AP4_UI32)mdat_size);
357 output.Seek(mdat_out_end);
358
359 // update the moof if needed
360 output.Seek(moof_out_start);
361 moof->Write(output);
362 output.Seek(mdat_out_end);
363
364 // update the sidx if we have one
365 if (sidx && fragment_index < sidx->GetReferences().ItemCount()) {
366 if (fragment_index == 0) {
367 sidx->SetFirstOffset(moof_out_start-(sidx_position+sidx->GetSize()));
368 }
369 AP4_LargeSize fragment_size = mdat_out_end-moof_out_start;
370 AP4_SidxAtom::Reference& sidx_ref = sidx->UseReferences()[fragment_index];
371 sidx_ref.m_ReferencedSize = (AP4_UI32)fragment_size;
372 }
373
374 // cleanup
375 delete fragment;
376
377 for (unsigned int i=0; i<handlers.ItemCount(); i++) {
378 delete handlers[i];
379 }
380 for (unsigned int i=0; i<sample_tables.ItemCount(); i++) {
381 delete sample_tables[i];
382 }
383 }
384
385 // update the mfra if we have one
386 if (mfra) {
387 for (AP4_List<AP4_Atom>::Item* mfra_item = mfra->GetChildren().FirstItem();
388 mfra_item;
389 mfra_item = mfra_item->GetNext()) {
390 if (mfra_item->GetData()->GetType() != AP4_ATOM_TYPE_TFRA) continue;
391 AP4_TfraAtom* tfra = AP4_DYNAMIC_CAST(AP4_TfraAtom, mfra_item->GetData());
392 if (tfra == NULL) continue;
393 AP4_Array<AP4_TfraAtom::Entry>& entries = tfra->GetEntries();
394 AP4_Cardinal entry_count = entries.ItemCount();
395 for (unsigned int i=0; i<entry_count; i++) {
396 const FragmentMapEntry* found = FindFragmentMapEntry(fragment_map, entries[i].m_MoofOffset);
397 if (found) {
398 entries[i].m_MoofOffset = found->after;
399 }
400 }
401 }
402 }
343403
344404 return AP4_SUCCESS;
345405 }
355415 AP4_Position /* moof_offset */)
356416 {
357417 // find the matching track handler
358 for (unsigned int i=0; i<m_TrackData.ItemCount(); i++) {
418 for (unsigned int i=0; i<m_TrackIds.ItemCount(); i++) {
359419 AP4_TfhdAtom* tfhd = AP4_DYNAMIC_CAST(AP4_TfhdAtom, traf->GetChild(AP4_ATOM_TYPE_TFHD));
360 if (tfhd && m_TrackData[i].new_id == tfhd->GetTrackId()) {
361 return new AP4_DefaultFragmentHandler(m_TrackData[i].track_handler);
420 if (tfhd && m_TrackIds[i] == tfhd->GetTrackId()) {
421 return new AP4_DefaultFragmentHandler(m_TrackHandlers[i]);
362422 }
363423 }
364424
415475 } else if (!fragments && (in_fragments || atom->GetType() == AP4_ATOM_TYPE_MOOF)) {
416476 in_fragments = true;
417477 frags.Add(new AP4_AtomLocator(atom, stream_offset));
418 break;
478 continue;
419479 }
420480 top_level.AddChild(atom);
421481 }
456516 trak_atoms = &moov->GetTrakAtoms();
457517 track_count = trak_atoms->ItemCount();
458518 cursors = new AP4_SampleCursor[track_count];
459 m_TrackData.SetItemCount(track_count);
460 m_StreamData.SetItemCount(1);
461 m_StreamData[0].stream = &input;
462
463 unsigned int index = 0;
519 m_TrackHandlers.SetItemCount(track_count);
520 m_TrackIds.SetItemCount(track_count);
521 for (AP4_Ordinal i=0; i<track_count; i++) {
522 m_TrackHandlers[i] = NULL;
523 m_TrackIds[i] = 0;
524 }
525
526 unsigned int index = 0;
464527 for (AP4_List<AP4_TrakAtom>::Item* item = trak_atoms->FirstItem(); item; item=item->GetNext()) {
465528 AP4_TrakAtom* trak = item->GetData();
466529
477540 break;
478541 }
479542 }
480 AP4_ContainerAtom *mvex = AP4_DYNAMIC_CAST(AP4_ContainerAtom, moov->GetChild(AP4_ATOM_TYPE_MVEX));
481 AP4_TrexAtom* trex = NULL;
482 if (mvex) {
483 for (AP4_List<AP4_Atom>::Item* item = mvex->GetChildren().FirstItem(); item; item = item->GetNext()) {
484 AP4_Atom* atom = item->GetData();
485 if (atom->GetType() == AP4_ATOM_TYPE_TREX) {
486 trex = AP4_DYNAMIC_CAST(AP4_TrexAtom, atom);
487 if (trex && trex->GetTrackId() == trak->GetId())
488 break;
489 trex = NULL;
490 }
491 }
492 }
493 // create the track handler
494 m_TrackData[index].track_handler = CreateTrackHandler(trak, trex);
495 m_TrackData[index].new_id = trak->GetId();
496
497 cursors[index].m_Locator.m_TrakIndex = index;
543
544 // create the track handler
545 m_TrackHandlers[index] = CreateTrackHandler(trak);
546 m_TrackIds[index] = trak->GetId();
547 cursors[index].m_Locator.m_TrakIndex = index;
498548 cursors[index].m_Locator.m_SampleTable = new AP4_AtomSampleTable(stbl, *trak_data_stream);
499549 cursors[index].m_Locator.m_SampleIndex = 0;
500550 cursors[index].m_Locator.m_ChunkIndex = 0;
514564 int cursor = -1;
515565 for (unsigned int i=0; i<track_count; i++) {
516566 if (!cursors[i].m_EndReached &&
567 cursors[i].m_Locator.m_SampleTable &&
517568 cursors[i].m_Locator.m_Sample.GetOffset() <= min_offset) {
518569 min_offset = cursors[i].m_Locator.m_Sample.GetOffset();
519570 cursor = i;
559610 locator.m_SampleTable->SetChunkOffset(locator.m_ChunkIndex, current_chunk_offset);
560611 }
561612 AP4_Size sample_size;
562 TrackHandler* handler = m_TrackData[locator.m_TrakIndex].track_handler;
613 TrackHandler* handler = m_TrackHandlers[locator.m_TrakIndex];
563614 if (handler) {
564615 sample_size = handler->GetProcessedSampleSize(locator.m_Sample);
565616 locator.m_SampleTable->SetSampleSize(locator.m_SampleIndex, sample_size);
572623
573624 // process the tracks (ex: sample descriptions processing)
574625 for (AP4_Ordinal i=0; i<track_count; i++) {
575 TrackHandler* handler = m_TrackData[i].track_handler;
576 if (handler)
577 handler->ProcessTrack();
626 TrackHandler* handler = m_TrackHandlers[i];
627 if (handler) handler->ProcessTrack();
578628 }
579629 }
580630
631681 for (unsigned int i=0; i<locators.ItemCount(); i++) {
632682 AP4_SampleLocator& locator = locators[i];
633683 locator.m_Sample.ReadData(data_in);
634 TrackHandler* handler = m_TrackData[locator.m_TrakIndex].track_handler;
684 TrackHandler* handler = m_TrackHandlers[locator.m_TrakIndex];
635685 if (handler) {
636686 result = handler->ProcessSample(data_in, data_out);
637687 if (AP4_FAILED(result)) return result;
651701 output.Tell(after);
652702 AP4_ASSERT(after-before == mdat_payload_size);
653703 #endif
654 }
655 else
656 m_StreamData[0].stream = fragments;
704 }
657705
658706 // find the position of the sidx atom
659707 AP4_Position sidx_position = 0;
660 if (sidx) {
661 for (AP4_List<AP4_Atom>::Item* item = top_level.GetChildren().FirstItem();
662 item;
663 item = item->GetNext()) {
664 AP4_Atom* atom = item->GetData();
665 if (atom->GetType() == AP4_ATOM_TYPE_SIDX) {
666 break;
667 }
668 sidx_position += atom->GetSize();
669 }
670 }
708 if (sidx) {
709 for (AP4_List<AP4_Atom>::Item* item = top_level.GetChildren().FirstItem();
710 item;
711 item = item->GetNext()) {
712 AP4_Atom* atom = item->GetData();
713 if (atom->GetType() == AP4_ATOM_TYPE_SIDX) {
714 break;
715 }
716 sidx_position += atom->GetSize();
717 }
718 }
671719
672720 // process the fragments, if any
673 AP4_Array<AP4_Position> moof_offsets, mdat_offsets;
674 moof_offsets.SetItemCount(1);
675 mdat_offsets.SetItemCount(1);
676
677 while (frags.ItemCount() > 0)
678 {
679 for (AP4_List<AP4_AtomLocator>::Item *locator(frags.FirstItem()); locator; locator = locator->GetNext())
680 {
681 AP4_ContainerAtom *moof(AP4_DYNAMIC_CAST(AP4_ContainerAtom, locator->GetData()->m_Atom));
682 moof_offsets[0] = locator->GetData()->m_Offset;
683 mdat_offsets[0] = moof_offsets[0] + moof->GetSize() + AP4_ATOM_HEADER_SIZE;
684
685 result = ProcessFragment(moof, sidx, sidx_position, output, moof_offsets, mdat_offsets);
686 if (AP4_FAILED(result))
687 return result;
688 }
689 frags.DeleteReferences();
690
691 AP4_Atom* atom = NULL;
692 input.Tell(stream_offset);
693 if (AP4_SUCCEEDED(atom_factory.CreateAtomFromStream(input, atom)))
694 {
695 if (atom->GetType() == AP4_ATOM_TYPE_MOOF)
696 frags.Add(new AP4_AtomLocator(atom, stream_offset));
697 else
698 delete atom;
699 }
700 }
701
702 // update the mfra if we have one
703 if (mfra) {
704 for (AP4_List<AP4_Atom>::Item* mfra_item = mfra->GetChildren().FirstItem(); mfra_item; mfra_item = mfra_item->GetNext())
705 {
706 if (mfra_item->GetData()->GetType() != AP4_ATOM_TYPE_TFRA)
707 continue;
708 AP4_TfraAtom* tfra = AP4_DYNAMIC_CAST(AP4_TfraAtom, mfra_item->GetData());
709 if (tfra == NULL)
710 continue;
711 AP4_Array<AP4_TfraAtom::Entry>& entries = tfra->GetEntries();
712 AP4_Cardinal entry_count = entries.ItemCount();
713 for (unsigned int i = 0; i<entry_count; i++) {
714 entries[i].m_MoofOffset = FindFragmentMapEntry(entries[i].m_MoofOffset);
715 }
716 }
717 }
718
721 result = ProcessFragments(moov, frags, mfra, sidx, sidx_position, fragments?*fragments:input, output);
722 if (AP4_FAILED(result)) return result;
723
719724 // update and re-write the sidx if we have one
720725 if (sidx && sidx_position) {
721726 AP4_Position where = 0;
734739 }
735740
736741 // cleanup
737 for (AP4_Ordinal i=0; i<track_count; i++)
742 for (AP4_Ordinal i=0; i<track_count; i++) {
738743 delete cursors[i].m_Locator.m_SampleTable;
739 m_TrackData.Clear();
744 delete m_TrackHandlers[i];
745 }
746 m_TrackHandlers.Clear();
740747 delete[] cursors;
741748 }
742749
743750 // cleanup
744751 frags.DeleteReferences();
745752 delete mfra;
753 if (fragments) {
754 // with a fragments stream, `moov` isn't inclued in `top_level`
755 // so we need to delete it here
756 delete moov;
757 }
746758
747759 return AP4_SUCCESS;
748 }
749
750 AP4_Result
751 AP4_Processor::NormalizeTRAF(AP4_ContainerAtom *atom, AP4_UI32 start, AP4_UI32 end, AP4_UI32 &index)
752 {
753 for (; AP4_Atom* child = atom->GetChild(AP4_ATOM_TYPE_TRAF, index);) {
754 AP4_TrafAtom* traf = AP4_DYNAMIC_CAST(AP4_TrafAtom, child);
755 AP4_TfhdAtom* tfhd = AP4_DYNAMIC_CAST(AP4_TfhdAtom, traf->GetChild(AP4_ATOM_TYPE_TFHD));
756 while (start < end && m_TrackData[start].original_id != tfhd->GetTrackId())
757 ;
758 tfhd->SetTrackId(m_TrackData[start].new_id);
759 traf->SetInternalTrackId(start);
760 ++index;
761 }
762 return AP4_SUCCESS;
763 }
764
765 /*----------------------------------------------------------------------
766 | AP4_Processor::MuxStream
767 +---------------------------------------------------------------------*/
768 AP4_Result
769 AP4_Processor::MuxStream(
770 AP4_Array<AP4_ByteStream *> &input,
771 AP4_ByteStream& output,
772 AP4_UI08 partitions,
773 AP4_AtomFactory& atom_factory)
774 {
775 AP4_Result result;
776 AP4_UI64 stream_offset = 0;
777
778 if (partitions & 1)
779 {
780 // read all atoms.
781 // keep all atoms except [mdat]
782 // keep a ref to [moov]
783 // put [moof] atoms in a separate list
784 AP4_AtomParent top_level;
785 AP4_Array<AP4_MoovAtom*> moov;
786 AP4_Size track_count(0);
787
788 for(AP4_Size streamid(0); streamid < input.ItemCount(); ++streamid)
789 {
790 for (AP4_Atom* atom = NULL; AP4_SUCCEEDED(atom_factory.CreateAtomFromStream(*input[streamid], atom)); input[streamid]->Tell(stream_offset))
791 {
792 if (atom->GetType() == AP4_ATOM_TYPE_MFRA) {
793 delete atom;
794 continue;
795 }
796 else if (atom->GetType() == AP4_ATOM_TYPE_SIDX) {
797 delete atom;
798 continue;
799 }
800 else if (atom->GetType() == AP4_ATOM_TYPE_SSIX) {
801 delete atom;
802 continue;
803 }
804 if (streamid == 0)
805 top_level.AddChild(atom);
806 else if (atom->GetType() != AP4_ATOM_TYPE_MOOV)
807 delete atom;
808 if (atom->GetType() == AP4_ATOM_TYPE_MOOV)
809 {
810 moov.Append(AP4_DYNAMIC_CAST(AP4_MoovAtom,atom));
811 break;
812 }
813 }
814 if (moov.ItemCount() == streamid)
815 return AP4_ERROR_INVALID_FORMAT;
816
817 while (AP4_SUCCEEDED(moov[streamid]->DeleteChild(AP4_ATOM_TYPE_PSSH, 0)));
818
819 // Remove tracks we cannot handle
820 for (AP4_List<AP4_TrakAtom>::Item *item(moov[streamid]->GetTrakAtoms().FirstItem()); item;)
821 if (!item->GetData()->FindChild("mdia/minf/stbl"))
822 moov[streamid]->GetTrakAtoms().Remove(item);
823 else
824 item = item->GetNext();
825 track_count += moov[streamid]->GetTrakAtoms().ItemCount();
826 }
827
828 // initialize the processor
829 if (AP4_FAILED(result = Initialize(top_level, *input[0])))
830 return result;
831
832 // process the tracks if we have a moov atom
833 m_TrackData.SetItemCount(track_count);
834 m_StreamData.SetItemCount(input.ItemCount());
835
836 //NormalizeTREX(mvex, 0, m_TrackCounts[0], m_TrackCounts[1]);
837 AP4_Cardinal internal_index(0);
838 AP4_ContainerAtom *mvex_base(0);
839 AP4_List<AP4_TrakAtom>::Item *item = NULL;
840
841 for (AP4_Size streamid(0); streamid < input.ItemCount(); ++streamid)
842 {
843 m_StreamData[streamid].trackStart = internal_index;
844 m_StreamData[streamid].stream = input[streamid];
845 if (streamid)
846 moov[0]->AddTrakAtoms(moov[streamid]->GetTrakAtoms(), item);
847 else
848 item = moov[streamid]->GetTrakAtoms().FirstItem();
849
850 for (; item; item = item->GetNext())
851 {
852 PERTRACK &track_data(m_TrackData[internal_index]);
853 track_data.original_id = item->GetData()->GetId();
854 item->GetData()->SetId(track_data.new_id = internal_index + 1);
855
856 if (AP4_MdhdAtom* mdhd = AP4_DYNAMIC_CAST(AP4_MdhdAtom, item->GetData()->FindChild("mdia/mdhd")))
857 track_data.timescale = mdhd->GetTimeScale();
858 else
859 track_data.timescale = 1;
860
861 AP4_ContainerAtom *mvex = AP4_DYNAMIC_CAST(AP4_ContainerAtom, moov[streamid]->GetChild(AP4_ATOM_TYPE_MVEX, 0));
862 if (!mvex)
863 return AP4_ERROR_INVALID_FORMAT;
864
865 if (!item->GetData()->GetDuration())
866 {
867 AP4_MehdAtom *mehd(AP4_DYNAMIC_CAST(AP4_MehdAtom, mvex->GetChild(AP4_ATOM_TYPE_MEHD, 0)));
868 item->GetData()->SetDuration(mehd? mehd->GetDuration():0);
869 }
870
871 AP4_TrexAtom *trex(NULL);
872 unsigned int index(0);
873 for (; !trex && (trex = AP4_DYNAMIC_CAST(AP4_TrexAtom, mvex->GetChild(AP4_ATOM_TYPE_TREX, index++)));)
874 if(trex->GetTrackId() != track_data.original_id)
875 trex = NULL;
876 if (!trex)
877 return AP4_ERROR_INVALID_FORMAT;
878
879 if (mvex_base)
880 {
881 trex = AP4_DYNAMIC_CAST(AP4_TrexAtom, trex->Clone());
882 mvex_base->AddChild(trex);
883 }
884 else
885 mvex_base = mvex;
886 trex->SetTrackId(track_data.new_id);
887
888 track_data.track_handler = CreateTrackHandler(item->GetData(), trex);
889 track_data.track_handler->ProcessTrack();
890 track_data.streamId = streamid;
891 ++m_StreamData[streamid].trackCount;
892 ++internal_index;
893 }
894 }
895 // We don't need the other moovs anymore.....
896 moov.SetItemCount(1);
897
898 AP4_MvhdAtom *mvhd(AP4_DYNAMIC_CAST(AP4_MvhdAtom, moov[0]->GetChild(AP4_ATOM_TYPE_MVHD, 0)));
899 if (!mvhd->GetDuration())
900 {
901 AP4_MehdAtom *mehd(AP4_DYNAMIC_CAST(AP4_MehdAtom, mvex_base->GetChild(AP4_ATOM_TYPE_MEHD, 0)));
902 mvhd->SetDuration(mehd ? mehd->GetDuration() : 0);
903 }
904
905 // finalize the processor
906 Finalize(top_level);
907
908 // calculate the size of all atoms combined
909 AP4_UI64 atoms_size = 0;
910 top_level.GetChildren().Apply(AP4_AtomSizeAdder(atoms_size));
911
912 // write all atoms
913 top_level.GetChildren().Apply(AP4_AtomListWriter(output));
914 m_MoovAtom = moov[0];
915 m_MoovAtom->Detach();
916 }
917
918 if (partitions & 2)
919 {
920 // process the fragments, if any
921 result = AP4_SUCCESS;
922 AP4_Array<AP4_UI64> moof_positions, mdat_positions;
923 moof_positions.SetItemCount(input.ItemCount());
924 mdat_positions.SetItemCount(input.ItemCount());
925
926 for (;;)
927 {
928 AP4_ContainerAtom *moof = NULL;
929 AP4_UI32 track_index(0);
930
931 #if 0
932 for (AP4_Cardinal streamid(0); streamid < input.ItemCount(); ++streamid)
933 {
934 AP4_Atom* atom = NULL;
935 if (AP4_SUCCEEDED(input[streamid]->Tell(stream_offset)) && AP4_SUCCEEDED(atom_factory.CreateAtomFromStream(*input[streamid], atom)))
936 {
937 if (atom->GetType() != AP4_ATOM_TYPE_MOOF)
938 return AP4_ERROR_INVALID_FORMAT;
939
940 moof_positions[streamid] = stream_offset;
941 mdat_positions[streamid] = stream_offset + atom->GetSize() + +AP4_ATOM_HEADER_SIZE;
942
943 if (moof)
944 {
945 int index(0);
946 for (; AP4_Atom* child = AP4_DYNAMIC_CAST(AP4_ContainerAtom, atom)->GetChild(AP4_ATOM_TYPE_TRAF, index++);)
947 moof->AddChild(child->Clone());
948 delete atom;
949 }
950 else
951 moof = AP4_DYNAMIC_CAST(AP4_ContainerAtom, atom);
952 NormalizeTRAF(AP4_DYNAMIC_CAST(AP4_ContainerAtom, moof), m_StreamData[streamid].trackStart,
953 m_StreamData[streamid].trackStart + m_StreamData[streamid].trackCount, track_index);
954 }
955 else
956 delete atom;
957 }
958 #else
959 double mindts(9999999999.0);
960 AP4_Cardinal nextStream(~0);
961 for (AP4_Cardinal track(0); track < m_TrackData.ItemCount(); ++track)
962 if ((double)m_TrackData[track].dts / m_TrackData[track].timescale < mindts)
963 {
964 mindts = (double)m_TrackData[track].dts / m_TrackData[track].timescale;
965 nextStream = m_TrackData[track].streamId;
966 }
967
968 AP4_Atom* atom = NULL;
969 if (AP4_SUCCEEDED(result = input[nextStream]->Tell(stream_offset)) && AP4_SUCCEEDED(result = atom_factory.CreateAtomFromStream(*input[nextStream], atom)))
970 {
971 if (atom->GetType() != AP4_ATOM_TYPE_MOOF)
972 return AP4_ERROR_INVALID_FORMAT;
973 } else if (atom)
974 return result;
975
976 moof_positions[nextStream] = stream_offset;
977 mdat_positions[nextStream] = stream_offset + atom->GetSize() + +AP4_ATOM_HEADER_SIZE;
978
979 moof = AP4_DYNAMIC_CAST(AP4_ContainerAtom, atom);
980 NormalizeTRAF(AP4_DYNAMIC_CAST(AP4_ContainerAtom, moof), m_StreamData[nextStream].trackStart,
981 m_StreamData[nextStream].trackStart + m_StreamData[nextStream].trackCount, track_index);
982 #endif
983 if (!moof)
984 break;
985
986 if (AP4_FAILED(result = ProcessFragment(moof, NULL, 0, output, moof_positions, mdat_positions)))
987 return result;
988
989 delete moof;
990 moof = NULL;
991 }
992
993 // cleanup
994 m_TrackData.Clear();
995 m_StreamData.Clear();
996 }
997
998 return AP4_SUCCESS;
999 }
1000
1001
1002 AP4_Result
1003 AP4_Processor::Mux(AP4_Array<AP4_ByteStream *> &input,
1004 AP4_ByteStream& output,
1005 AP4_UI08 partitions,
1006 ProgressListener* listener,
1007 AP4_AtomFactory& atom_factory)
1008 {
1009 return MuxStream(input, output, partitions, atom_factory);
1010760 }
1011761
1012762 /*----------------------------------------------------------------------
1043793 ProgressListener* /* listener */)
1044794 {
1045795 // default implementation: do nothing
1046 fragment_map_.Clear();
1047 m_TrackData.Clear();
1048 m_StreamData.Clear();
1049
1050 delete m_MoovAtom;
1051 m_MoovAtom = 0;
1052
1053 return AP4_SUCCESS;
796 return AP4_SUCCESS;
1054797 }
1055798
1056799 /*----------------------------------------------------------------------
4343 class AP4_ContainerAtom;
4444 class AP4_ByteStream;
4545 class AP4_DataBuffer;
46 class AP4_MoovAtom;
4746 class AP4_TrakAtom;
4847 class AP4_TrexAtom;
4948 class AP4_SidxAtom;
5049 class AP4_FragmentSampleTable;
51 struct FragmentMapEntry;
5250 struct AP4_AtomLocator;
5351
5452 /*----------------------------------------------------------------------
5654 +---------------------------------------------------------------------*/
5755 class AP4_Processor {
5856 public:
59 AP4_Processor() :m_MoovAtom(0){};
6057 /**
6158 * Abstract class that defines the interface implemented by progress
6259 * listeners. A progress listener is called during the AP4_Processor::Process()
8986 public:
9087 AP4_IMPLEMENT_DYNAMIC_CAST(TrackHandler)
9188
92 TrackHandler(AP4_TrakAtom* trak, AP4_TrexAtom* trex) : m_trak_atom(trak), m_trex_atom(trex){};
93
9489 /**
9590 * Default destructor.
9691 */
9792 virtual ~TrackHandler() {}
9893
99 /**
100 * return the trak atom assigned with this class.
101 */
102 AP4_TrakAtom *GetTrakAtom() const { return m_trak_atom; };
103
104 /**
105 * return the trex atom assigned with this class.
106 */
107 AP4_TrexAtom *GetTrexAtom() const { return m_trex_atom; };
108
109 /**
94 /**
11095 * A track handler may override this method if it needs to modify
11196 * the track atoms before processing the track samples.
11297 */
127112 */
128113 virtual AP4_Result ProcessSample(AP4_DataBuffer& data_in,
129114 AP4_DataBuffer& data_out) = 0;
130 private:
131 AP4_TrakAtom* m_trak_atom;
132 AP4_TrexAtom* m_trex_atom;
133 };
115 };
134116
135117 /**
136118 * Abstract class that defines the interface implemented by concrete
178160 /**
179161 * Default destructor
180162 */
181 virtual ~AP4_Processor();
182
183 AP4_Result Mux(AP4_Array<AP4_ByteStream *> &input,
184 AP4_ByteStream& output,
185 AP4_UI08 partitions,
186 ProgressListener* listener = NULL,
187 AP4_AtomFactory& atom_factory =
188 AP4_DefaultAtomFactory::Instance);
163 virtual ~AP4_Processor() { m_ExternalTrackData.DeleteReferences(); }
189164
190165 /**
191166 * Process the input stream into an output stream.
200175 AP4_ByteStream& output,
201176 ProgressListener* listener = NULL,
202177 AP4_AtomFactory& atom_factory =
203 AP4_DefaultAtomFactory::Instance);
178 AP4_DefaultAtomFactory::Instance_);
204179
205180 /**
206181 * Process a fragment input stream into an output stream.
217192 AP4_ByteStream& init,
218193 ProgressListener* listener = NULL,
219194 AP4_AtomFactory& atom_factory =
220 AP4_DefaultAtomFactory::Instance);
195 AP4_DefaultAtomFactory::Instance_);
221196
222197 /**
223198 * This method can be overridden by concrete subclasses.
242217 /**
243218 * This method can be overridden by concrete subclasses.
244219 * It is called once for each track in the input file.
245 * @param track Pointer to the track for which a handler should be
220 * @param trak Pointer to the track for which a handler should be
246221 * created.
247222 * @return A pointer to a track handler, or NULL if no handler
248223 * needs to be created for that track.
249224 */
250 virtual TrackHandler* CreateTrackHandler(AP4_TrakAtom* /*trak*/, AP4_TrexAtom* /*trex*/) { return NULL; }
225 virtual TrackHandler* CreateTrackHandler(AP4_TrakAtom* trak) { (void)trak; return NULL; }
251226
252227 /**
253228 * This method can be overridden by concrete subclasses.
276251 AP4_ByteStream* m_MediaData;
277252 };
278253
279 AP4_Result NormalizeTRAF(AP4_ContainerAtom *atom, AP4_UI32 start, AP4_UI32 end, AP4_UI32 &index);
280
281 AP4_Result Process(AP4_ByteStream& input,
254 AP4_Result Process(AP4_ByteStream& input,
282255 AP4_ByteStream& output,
283256 AP4_ByteStream* fragments,
284257 ProgressListener* listener,
285258 AP4_AtomFactory& atom_factory);
286259
287 AP4_Result MuxStream(
288 AP4_Array<AP4_ByteStream *> &input,
289 AP4_ByteStream& output,
290 AP4_UI08 partitions,
291 AP4_AtomFactory& atom_factory);
292
293
294 AP4_Result ProcessFragment(
295 AP4_ContainerAtom* moof,
296 AP4_SidxAtom* sidx,
297 AP4_Position sidx_position,
298 AP4_ByteStream& output,
299 AP4_Array<AP4_Position> &moof_locations,
300 AP4_Array<AP4_Position> &mdat_positions);
260 AP4_Result ProcessFragments(AP4_MoovAtom* moov,
261 AP4_List<AP4_AtomLocator>& atoms,
262 AP4_ContainerAtom* mfra,
263 AP4_SidxAtom* sidx,
264 AP4_Position sidx_position,
265 AP4_ByteStream& input,
266 AP4_ByteStream& output);
267
301268
302269 AP4_List<ExternalTrackData> m_ExternalTrackData;
303 struct PERTRACK
304 {
305 PERTRACK() :new_id(0), original_id(0), track_handler(0), streamId(0), dts(0), timescale(1){};
306 ~PERTRACK() { delete track_handler; track_handler = 0; };
307
308 AP4_UI32 new_id; //new id
309 AP4_UI32 original_id;
310 TrackHandler* track_handler;
311 AP4_Cardinal streamId;
312 AP4_UI64 dts, timescale;
313
314 };
315 AP4_Array<PERTRACK> m_TrackData;
316
317 struct PERSTREAM
318 {
319 PERSTREAM() : stream(0), trackStart(0), trackCount(0){};
320 AP4_ByteStream* stream;
321 AP4_UI16 trackStart;
322 AP4_UI16 trackCount;
323 };
324 AP4_Array<PERSTREAM> m_StreamData;
325
326 AP4_MoovAtom *m_MoovAtom;
327
328 private:
329 typedef struct {
330 AP4_UI64 before;
331 AP4_UI64 after;
332 } FragmentMapEntry;
333 AP4_Array<FragmentMapEntry> fragment_map_;
334 AP4_UI64 FindFragmentMapEntry(AP4_UI64 fragment_offset);
270 AP4_Array<AP4_UI32> m_TrackIds;
271 AP4_Array<TrackHandler*> m_TrackHandlers;
335272 };
336273
337274 #endif // _AP4_PROCESSOR_H_
8181 AP4_EncaSampleEntry::ToSampleDescription()
8282 {
8383 // get the original sample format
84 AP4_FrmaAtom* frma = static_cast<AP4_FrmaAtom*>(FindChild("sinf/frma"));
84 AP4_FrmaAtom* frma = AP4_DYNAMIC_CAST(AP4_FrmaAtom, FindChild("sinf/frma"));
8585
8686 // get the schi atom
8787 AP4_ContainerAtom* schi;
88 schi = static_cast<AP4_ContainerAtom*>(FindChild("sinf/schi"));
88 schi = AP4_DYNAMIC_CAST(AP4_ContainerAtom, FindChild("sinf/schi"));
8989
9090 // get the scheme info
91 AP4_SchmAtom* schm = static_cast<AP4_SchmAtom*>(FindChild("sinf/schm"));
91 AP4_SchmAtom* schm = AP4_DYNAMIC_CAST(AP4_SchmAtom, FindChild("sinf/schm"));
9292 AP4_UI32 original_format = frma?frma->GetOriginalFormat():AP4_ATOM_TYPE_MP4A;
9393 if (schm) {
9494 // create the original sample description
180180 AP4_EncvSampleEntry::ToSampleDescription()
181181 {
182182 // get the original sample format
183 AP4_FrmaAtom* frma = static_cast<AP4_FrmaAtom*>(FindChild("sinf/frma"));
183 AP4_FrmaAtom* frma = AP4_DYNAMIC_CAST(AP4_FrmaAtom, FindChild("sinf/frma"));
184184
185185 // get the schi atom
186186 AP4_ContainerAtom* schi;
187 schi = static_cast<AP4_ContainerAtom*>(FindChild("sinf/schi"));
187 schi = AP4_DYNAMIC_CAST(AP4_ContainerAtom, FindChild("sinf/schi"));
188188
189189 // get the scheme info
190 AP4_SchmAtom* schm = static_cast<AP4_SchmAtom*>(FindChild("sinf/schm"));
190 AP4_SchmAtom* schm = AP4_DYNAMIC_CAST(AP4_SchmAtom, FindChild("sinf/schm"));
191191 AP4_UI32 original_format = frma?frma->GetOriginalFormat():AP4_ATOM_TYPE_MP4V;
192192 if (schm) {
193193 // create the sample description
231231 case AP4_SAMPLE_FORMAT_AVC2:
232232 case AP4_SAMPLE_FORMAT_AVC3:
233233 case AP4_SAMPLE_FORMAT_AVC4:
234 case AP4_SAMPLE_FORMAT_DVAV:
235 case AP4_SAMPLE_FORMAT_DVA1:
234236 return new AP4_AvcSampleDescription(
235237 format,
236238 m_Width,
238240 m_Depth,
239241 m_CompressorName.GetChars(),
240242 this);
241
243
242244 case AP4_SAMPLE_FORMAT_HVC1:
243245 case AP4_SAMPLE_FORMAT_HEV1:
244246 case AP4_SAMPLE_FORMAT_DVHE:
245247 case AP4_SAMPLE_FORMAT_DVH1:
246248 return new AP4_HevcSampleDescription(
249 format,
250 m_Width,
251 m_Height,
252 m_Depth,
253 m_CompressorName.GetChars(),
254 this);
255
256 case AP4_SAMPLE_FORMAT_AV01:
257 return new AP4_Av1SampleDescription(
247258 format,
248259 m_Width,
249260 m_Height,
801812 key,
802813 key_size,
803814 block_cipher_factory,
804 NULL,
815 NULL,
805816 decrypter);
806817 if (AP4_FAILED(result)) return NULL;
807818 return decrypter;
870881 | AP4_StandardDecryptingProcessor:CreateTrackHandler
871882 +---------------------------------------------------------------------*/
872883 AP4_Processor::TrackHandler*
873 AP4_StandardDecryptingProcessor::CreateTrackHandler(AP4_TrakAtom* trak, AP4_TrexAtom* trex)
884 AP4_StandardDecryptingProcessor::CreateTrackHandler(AP4_TrakAtom* trak)
874885 {
875886 // find the stsd atom
876887 AP4_StsdAtom* stsd = AP4_DYNAMIC_CAST(AP4_StsdAtom, trak->FindChild("mdia/minf/stbl/stsd"));
890901 const AP4_DataBuffer* key = m_KeyMap.GetKey(trak->GetId());
891902 if (key) {
892903 AP4_OmaDcfTrackDecrypter* handler = NULL;
893 AP4_Result result = AP4_OmaDcfTrackDecrypter::Create(trak,
894 trex,
895 key->GetData(),
904 AP4_Result result = AP4_OmaDcfTrackDecrypter::Create(key->GetData(),
896905 key->GetDataSize(),
897906 protected_desc,
898907 entry,
905914 const AP4_DataBuffer* key = m_KeyMap.GetKey(trak->GetId());
906915 if (key) {
907916 AP4_IsmaTrackDecrypter* handler = NULL;
908 AP4_Result result = AP4_IsmaTrackDecrypter::Create(trak,
909 trex,
910 key->GetData(),
917 AP4_Result result = AP4_IsmaTrackDecrypter::Create(key->GetData(),
911918 key->GetDataSize(),
912919 protected_desc,
913920 entry,
152152 AP4_Result GetKeyAndIvByKid(const AP4_UI08* kid, const AP4_DataBuffer*& key, const AP4_DataBuffer*& iv);
153153 const AP4_DataBuffer* GetKey(AP4_UI32 track_id) const;
154154 const AP4_DataBuffer* GetKeyByKid(const AP4_UI08* kid) const;
155 const AP4_Cardinal GetItemCount() const { return m_KeyEntries.ItemCount(); };
156 const AP4_DataBuffer* GetLastInsertedKey() const { return &m_KeyEntries.LastItem()->GetData()->m_Key;};
157
155
158156 private:
159157 // types
160158 class KeyEntry {
394392 // methods
395393 virtual AP4_Size GetDecryptedSampleSize(AP4_Sample& sample) { return sample.GetSize(); }
396394 virtual AP4_Result SetSampleIndex(AP4_Ordinal /*index*/) { return AP4_SUCCESS; }
397 virtual AP4_Result DecryptSampleData(AP4_UI32 poolid,
395 virtual AP4_Result DecryptSampleData(AP4_UI32 poolid,
398396 AP4_DataBuffer& data_in,
399397 AP4_DataBuffer& data_out,
400398 const AP4_UI08* iv = NULL) = 0;
417415 virtual AP4_Result Initialize(AP4_AtomParent& top_level,
418416 AP4_ByteStream& stream,
419417 ProgressListener* listener);
420 virtual AP4_Processor::TrackHandler* CreateTrackHandler(AP4_TrakAtom* trak, AP4_TrexAtom* trex);
418 virtual AP4_Processor::TrackHandler* CreateTrackHandler(AP4_TrakAtom* trak);
421419
422420 private:
423421 // members
5151 {
5252 AP4_UI08 version;
5353 AP4_UI32 flags;
54 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
5455 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
5556 if (version > 1) return NULL;
5657 return new AP4_PsshAtom(size, version, flags, stream);
5960 /*----------------------------------------------------------------------
6061 | AP4_PsshAtom::AP4_PsshAtom
6162 +---------------------------------------------------------------------*/
62 AP4_PsshAtom::AP4_PsshAtom(const unsigned char* system_id) :
63 AP4_Atom(AP4_ATOM_TYPE_PSSH, AP4_FULL_ATOM_HEADER_SIZE+16+4, 0, 0)
63 AP4_PsshAtom::AP4_PsshAtom(const unsigned char* system_id,
64 const AP4_UI08* kids,
65 unsigned int kid_count) :
66 AP4_Atom(AP4_ATOM_TYPE_PSSH, AP4_FULL_ATOM_HEADER_SIZE+16+4+((kids && kid_count)?4+16*kid_count:0), (kids && kid_count)?1:0, 0),
67 m_KidCount(kid_count)
6468 {
6569 AP4_CopyMemory(m_SystemId, system_id, 16);
70 if (kids && kid_count) {
71 m_Kids.SetData(kids, kid_count*16);
72 }
6673 }
6774
6875 /*----------------------------------------------------------------------
7582 AP4_Atom(AP4_ATOM_TYPE_PSSH, size, version, flags),
7683 m_KidCount(0)
7784 {
85 if (size < AP4_FULL_ATOM_HEADER_SIZE + 20) {
86 return;
87 }
7888 stream.Read(m_SystemId, 16);
7989 if (m_Version > 0) {
8090 stream.ReadUI32(m_KidCount);
81 if (m_KidCount > size) return;
91 if (m_KidCount > (size - (AP4_FULL_ATOM_HEADER_SIZE + 20))/16) {
92 m_KidCount = 0;
93 return;
94 }
8295 m_Kids.SetDataSize(m_KidCount*16);
8396 stream.Read(m_Kids.UseData(), m_KidCount*16);
8497 }
234247 if (AP4_CompareMemory(m_SystemId, AP4_MARLIN_PSSH_SYSTEM_ID, 16) == 0) {
235248 AP4_MemoryByteStream* mbs = new AP4_MemoryByteStream(m_Data);
236249 AP4_Atom* atom;
237 AP4_AtomFactory& atom_factory = AP4_DefaultAtomFactory::Instance;
250 AP4_DefaultAtomFactory atom_factory;
238251 while (atom_factory.CreateAtomFromStream(*mbs, atom) == AP4_SUCCESS) {
239252 AP4_Position position;
240253 mbs->Tell(position);
4545 static AP4_PsshAtom* Create(AP4_Size size, AP4_ByteStream& stream);
4646
4747 // methods
48 AP4_PsshAtom(const unsigned char* system_id);
48 AP4_PsshAtom(const unsigned char* system_id, const AP4_UI08* kids = NULL, unsigned int kid_count = 0);
4949 virtual AP4_Result InspectFields(AP4_AtomInspector& inspector);
5050 virtual AP4_Result WriteFields(AP4_ByteStream& stream);
5151
5454 const int AP4_ERROR_INVALID_RTP_PACKET_EXTRA_DATA = -20;
5555 const int AP4_ERROR_BUFFER_TOO_SMALL = -21;
5656 const int AP4_ERROR_NOT_ENOUGH_DATA = -22;
57 const int AP4_ERROR_NOT_ENOUGH_SPACE = -23;
58 const int AP4_ERROR_STREAM_CHANGED = -24;
5957
6058 /*----------------------------------------------------------------------
6159 | utility functions
4545 {
4646 AP4_UI08 version;
4747 AP4_UI32 flags;
48 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4849 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4950 if (version > 1) return NULL;
5051 return new AP4_SaioAtom(size, version, flags, stream);
162163 inspector.AddField("aux info type", m_AuxInfoType, AP4_AtomInspector::HINT_HEX);
163164 inspector.AddField("aux info type parameter", m_AuxInfoTypeParameter, AP4_AtomInspector::HINT_HEX);
164165 }
165 inspector.AddField("entry count", m_Entries.ItemCount());
166 inspector.AddField("entry_count", m_Entries.ItemCount());
166167
167168 if (inspector.GetVerbosity() >= 2) {
168 char header[32];
169 inspector.StartArray("entries", m_Entries.ItemCount());
169170 for (AP4_Ordinal i=0; i<m_Entries.ItemCount(); i++) {
170 AP4_FormatString(header, sizeof(header), "entry %8d", i);
171 inspector.AddField(header, m_Entries[i]);
171 inspector.AddField(NULL, m_Entries[i]);
172172 }
173 inspector.EndArray();
173174 }
174175
175176 return AP4_SUCCESS;
4545 {
4646 AP4_UI08 version;
4747 AP4_UI32 flags;
48 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4849 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4950 if (version > 0) return NULL;
5051 return new AP4_SaizAtom(size, version, flags, stream);
8384 stream.ReadUI32(m_SampleCount);
8485 remains -= 5;
8586 if (m_DefaultSampleInfoSize == 0) {
86 // means that the sample info entries have different sizes
87 // means that the sample info entries have different sizes
8788 if (m_SampleCount > remains) m_SampleCount = remains; // sanity check
8889 AP4_Cardinal sample_count = m_SampleCount;
8990 m_Entries.SetItemCount(sample_count);
147148 } else {
148149 // check the sample index
149150 if (sample >= m_SampleCount) {
151 // just return a 0 size, not an error, because of the possibility
152 // that we have a degenerate case where sample_count is 0 and
153 // the default_sample_info_size is also 0
150154 sample_info_size = 0;
151 return AP4_ERROR_OUT_OF_RANGE;
152155 } else {
153156 sample_info_size = m_Entries[sample];
154157 }
220223 inspector.AddField("sample count", m_SampleCount);
221224
222225 if (inspector.GetVerbosity() >= 2) {
223 char header[32];
226 inspector.StartArray("entries", m_Entries.ItemCount());
224227 for (AP4_Ordinal i=0; i<m_Entries.ItemCount(); i++) {
225 AP4_FormatString(header, sizeof(header), "entry %8d", i);
226 inspector.AddField(header, m_Entries[i]);
227 }
228 }
229
230 return AP4_SUCCESS;
231 }
228 inspector.AddField(NULL, m_Entries[i]);
229 }
230 inspector.EndArray();
231 }
232
233 return AP4_SUCCESS;
234 }
142142 // check the size
143143 if (m_Size < size+offset) return AP4_FAILURE;
144144
145 // check if there's enough data in the stream
146 AP4_LargeSize stream_size = 0;
147 AP4_Result result = m_DataStream->GetSize(stream_size);
148 if (AP4_SUCCEEDED(result)) {
149 if (size + offset > stream_size) {
150 return AP4_ERROR_OUT_OF_RANGE;
151 }
152 }
153
145154 // set the buffer size
146 AP4_Result result = data.SetDataSize(size);
155 result = data.SetDataSize(size);
147156 if (AP4_FAILED(result)) return result;
148157
149158 // get the data from the stream
3434 #include "Ap4SampleEntry.h"
3535 #include "Ap4AvccAtom.h"
3636 #include "Ap4HvccAtom.h"
37 #include "Ap4VpccAtom.h"
38 #include "Ap4Av1cAtom.h"
3739 #include "Ap4Utils.h"
3840 #include "Ap4Mp4AudioInfo.h"
3941
5254 AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_MpegSystemSampleDescription)
5355 AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_AvcSampleDescription)
5456 AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_HevcSampleDescription)
57 AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_Av1SampleDescription)
5558 AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_SubtitleSampleDescription)
59 AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_Ac3SampleDescription)
60 AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_Eac3SampleDescription)
61 AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_Ac4SampleDescription)
5662
5763 /*----------------------------------------------------------------------
5864 | AP4_GetFormatName
6975 case AP4_SAMPLE_FORMAT_AVC2: return "H.264";
7076 case AP4_SAMPLE_FORMAT_AVC3: return "H.264";
7177 case AP4_SAMPLE_FORMAT_AVC4: return "H.264";
78 case AP4_SAMPLE_FORMAT_DVAV: return "Dolby Vision (H.264)";
79 case AP4_SAMPLE_FORMAT_DVA1: return "Dolby Vision (H.264)";
7280 case AP4_SAMPLE_FORMAT_HEV1: return "H.265";
7381 case AP4_SAMPLE_FORMAT_HVC1: return "H.265";
82 case AP4_SAMPLE_FORMAT_DVH1: return "Dolby Vision (H.265)";
83 case AP4_SAMPLE_FORMAT_DVHE: return "Dolby Vision (H.265)";
84 case AP4_SAMPLE_FORMAT_AV01: return "AV1";
7485 case AP4_SAMPLE_FORMAT_OVC1: return "VC-1";
7586 case AP4_SAMPLE_FORMAT_OWMA: return "WMA";
7687 case AP4_SAMPLE_FORMAT_AC_3: return "Dolby Digital (AC-3)";
7788 case AP4_SAMPLE_FORMAT_EC_3: return "Dolby Digital Plus (Enhanced AC-3)";
89 case AP4_SAMPLE_FORMAT_AC_4: return "Dolby AC-4";
7890 case AP4_SAMPLE_FORMAT_DTSC: return "DTS";
7991 case AP4_SAMPLE_FORMAT_DTSH: return "DTS-HD";
8092 case AP4_SAMPLE_FORMAT_DTSL: return "DTS-HD Lossless";
100112 case AP4_SAMPLE_FORMAT_TX3G: return "Timed Text";
101113 case AP4_SAMPLE_FORMAT_VC_1: return "SMPTE VC-1";
102114 case AP4_SAMPLE_FORMAT_XML_: return "XML Metadata";
115 case AP4_SAMPLE_FORMAT_STPP: return "Timed Text";
116 case AP4_SAMPLE_FORMAT_VP8: return "VP8";
117 case AP4_SAMPLE_FORMAT_VP9: return "VP9";
118 case AP4_SAMPLE_FORMAT_VP10: return "VP10";
103119 default: return NULL;
104120 }
105121 }
188204 AP4_Result
189205 AP4_SampleDescription::GetCodecString(AP4_String& codec)
190206 {
191 codec = "";
207 char coding[5];
208 AP4_FormatFourChars(coding, m_Format);
209 codec.Assign(coding, 4);
210
192211 return AP4_SUCCESS;
193212 }
194213
197216 +---------------------------------------------------------------------*/
198217 AP4_UnknownSampleDescription::AP4_UnknownSampleDescription(AP4_Atom* atom) :
199218 AP4_SampleDescription(AP4_SampleDescription::TYPE_UNKNOWN,
200 atom->GetType(),
219 atom->GetType(),
201220 NULL),
202221 m_Atom(atom->Clone())
203222 {
220239 AP4_Atom* atom_clone = NULL;
221240 if (m_Atom) {
222241 atom_clone = m_Atom->Clone();
223 if (atom_clone == NULL) {
224 if (result) *result = AP4_FAILURE;
225 return NULL;
226 }
242 }
243 if (atom_clone == NULL) {
244 if (result) *result = AP4_FAILURE;
245 return NULL;
227246 }
228247 if (result) *result = AP4_SUCCESS;
229248 return new AP4_UnknownSampleDescription(atom_clone);
249268 AP4_GenericAudioSampleDescription::ToAtom() const
250269 {
251270 AP4_AudioSampleEntry* sample_entry = new AP4_AudioSampleEntry(m_Format,
252 m_SampleRate,
271 m_SampleRate<<16,
253272 m_SampleSize,
254273 m_ChannelCount);
255274 AP4_AtomParent& details = const_cast<AP4_AtomParent&>(m_Details);
260279 sample_entry->AddChild(child->Clone());
261280 }
262281 return sample_entry;
282 }
283
284 /*----------------------------------------------------------------------
285 | AP4_GenericVideoSampleDescription::GetCodecString
286 +---------------------------------------------------------------------*/
287 AP4_Result
288 AP4_GenericVideoSampleDescription::GetCodecString(AP4_String& codec)
289 {
290 // VPx override
291 AP4_VpccAtom* vpcc = AP4_DYNAMIC_CAST(AP4_VpccAtom, m_Details.GetChild(AP4_ATOM_TYPE_VPCC));
292 if (vpcc) {
293 return vpcc->GetCodecString(GetFormat(), codec);
294 }
295
296 return AP4_SampleDescription::GetCodecString(codec);
263297 }
264298
265299 /*----------------------------------------------------------------------
295329 AP4_UI08 level,
296330 AP4_UI08 profile_compatibility,
297331 AP4_UI08 length_size,
332 AP4_UI08 chroma_format,
333 AP4_UI08 bit_depth_luma_minus8,
334 AP4_UI08 bit_depth_chroma_minus8,
298335 const AP4_Array<AP4_DataBuffer>& sequence_parameters,
299336 const AP4_Array<AP4_DataBuffer>& picture_parameters) :
300337 AP4_SampleDescription(TYPE_AVC, format, NULL),
304341 level,
305342 profile_compatibility,
306343 length_size,
344 chroma_format,
345 bit_depth_luma_minus8,
346 bit_depth_chroma_minus8,
307347 sequence_parameters,
308348 picture_parameters);
309349 m_Details.AddChild(m_AvccAtom);
343383 AP4_VideoSampleDescription(width, height, depth, compressor_name),
344384 m_AvccAtom(NULL)
345385 {
346 AP4_AvccAtom* avcc = AP4_DYNAMIC_CAST(AP4_AvccAtom, details->GetChild(AP4_ATOM_TYPE_AVCC));
386 AP4_AvccAtom* avcc = AP4_DYNAMIC_CAST(AP4_AvccAtom, m_Details.GetChild(AP4_ATOM_TYPE_AVCC));
347387 if (avcc) {
348 m_AvccAtom = new AP4_AvccAtom(*avcc);
388 m_AvccAtom = avcc;
349389 } else {
350390 // shoud never happen
351391 m_AvccAtom = new AP4_AvccAtom();
352 }
353 m_Details.AddChild(m_AvccAtom);
392 m_Details.AddChild(m_AvccAtom);
393 }
354394 }
355395
356396 /*----------------------------------------------------------------------
358398 +---------------------------------------------------------------------*/
359399 AP4_Result
360400 AP4_AvcSampleDescription::GetCodecString(AP4_String& codec) {
401 // Dolby Vision override
402 AP4_DvccAtom* dvcc = AP4_DYNAMIC_CAST(AP4_DvccAtom, m_Details.GetChild(AP4_ATOM_TYPE_DVCC));
403 if (dvcc) {
404 return dvcc->GetCodecString(this, codec);
405 }
406
361407 char coding[5];
362408 AP4_FormatFourChars(coding, GetFormat());
363409 char workspace[64];
384430 m_Height,
385431 m_Depth,
386432 m_CompressorName.GetChars(),
387 *m_AvccAtom);
433 &m_Details);
434 }
435
436 /*----------------------------------------------------------------------
437 | AP4_AvcDoviSampleDescription::AP4_AvcDoviSampleDescription
438 +---------------------------------------------------------------------*/
439 AP4_AvcDoviSampleDescription::AP4_AvcDoviSampleDescription(AP4_UI32 format,
440 AP4_UI16 width,
441 AP4_UI16 height,
442 AP4_UI16 depth,
443 const char* compressor_name,
444 AP4_UI08 profile,
445 AP4_UI08 level,
446 AP4_UI08 profile_compatibility,
447 AP4_UI08 length_size,
448 const AP4_Array<AP4_DataBuffer>& sequence_parameters,
449 const AP4_Array<AP4_DataBuffer>& picture_parameters,
450 AP4_UI08 chroma_format,
451 AP4_UI08 bit_depth_luma_minus8,
452 AP4_UI08 bit_depth_chroma_minus8,
453 AP4_UI08 dv_version_major,
454 AP4_UI08 dv_version_minor,
455 AP4_UI08 dv_profile,
456 AP4_UI08 dv_level,
457 bool rpu_present_flag,
458 bool el_present_flag,
459 bool bl_present_flag,
460 AP4_UI08 dv_bl_signal_compatibility_id) :
461 AP4_AvcSampleDescription(format,
462 width,
463 height,
464 depth,
465 compressor_name,
466 profile,
467 level,
468 profile_compatibility,
469 length_size,
470 chroma_format,
471 bit_depth_luma_minus8,
472 bit_depth_chroma_minus8,
473 sequence_parameters,
474 picture_parameters)
475 {
476 m_DvccAtom = new AP4_DvccAtom(dv_version_major,
477 dv_version_minor,
478 dv_profile,
479 dv_level,
480 rpu_present_flag,
481 el_present_flag,
482 bl_present_flag,
483 dv_bl_signal_compatibility_id);
484 m_Details.AddChild(m_DvccAtom);
388485 }
389486
390487 /*----------------------------------------------------------------------
421518 AP4_VideoSampleDescription(width, height, depth, compressor_name),
422519 m_HvccAtom(NULL)
423520 {
424 AP4_HvccAtom* hvcc = AP4_DYNAMIC_CAST(AP4_HvccAtom, details->GetChild(AP4_ATOM_TYPE_HVCC));
521 AP4_HvccAtom* hvcc = AP4_DYNAMIC_CAST(AP4_HvccAtom, m_Details.GetChild(AP4_ATOM_TYPE_HVCC));
425522 if (hvcc) {
426 m_HvccAtom = new AP4_HvccAtom(*hvcc);
523 m_HvccAtom = hvcc;
427524 } else {
428525 // shoud never happen
429526 m_HvccAtom = new AP4_HvccAtom();
430 }
527 m_Details.AddChild(m_HvccAtom);
528 }
529 }
530
531 /*----------------------------------------------------------------------
532 | AP4_HevcSampleDescription::AP4_HevcSampleDescription
533 +---------------------------------------------------------------------*/
534 AP4_HevcSampleDescription::AP4_HevcSampleDescription(AP4_UI32 format,
535 AP4_UI16 width,
536 AP4_UI16 height,
537 AP4_UI16 depth,
538 const char* compressor_name,
539 AP4_UI08 general_profile_space,
540 AP4_UI08 general_tier_flag,
541 AP4_UI08 general_profile,
542 AP4_UI32 general_profile_compatibility_flags,
543 AP4_UI64 general_constraint_indicator_flags,
544 AP4_UI08 general_level,
545 AP4_UI32 min_spatial_segmentation,
546 AP4_UI08 parallelism_type,
547 AP4_UI08 chroma_format,
548 AP4_UI08 luma_bit_depth,
549 AP4_UI08 chroma_bit_depth,
550 AP4_UI16 average_frame_rate,
551 AP4_UI08 constant_frame_rate,
552 AP4_UI08 num_temporal_layers,
553 AP4_UI08 temporal_id_nested,
554 AP4_UI08 nalu_length_size,
555 const AP4_Array<AP4_DataBuffer>& video_parameters,
556 AP4_UI08 video_parameters_completeness,
557 const AP4_Array<AP4_DataBuffer>& sequence_parameters,
558 AP4_UI08 sequence_parameters_completeness,
559 const AP4_Array<AP4_DataBuffer>& picture_parameters,
560 AP4_UI08 picture_parameters_completeness) :
561 AP4_SampleDescription(TYPE_HEVC, format, NULL),
562 AP4_VideoSampleDescription(width, height, depth, compressor_name)
563 {
564 m_HvccAtom = new AP4_HvccAtom(general_profile_space,
565 general_tier_flag,
566 general_profile,
567 general_profile_compatibility_flags,
568 general_constraint_indicator_flags,
569 general_level,
570 min_spatial_segmentation,
571 parallelism_type,
572 chroma_format,
573 luma_bit_depth,
574 chroma_bit_depth,
575 average_frame_rate,
576 constant_frame_rate,
577 num_temporal_layers,
578 temporal_id_nested,
579 nalu_length_size,
580 video_parameters,
581 video_parameters_completeness,
582 sequence_parameters,
583 sequence_parameters_completeness,
584 picture_parameters,
585 picture_parameters_completeness);
431586 m_Details.AddChild(m_HvccAtom);
432587 }
433588
445600 bits >>= 1;
446601 count--;
447602 }
448 return reverse_bits << count;
603 return (count < 32) ? (reverse_bits << count) : 0;
449604 }
450605
451606 /*----------------------------------------------------------------------
453608 +---------------------------------------------------------------------*/
454609 AP4_Result
455610 AP4_HevcSampleDescription::GetCodecString(AP4_String& codec) {
611 // Dolby Vision override
612 AP4_DvccAtom* dvcc = AP4_DYNAMIC_CAST(AP4_DvccAtom, m_Details.GetChild(AP4_ATOM_TYPE_DVCC));
613 if (dvcc) {
614 return dvcc->GetCodecString(this, codec);
615 }
616
456617 char coding[5];
457618 AP4_FormatFourChars(coding, GetFormat());
458619 char profile_space[2] = {0,0};
490651 m_Height,
491652 m_Depth,
492653 m_CompressorName.GetChars(),
493 *m_HvccAtom);
654 &m_Details);
655 }
656
657 /*----------------------------------------------------------------------
658 | AP4_HevcDoviSampleDescription::AP4_HevcDoviSampleDescription
659 +---------------------------------------------------------------------*/
660 AP4_HevcDoviSampleDescription::AP4_HevcDoviSampleDescription(AP4_UI32 format,
661 AP4_UI16 width,
662 AP4_UI16 height,
663 AP4_UI16 depth,
664 const char* compressor_name,
665 AP4_UI08 general_profile_space,
666 AP4_UI08 general_tier_flag,
667 AP4_UI08 general_profile,
668 AP4_UI32 general_profile_compatibility_flags,
669 AP4_UI64 general_constraint_indicator_flags,
670 AP4_UI08 general_level,
671 AP4_UI32 min_spatial_segmentation,
672 AP4_UI08 parallelism_type,
673 AP4_UI08 chroma_format,
674 AP4_UI08 luma_bit_depth,
675 AP4_UI08 chroma_bit_depth,
676 AP4_UI16 average_frame_rate,
677 AP4_UI08 constant_frame_rate,
678 AP4_UI08 num_temporal_layers,
679 AP4_UI08 temporal_id_nested,
680 AP4_UI08 nalu_length_size,
681 const AP4_Array<AP4_DataBuffer>& video_parameters,
682 AP4_UI08 video_parameters_completeness,
683 const AP4_Array<AP4_DataBuffer>& sequence_parameters,
684 AP4_UI08 sequence_parameters_completeness,
685 const AP4_Array<AP4_DataBuffer>& picture_parameters,
686 AP4_UI08 picture_parameters_completeness,
687 AP4_UI08 dv_version_major,
688 AP4_UI08 dv_version_minor,
689 AP4_UI08 dv_profile,
690 AP4_UI08 dv_level,
691 bool rpu_present_flag,
692 bool el_present_flag,
693 bool bl_present_flag,
694 AP4_UI08 dv_bl_signal_compatibility_id) :
695 AP4_HevcSampleDescription(format,
696 width,
697 height,
698 depth,
699 compressor_name,
700 general_profile_space,
701 general_tier_flag,
702 general_profile,
703 general_profile_compatibility_flags,
704 general_constraint_indicator_flags,
705 general_level,
706 min_spatial_segmentation,
707 parallelism_type,
708 chroma_format,
709 luma_bit_depth,
710 chroma_bit_depth,
711 average_frame_rate,
712 constant_frame_rate,
713 num_temporal_layers,
714 temporal_id_nested,
715 nalu_length_size,
716 video_parameters,
717 video_parameters_completeness,
718 sequence_parameters,
719 sequence_parameters_completeness,
720 picture_parameters,
721 picture_parameters_completeness)
722 {
723 m_DvccAtom = new AP4_DvccAtom(dv_version_major,
724 dv_version_minor,
725 dv_profile,
726 dv_level,
727 rpu_present_flag,
728 el_present_flag,
729 bl_present_flag,
730 dv_bl_signal_compatibility_id);
731 m_Details.AddChild(m_DvccAtom);
732 }
733
734 /*----------------------------------------------------------------------
735 | AP4_Av1SampleDescription::AP4_Av1SampleDescription
736 +---------------------------------------------------------------------*/
737 AP4_Av1SampleDescription::AP4_Av1SampleDescription(AP4_UI32 format,
738 AP4_UI16 width,
739 AP4_UI16 height,
740 AP4_UI16 depth,
741 const char* compressor_name,
742 AP4_UI08 version,
743 AP4_UI08 seq_profile,
744 AP4_UI08 seq_level_idx_0,
745 AP4_UI08 seq_tier_0,
746 AP4_UI08 high_bitdepth,
747 AP4_UI08 twelve_bit,
748 AP4_UI08 monochrome,
749 AP4_UI08 chroma_subsampling_x,
750 AP4_UI08 chroma_subsampling_y,
751 AP4_UI08 chroma_sample_position,
752 AP4_UI08 initial_presentation_delay_present,
753 AP4_UI08 initial_presentation_delay_minus_one,
754 const AP4_UI08* config_obus,
755 AP4_Size config_obus_size) :
756 AP4_SampleDescription(TYPE_AV1, format, NULL),
757 AP4_VideoSampleDescription(width, height, depth, compressor_name)
758 {
759 m_Av1cAtom = new AP4_Av1cAtom(version,
760 seq_profile,
761 seq_level_idx_0,
762 seq_tier_0,
763 high_bitdepth,
764 twelve_bit,
765 monochrome,
766 chroma_subsampling_x,
767 chroma_subsampling_y,
768 chroma_sample_position,
769 initial_presentation_delay_present,
770 initial_presentation_delay_minus_one,
771 config_obus,
772 config_obus_size);
773 m_Details.AddChild(m_Av1cAtom);
774 }
775
776 /*----------------------------------------------------------------------
777 | AP4_Av1SampleDescription::AP4_Av1SampleDescription
778 +---------------------------------------------------------------------*/
779 AP4_Av1SampleDescription::AP4_Av1SampleDescription(AP4_UI32 format,
780 AP4_UI16 width,
781 AP4_UI16 height,
782 AP4_UI16 depth,
783 const char* compressor_name,
784 const AP4_Av1cAtom* av1c) :
785 AP4_SampleDescription(TYPE_AV1, format, NULL),
786 AP4_VideoSampleDescription(width, height, depth, compressor_name)
787 {
788 if (av1c) {
789 m_Av1cAtom = new AP4_Av1cAtom(*av1c);
790 } else {
791 // should never happen
792 m_Av1cAtom = new AP4_Av1cAtom();
793 }
794 m_Details.AddChild(m_Av1cAtom);
795 }
796
797 /*----------------------------------------------------------------------
798 | AP4_Av1SampleDescription::AP4_Av1SampleDescription
799 +---------------------------------------------------------------------*/
800 AP4_Av1SampleDescription::AP4_Av1SampleDescription(AP4_UI32 format,
801 AP4_UI16 width,
802 AP4_UI16 height,
803 AP4_UI16 depth,
804 const char* compressor_name,
805 AP4_AtomParent* details) :
806 AP4_SampleDescription(TYPE_AV1, format, details),
807 AP4_VideoSampleDescription(width, height, depth, compressor_name),
808 m_Av1cAtom(NULL)
809 {
810 AP4_Av1cAtom* av1c = AP4_DYNAMIC_CAST(AP4_Av1cAtom, m_Details.GetChild(AP4_ATOM_TYPE_AV1C));
811 if (av1c) {
812 m_Av1cAtom = av1c;
813 } else {
814 // shoud never happen
815 m_Av1cAtom = new AP4_Av1cAtom();
816 m_Details.AddChild(m_Av1cAtom);
817 }
818 }
819
820 /*----------------------------------------------------------------------
821 | AP4_Av1cSampleDescription::GetCodecString
822 +---------------------------------------------------------------------*/
823 AP4_Result
824 AP4_Av1SampleDescription::GetCodecString(AP4_String& codec) {
825 AP4_UI08 bit_depth = 10;
826 AP4_UI08 color_primaries = 1;
827 AP4_UI08 transfer_characteristics = 1;
828 AP4_UI08 matrix_coefficients = 1;
829 AP4_UI08 video_full_range_flag = 0;
830 char coding[5];
831 AP4_FormatFourChars(coding, GetFormat());
832 char workspace[64];
833 AP4_FormatString(workspace,
834 sizeof(workspace),
835 "%s.%d.%02d%c.%02d.%d.%d%d%d.%02d.%02d.%02d.%d",
836 coding,
837 this->GetSeqProfile(),
838 this->GetSeqLevelIdx0() >> 4,
839 this->GetSeqTier0() == 0 ? 'M' : 'H',
840 bit_depth,
841 this->GetMonochrome(),
842 this->GetChromaSubsamplingX(),
843 this->GetChromaSubsamplingY(),
844 (this->GetChromaSubsamplingX() == 1 && this->GetChromaSubsamplingY() == 1) ?
845 this->GetChromaSamplePosition() : 0,
846 color_primaries,
847 transfer_characteristics,
848 matrix_coefficients,
849 video_full_range_flag);
850 codec = workspace;
851
852 return AP4_SUCCESS;
853 }
854
855 /*----------------------------------------------------------------------
856 | AP4_Av1SampleDescription::ToAtom
857 +---------------------------------------------------------------------*/
858 AP4_Atom*
859 AP4_Av1SampleDescription::ToAtom() const
860 {
861 return new AP4_Av1SampleEntry(m_Format,
862 m_Width,
863 m_Height,
864 m_Depth,
865 m_CompressorName.GetChars(),
866 &m_Details);
494867 }
495868
496869 /*----------------------------------------------------------------------
7211094 }
7221095
7231096 /*----------------------------------------------------------------------
1097 | AP4_Ac3SampleDescription::AP4_Ac3SampleDescription
1098 +---------------------------------------------------------------------*/
1099 AP4_Ac3SampleDescription::AP4_Ac3SampleDescription(AP4_UI32 sample_rate,
1100 AP4_UI16 sample_size,
1101 AP4_UI16 channel_count,
1102 const AP4_Dac3Atom* dac3):
1103 AP4_SampleDescription(TYPE_AC3, AP4_SAMPLE_FORMAT_AC_3, NULL),
1104 AP4_AudioSampleDescription(sample_rate, sample_size, channel_count)
1105 {
1106 if (dac3) {
1107 m_Dac3Atom = new AP4_Dac3Atom(*dac3);
1108 } else {
1109 // TODO: add default construtor, m_Dac3Atom = new AP4_Dac3Atom() / should never happen
1110 m_Dac3Atom = NULL;
1111 }
1112 m_Details.AddChild(m_Dac3Atom);
1113 }
1114
1115 /*----------------------------------------------------------------------
1116 | AP4_Ac3SampleDescription::AP4_Ac3SampleDescription
1117 +---------------------------------------------------------------------*/
1118 AP4_Ac3SampleDescription::AP4_Ac3SampleDescription(AP4_UI32 sample_rate,
1119 AP4_UI16 sample_size,
1120 AP4_UI16 channel_count,
1121 AP4_AtomParent* details) :
1122 AP4_SampleDescription(TYPE_AC3, AP4_SAMPLE_FORMAT_AC_3, details),
1123 AP4_AudioSampleDescription(sample_rate, sample_size, channel_count),
1124 m_Dac3Atom(NULL)
1125 {
1126 AP4_Dac3Atom* ac3 = AP4_DYNAMIC_CAST(AP4_Dac3Atom, m_Details.GetChild(AP4_SAMPLE_FORMAT_AC_3));
1127 if (ac3) {
1128 m_Dac3Atom = ac3;
1129 } else {
1130 // TODO: add default construtor, m_Dac3Atom = new AP4_Dac3Atom() / should never happen
1131 m_Dac3Atom = NULL;
1132 m_Details.AddChild(m_Dac3Atom);
1133 }
1134 }
1135
1136 /*----------------------------------------------------------------------
1137 | AP4_Ac3SampleDescription::AP4_Ac3SampleDescription
1138 +---------------------------------------------------------------------*/
1139
1140 AP4_Ac3SampleDescription::AP4_Ac3SampleDescription(AP4_UI32 sample_rate,
1141 AP4_UI16 sample_size,
1142 AP4_UI16 channel_count,
1143 AP4_UI32 size,
1144 const AP4_Dac3Atom::StreamInfo* ac3_stream_info):
1145 AP4_SampleDescription(TYPE_AC3, AP4_SAMPLE_FORMAT_AC_3, NULL),
1146 AP4_AudioSampleDescription(sample_rate, sample_size, channel_count)
1147 {
1148 m_Dac3Atom = new AP4_Dac3Atom(ac3_stream_info);
1149 m_Details.AddChild(m_Dac3Atom);
1150 }
1151
1152 /*----------------------------------------------------------------------
1153 | AP4_Ac3SampleDescription::ToAtom
1154 +---------------------------------------------------------------------*/
1155
1156 AP4_Atom*
1157 AP4_Ac3SampleDescription::ToAtom() const
1158 {
1159 return new AP4_Ac3SampleEntry(m_Format,
1160 m_SampleRate<<16,
1161 m_SampleSize,
1162 m_ChannelCount,
1163 &m_Details);
1164 }
1165
1166 /*----------------------------------------------------------------------
1167 | AP4_Eac3SampleDescription::AP4_Eac3SampleDescription
1168 +---------------------------------------------------------------------*/
1169 AP4_Eac3SampleDescription::AP4_Eac3SampleDescription():
1170 AP4_SampleDescription(TYPE_EAC3, AP4_SAMPLE_FORMAT_EC_3, NULL),
1171 AP4_AudioSampleDescription(48000, 16, 2)
1172 {
1173 m_Details.AddChild(new AP4_Dec3Atom());
1174 }
1175
1176 /*----------------------------------------------------------------------
1177 | AP4_Eac3SampleDescription::AP4_Eac3SampleDescription
1178 +---------------------------------------------------------------------*/
1179 AP4_Eac3SampleDescription::AP4_Eac3SampleDescription(AP4_UI32 sample_rate,
1180 AP4_UI16 sample_size,
1181 AP4_UI16 channel_count,
1182 const AP4_Dec3Atom* dec3):
1183 AP4_SampleDescription(TYPE_EAC3, AP4_SAMPLE_FORMAT_EC_3, NULL),
1184 AP4_AudioSampleDescription(sample_rate, sample_size, channel_count)
1185 {
1186 if (dec3) {
1187 m_Dec3Atom = new AP4_Dec3Atom(*dec3);
1188 } else {
1189 // shoud never happen
1190 m_Dec3Atom = new AP4_Dec3Atom();
1191 }
1192 m_Details.AddChild(m_Dec3Atom);
1193 }
1194
1195 /*----------------------------------------------------------------------
1196 | AP4_Eac3SampleDescription::AP4_Eac3SampleDescription
1197 +---------------------------------------------------------------------*/
1198 AP4_Eac3SampleDescription::AP4_Eac3SampleDescription(AP4_UI32 sample_rate,
1199 AP4_UI16 sample_size,
1200 AP4_UI16 channel_count,
1201 AP4_AtomParent* details) :
1202 AP4_SampleDescription(TYPE_EAC3, AP4_SAMPLE_FORMAT_EC_3, details),
1203 AP4_AudioSampleDescription(sample_rate, sample_size, channel_count),
1204 m_Dec3Atom(NULL)
1205 {
1206 AP4_Dec3Atom* eac3 = AP4_DYNAMIC_CAST(AP4_Dec3Atom, m_Details.GetChild(AP4_SAMPLE_FORMAT_EC_3));
1207 if (eac3) {
1208 m_Dec3Atom = eac3;
1209 } else {
1210 // shoud never happen
1211 m_Dec3Atom = new AP4_Dec3Atom();
1212 m_Details.AddChild(m_Dec3Atom);
1213 }
1214 }
1215
1216 /*----------------------------------------------------------------------
1217 | AP4_Eac3SampleDescription::AP4_Eac3SampleDescription
1218 +---------------------------------------------------------------------*/
1219
1220 AP4_Eac3SampleDescription::AP4_Eac3SampleDescription(AP4_UI32 sample_rate,
1221 AP4_UI16 sample_size,
1222 AP4_UI16 channel_count,
1223 AP4_UI32 size,
1224 const AP4_Dec3Atom::SubStream* subStream,
1225 const AP4_UI32 complexity_index_type_a):
1226 AP4_SampleDescription(TYPE_EAC3, AP4_SAMPLE_FORMAT_EC_3, NULL),
1227 AP4_AudioSampleDescription(sample_rate, sample_size, channel_count)
1228 {
1229 m_Dec3Atom = new AP4_Dec3Atom(size, subStream, complexity_index_type_a);
1230 m_Details.AddChild(m_Dec3Atom);
1231 }
1232
1233 /*----------------------------------------------------------------------
1234 | AP4_Eac3SampleDescription::ToAtom
1235 +---------------------------------------------------------------------*/
1236
1237 AP4_Atom*
1238 AP4_Eac3SampleDescription::ToAtom() const
1239 {
1240 return new AP4_Eac3SampleEntry(m_Format,
1241 m_SampleRate<<16,
1242 m_SampleSize,
1243 m_ChannelCount,
1244 &m_Details);
1245 }
1246
1247 /*----------------------------------------------------------------------
1248 | AP4_Ac4SampleDescription::AP4_Ac4SampleDescription
1249 +---------------------------------------------------------------------*/
1250 AP4_Ac4SampleDescription::AP4_Ac4SampleDescription(AP4_UI32 sample_rate,
1251 AP4_UI16 sample_size,
1252 AP4_UI16 channel_count,
1253 const AP4_Dac4Atom* dac4):
1254 AP4_SampleDescription(TYPE_AC4, AP4_SAMPLE_FORMAT_AC_4, NULL),
1255 AP4_AudioSampleDescription(sample_rate, sample_size, channel_count)
1256 {
1257 if (dac4) {
1258 m_Dac4Atom = dac4->CloneConst();
1259 ;
1260 } else {
1261 // TODO: add default construtor, m_Dac4Atom = new AP4_Dac4Atom() / should never happen
1262 m_Dac4Atom = NULL;
1263 }
1264 m_Details.AddChild(m_Dac4Atom);
1265 }
1266
1267 /*----------------------------------------------------------------------
1268 | AP4_Ac4SampleDescription::AP4_Ac4SampleDescription
1269 +---------------------------------------------------------------------*/
1270 AP4_Ac4SampleDescription::AP4_Ac4SampleDescription(AP4_UI32 sample_rate,
1271 AP4_UI16 sample_size,
1272 AP4_UI16 channel_count,
1273 AP4_AtomParent* details) :
1274 AP4_SampleDescription(TYPE_AC4, AP4_SAMPLE_FORMAT_AC_4, details),
1275 AP4_AudioSampleDescription(sample_rate, sample_size, channel_count),
1276 m_Dac4Atom(NULL)
1277 {
1278 AP4_Dac4Atom* ac4 = AP4_DYNAMIC_CAST(AP4_Dac4Atom, m_Details.GetChild(AP4_ATOM_TYPE_AC_4));
1279 if (ac4) {
1280 m_Dac4Atom = ac4;
1281 } else {
1282 // TODO: add default construtor, m_Dac4Atom = new AP4_Dac4Atom() / should never happen
1283 m_Dac4Atom = NULL;
1284 m_Details.AddChild(m_Dac4Atom);
1285 }
1286 }
1287
1288 /*----------------------------------------------------------------------
1289 | AP4_Ac4SampleDescription::AP4_Ac4SampleDescription
1290 +---------------------------------------------------------------------*/
1291 AP4_Ac4SampleDescription::AP4_Ac4SampleDescription(AP4_UI32 sample_rate,
1292 AP4_UI16 sample_size,
1293 AP4_UI16 channel_count,
1294 AP4_UI32 size,
1295 const AP4_Dac4Atom::Ac4Dsi* ac4Dsi):
1296 AP4_SampleDescription(TYPE_AC4, AP4_SAMPLE_FORMAT_AC_4, NULL),
1297 AP4_AudioSampleDescription(sample_rate, sample_size, channel_count)
1298 {
1299 m_Dac4Atom = new AP4_Dac4Atom(size, ac4Dsi);
1300 m_Details.AddChild(m_Dac4Atom);
1301 }
1302
1303 /*----------------------------------------------------------------------
1304 | AP4_Ac4SampleDescription::ToAtom
1305 +---------------------------------------------------------------------*/
1306
1307 AP4_Atom*
1308 AP4_Ac4SampleDescription::ToAtom() const
1309 {
1310 return new AP4_Ac4SampleEntry(m_Format,
1311 m_SampleRate<<16,
1312 m_SampleSize,
1313 m_ChannelCount,
1314 &m_Details);
1315 }
1316
1317 /*----------------------------------------------------------------------
7241318 | AP4_MpegVideoSampleDescription::AP4_MpegVideoSampleDescription
7251319 +---------------------------------------------------------------------*/
7261320 AP4_MpegVideoSampleDescription::AP4_MpegVideoSampleDescription(
7811375 switch (type) {
7821376 case AP4_STREAM_TYPE_FORBIDDEN: return "INVALID";
7831377 case AP4_STREAM_TYPE_OD: return "Object Descriptor";
784 case AP4_STREAM_TYPE_CR: return "CR";
1378 case AP4_STREAM_TYPE_CR: return "CR";
7851379 case AP4_STREAM_TYPE_BIFS: return "BIFS";
7861380 case AP4_STREAM_TYPE_VISUAL: return "Visual";
7871381 case AP4_STREAM_TYPE_AUDIO: return "Audio";
8311425 case AP4_OTI_DTS_HIRES_AUDIO: return "DTS High Resolution Audio";
8321426 case AP4_OTI_DTS_MASTER_AUDIO: return "DTS Master Audio";
8331427 case AP4_OTI_DTS_EXPRESS_AUDIO: return "DTS Express/LBR Audio";
1428 case AP4_OTI_OPUS_AUDIO: return "Opus Audio";
1429 case AP4_OTI_VP9_VIDEO: return "VP9 Video";
1430 case AP4_OTI_VORBIS_AUDIO: return "Vorbis Audio";
8341431 case AP4_OTI_13K_VOICE: return "13K Voice";
8351432 default: return "UNKNOWN";
8361433 }
8801477 case AP4_MPEG4_AUDIO_OBJECT_TYPE_ER_AAC_ELD: return "Error Resilient AAC ELD";
8811478 case AP4_MPEG4_AUDIO_OBJECT_TYPE_SMR_SIMPLE: return "SMR Simple";
8821479 case AP4_MPEG4_AUDIO_OBJECT_TYPE_SMR_MAIN: return "SMR Main";
1480 case AP4_MPEG4_AUDIO_OBJECT_TYPE_USAC: return "USAC";
1481 case AP4_MPEG4_AUDIO_OBJECT_TYPE_SAOC: return "SAOC";
8831482 default: return "UNKNOWN";
8841483 }
8851484 }
3838 #include "Ap4Array.h"
3939 #include "Ap4AvccAtom.h"
4040 #include "Ap4HvccAtom.h"
41 #include "Ap4Av1cAtom.h"
4142 #include "Ap4DynamicCast.h"
43 #include "Ap4Dac4Atom.h"
44 #include "Ap4Dec3Atom.h"
45 #include "Ap4Dac3Atom.h"
46 #include "Ap4DvccAtom.h"
4247
4348 /*----------------------------------------------------------------------
4449 | class references
5661 const AP4_UI32 AP4_SAMPLE_FORMAT_AVC2 = AP4_ATOM_TYPE('a','v','c','2');
5762 const AP4_UI32 AP4_SAMPLE_FORMAT_AVC3 = AP4_ATOM_TYPE('a','v','c','3');
5863 const AP4_UI32 AP4_SAMPLE_FORMAT_AVC4 = AP4_ATOM_TYPE('a','v','c','4');
64 const AP4_UI32 AP4_SAMPLE_FORMAT_DVAV = AP4_ATOM_TYPE('d','v','a','v');
65 const AP4_UI32 AP4_SAMPLE_FORMAT_DVA1 = AP4_ATOM_TYPE('d','v','a','1');
5966 const AP4_UI32 AP4_SAMPLE_FORMAT_HVC1 = AP4_ATOM_TYPE('h','v','c','1');
6067 const AP4_UI32 AP4_SAMPLE_FORMAT_HEV1 = AP4_ATOM_TYPE('h','e','v','1');
6168 const AP4_UI32 AP4_SAMPLE_FORMAT_DVHE = AP4_ATOM_TYPE('d','v','h','e');
6269 const AP4_UI32 AP4_SAMPLE_FORMAT_DVH1 = AP4_ATOM_TYPE('d','v','h','1');
70 const AP4_UI32 AP4_SAMPLE_FORMAT_AV01 = AP4_ATOM_TYPE('a','v','0','1');
6371 const AP4_UI32 AP4_SAMPLE_FORMAT_ALAC = AP4_ATOM_TYPE('a','l','a','c');
6472 const AP4_UI32 AP4_SAMPLE_FORMAT_OWMA = AP4_ATOM_TYPE('o','w','m','a');
6573 const AP4_UI32 AP4_SAMPLE_FORMAT_OVC1 = AP4_ATOM_TYPE('o','v','c','1');
6775 const AP4_UI32 AP4_SAMPLE_FORMAT_DRAC = AP4_ATOM_TYPE('d','r','a','c');
6876 const AP4_UI32 AP4_SAMPLE_FORMAT_DRA1 = AP4_ATOM_TYPE('d','r','a','1');
6977 const AP4_UI32 AP4_SAMPLE_FORMAT_AC_3 = AP4_ATOM_TYPE('a','c','-','3');
78 const AP4_UI32 AP4_SAMPLE_FORMAT_AC_4 = AP4_ATOM_TYPE('a','c','-','4');
7079 const AP4_UI32 AP4_SAMPLE_FORMAT_EC_3 = AP4_ATOM_TYPE('e','c','-','3');
7180 const AP4_UI32 AP4_SAMPLE_FORMAT_DTSC = AP4_ATOM_TYPE('d','t','s','c');
7281 const AP4_UI32 AP4_SAMPLE_FORMAT_DTSH = AP4_ATOM_TYPE('d','t','s','h');
8998 const AP4_UI32 AP4_SAMPLE_FORMAT_TWOS = AP4_ATOM_TYPE('t','w','o','s');
9099 const AP4_UI32 AP4_SAMPLE_FORMAT_TX3G = AP4_ATOM_TYPE('t','x','3','g');
91100 const AP4_UI32 AP4_SAMPLE_FORMAT_VC_1 = AP4_ATOM_TYPE('v','c','-','1');
101 const AP4_UI32 AP4_SAMPLE_FORMAT_XML_ = AP4_ATOM_TYPE('x','m','l',' ');
92102 const AP4_UI32 AP4_SAMPLE_FORMAT_STPP = AP4_ATOM_TYPE('s','t','p','p');
93 const AP4_UI32 AP4_SAMPLE_FORMAT_XML_ = AP4_ATOM_TYPE('x','m','l',' ');
94103 const AP4_UI32 AP4_SAMPLE_FORMAT_WVTT = AP4_ATOM_TYPE('w','v','t','t');
95 const AP4_UI32 AP4_SAMPLE_FORMAT_VP09 = AP4_ATOM_TYPE('v','p','0','9');
104 const AP4_UI32 AP4_SAMPLE_FORMAT_FLAC = AP4_ATOM_TYPE('f','L','a','C');
105 const AP4_UI32 AP4_SAMPLE_FORMAT_OPUS = AP4_ATOM_TYPE('O','p','u','s');
106 const AP4_UI32 AP4_SAMPLE_FORMAT_VP8 = AP4_ATOM_TYPE('v','p','0','8');
107 const AP4_UI32 AP4_SAMPLE_FORMAT_VP9 = AP4_ATOM_TYPE('v','p','0','9');
108 const AP4_UI32 AP4_SAMPLE_FORMAT_VP10 = AP4_ATOM_TYPE('v','p','1','0');
96109
97110 const char*
98111 AP4_GetFormatName(AP4_UI32 format);
110123 TYPE_UNKNOWN = 0x00,
111124 TYPE_MPEG = 0x01,
112125 TYPE_PROTECTED = 0x02,
113 TYPE_AVC = 0x03,
114 TYPE_HEVC = 0x04,
115 TYPE_SUBTITLES = 0x05
126 TYPE_SUBTITLES = 0x03,
127 TYPE_AVC = 0x04,
128 TYPE_HEVC = 0x05,
129 TYPE_AV1 = 0x06,
130 TYPE_AC3 = 0x07,
131 TYPE_EAC3 = 0x08,
132 TYPE_AC4 = 0x09
116133 };
117134
118135 // constructors & destructor
265282 AP4_VideoSampleDescription(width, height, depth, compressor_name) {}
266283
267284 // inherited from AP4_SampleDescription
268 virtual AP4_Atom* ToAtom() const;
285 virtual AP4_Atom* ToAtom() const;
286 virtual AP4_Result GetCodecString(AP4_String& codec);
269287 };
270288
271289 /*----------------------------------------------------------------------
301319 AP4_UI08 level,
302320 AP4_UI08 profile_compatibility,
303321 AP4_UI08 nalu_length_size,
322 AP4_UI08 chroma_format,
323 AP4_UI08 bit_depth_luma_minus8,
324 AP4_UI08 bit_depth_chroma_minus8,
304325 const AP4_Array<AP4_DataBuffer>& sequence_parameters,
305326 const AP4_Array<AP4_DataBuffer>& picture_parameters);
306327
313334 AP4_Array<AP4_DataBuffer>& GetSequenceParameters() {return m_AvccAtom->GetSequenceParameters(); }
314335 AP4_Array<AP4_DataBuffer>& GetPictureParameters() { return m_AvccAtom->GetPictureParameters(); }
315336 const AP4_DataBuffer& GetRawBytes() const { return m_AvccAtom->GetRawBytes(); }
337 AP4_UI08 GetChromaFormat() const { return m_AvccAtom->GetChromaFormat(); }
338 AP4_UI08 GetBitDepthLumaMinus8() const { return m_AvccAtom->GetBitDepthLumaMinus8(); }
339 AP4_UI08 GetBitDepthChromaMinus8() const { return m_AvccAtom->GetBitDepthChromaMinus8(); }
316340
317341 // inherited from AP4_SampleDescription
318342 virtual AP4_Atom* ToAtom() const;
325349
326350 private:
327351 AP4_AvccAtom* m_AvccAtom;
352 };
353
354 /*----------------------------------------------------------------------
355 | AP4_AvcDoviSampleDescription
356 +---------------------------------------------------------------------*/
357 class AP4_AvcDoviSampleDescription : public AP4_AvcSampleDescription
358 {
359 public:
360 AP4_AvcDoviSampleDescription(AP4_UI32 format,
361 AP4_UI16 width,
362 AP4_UI16 height,
363 AP4_UI16 depth,
364 const char* compressor_name,
365 AP4_UI08 profile,
366 AP4_UI08 level,
367 AP4_UI08 profile_compatibility,
368 AP4_UI08 nalu_length_size,
369 const AP4_Array<AP4_DataBuffer>& sequence_parameters,
370 const AP4_Array<AP4_DataBuffer>& picture_parameters,
371 AP4_UI08 chroma_format,
372 AP4_UI08 bit_depth_luma_minus8,
373 AP4_UI08 bit_depth_chroma_minus8,
374 AP4_UI08 dv_version_major,
375 AP4_UI08 dv_version_minor,
376 AP4_UI08 dv_profile,
377 AP4_UI08 dv_level,
378 bool rpu_present_flag,
379 bool el_present_flag,
380 bool bl_present_flag,
381 AP4_UI08 dv_bl_signal_compatibility_id);
382 private:
383 AP4_DvccAtom* m_DvccAtom;
328384 };
329385
330386 /*----------------------------------------------------------------------
351407 const char* compressor_name,
352408 AP4_AtomParent* details);
353409
410 AP4_HevcSampleDescription(AP4_UI32 format,
411 AP4_UI16 width,
412 AP4_UI16 height,
413 AP4_UI16 depth,
414 const char* compressor_name,
415 AP4_UI08 general_profile_space,
416 AP4_UI08 general_tier_flag,
417 AP4_UI08 general_profile,
418 AP4_UI32 general_profile_compatibility_flags,
419 AP4_UI64 general_constraint_indicator_flags,
420 AP4_UI08 general_level,
421 AP4_UI32 min_spatial_segmentation,
422 AP4_UI08 parallelism_type,
423 AP4_UI08 chroma_format,
424 AP4_UI08 luma_bit_depth,
425 AP4_UI08 chroma_bit_depth,
426 AP4_UI16 average_frame_rate,
427 AP4_UI08 constant_frame_rate,
428 AP4_UI08 num_temporal_layers,
429 AP4_UI08 temporal_id_nested,
430 AP4_UI08 nalu_length_size,
431 const AP4_Array<AP4_DataBuffer>& video_parameters,
432 AP4_UI08 video_parameters_completeness,
433 const AP4_Array<AP4_DataBuffer>& sequence_parameters,
434 AP4_UI08 sequence_parameters_completeness,
435 const AP4_Array<AP4_DataBuffer>& picture_parameters,
436 AP4_UI08 picture_parameters_completeness);
437
354438 // accessors
355439 AP4_UI08 GetConfigurationVersion() const { return m_HvccAtom->GetConfigurationVersion(); }
356440 AP4_UI08 GetGeneralProfileSpace() const { return m_HvccAtom->GetGeneralProfileSpace(); }
386470 };
387471
388472 /*----------------------------------------------------------------------
473 | AP4_HevcDoviSampleDescription
474 +---------------------------------------------------------------------*/
475 class AP4_HevcDoviSampleDescription : public AP4_HevcSampleDescription
476 {
477 public:
478 AP4_HevcDoviSampleDescription(AP4_UI32 format,
479 AP4_UI16 width,
480 AP4_UI16 height,
481 AP4_UI16 depth,
482 const char* compressor_name,
483 AP4_UI08 general_profile_space,
484 AP4_UI08 general_tier_flag,
485 AP4_UI08 general_profile,
486 AP4_UI32 general_profile_compatibility_flags,
487 AP4_UI64 general_constraint_indicator_flags,
488 AP4_UI08 general_level,
489 AP4_UI32 min_spatial_segmentation,
490 AP4_UI08 parallelism_type,
491 AP4_UI08 chroma_format,
492 AP4_UI08 luma_bit_depth,
493 AP4_UI08 chroma_bit_depth,
494 AP4_UI16 average_frame_rate,
495 AP4_UI08 constant_frame_rate,
496 AP4_UI08 num_temporal_layers,
497 AP4_UI08 temporal_id_nested,
498 AP4_UI08 nalu_length_size,
499 const AP4_Array<AP4_DataBuffer>& video_parameters,
500 AP4_UI08 video_parameters_completeness,
501 const AP4_Array<AP4_DataBuffer>& sequence_parameters,
502 AP4_UI08 sequence_parameters_completeness,
503 const AP4_Array<AP4_DataBuffer>& picture_parameters,
504 AP4_UI08 picture_parameters_completeness,
505 AP4_UI08 dv_version_major,
506 AP4_UI08 dv_version_minor,
507 AP4_UI08 dv_profile,
508 AP4_UI08 dv_level,
509 bool rpu_present_flag,
510 bool el_present_flag,
511 bool bl_present_flag,
512 AP4_UI08 dv_bl_signal_compatibility_id);
513 private:
514 AP4_DvccAtom* m_DvccAtom;
515 };
516
517 /*----------------------------------------------------------------------
518 | AP4_Av1SampleDescription
519 +---------------------------------------------------------------------*/
520 class AP4_Av1SampleDescription : public AP4_SampleDescription,
521 public AP4_VideoSampleDescription
522 {
523 public:
524 AP4_IMPLEMENT_DYNAMIC_CAST_D2(AP4_Av1SampleDescription, AP4_SampleDescription, AP4_VideoSampleDescription)
525
526 // constructors
527 AP4_Av1SampleDescription(AP4_UI32 format, // av01
528 AP4_UI16 width,
529 AP4_UI16 height,
530 AP4_UI16 depth,
531 const char* compressor_name,
532 const AP4_Av1cAtom* av1c);
533
534 AP4_Av1SampleDescription(AP4_UI32 format, // av01
535 AP4_UI16 width,
536 AP4_UI16 height,
537 AP4_UI16 depth,
538 const char* compressor_name,
539 AP4_AtomParent* details);
540
541 AP4_Av1SampleDescription(AP4_UI32 format,
542 AP4_UI16 width,
543 AP4_UI16 height,
544 AP4_UI16 depth,
545 const char* compressor_name,
546 AP4_UI08 version,
547 AP4_UI08 seq_profile,
548 AP4_UI08 seq_level_idx_0,
549 AP4_UI08 seq_tier_0,
550 AP4_UI08 high_bitdepth,
551 AP4_UI08 twelve_bit,
552 AP4_UI08 monochrome,
553 AP4_UI08 chroma_subsampling_x,
554 AP4_UI08 chroma_subsampling_y,
555 AP4_UI08 chroma_sample_position,
556 AP4_UI08 initial_presentation_delay_present,
557 AP4_UI08 initial_presentation_delay_minus_one,
558 const AP4_UI08* config_obus,
559 AP4_Size config_obus_size);
560
561 // accessors
562 AP4_UI08 GetSeqProfile() const { return m_Av1cAtom->GetSeqProfile(); }
563 AP4_UI08 GetSeqLevelIdx0() const { return m_Av1cAtom->GetSeqLevelIdx0(); }
564 AP4_UI08 GetSeqTier0() const { return m_Av1cAtom->GetSeqTier0(); }
565 AP4_UI08 GetHighBitDepth() const { return m_Av1cAtom->GetHighBitDepth(); }
566 AP4_UI08 GetTwelveBit() const { return m_Av1cAtom->GetTwelveBit(); }
567 AP4_UI08 GetMonochrome() const { return m_Av1cAtom->GetMonochrome(); }
568 AP4_UI08 GetChromaSubsamplingX() const { return m_Av1cAtom->GetChromaSubsamplingX(); }
569 AP4_UI08 GetChromaSubsamplingY() const { return m_Av1cAtom->GetChromaSubsamplingY(); }
570 AP4_UI08 GetChromaSamplePosition() const { return m_Av1cAtom->GetChromaSamplePosition(); }
571 AP4_UI08 GetInitialPresentationDelayPresent() const { return m_Av1cAtom->GetInitialPresentationDelayPresent(); }
572 AP4_UI08 GetInitialPresentationDelayMinusOne() const { return m_Av1cAtom->GetInitialPresentationDelayMinusOne(); }
573 const AP4_DataBuffer& GetConfigObus() const { return m_Av1cAtom->GetConfigObus(); }
574
575 // inherited from AP4_SampleDescription
576 virtual AP4_Atom* ToAtom() const;
577 virtual AP4_Result GetCodecString(AP4_String& codec);
578
579 // static methods
580 static const char* GetProfileName(AP4_UI08 profile) {
581 return AP4_Av1cAtom::GetProfileName(profile);
582 }
583
584 private:
585 AP4_Av1cAtom* m_Av1cAtom;
586 };
587
588
589 /*----------------------------------------------------------------------
389590 | AP4_MpegSampleDescription
390591 +---------------------------------------------------------------------*/
391592 class AP4_MpegSampleDescription : public AP4_SampleDescription
495696 * Type. For other sample descriptions, this method returns 0.
496697 */
497698 Mpeg4AudioObjectType GetMpeg4AudioObjectType() const;
699 };
700
701 /*----------------------------------------------------------------------
702 | AP4_Ac3SampleDescription
703 +---------------------------------------------------------------------*/
704 class AP4_Ac3SampleDescription : public AP4_SampleDescription,
705 public AP4_AudioSampleDescription
706 {
707 public:
708 AP4_IMPLEMENT_DYNAMIC_CAST_D2(AP4_Ac3SampleDescription, AP4_SampleDescription, AP4_AudioSampleDescription)
709
710 // constructors
711 AP4_Ac3SampleDescription(AP4_UI32 sample_rate,
712 AP4_UI16 sample_size,
713 AP4_UI16 channel_count,
714 const AP4_Dac3Atom* dac3Atom);
715
716 AP4_Ac3SampleDescription(AP4_UI32 sample_rate,
717 AP4_UI16 sample_size,
718 AP4_UI16 channel_count,
719 AP4_AtomParent* details);
720
721 AP4_Ac3SampleDescription(AP4_UI32 sample_rate,
722 AP4_UI16 sample_size,
723 AP4_UI16 channel_count,
724 AP4_UI32 size, // DSI size
725 const AP4_Dac3Atom::StreamInfo* ac3_stream_info);
726
727 // inherited from AP4_SampleDescription
728 virtual AP4_Result GetCodecString(AP4_String& codec) { codec = "ac-3"; return AP4_SUCCESS; }
729 virtual AP4_Atom* ToAtom() const;
730
731 private:
732 AP4_Dac3Atom* m_Dac3Atom;
733 };
734
735 /*----------------------------------------------------------------------
736 | AP4_Eac3SampleDescription
737 +---------------------------------------------------------------------*/
738 class AP4_Eac3SampleDescription : public AP4_SampleDescription,
739 public AP4_AudioSampleDescription
740 {
741 public:
742 AP4_IMPLEMENT_DYNAMIC_CAST_D2(AP4_Eac3SampleDescription, AP4_SampleDescription, AP4_AudioSampleDescription)
743
744 // constructors
745 AP4_Eac3SampleDescription();
746 AP4_Eac3SampleDescription(AP4_UI32 sample_rate,
747 AP4_UI16 sample_size,
748 AP4_UI16 channel_count,
749 const AP4_Dec3Atom* dec3Atom);
750
751 AP4_Eac3SampleDescription(AP4_UI32 sample_rate,
752 AP4_UI16 sample_size,
753 AP4_UI16 channel_count,
754 AP4_AtomParent* details);
755
756 AP4_Eac3SampleDescription(AP4_UI32 sample_rate,
757 AP4_UI16 sample_size,
758 AP4_UI16 channel_count,
759 AP4_UI32 size, // DSI size
760 const AP4_Dec3Atom::SubStream* subStream,
761 const AP4_UI32 complexity_index_type_a);
762
763 // inherited from AP4_SampleDescription
764 virtual AP4_Result GetCodecString(AP4_String& codec) { codec = "ec-3"; return AP4_SUCCESS; }
765 virtual AP4_Atom* ToAtom() const;
766
767 private:
768 AP4_Dec3Atom* m_Dec3Atom;
769 };
770
771 /*----------------------------------------------------------------------
772 | AP4_Ac4SampleDescription
773 +---------------------------------------------------------------------*/
774 class AP4_Ac4SampleDescription : public AP4_SampleDescription,
775 public AP4_AudioSampleDescription
776 {
777 public:
778 AP4_IMPLEMENT_DYNAMIC_CAST_D2(AP4_Ac4SampleDescription, AP4_SampleDescription, AP4_AudioSampleDescription)
779
780 // constructors
781 AP4_Ac4SampleDescription(AP4_UI32 sample_rate,
782 AP4_UI16 sample_size,
783 AP4_UI16 channel_count,
784 const AP4_Dac4Atom* dac4Atom);
785
786 AP4_Ac4SampleDescription(AP4_UI32 sample_rate,
787 AP4_UI16 sample_size,
788 AP4_UI16 channel_count,
789 AP4_AtomParent* details);
790
791 AP4_Ac4SampleDescription(AP4_UI32 sample_rate,
792 AP4_UI16 sample_size,
793 AP4_UI16 channel_count,
794 AP4_UI32 size, // DSI size
795 const AP4_Dac4Atom::Ac4Dsi* ac4Dsi);
796
797 // inherited from AP4_SampleDescription
798 virtual AP4_Result GetCodecString(AP4_String& codec) { m_Dac4Atom->GetCodecString(codec); return AP4_SUCCESS; }
799 virtual AP4_Atom* ToAtom() const;
800
801 private:
802 AP4_Dac4Atom* m_Dac4Atom;
498803 };
499804
500805 /*----------------------------------------------------------------------
560865 +---------------------------------------------------------------------*/
561866 const AP4_MpegSampleDescription::StreamType AP4_STREAM_TYPE_FORBIDDEN = 0x00;
562867 const AP4_MpegSampleDescription::StreamType AP4_STREAM_TYPE_OD = 0x01;
563 const AP4_MpegSampleDescription::StreamType AP4_STREAM_TYPE_CR = 0x02;
868 const AP4_MpegSampleDescription::StreamType AP4_STREAM_TYPE_CR = 0x02;
564869 const AP4_MpegSampleDescription::StreamType AP4_STREAM_TYPE_BIFS = 0x03;
565870 const AP4_MpegSampleDescription::StreamType AP4_STREAM_TYPE_VISUAL = 0x04;
566871 const AP4_MpegSampleDescription::StreamType AP4_STREAM_TYPE_AUDIO = 0x05;
603908 const AP4_MpegSampleDescription::OTI AP4_OTI_DTS_HIRES_AUDIO = 0xAA;
604909 const AP4_MpegSampleDescription::OTI AP4_OTI_DTS_MASTER_AUDIO = 0xAB;
605910 const AP4_MpegSampleDescription::OTI AP4_OTI_DTS_EXPRESS_AUDIO = 0xAC;
911 const AP4_MpegSampleDescription::OTI AP4_OTI_OPUS_AUDIO = 0xAD;
912 const AP4_MpegSampleDescription::OTI AP4_OTI_VP9_VIDEO = 0xB1;
913 const AP4_MpegSampleDescription::OTI AP4_OTI_VORBIS_AUDIO = 0xDD; // Not standard!
606914 const AP4_MpegSampleDescription::OTI AP4_OTI_13K_VOICE = 0xE1;
607915
608916 const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_AAC_MAIN = 1; /**< AAC Main Profile */
642950 const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_ER_AAC_ELD = 39; /**< Error Resilient AAC ELD */
643951 const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_SMR_SIMPLE = 40; /**< SMR Simple */
644952 const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_SMR_MAIN = 41; /**< SMR Main */
953 const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_USAC = 42; /**< USAC */
954 const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_SAOC = 43; /**< SAOC */
645955
646956 #endif // _AP4_SAMPLE_DESCRIPTION_H_
647957
3434 #include "Ap4TimsAtom.h"
3535 #include "Ap4SampleDescription.h"
3636 #include "Ap4AvccAtom.h"
37 #include "Ap4Dac3Atom.h"
3837
3938 /*----------------------------------------------------------------------
4039 | dynamic cast support
4443 /*----------------------------------------------------------------------
4544 | AP4_SampleEntry::AP4_SampleEntry
4645 +---------------------------------------------------------------------*/
47 AP4_SampleEntry::AP4_SampleEntry(AP4_Atom::Type format) :
46 AP4_SampleEntry::AP4_SampleEntry(AP4_Atom::Type format, const AP4_AtomParent* details) :
4847 AP4_ContainerAtom(format),
4948 m_DataReferenceIndex(1)
5049 {
5554 m_Reserved1[4] = 0;
5655 m_Reserved1[5] = 0;
5756 m_Size32 += 8;
57
58 if (details) {
59 details->CopyChildren(*this);
60 }
5861 }
5962
6063 /*----------------------------------------------------------------------
454457 if (m_QtVersion == 2) {
455458 return (AP4_UI16)m_QtV2ChannelCount;
456459 } else {
457 AP4_Atom *child;
458 if (GetType() == AP4_ATOM_TYPE_AC_3 && (child = GetChild(AP4_ATOM_TYPE_DAC3)))
459 return AP4_DYNAMIC_CAST(AP4_Dac3Atom, child)->GetChannels();
460
461460 return m_ChannelCount;
462461 }
463462 }
679678 }
680679
681680 /*----------------------------------------------------------------------
681 | AP4_Ac3SampleEntry::AP4_Ac3SampleEntry
682 +---------------------------------------------------------------------*/
683 AP4_Ac3SampleEntry::AP4_Ac3SampleEntry(AP4_UI32 format,
684 AP4_UI32 sample_rate,
685 AP4_UI16 sample_size,
686 AP4_UI16 channel_count,
687 const AP4_AtomParent *details):
688 AP4_AudioSampleEntry(format, sample_rate, sample_size, channel_count)
689 {
690 if (details){
691 AP4_AtomParent* parent = new AP4_AtomParent();
692 details->CopyChildren(*parent);
693 AP4_Atom* child = parent->GetChild(AP4_ATOM_TYPE_DAC3);
694 child->Detach();
695 AddChild(child);
696 }
697 }
698
699 /*----------------------------------------------------------------------
700 | AP4_Ac3SampleEntry::AP4_Ac3SampleEntry
701 +---------------------------------------------------------------------*/
702 AP4_Ac3SampleEntry::AP4_Ac3SampleEntry(AP4_UI32 type,
703 AP4_Size size,
704 AP4_ByteStream& stream,
705 AP4_AtomFactory& atom_factory) :
706 AP4_AudioSampleEntry(type, size, stream, atom_factory)
707 {
708 }
709
710 /*----------------------------------------------------------------------
711 | AP4_Ac3SampleEntry::ToSampleDescription
712 +---------------------------------------------------------------------*/
713 AP4_SampleDescription*
714 AP4_Ac3SampleEntry::ToSampleDescription()
715 {
716 // find the dac3 atom
717 AP4_Dac3Atom* dac3 = AP4_DYNAMIC_CAST(AP4_Dac3Atom, GetChild(AP4_ATOM_TYPE_DAC3));
718 if (dac3 == NULL) {
719 return NULL;
720 }else{
721 return new AP4_Ac3SampleDescription(GetSampleRate(),
722 GetSampleSize(),
723 GetChannelCount(),
724 dac3);
725 }
726 }
727
728 /*----------------------------------------------------------------------
729 | AP4_Eac3SampleEntry::AP4_Eac3SampleEntry
730 +---------------------------------------------------------------------*/
731 AP4_Eac3SampleEntry::AP4_Eac3SampleEntry(AP4_UI32 format,
732 AP4_UI32 sample_rate,
733 AP4_UI16 sample_size,
734 AP4_UI16 channel_count,
735 const AP4_AtomParent *details):
736 AP4_AudioSampleEntry(format, sample_rate, sample_size, channel_count)
737 {
738 if (details){
739 AP4_Atom* child = details->GetChild(AP4_ATOM_TYPE_DEC3)->Clone();
740 AddChild(child);
741 }
742 }
743
744 /*----------------------------------------------------------------------
745 | AP4_Eac3SampleEntry::AP4_Eac3SampleEntry
746 +---------------------------------------------------------------------*/
747 AP4_Eac3SampleEntry::AP4_Eac3SampleEntry(AP4_UI32 type,
748 AP4_Size size,
749 AP4_ByteStream& stream,
750 AP4_AtomFactory& atom_factory) :
751 AP4_AudioSampleEntry(type, size, stream, atom_factory)
752 {
753 }
754
755 /*----------------------------------------------------------------------
756 | AP4_Eac3SampleEntry::ToSampleDescription
757 +---------------------------------------------------------------------*/
758 AP4_SampleDescription*
759 AP4_Eac3SampleEntry::ToSampleDescription()
760 {
761 // find the dec3 atom
762 AP4_Dec3Atom* dec3 = AP4_DYNAMIC_CAST(AP4_Dec3Atom, GetChild(AP4_ATOM_TYPE_DEC3));
763 if (dec3 == NULL) {
764 // shall never happen
765 return new AP4_Eac3SampleDescription();
766 }else{
767 return new AP4_Eac3SampleDescription(GetSampleRate(),
768 GetSampleSize(),
769 GetChannelCount(),
770 dec3);
771 }
772 }
773
774 /*----------------------------------------------------------------------
775 | AP4_Ac4SampleEntry::AP4_Ac4SampleEntry
776 +---------------------------------------------------------------------*/
777 AP4_Ac4SampleEntry::AP4_Ac4SampleEntry(AP4_UI32 format,
778 AP4_UI32 sample_rate,
779 AP4_UI16 sample_size,
780 AP4_UI16 channel_count,
781 const AP4_AtomParent* details):
782 AP4_AudioSampleEntry(format, sample_rate, sample_size, channel_count)
783 {
784 if (details){
785 AP4_AtomParent* parent = new AP4_AtomParent();
786 details->CopyChildren(*parent);
787 AP4_Atom* child = parent->GetChild(AP4_ATOM_TYPE_DAC4);
788 child->Detach();
789 AddChild(child);
790 }
791 }
792
793 /*----------------------------------------------------------------------
794 | AP4_Ac4SampleEntry::AP4_Ac4SampleEntry
795 +---------------------------------------------------------------------*/
796 AP4_Ac4SampleEntry::AP4_Ac4SampleEntry(AP4_UI32 type,
797 AP4_Size size,
798 AP4_ByteStream& stream,
799 AP4_AtomFactory& atom_factory) :
800 AP4_AudioSampleEntry(type, size, stream, atom_factory)
801 {
802 }
803
804 /*----------------------------------------------------------------------
805 | AP4_Ac4SampleEntry::ToSampleDescription
806 +---------------------------------------------------------------------*/
807 AP4_SampleDescription*
808 AP4_Ac4SampleEntry::ToSampleDescription()
809 {
810 // find the dac4 atom
811 AP4_Dac4Atom* dac4 = AP4_DYNAMIC_CAST(AP4_Dac4Atom, GetChild(AP4_ATOM_TYPE_DAC4));
812 if (dac4 == NULL) {
813 return NULL;
814 } else{
815 return new AP4_Ac4SampleDescription(GetSampleRate(),
816 GetSampleSize(),
817 GetChannelCount(),
818 dac4);
819 }
820 }
821
822 /*----------------------------------------------------------------------
682823 | AP4_Mp4aSampleEntry::AP4_Mp4aSampleEntry
683824 +---------------------------------------------------------------------*/
684825 AP4_Mp4aSampleEntry::AP4_Mp4aSampleEntry(AP4_UI32 sample_rate,
711852 AP4_UI16 width,
712853 AP4_UI16 height,
713854 AP4_UI16 depth,
714 const char* compressor_name) :
715 AP4_SampleEntry(format),
855 const char* compressor_name,
856 const AP4_AtomParent* details) :
857 AP4_SampleEntry(format, details),
716858 m_Predefined1(0),
717859 m_Reserved2(0),
718860 m_Width(width),
771913 stream.ReadUI32(m_Reserved3);
772914 stream.ReadUI16(m_FrameCount);
773915
774 char compressor_name[33];
916 AP4_UI08 compressor_name[33];
917 compressor_name[32] = 0;
775918 stream.Read(compressor_name, 32);
776 int name_length = compressor_name[0];
919 AP4_UI08 name_length = compressor_name[0];
777920 if (name_length < 32) {
778921 compressor_name[name_length+1] = 0; // force null termination
779 m_CompressorName = &compressor_name[1];
922 m_CompressorName = (const char*)(&compressor_name[1]);
780923 }
781924
782925 stream.ReadUI16(m_Depth);
9721115 AP4_UI16 height,
9731116 AP4_UI16 depth,
9741117 const char* compressor_name,
975 const AP4_AvccAtom& avcc) :
1118 const AP4_AtomParent* details) :
9761119 AP4_VisualSampleEntry(format,
9771120 width,
9781121 height,
9791122 depth,
980 compressor_name)
981 {
982 AddChild(new AP4_AvccAtom(avcc));
1123 compressor_name,
1124 details)
1125 {
9831126 }
9841127
9851128 /*----------------------------------------------------------------------
9911134 AP4_AtomFactory& atom_factory) :
9921135 AP4_VisualSampleEntry(format, size, stream, atom_factory)
9931136 {
994 }
995
996 /*----------------------------------------------------------------------
997 | AP4_HevcSampleEntry::AP4_HevcSSampleEntry
998 +---------------------------------------------------------------------*/
999 AP4_HevcSampleEntry::AP4_HevcSampleEntry(AP4_UI32 format,
1000 AP4_UI16 width,
1001 AP4_UI16 height,
1002 AP4_UI16 depth,
1003 const char* compressor_name,
1004 const AP4_HvccAtom& hvcc) :
1005 AP4_VisualSampleEntry(format,
1006 width,
1007 height,
1008 depth,
1009 compressor_name)
1010 {
1011 AddChild(new AP4_HvccAtom(hvcc));
10121137 }
10131138
10141139 /*----------------------------------------------------------------------
10231148 m_Height,
10241149 m_Depth,
10251150 m_CompressorName.GetChars(),
1026 AP4_DYNAMIC_CAST(AP4_AvccAtom, GetChild(AP4_ATOM_TYPE_AVCC)));
1151 this);
1152 }
1153
1154 /*----------------------------------------------------------------------
1155 | AP4_HevcSampleEntry::AP4_HevcSampleEntry
1156 +---------------------------------------------------------------------*/
1157 AP4_HevcSampleEntry::AP4_HevcSampleEntry(AP4_UI32 format,
1158 AP4_UI16 width,
1159 AP4_UI16 height,
1160 AP4_UI16 depth,
1161 const char* compressor_name,
1162 const AP4_AtomParent* details) :
1163 AP4_VisualSampleEntry(format,
1164 width,
1165 height,
1166 depth,
1167 compressor_name,
1168 details)
1169 {
10271170 }
10281171
10291172 /*----------------------------------------------------------------------
10491192 m_Height,
10501193 m_Depth,
10511194 m_CompressorName.GetChars(),
1052 AP4_DYNAMIC_CAST(AP4_HvccAtom, GetChild(AP4_ATOM_TYPE_HVCC)));
1195 this);
1196 }
1197
1198 /*----------------------------------------------------------------------
1199 | AP4_Av1SampleEntry::AP4_Av1SampleEntry
1200 +---------------------------------------------------------------------*/
1201 AP4_Av1SampleEntry::AP4_Av1SampleEntry(AP4_UI32 format,
1202 AP4_UI16 width,
1203 AP4_UI16 height,
1204 AP4_UI16 depth,
1205 const char* compressor_name,
1206 const AP4_AtomParent* details) :
1207 AP4_VisualSampleEntry(format,
1208 width,
1209 height,
1210 depth,
1211 compressor_name,
1212 details)
1213 {
1214 }
1215
1216 /*----------------------------------------------------------------------
1217 | AP4_Av1SampleEntry::AP4_Av1SampleEntry
1218 +---------------------------------------------------------------------*/
1219 AP4_Av1SampleEntry::AP4_Av1SampleEntry(AP4_UI32 format,
1220 AP4_Size size,
1221 AP4_ByteStream& stream,
1222 AP4_AtomFactory& atom_factory) :
1223 AP4_VisualSampleEntry(format, size, stream, atom_factory)
1224 {
1225 }
1226
1227 /*----------------------------------------------------------------------
1228 | AP4_Av1SampleEntry::ToSampleDescription
1229 +---------------------------------------------------------------------*/
1230 AP4_SampleDescription*
1231 AP4_Av1SampleEntry::ToSampleDescription()
1232 {
1233 return new AP4_Av1SampleDescription(
1234 m_Type,
1235 m_Width,
1236 m_Height,
1237 m_Depth,
1238 m_CompressorName.GetChars(),
1239 this);
10531240 }
10541241
10551242 /*----------------------------------------------------------------------
5454 AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_SampleEntry, AP4_ContainerAtom)
5555
5656 // methods
57 AP4_SampleEntry(AP4_Atom::Type format);
57 AP4_SampleEntry(AP4_Atom::Type format, const AP4_AtomParent* details = NULL);
5858 AP4_SampleEntry(AP4_Atom::Type format,
5959 AP4_Size size,
6060 AP4_ByteStream& stream,
185185 AP4_UI16 width,
186186 AP4_UI16 height,
187187 AP4_UI16 depth,
188 const char* compressor_name);
188 const char* compressor_name,
189 const AP4_AtomParent* details = NULL);
189190 AP4_VisualSampleEntry(AP4_Atom::Type format,
190191 AP4_Size size,
191192 AP4_ByteStream& stream,
264265 };
265266
266267 /*----------------------------------------------------------------------
268 | AP4_Ac3SampleEntry
269 +---------------------------------------------------------------------*/
270 class AP4_Ac3SampleEntry : public AP4_AudioSampleEntry
271 {
272 public:
273 AP4_Ac3SampleEntry(AP4_UI32 format,
274 AP4_UI32 sample_rate,
275 AP4_UI16 sample_size,
276 AP4_UI16 channel_count,
277 const AP4_AtomParent* details);
278 AP4_Ac3SampleEntry(AP4_UI32 type,
279 AP4_Size size,
280 AP4_ByteStream& stream,
281 AP4_AtomFactory& atom_factory);
282
283 // inherited from AP4_SampleEntry
284 virtual AP4_SampleDescription* ToSampleDescription();
285 };
286
287 /*----------------------------------------------------------------------
288 | AP4_Eac3SampleEntry
289 +---------------------------------------------------------------------*/
290 class AP4_Eac3SampleEntry : public AP4_AudioSampleEntry
291 {
292 public:
293 AP4_Eac3SampleEntry(AP4_UI32 format,
294 AP4_UI32 sample_rate,
295 AP4_UI16 sample_size,
296 AP4_UI16 channel_count,
297 const AP4_AtomParent* details);
298 AP4_Eac3SampleEntry(AP4_UI32 type,
299 AP4_Size size,
300 AP4_ByteStream& stream,
301 AP4_AtomFactory& atom_factory);
302
303 // inherited from AP4_SampleEntry
304 virtual AP4_SampleDescription* ToSampleDescription();
305 };
306
307
308 /*----------------------------------------------------------------------
309 | AP4_Ac4SampleEntry
310 +---------------------------------------------------------------------*/
311 class AP4_Ac4SampleEntry : public AP4_AudioSampleEntry
312 {
313 public:
314 AP4_Ac4SampleEntry(AP4_UI32 format,
315 AP4_UI32 sample_rate,
316 AP4_UI16 sample_size,
317 AP4_UI16 channel_count,
318 const AP4_AtomParent* details);
319 AP4_Ac4SampleEntry(AP4_UI32 type,
320 AP4_Size size,
321 AP4_ByteStream& stream,
322 AP4_AtomFactory& atom_factory);
323
324 // inherited from AP4_SampleEntry
325 virtual AP4_SampleDescription* ToSampleDescription();
326 };
327
328 /*----------------------------------------------------------------------
267329 | AP4_MpegVideoSampleEntry
268330 +---------------------------------------------------------------------*/
269331 class AP4_MpegVideoSampleEntry : public AP4_VisualSampleEntry
327389 AP4_Mp4vSampleEntry(AP4_Size size,
328390 AP4_ByteStream& stream,
329391 AP4_AtomFactory& atom_factory);
392
330393 AP4_Mp4vSampleEntry(AP4_UI16 width,
331394 AP4_UI16 height,
332395 AP4_UI16 depth,
345408 AP4_Size size,
346409 AP4_ByteStream& stream,
347410 AP4_AtomFactory& atom_factory);
411
348412 AP4_AvcSampleEntry(AP4_UI32 format, // avc1, avc2, avc3, avc4
349413 AP4_UI16 width,
350414 AP4_UI16 height,
351415 AP4_UI16 depth,
352416 const char* compressor_name,
353 const AP4_AvccAtom& avcc);
417 const AP4_AtomParent* details);
354418
355419 // inherited from AP4_SampleEntry
356420 virtual AP4_SampleDescription* ToSampleDescription();
373437 AP4_UI16 height,
374438 AP4_UI16 depth,
375439 const char* compressor_name,
376 const AP4_HvccAtom& hvcc);
440 const AP4_AtomParent* details);
441
442 // inherited from AP4_SampleEntry
443 virtual AP4_SampleDescription* ToSampleDescription();
444 };
445
446 /*----------------------------------------------------------------------
447 | AP4_Av1SampleEntry
448 +---------------------------------------------------------------------*/
449 class AP4_Av1SampleEntry : public AP4_VisualSampleEntry
450 {
451 public:
452 // constructors
453 AP4_Av1SampleEntry(AP4_UI32 format, // av01
454 AP4_Size size,
455 AP4_ByteStream& stream,
456 AP4_AtomFactory& atom_factory);
457
458 AP4_Av1SampleEntry(AP4_UI32 format, // av01
459 AP4_UI16 width,
460 AP4_UI16 height,
461 AP4_UI16 depth,
462 const char* compressor_name,
463 const AP4_AtomParent* details);
377464
378465 // inherited from AP4_SampleEntry
379466 virtual AP4_SampleDescription* ToSampleDescription();
5757 // create the stsd atom
5858 AP4_StsdAtom* stsd = new AP4_StsdAtom(this);
5959
60 // create the stts atom
61 AP4_SttsAtom* stts = new AP4_SttsAtom();
62
63 // create the stsc atom
64 AP4_StscAtom* stsc = new AP4_StscAtom();
65
6066 // create the stsz atom
6167 AP4_StszAtom* stsz = new AP4_StszAtom();
62
63 // create the stsc atom
64 AP4_StscAtom* stsc = new AP4_StscAtom();
65
66 // create the stts atom
67 AP4_SttsAtom* stts = new AP4_SttsAtom();
6868
6969 // create the stss atom
7070 AP4_StssAtom* stss = new AP4_StssAtom();
179179
180180 // attach the children of stbl
181181 stbl->AddChild(stsd);
182 stbl->AddChild(stsz);
183 stbl->AddChild(stsc);
184182 stbl->AddChild(stts);
185183 if (ctts) stbl->AddChild(ctts);
184 stbl->AddChild(stsc);
185 stbl->AddChild(stsz);
186186 if (!all_samples_are_sync && stss->GetEntries().ItemCount() != 0) {
187187 stbl->AddChild(stss);
188188 } else {
190190 }
191191
192192 // see if we need a co64 or an stco atom
193 AP4_Size chunk_count = chunk_offsets.ItemCount();
193 AP4_Size chunk_count = chunk_offsets.ItemCount();
194194 if (current_chunk_offset <= 0xFFFFFFFF) {
195195 // make an array of 32-bit entries
196196 AP4_UI32* chunk_offsets_32 = new AP4_UI32[chunk_count];
4545 {
4646 AP4_UI08 version;
4747 AP4_UI32 flags;
48 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4849 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4950 if (version > 1) return NULL;
5051 return new AP4_SbgpAtom(size, version, flags, stream);
136137 inspector.AddField("entry_count", m_Entries.ItemCount());
137138
138139 if (inspector.GetVerbosity() >= 2) {
139 char header[32];
140 char value[128];
140 inspector.StartArray("entries", m_Entries.ItemCount());
141141 for (AP4_Ordinal i=0; i<m_Entries.ItemCount(); i++) {
142 AP4_FormatString(header, sizeof(header), "entry %02d", i);
143 AP4_FormatString(value, sizeof(value), "c:%u,g:%u", m_Entries[i].sample_count, m_Entries[i].group_description_index);
144 inspector.AddField(header, value);
142 inspector.StartObject(NULL, 2, true);
143 inspector.AddField("sample_count", m_Entries[i].sample_count);
144 inspector.AddField("group_description_index", m_Entries[i].group_description_index);
145 inspector.EndObject();
145146 }
147 inspector.EndArray();
146148 }
147149
148150 return AP4_SUCCESS;
4747 {
4848 AP4_UI08 version;
4949 AP4_UI32 flags;
50 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
5051 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
5152 if (version != 0) return NULL;
5253 if (size < AP4_FULL_ATOM_HEADER_SIZE+6) return NULL;
11 |
22 | AP4 - Segment Builder
33 |
4 | Copyright 2002-2014 Axiomatic Systems, LLC
4 | Copyright 2002-2019 Axiomatic Systems, LLC
55 |
66 |
77 | This file is part of Bento4/AP4 (MP4 Atom Processing Library).
2828 /*----------------------------------------------------------------------
2929 | includes
3030 +---------------------------------------------------------------------*/
31 #include <stdio.h> // FIXME: testing
3231 #include "Ap4SegmentBuilder.h"
3332 #include "Ap4Results.h"
3433 #include "Ap4ByteStream.h"
4645 /*----------------------------------------------------------------------
4746 | constants
4847 +---------------------------------------------------------------------*/
49 const AP4_UI32 AP4_SEGMENT_BUILDER_DEFAULT_TIMESCALE = 1000;
48 const AP4_UI32 AP4_SEGMENT_BUILDER_DEFAULT_TIMESCALE = 1000;
49 const unsigned int AP4_STREAM_FEEDER_DEFAULT_BUFFER_SIZE = 65536;
5050
5151 /*----------------------------------------------------------------------
5252 | AP4_SegmentBuilder::AP4_SegmentBuilder
8787 }
8888
8989 /*----------------------------------------------------------------------
90 | AP4_FeedSegmentBuilder::AP4_FeedSegmentBuilder
91 +---------------------------------------------------------------------*/
92 AP4_FeedSegmentBuilder::AP4_FeedSegmentBuilder(AP4_Track::Type track_type,
93 AP4_UI32 track_id,
94 AP4_UI64 media_time_origin) :
95 AP4_SegmentBuilder(track_type, track_id, media_time_origin)
96 {
97 }
98
99 /*----------------------------------------------------------------------
100 | AP4_AvcSegmentBuilder::AP4_AvcSegmentBuilder
101 +---------------------------------------------------------------------*/
102 AP4_AvcSegmentBuilder::AP4_AvcSegmentBuilder(AP4_UI32 track_id,
103 double frames_per_second,
104 AP4_UI64 media_time_origin) :
105 AP4_FeedSegmentBuilder(AP4_Track::TYPE_VIDEO, track_id, media_time_origin),
106 m_FramesPerSecond(frames_per_second)
107 {
108 m_Timescale = (unsigned int)(frames_per_second*1000.0);
109 }
110
111 /*----------------------------------------------------------------------
11290 | AP4_SegmentBuilder::WriteMediaSegment
11391 +---------------------------------------------------------------------*/
11492 AP4_Result
11896 if (m_TrackType == AP4_Track::TYPE_VIDEO) {
11997 tfhd_flags |= AP4_TFHD_FLAG_DEFAULT_SAMPLE_FLAGS_PRESENT;
12098 }
121
99
122100 // setup the moof structure
123101 AP4_ContainerAtom* moof = new AP4_ContainerAtom(AP4_ATOM_TYPE_MOOF);
124102 AP4_MfhdAtom* mfhd = new AP4_MfhdAtom(sequence_number);
167145 trun_entry.sample_duration = m_Samples[i].GetDuration();
168146 trun_entry.sample_size = m_Samples[i].GetSize();
169147 trun_entry.sample_composition_time_offset = m_Samples[i].GetCtsDelta();
170
148
171149 mdat_size += trun_entry.sample_size;
172150 }
173151
211189 }
212190
213191 /*----------------------------------------------------------------------
214 | AP4_AvcSegmentBuilder::Feed
215 +---------------------------------------------------------------------*/
216 AP4_Result
217 AP4_AvcSegmentBuilder::Feed(const void* data,
218 AP4_Size data_size,
219 AP4_Size& bytes_consumed)
220 {
221 AP4_Result result;
222
223 AP4_AvcFrameParser::AccessUnitInfo access_unit_info;
224 result = m_FrameParser.Feed(data, data_size, bytes_consumed, access_unit_info, data == NULL);
225 if (AP4_FAILED(result)) return result;
226
227 // check if we have an access unit
228 if (access_unit_info.nal_units.ItemCount()) {
229 // compute the total size of the sample data
230 unsigned int sample_data_size = 0;
231 for (unsigned int i=0; i<access_unit_info.nal_units.ItemCount(); i++) {
232 sample_data_size += 4+access_unit_info.nal_units[i]->GetDataSize();
233 }
234
235 // format the sample data
236 AP4_MemoryByteStream* sample_data = new AP4_MemoryByteStream(sample_data_size);
237 for (unsigned int i=0; i<access_unit_info.nal_units.ItemCount(); i++) {
238 sample_data->WriteUI32(access_unit_info.nal_units[i]->GetDataSize());
239 sample_data->Write(access_unit_info.nal_units[i]->GetData(), access_unit_info.nal_units[i]->GetDataSize());
240 }
241
242 // compute the timestamp in a drift-less manner
243 AP4_UI32 duration = 0;
244 AP4_UI64 dts = 0;
245 if (m_Timescale !=0 && m_FramesPerSecond != 0.0) {
246 AP4_UI64 this_sample_time = m_MediaStartTime+m_MediaDuration;
247 AP4_UI64 next_sample_time = (AP4_UI64)((double)m_Timescale*(double)(m_SampleStartNumber+m_Samples.ItemCount()+1)/m_FramesPerSecond);
248 duration = (AP4_UI32)(next_sample_time-this_sample_time);
249 dts = (AP4_UI64)((double)m_Timescale/m_FramesPerSecond*(double)m_Samples.ItemCount());
250 }
251
252 // create a new sample and add it to the list
253 AP4_Sample sample(*sample_data, 0, sample_data_size, duration, 0, dts, 0, access_unit_info.is_idr);
254 AddSample(sample);
255 sample_data->Release();
256
257 // remember the sample order
258 m_SampleOrders.Append(SampleOrder(access_unit_info.decode_order, access_unit_info.display_order));
259
260 // free the memory buffers
261 for (unsigned int i=0; i<access_unit_info.nal_units.ItemCount(); i++) {
262 delete access_unit_info.nal_units[i];
263 }
264 access_unit_info.nal_units.Clear();
265
266 return 1; // one access unit returned
267 }
268
269 return AP4_SUCCESS;
270 }
271
272 /*----------------------------------------------------------------------
273 | AP4_AvcSegmentBuilder::SortSamples
192 | AP4_FeedSegmentBuilder::AP4_FeedSegmentBuilder
193 +---------------------------------------------------------------------*/
194 AP4_FeedSegmentBuilder::AP4_FeedSegmentBuilder(AP4_Track::Type track_type,
195 AP4_UI32 track_id,
196 AP4_UI64 media_time_origin) :
197 AP4_SegmentBuilder(track_type, track_id, media_time_origin)
198 {
199 }
200
201 /*----------------------------------------------------------------------
202 | AP4_VideoSegmentBuilder::AP4_VideoSegmentBuilder
203 +---------------------------------------------------------------------*/
204 AP4_VideoSegmentBuilder::AP4_VideoSegmentBuilder(AP4_UI32 track_id,
205 double frames_per_second,
206 AP4_UI64 media_time_origin) :
207 AP4_FeedSegmentBuilder(AP4_Track::TYPE_VIDEO, track_id, media_time_origin),
208 m_FramesPerSecond(frames_per_second)
209 {
210 m_Timescale = (unsigned int)(frames_per_second*1000.0);
211 }
212
213 /*----------------------------------------------------------------------
214 | AP4_VideoSegmentBuilder::SortSamples
274215 +---------------------------------------------------------------------*/
275216 void
276 AP4_AvcSegmentBuilder::SortSamples(SampleOrder* array, unsigned int n)
217 AP4_VideoSegmentBuilder::SortSamples(SampleOrder* array, unsigned int n)
277218 {
278219 if (n < 2) {
279220 return;
299240 }
300241
301242 /*----------------------------------------------------------------------
302 | AP4_AvcSegmentBuilder::WriteMediaSegment
303 +---------------------------------------------------------------------*/
304 AP4_Result
305 AP4_AvcSegmentBuilder::WriteMediaSegment(AP4_ByteStream& stream, unsigned int sequence_number)
243 | AP4_VideoSegmentBuilder::WriteVideoInitSegment
244 +---------------------------------------------------------------------*/
245 AP4_Result
246 AP4_VideoSegmentBuilder::WriteVideoInitSegment(AP4_ByteStream& stream,
247 AP4_SampleDescription* sample_description,
248 unsigned int width,
249 unsigned int height,
250 AP4_UI32 brand)
251 {
252 // create the output file object
253 AP4_Movie* output_movie = new AP4_Movie(AP4_SEGMENT_BUILDER_DEFAULT_TIMESCALE);
254
255 // create an mvex container
256 AP4_ContainerAtom* mvex = new AP4_ContainerAtom(AP4_ATOM_TYPE_MVEX);
257 AP4_MehdAtom* mehd = new AP4_MehdAtom(0);
258 mvex->AddChild(mehd);
259
260 // create a sample table (with no samples) to hold the sample description
261 AP4_SyntheticSampleTable* sample_table = new AP4_SyntheticSampleTable();
262 sample_table->AddSampleDescription(sample_description, true);
263
264 // create the track
265 AP4_Track* output_track = new AP4_Track(AP4_Track::TYPE_VIDEO,
266 sample_table,
267 m_TrackId,
268 AP4_SEGMENT_BUILDER_DEFAULT_TIMESCALE,
269 0,
270 m_Timescale,
271 0,
272 m_TrackLanguage.GetChars(),
273 width << 16,
274 height << 16);
275 output_movie->AddTrack(output_track);
276
277 // add a trex entry to the mvex container
278 AP4_TrexAtom* trex = new AP4_TrexAtom(m_TrackId,
279 1,
280 0,
281 0,
282 0);
283 mvex->AddChild(trex);
284
285 // update the mehd duration
286 // TBD mehd->SetDuration(0);
287
288 // the mvex container to the moov container
289 output_movie->GetMoovAtom()->AddChild(mvex);
290
291 // write the ftyp atom
292 AP4_Array<AP4_UI32> brands;
293 brands.Append(AP4_FILE_BRAND_ISOM);
294 brands.Append(AP4_FILE_BRAND_MP42);
295 brands.Append(AP4_FILE_BRAND_MP41);
296 brands.Append(brand);
297
298 AP4_FtypAtom* ftyp = new AP4_FtypAtom(AP4_FILE_BRAND_MP42, 1, &brands[0], brands.ItemCount());
299 ftyp->Write(stream);
300 delete ftyp;
301
302 // write the moov atom
303 AP4_Result result = output_movie->GetMoovAtom()->Write(stream);
304 if (AP4_FAILED(result)) {
305 return result;
306 }
307
308 // cleanup
309 delete output_movie;
310
311 return AP4_SUCCESS;
312 }
313
314 /*----------------------------------------------------------------------
315 | AP4_VideoSegmentBuilder::WriteMediaSegment
316 +---------------------------------------------------------------------*/
317 AP4_Result
318 AP4_VideoSegmentBuilder::WriteMediaSegment(AP4_ByteStream& stream, unsigned int sequence_number)
306319 {
307320 if (m_SampleOrders.ItemCount() > 1) {
308321 // rebase the decode order
352365 }
353366
354367 /*----------------------------------------------------------------------
368 | AP4_AvcSegmentBuilder::AP4_AvcSegmentBuilder
369 +---------------------------------------------------------------------*/
370 AP4_AvcSegmentBuilder::AP4_AvcSegmentBuilder(AP4_UI32 track_id,
371 double frames_per_second,
372 AP4_UI64 media_time_origin) :
373 AP4_VideoSegmentBuilder(track_id, frames_per_second, media_time_origin)
374 {
375 }
376
377 /*----------------------------------------------------------------------
378 | AP4_AvcSegmentBuilder::Feed
379 +---------------------------------------------------------------------*/
380 AP4_Result
381 AP4_AvcSegmentBuilder::Feed(const void* data,
382 AP4_Size data_size,
383 AP4_Size& bytes_consumed)
384 {
385 AP4_Result result;
386
387 AP4_AvcFrameParser::AccessUnitInfo access_unit_info;
388 result = m_FrameParser.Feed(data, data_size, bytes_consumed, access_unit_info, data == NULL);
389 if (AP4_FAILED(result)) return result;
390
391 // check if we have an access unit
392 if (access_unit_info.nal_units.ItemCount()) {
393 // compute the total size of the sample data
394 unsigned int sample_data_size = 0;
395 for (unsigned int i=0; i<access_unit_info.nal_units.ItemCount(); i++) {
396 sample_data_size += 4+access_unit_info.nal_units[i]->GetDataSize();
397 }
398
399 // format the sample data
400 AP4_MemoryByteStream* sample_data = new AP4_MemoryByteStream(sample_data_size);
401 for (unsigned int i=0; i<access_unit_info.nal_units.ItemCount(); i++) {
402 sample_data->WriteUI32(access_unit_info.nal_units[i]->GetDataSize());
403 sample_data->Write(access_unit_info.nal_units[i]->GetData(), access_unit_info.nal_units[i]->GetDataSize());
404 }
405
406 // compute the timestamp in a drift-less manner
407 AP4_UI32 duration = 0;
408 AP4_UI64 dts = 0;
409 if (m_Timescale !=0 && m_FramesPerSecond != 0.0) {
410 AP4_UI64 this_sample_time = m_MediaStartTime+m_MediaDuration;
411 AP4_UI64 next_sample_time = (AP4_UI64)((double)m_Timescale*(double)(m_SampleStartNumber+m_Samples.ItemCount()+1)/m_FramesPerSecond);
412 duration = (AP4_UI32)(next_sample_time-this_sample_time);
413 dts = (AP4_UI64)((double)m_Timescale/m_FramesPerSecond*(double)m_Samples.ItemCount());
414 }
415
416 // create a new sample and add it to the list
417 AP4_Sample sample(*sample_data, 0, sample_data_size, duration, 0, dts, 0, access_unit_info.is_idr);
418 AddSample(sample);
419 sample_data->Release();
420
421 // remember the sample order
422 m_SampleOrders.Append(SampleOrder(access_unit_info.decode_order, access_unit_info.display_order));
423
424 // free the memory buffers
425 for (unsigned int i=0; i<access_unit_info.nal_units.ItemCount(); i++) {
426 delete access_unit_info.nal_units[i];
427 }
428 access_unit_info.nal_units.Clear();
429
430 return 1; // one access unit returned
431 }
432
433 return AP4_SUCCESS;
434 }
435
436 /*----------------------------------------------------------------------
355437 | AP4_AvcSegmentBuilder::WriteInitSegment
356438 +---------------------------------------------------------------------*/
357439 AP4_Result
358440 AP4_AvcSegmentBuilder::WriteInitSegment(AP4_ByteStream& stream)
359441 {
360 AP4_Result result;
361
362442 // compute the track parameters
363443 AP4_AvcSequenceParameterSet* sps = NULL;
364444 for (unsigned int i=0; i<=AP4_AVC_SPS_MAX_ID; i++) {
402482 sps->constraint_set2_flag<<5 |
403483 sps->constraint_set3_flag<<4),
404484 4,
485 sps->chroma_format_idc,
486 sps->bit_depth_luma_minus8,
487 sps->bit_depth_chroma_minus8,
405488 sps_array,
406489 pps_array);
407
408 // create the output file object
409 AP4_Movie* output_movie = new AP4_Movie(AP4_SEGMENT_BUILDER_DEFAULT_TIMESCALE);
410
411 // create an mvex container
412 AP4_ContainerAtom* mvex = new AP4_ContainerAtom(AP4_ATOM_TYPE_MVEX);
413 AP4_MehdAtom* mehd = new AP4_MehdAtom(0);
414 mvex->AddChild(mehd);
415
416 // create a sample table (with no samples) to hold the sample description
417 AP4_SyntheticSampleTable* sample_table = new AP4_SyntheticSampleTable();
418 sample_table->AddSampleDescription(sample_description, true);
419
420 // create the track
421 AP4_Track* output_track = new AP4_Track(AP4_Track::TYPE_VIDEO,
422 sample_table,
423 m_TrackId,
424 AP4_SEGMENT_BUILDER_DEFAULT_TIMESCALE,
425 0,
426 m_Timescale,
427 0,
428 m_TrackLanguage.GetChars(),
429 video_width << 16,
430 video_height << 16);
431 output_movie->AddTrack(output_track);
432
433 // add a trex entry to the mvex container
434 AP4_TrexAtom* trex = new AP4_TrexAtom(m_TrackId,
435 1,
436 0,
437 0,
438 0);
439 mvex->AddChild(trex);
440
441 // update the mehd duration
442 // TBD mehd->SetDuration(0);
443
444 // the mvex container to the moov container
445 output_movie->GetMoovAtom()->AddChild(mvex);
446
447 // write the ftyp atom
448 AP4_Array<AP4_UI32> brands;
449 brands.Append(AP4_FILE_BRAND_ISOM);
450 brands.Append(AP4_FILE_BRAND_MP42);
451 brands.Append(AP4_FILE_BRAND_MP41);
452
453 AP4_FtypAtom* ftyp = new AP4_FtypAtom(AP4_FILE_BRAND_MP42, 1, &brands[0], brands.ItemCount());
454 ftyp->Write(stream);
455 delete ftyp;
456
457 // write the moov atom
458 result = output_movie->GetMoovAtom()->Write(stream);
459 if (AP4_FAILED(result)) {
460 return result;
461 }
462
463 // cleanup
464 delete output_movie;
490
491 // let the base class finish the work
492 return AP4_VideoSegmentBuilder::WriteVideoInitSegment(stream,
493 sample_description,
494 video_width,
495 video_height,
496 AP4_FILE_BRAND_AVC1);
497 }
498
499 /*----------------------------------------------------------------------
500 | AP4_HevcSegmentBuilder::AP4_HevcSegmentBuilder
501 +---------------------------------------------------------------------*/
502 AP4_HevcSegmentBuilder::AP4_HevcSegmentBuilder(AP4_UI32 track_id,
503 double frames_per_second,
504 AP4_UI32 video_format,
505 AP4_UI64 media_time_origin) :
506 AP4_VideoSegmentBuilder(track_id, frames_per_second, media_time_origin),
507 m_VideoFormat(video_format)
508 {
509 }
510
511 /*----------------------------------------------------------------------
512 | AP4_HevcSegmentBuilder::Feed
513 +---------------------------------------------------------------------*/
514 AP4_Result
515 AP4_HevcSegmentBuilder::Feed(const void* data,
516 AP4_Size data_size,
517 AP4_Size& bytes_consumed)
518 {
519 AP4_Result result;
520
521 AP4_HevcFrameParser::AccessUnitInfo access_unit_info;
522 result = m_FrameParser.Feed(data, data_size, bytes_consumed, access_unit_info, data == NULL);
523 if (AP4_FAILED(result)) return result;
524
525 // check if we have an access unit
526 if (access_unit_info.nal_units.ItemCount()) {
527 // compute the total size of the sample data
528 unsigned int sample_data_size = 0;
529 for (unsigned int i=0; i<access_unit_info.nal_units.ItemCount(); i++) {
530 sample_data_size += 4+access_unit_info.nal_units[i]->GetDataSize();
531 }
532
533 // format the sample data
534 AP4_MemoryByteStream* sample_data = new AP4_MemoryByteStream(sample_data_size);
535 for (unsigned int i=0; i<access_unit_info.nal_units.ItemCount(); i++) {
536 sample_data->WriteUI32(access_unit_info.nal_units[i]->GetDataSize());
537 sample_data->Write(access_unit_info.nal_units[i]->GetData(), access_unit_info.nal_units[i]->GetDataSize());
538 }
539
540 // compute the timestamp in a drift-less manner
541 AP4_UI32 duration = 0;
542 AP4_UI64 dts = 0;
543 if (m_Timescale !=0 && m_FramesPerSecond != 0.0) {
544 AP4_UI64 this_sample_time = m_MediaStartTime+m_MediaDuration;
545 AP4_UI64 next_sample_time = (AP4_UI64)((double)m_Timescale*(double)(m_SampleStartNumber+m_Samples.ItemCount()+1)/m_FramesPerSecond);
546 duration = (AP4_UI32)(next_sample_time-this_sample_time);
547 dts = (AP4_UI64)((double)m_Timescale/m_FramesPerSecond*(double)m_Samples.ItemCount());
548 }
549
550 // create a new sample and add it to the list
551 AP4_Sample sample(*sample_data, 0, sample_data_size, duration, 0, dts, 0, access_unit_info.is_random_access);
552 AddSample(sample);
553 sample_data->Release();
554
555 // remember the sample order
556 m_SampleOrders.Append(SampleOrder(access_unit_info.decode_order, access_unit_info.display_order));
557
558 // free the memory buffers
559 for (unsigned int i=0; i<access_unit_info.nal_units.ItemCount(); i++) {
560 delete access_unit_info.nal_units[i];
561 }
562 access_unit_info.nal_units.Clear();
563
564 return 1; // one access unit returned
565 }
465566
466567 return AP4_SUCCESS;
568 }
569
570 /*----------------------------------------------------------------------
571 | AP4_HevcSegmentBuilder::WriteInitSegment
572 +---------------------------------------------------------------------*/
573 AP4_Result
574 AP4_HevcSegmentBuilder::WriteInitSegment(AP4_ByteStream& stream)
575 {
576 // check that we have at least one SPS
577 AP4_HevcSequenceParameterSet* sps = NULL;
578 for (unsigned int i=0; i<=AP4_HEVC_SPS_MAX_ID; i++) {
579 sps = m_FrameParser.GetSequenceParameterSets()[i];
580 if (sps) break;
581 }
582 if (sps == NULL) {
583 return AP4_ERROR_INVALID_FORMAT;
584 }
585 unsigned int video_width = 0;
586 unsigned int video_height = 0;
587 sps->GetInfo(video_width, video_height);
588
589 // collect parameters from the first SPS entry
590 // TODO: synthesize from multiple SPS entries if we have more than one
591 AP4_UI08 general_profile_space = sps->profile_tier_level.general_profile_space;
592 AP4_UI08 general_tier_flag = sps->profile_tier_level.general_tier_flag;
593 AP4_UI08 general_profile = sps->profile_tier_level.general_profile_idc;
594 AP4_UI32 general_profile_compatibility_flags = sps->profile_tier_level.general_profile_compatibility_flags;
595 AP4_UI64 general_constraint_indicator_flags = sps->profile_tier_level.general_constraint_indicator_flags;
596 AP4_UI08 general_level = sps->profile_tier_level.general_level_idc;
597 AP4_UI32 min_spatial_segmentation = 0; // TBD (should read from VUI if present)
598 AP4_UI08 parallelism_type = 0; // unknown
599 AP4_UI08 chroma_format = sps->chroma_format_idc;
600 AP4_UI08 luma_bit_depth = 8; // hardcoded temporarily, should be read from the bitstream
601 AP4_UI08 chroma_bit_depth = 8; // hardcoded temporarily, should be read from the bitstream
602 AP4_UI16 average_frame_rate = 0; // unknown
603 AP4_UI08 constant_frame_rate = 0; // unknown
604 AP4_UI08 num_temporal_layers = 0; // unknown
605 AP4_UI08 temporal_id_nested = 0; // unknown
606 AP4_UI08 nalu_length_size = 4;
607
608 // collect the VPS, SPS and PPS into arrays
609 AP4_Array<AP4_DataBuffer> vps_array;
610 for (unsigned int i=0; i<=AP4_HEVC_VPS_MAX_ID; i++) {
611 if (m_FrameParser.GetVideoParameterSets()[i]) {
612 vps_array.Append(m_FrameParser.GetVideoParameterSets()[i]->raw_bytes);
613 }
614 }
615 AP4_Array<AP4_DataBuffer> sps_array;
616 for (unsigned int i=0; i<=AP4_HEVC_SPS_MAX_ID; i++) {
617 if (m_FrameParser.GetSequenceParameterSets()[i]) {
618 sps_array.Append(m_FrameParser.GetSequenceParameterSets()[i]->raw_bytes);
619 }
620 }
621 AP4_Array<AP4_DataBuffer> pps_array;
622 for (unsigned int i=0; i<=AP4_HEVC_PPS_MAX_ID; i++) {
623 if (m_FrameParser.GetPictureParameterSets()[i]) {
624 pps_array.Append(m_FrameParser.GetPictureParameterSets()[i]->raw_bytes);
625 }
626 }
627
628 // setup the video the sample descripton
629 AP4_UI08 parameters_completeness = (m_VideoFormat == AP4_SAMPLE_FORMAT_HVC1 ? 1 : 0);
630 AP4_HevcSampleDescription* sample_description =
631 new AP4_HevcSampleDescription(m_VideoFormat,
632 video_width,
633 video_height,
634 24,
635 "HEVC Coding",
636 general_profile_space,
637 general_tier_flag,
638 general_profile,
639 general_profile_compatibility_flags,
640 general_constraint_indicator_flags,
641 general_level,
642 min_spatial_segmentation,
643 parallelism_type,
644 chroma_format,
645 luma_bit_depth,
646 chroma_bit_depth,
647 average_frame_rate,
648 constant_frame_rate,
649 num_temporal_layers,
650 temporal_id_nested,
651 nalu_length_size,
652 vps_array,
653 parameters_completeness,
654 sps_array,
655 parameters_completeness,
656 pps_array,
657 parameters_completeness);
658
659 // let the base class finish the work
660 return AP4_VideoSegmentBuilder::WriteVideoInitSegment(stream,
661 sample_description,
662 video_width,
663 video_height,
664 AP4_FILE_BRAND_HVC1);
467665 }
468666
469667 /*----------------------------------------------------------------------
550748 bytes_consumed += can_feed;
551749 }
552750 }
553
554751 return AP4_SUCCESS;
555752 }
556753
621818
622819 return result;
623820 }
821
822 /*----------------------------------------------------------------------
823 | AP4_StreamFeeder::AP4_StreamFeeder
824 +---------------------------------------------------------------------*/
825 AP4_StreamFeeder::AP4_StreamFeeder(AP4_ByteStream* source, AP4_FeedSegmentBuilder& builder) :
826 m_Source(source),
827 m_Builder(builder),
828 m_FeedBuffer(NULL),
829 m_FeedBufferSize(0),
830 m_FeedBytesPending(0),
831 m_FeedBytesParsed(0)
832 {
833 AP4_ASSERT(source);
834 source->AddReference();
835 m_FeedBuffer = new AP4_UI08[AP4_STREAM_FEEDER_DEFAULT_BUFFER_SIZE];
836 if (m_FeedBuffer) {
837 m_FeedBufferSize = AP4_STREAM_FEEDER_DEFAULT_BUFFER_SIZE;
838 }
839 }
840
841 /*----------------------------------------------------------------------
842 | AP4_StreamFeeder::~AP4_StreamFeeder
843 +---------------------------------------------------------------------*/
844 AP4_StreamFeeder::~AP4_StreamFeeder()
845 {
846 m_Source->Release();
847 delete[] m_FeedBuffer;
848 }
849
850 /*----------------------------------------------------------------------
851 | AP4_StreamFeeder::Feed
852 +---------------------------------------------------------------------*/
853 AP4_Result
854 AP4_StreamFeeder::Feed()
855 {
856 // read more data if the buffer is empty
857 if (m_FeedBytesPending == 0) {
858 m_FeedBytesParsed = 0;
859 if (!m_FeedBufferSize) return AP4_ERROR_INTERNAL;
860 AP4_Result result = m_Source->ReadPartial(m_FeedBuffer, m_FeedBufferSize, m_FeedBytesPending);
861 if (AP4_FAILED(result)) {
862 return result;
863 }
864 if (m_FeedBytesPending == 0) {
865 return AP4_ERROR_EOS;
866 }
867 }
868
869 // feed the builder
870 AP4_Size bytes_consumed = 0;
871 AP4_Result result = m_Builder.Feed(&m_FeedBuffer[m_FeedBytesParsed], m_FeedBytesPending, bytes_consumed);
872 if (result < 0) return result;
873
874 // update counters
875 m_FeedBytesParsed += bytes_consumed;
876 m_FeedBytesPending -= bytes_consumed;
877
878 return AP4_SUCCESS;
879 }
3333 +---------------------------------------------------------------------*/
3434 #include "Ap4Types.h"
3535 #include "../Codecs/Ap4AvcParser.h"
36 #include "../Codecs/Ap4HevcParser.h"
3637 #include "../Codecs/Ap4AdtsParser.h"
3738 #include "Ap4List.h"
3839 #include "Ap4Sample.h"
3940 #include "Ap4String.h"
4041 #include "Ap4Track.h"
42 #include "Ap4SampleDescription.h"
4143
4244 /*----------------------------------------------------------------------
4345 | class references
6668
6769 // methods
6870 virtual AP4_Result AddSample(AP4_Sample& sample);
71 //virtual AP4_Result CreateTrack(AP4_Track*& track); // create an AP4_Track object representing the media so far
6972 virtual AP4_Result WriteMediaSegment(AP4_ByteStream& stream, unsigned int sequence_number);
7073 virtual AP4_Result WriteInitSegment(AP4_ByteStream& stream) = 0;
7174
9699 // methods
97100 virtual AP4_Result Feed(const void* data,
98101 AP4_Size data_size,
99 AP4_Size& bytes_consumed) = 0;
100 };
101
102 /*----------------------------------------------------------------------
103 | AP4_AvcSegmentBuilder
104 +---------------------------------------------------------------------*/
105 class AP4_AvcSegmentBuilder : public AP4_FeedSegmentBuilder
106 {
107 public:
108 // constructor
109 AP4_AvcSegmentBuilder(AP4_UI32 track_id,
110 double frames_per_second,
111 AP4_UI64 media_time_origin = 0);
102 AP4_Size& bytes_consumed) = 0;
103 };
104
105 /*----------------------------------------------------------------------
106 | AP4_VideoSegmentBuilder
107 +---------------------------------------------------------------------*/
108 class AP4_VideoSegmentBuilder : public AP4_FeedSegmentBuilder
109 {
110 public:
111 // constructor
112 AP4_VideoSegmentBuilder(AP4_UI32 track_id,
113 double frames_per_second,
114 AP4_UI64 media_time_origin = 0);
112115
113116 // AP4_SegmentBuilder methods
114117 virtual AP4_Result WriteMediaSegment(AP4_ByteStream& stream, unsigned int sequence_number);
115 virtual AP4_Result WriteInitSegment(AP4_ByteStream& stream);
116
117 // methods
118 AP4_Result Feed(const void* data,
119 AP4_Size data_size,
120 AP4_Size& bytes_consumed);
121
118
122119 protected:
123120 // types
124121 struct SampleOrder {
125122 SampleOrder(AP4_UI32 decode_order, AP4_UI32 display_order) :
126123 m_DecodeOrder(decode_order),
127124 m_DisplayOrder(display_order) {}
128 AP4_UI32 m_DecodeOrder;
129 AP4_UI32 m_DisplayOrder;
125 AP4_UI32 m_DecodeOrder;
126 AP4_UI32 m_DisplayOrder;
130127 };
131128
132129 // methods
133130 void SortSamples(SampleOrder* array, unsigned int n);
134
135 // members
136 AP4_AvcFrameParser m_FrameParser;
131 AP4_Result WriteVideoInitSegment(AP4_ByteStream& stream,
132 AP4_SampleDescription* sample_description,
133 unsigned int width,
134 unsigned int height,
135 AP4_UI32 brand);
136
137 // members
137138 double m_FramesPerSecond;
138139 AP4_Array<SampleOrder> m_SampleOrders;
139140 };
140141
141142 /*----------------------------------------------------------------------
142 | AP4_AacSegmentBuilder
143 +---------------------------------------------------------------------*/
144 class AP4_AacSegmentBuilder : public AP4_FeedSegmentBuilder
145 {
146 public:
147 // constructor
148 AP4_AacSegmentBuilder(AP4_UI32 track_id, AP4_UI64 media_time_origin = 0);
149 ~AP4_AacSegmentBuilder();
143 | AP4_AvcSegmentBuilder
144 +---------------------------------------------------------------------*/
145 class AP4_AvcSegmentBuilder : public AP4_VideoSegmentBuilder
146 {
147 public:
148 // constructor
149 AP4_AvcSegmentBuilder(AP4_UI32 track_id,
150 double frames_per_second,
151 AP4_UI64 media_time_origin = 0);
150152
151153 // AP4_SegmentBuilder methods
152154 virtual AP4_Result WriteInitSegment(AP4_ByteStream& stream);
158160
159161 protected:
160162 // members
163 AP4_AvcFrameParser m_FrameParser;
164 };
165
166 /*----------------------------------------------------------------------
167 | AP4_HevcSegmentBuilder
168 +---------------------------------------------------------------------*/
169 class AP4_HevcSegmentBuilder : public AP4_VideoSegmentBuilder
170 {
171 public:
172 // constructor
173 AP4_HevcSegmentBuilder(AP4_UI32 track_id,
174 double frames_per_second,
175 AP4_UI32 video_format = AP4_SAMPLE_FORMAT_HEV1,
176 AP4_UI64 media_time_origin = 0);
177
178 // AP4_SegmentBuilder methods
179 virtual AP4_Result WriteInitSegment(AP4_ByteStream& stream);
180
181 // methods
182 AP4_Result Feed(const void* data,
183 AP4_Size data_size,
184 AP4_Size& bytes_consumed);
185
186 protected:
187 // members
188 AP4_HevcFrameParser m_FrameParser;
189 AP4_UI32 m_VideoFormat;
190 };
191
192 /*----------------------------------------------------------------------
193 | AP4_AacSegmentBuilder
194 +---------------------------------------------------------------------*/
195 class AP4_AacSegmentBuilder : public AP4_FeedSegmentBuilder
196 {
197 public:
198 // constructor
199 AP4_AacSegmentBuilder(AP4_UI32 track_id, AP4_UI64 media_time_origin = 0);
200 ~AP4_AacSegmentBuilder();
201
202 // AP4_SegmentBuilder methods
203 virtual AP4_Result WriteInitSegment(AP4_ByteStream& stream);
204
205 // methods
206 AP4_Result Feed(const void* data,
207 AP4_Size data_size,
208 AP4_Size& bytes_consumed);
209
210 protected:
211 // members
161212 AP4_AdtsParser m_FrameParser;
162213 AP4_MpegAudioSampleDescription* m_SampleDescription;
163214 };
164215
216 /*----------------------------------------------------------------------
217 | AP4_StreamFeeder
218 |
219 | Class that can be used to feed an AP4_FeedSegmentBuilder from a stream
220 +---------------------------------------------------------------------*/
221 class AP4_StreamFeeder
222 {
223 public:
224 // constructor and destructor
225 AP4_StreamFeeder(AP4_ByteStream* source, AP4_FeedSegmentBuilder& builder);
226 ~AP4_StreamFeeder();
227
228 // methods
229 AP4_Result Feed(); // Read some data from the stream and feed it to the builder
230
231 private:
232 AP4_ByteStream* m_Source;
233 AP4_FeedSegmentBuilder& m_Builder;
234 AP4_UI08* m_FeedBuffer;
235 AP4_Size m_FeedBufferSize;
236 AP4_Size m_FeedBytesPending; // number of bytes not yet parsed
237 AP4_Size m_FeedBytesParsed; // number of bytes already parsed
238 };
239
165240 #endif // _AP4_SEGMENT_BUILDER_H_
4444 {
4545 AP4_UI08 version;
4646 AP4_UI32 flags;
47 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4748 if (AP4_FAILED(ReadFullHeader(stream, version, flags))) return NULL;
4849 if (version != 0) return NULL;
4950 return new AP4_SencAtom(size, version, flags, stream);
8485 }
8586
8687 /*----------------------------------------------------------------------
88 | AP4_SencAtom::AP4_SencAtom
89 +---------------------------------------------------------------------*/
90 AP4_SencAtom::AP4_SencAtom(AP4_UI08 per_sample_iv_size,
91 AP4_UI08 constant_iv_size,
92 const AP4_UI08* constant_iv,
93 AP4_UI08 crypt_byte_block,
94 AP4_UI08 skip_byte_block):
95 AP4_Atom(AP4_ATOM_TYPE_SENC, AP4_FULL_ATOM_HEADER_SIZE+4, 0, 0),
96 AP4_CencSampleEncryption(*this,
97 per_sample_iv_size,
98 constant_iv_size,
99 constant_iv,
100 crypt_byte_block,
101 skip_byte_block)
102 {
103 }
104
105 /*----------------------------------------------------------------------
87106 | AP4_SencAtom::WriteFields
88107 +---------------------------------------------------------------------*/
89108 AP4_Result
4848 // constructors
4949 AP4_SencAtom(AP4_UI08 iv_size = 16);
5050 AP4_SencAtom(AP4_UI32 algorithm_id,
51 AP4_UI08 iv_size,
51 AP4_UI08 per_sample_iv_size,
5252 const AP4_UI08* kid);
53
53 AP4_SencAtom(AP4_UI08 per_sample_iv_size,
54 AP4_UI08 constant_iv_size,
55 const AP4_UI08* constant_iv,
56 AP4_UI08 crypt_byte_block,
57 AP4_UI08 skip_byte_block);
58
5459 // methods
5560 virtual AP4_Result InspectFields(AP4_AtomInspector& inspector);
5661 virtual AP4_Result WriteFields(AP4_ByteStream& stream);
4747 {
4848 AP4_UI08 version;
4949 AP4_UI32 flags;
50 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
5051 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
5152 if (version > 1) return NULL;
5253 return new AP4_SgpdAtom(size, version, flags, stream);
163164 inspector.AddField("entry_count", m_Entries.ItemCount());
164165
165166 // inspect entries
166 char header[32];
167 unsigned int i=0;
167 inspector.StartArray("entries");
168168 for (AP4_List<AP4_DataBuffer>::Item* item = m_Entries.FirstItem();
169169 item;
170170 item = item->GetNext()) {
171171 AP4_DataBuffer* entry = item->GetData();
172 AP4_FormatString(header, sizeof(header), "entry %02d", i);
173 ++i;
174 inspector.AddField(header, entry->GetData(), entry->GetDataSize());
172 inspector.AddField(NULL, entry->GetData(), entry->GetDataSize());
175173 }
174 inspector.EndArray();
176175
177176 return AP4_SUCCESS;
178177 }
4545 {
4646 AP4_UI08 version;
4747 AP4_UI32 flags;
48 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4849 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4950 if (version > 1) return NULL;
5051 return new AP4_SidxAtom(size, version, flags, stream);
155156
156157 if (inspector.GetVerbosity() >= 1) {
157158 AP4_UI32 reference_count = m_References.ItemCount();
159 inspector.StartArray("entries", reference_count);
158160 for (unsigned int i=0; i<reference_count; i++) {
159 char header[32];
160 AP4_FormatString(header, sizeof(header), "entry %04d", i);
161 char value[256];
162 AP4_FormatString(value, sizeof(value), "reference_type=%d, referenced_size=%u, subsegment_duration=%u, starts_with_SAP=%d, SAP_type=%d, SAP_delta_time=%d",
163 m_References[i].m_ReferenceType,
164 m_References[i].m_ReferencedSize,
165 m_References[i].m_SubsegmentDuration,
166 m_References[i].m_StartsWithSap,
167 m_References[i].m_SapType,
168 m_References[i].m_SapDeltaTime);
169 inspector.AddField(header, value);
161 inspector.StartObject(NULL, 6, true);
162 inspector.AddField("reference_type", m_References[i].m_ReferenceType);
163 inspector.AddField("referenced_size", m_References[i].m_ReferencedSize);
164 inspector.AddField("subsegment_duration", m_References[i].m_SubsegmentDuration);
165 inspector.AddField("starts_with_SAP", m_References[i].m_StartsWithSap);
166 inspector.AddField("SAP_type", m_References[i].m_SapType);
167 inspector.AddField("SAP_delta_time", m_References[i].m_SapDeltaTime);
168 inspector.EndObject();
170169 }
170 inspector.EndArray();
171171 }
172172
173173 return AP4_SUCCESS;
182182 m_References.SetItemCount(count);
183183 m_Size32 += m_References.ItemCount()*12;
184184 }
185
186
187 /*----------------------------------------------------------------------
188 | AP4_SidxAtom::GetDuration
189 +---------------------------------------------------------------------*/
190 AP4_UI64
191 AP4_SidxAtom::GetDuration() {
192
193 AP4_UI64 duration(0);
194 for (AP4_Cardinal i(0); i < m_References.ItemCount(); ++i)
195 duration += m_References[i].m_SubsegmentDuration;
196 return duration;
197 }
9494 const Reference& reference) {
9595 m_References[reference_index] = reference;
9696 }
97 AP4_UI64 GetDuration();
9897
9998 private:
10099 // methods
4040 {
4141 AP4_UI08 version;
4242 AP4_UI32 flags;
43 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4344 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4445 if (version != 0) return NULL;
4546 return new AP4_SmhdAtom(size, version, flags, stream);
4545 {
4646 AP4_UI08 version;
4747 AP4_UI32 flags;
48 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4849 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4950 if (version != 0) return NULL;
5051 return new AP4_StcoAtom(size, version, flags, stream);
7071 AP4_UI08 version,
7172 AP4_UI32 flags,
7273 AP4_ByteStream& stream) :
73 AP4_Atom(AP4_ATOM_TYPE_STCO, size, version, flags)
74 AP4_Atom(AP4_ATOM_TYPE_STCO, size, version, flags),
75 m_Entries(NULL),
76 m_EntryCount(0)
7477 {
78 if (size < AP4_FULL_ATOM_HEADER_SIZE + 4) {
79 return;
80 }
7581 stream.ReadUI32(m_EntryCount);
7682 if (m_EntryCount > (size-AP4_FULL_ATOM_HEADER_SIZE-4)/4) {
7783 m_EntryCount = (size-AP4_FULL_ATOM_HEADER_SIZE-4)/4;
173179 {
174180 inspector.AddField("entry_count", m_EntryCount);
175181 if (inspector.GetVerbosity() >= 1) {
176 char header[32];
182 inspector.StartArray("entries", m_EntryCount);
177183 for (AP4_Ordinal i=0; i<m_EntryCount; i++) {
178 AP4_FormatString(header, sizeof(header), "entry %8d", i);
179 inspector.AddField(header, m_Entries[i]);
184 inspector.AddField(NULL, m_Entries[i]);
180185 }
186 inspector.EndArray();
181187 }
182188
183189 return AP4_SUCCESS;
4040 {
4141 AP4_UI08 version;
4242 AP4_UI32 flags;
43 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4344 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4445 if (version != 0) return NULL;
4546 return new AP4_SthdAtom(size, version, flags, stream);
9999 const AP4_String&
100100 AP4_String::operator=(const AP4_String& s)
101101 {
102 if (&s == this) return s;
102 if (&s == this) return *this;
103103 if (m_Chars != &EmptyString) delete[] m_Chars;
104104 m_Length = s.m_Length;
105105 m_Chars = new char[m_Length+1];
4545 {
4646 AP4_UI08 version;
4747 AP4_UI32 flags;
48 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4849 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4950 if (version != 0) return NULL;
5051 return new AP4_StscAtom(size, version, flags, stream);
7172 {
7273 AP4_UI32 first_sample = 1;
7374 AP4_UI32 entry_count;
75 if (size - AP4_ATOM_HEADER_SIZE < 4) return;
7476 stream.ReadUI32(entry_count);
77 if ((size - AP4_ATOM_HEADER_SIZE - 4)/12 < entry_count) {
78 return;
79 }
7580 m_Entries.SetItemCount(entry_count);
7681 unsigned char* buffer = new unsigned char[entry_count*12];
7782 AP4_Result result = stream.Read(buffer, entry_count*12);
231236
232237 // dump table entries
233238 if (inspector.GetVerbosity() >= 1) {
234 char header[32];
235 char value[256];
239 inspector.StartArray("entries", m_Entries.ItemCount());
236240 for (unsigned int i=0; i<m_Entries.ItemCount(); i++) {
237 AP4_FormatString(header, sizeof(header), "entry %8d", i);
238 AP4_FormatString(value, sizeof(value),
239 "first_chunk=%d, first_sample=%d, chunk_count=%d, samples_per_chunk=%d, sample_desc_index=%d",
240 m_Entries[i].m_FirstChunk,
241 m_Entries[i].m_FirstSample,
242 m_Entries[i].m_ChunkCount,
243 m_Entries[i].m_SamplesPerChunk,
244 m_Entries[i].m_SampleDescriptionIndex);
245 inspector.AddField(header, value);
246 }
241 inspector.StartObject(NULL, 5, true);
242 inspector.AddField("first_chunk", m_Entries[i].m_FirstChunk);
243 inspector.AddField("first_sample", m_Entries[i].m_FirstSample);
244 inspector.AddField("chunk_count", m_Entries[i].m_ChunkCount);
245 inspector.AddField("samples_per_chunk", m_Entries[i].m_SamplesPerChunk);
246 inspector.AddField("sample_desc_index", m_Entries[i].m_SampleDescriptionIndex);
247 inspector.EndObject();
248 }
249 inspector.EndArray();
247250 }
248251
249252 return AP4_SUCCESS;
5050 {
5151 AP4_UI08 version;
5252 AP4_UI32 flags;
53 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
5354 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
5455 if (version > 1) return NULL;
5556 return new AP4_StsdAtom(size, version, flags, stream, atom_factory);
101102 atom))) {
102103 atom->SetParent(this);
103104 m_Children.Add(atom);
105 } else {
106 break;
104107 }
105108 }
106109
209212 AP4_Result
210213 AP4_StsdAtom::InspectFields(AP4_AtomInspector& inspector)
211214 {
212 inspector.AddField("entry-count", m_Children.ItemCount());
215 inspector.AddField("entry_count", m_Children.ItemCount());
213216
214217 // inspect children
215218 m_Children.Apply(AP4_AtomListInspector(inspector));
4545 {
4646 AP4_UI08 version;
4747 AP4_UI32 flags;
48 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4849 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4950 if (version != 0) return NULL;
5051 return new AP4_StssAtom(size, version, flags, stream);
6869 AP4_Atom(AP4_ATOM_TYPE_STSS, size, version, flags),
6970 m_LookupCache(0)
7071 {
72 if (size - AP4_ATOM_HEADER_SIZE < 4) return;
7173 AP4_UI32 entry_count;
7274 stream.ReadUI32(entry_count);
7375
7476 // check for bogus values
75 if (entry_count*4 > size) return;
77 if ((size - AP4_ATOM_HEADER_SIZE - 4) / 4 < entry_count) return;
7678
7779 // read the table into a local array for conversion
7880 unsigned char* buffer = new unsigned char[entry_count*4];
4545 {
4646 AP4_UI08 version;
4747 AP4_UI32 flags;
48 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4849 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4950 if (version != 0) return NULL;
5051 return new AP4_StszAtom(size, version, flags, stream);
6768 AP4_UI08 version,
6869 AP4_UI32 flags,
6970 AP4_ByteStream& stream) :
70 AP4_Atom(AP4_ATOM_TYPE_STSZ, size, version, flags)
71 {
71 AP4_Atom(AP4_ATOM_TYPE_STSZ, size, version, flags),
72 m_SampleSize(0),
73 m_SampleCount(0)
74 {
75 if (size < AP4_FULL_ATOM_HEADER_SIZE + 8) {
76 return;
77 }
78
7279 stream.ReadUI32(m_SampleSize);
7380 stream.ReadUI32(m_SampleCount);
7481 if (m_SampleSize == 0) { // means that the samples have different sizes
75 AP4_Cardinal sample_count = m_SampleCount;
76 m_Entries.SetItemCount(sample_count);
77 unsigned char* buffer = new unsigned char[sample_count*4];
78 AP4_Result result = stream.Read(buffer, sample_count*4);
82 // check for overflow
83 if (m_SampleCount > (size - AP4_FULL_ATOM_HEADER_SIZE - 8) / 4) {
84 return;
85 }
86
87 // read the entries
88 unsigned char* buffer = new unsigned char[m_SampleCount * 4];
89 AP4_Result result = stream.Read(buffer, m_SampleCount * 4);
7990 if (AP4_FAILED(result)) {
8091 delete[] buffer;
8192 return;
8293 }
83 for (unsigned int i=0; i<sample_count; i++) {
84 m_Entries[i] = AP4_BytesToUInt32BE(&buffer[i*4]);
94 m_Entries.SetItemCount((AP4_Cardinal)m_SampleCount);
95 for (unsigned int i = 0; i < m_SampleCount; i++) {
96 m_Entries[i] = AP4_BytesToUInt32BE(&buffer[i * 4]);
8597 }
8698 delete[] buffer;
8799 }
158170 // all samples must have the same size
159171 if (sample_size != m_SampleSize) {
160172 // not the same
161 if (sample == 1) {
173 if (sample == 1 && sample_size != 0) {
162174 // if this is the first sample, update the global size
163175 m_SampleSize = sample_size;
164176 return AP4_SUCCESS;
169181 }
170182 } else {
171183 // each sample has a different size
184 if (sample > m_Entries.ItemCount()) {
185 return AP4_ERROR_OUT_OF_RANGE;
186 }
172187 m_Entries[sample - 1] = sample_size;
173188 }
174189
196211 AP4_StszAtom::InspectFields(AP4_AtomInspector& inspector)
197212 {
198213 inspector.AddField("sample_size", m_SampleSize);
199 inspector.AddField("sample_count", m_Entries.ItemCount());
214 inspector.AddField("sample_count", m_SampleCount);
200215
201216 if (inspector.GetVerbosity() >= 2) {
202 char header[32];
217 inspector.StartArray("entries", m_Entries.ItemCount());
203218 for (AP4_Ordinal i=0; i<m_Entries.ItemCount(); i++) {
204 AP4_FormatString(header, sizeof(header), "entry %8d", i);
205 inspector.AddField(header, m_Entries[i]);
206 }
219 inspector.AddField(NULL, m_Entries[i]);
220 }
221 inspector.EndArray();
207222 }
208223
209224 return AP4_SUCCESS;
4545 {
4646 AP4_UI08 version;
4747 AP4_UI32 flags;
48 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4849 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4950 if (version != 0) return NULL;
5051 return new AP4_SttsAtom(size, version, flags, stream);
132133
133134 // update the sample and dts bases
134135 sample_start += entry.m_SampleCount;
135 dts_start += entry.m_SampleCount*entry.m_SampleDuration;
136 dts_start += (AP4_UI64)entry.m_SampleCount * (AP4_UI64)entry.m_SampleDuration;
136137 }
137138
138139 // sample is greater than the number of samples
220221 inspector.AddField("entry_count", m_Entries.ItemCount());
221222
222223 if (inspector.GetVerbosity() >= 1) {
223 char header[32];
224 char value[256];
224 inspector.StartArray("entries", m_Entries.ItemCount());
225225 for (AP4_Ordinal i=0; i<m_Entries.ItemCount(); i++) {
226 AP4_FormatString(header, sizeof(header), "entry %8d", i);
227 AP4_FormatString(value, sizeof(value),
228 "sample_count=%d, sample_duration=%d",
229 m_Entries[i].m_SampleCount,
230 m_Entries[i].m_SampleDuration);
231 inspector.AddField(header, value);
232 }
226 inspector.StartObject(NULL, 2, true);
227 inspector.AddField("sample_count", m_Entries[i].m_SampleCount);
228 inspector.AddField("sample_duration", m_Entries[i].m_SampleDuration);
229 inspector.EndObject();
230 }
231 inspector.EndArray();
233232 }
234233
235234 return AP4_SUCCESS;
4545 {
4646 AP4_UI08 version;
4747 AP4_UI32 flags;
48 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4849 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4950 if (version != 0) return NULL;
5051 return new AP4_Stz2Atom(size, version, flags, stream);
7071 AP4_UI08 version,
7172 AP4_UI32 flags,
7273 AP4_ByteStream& stream) :
73 AP4_Atom(AP4_ATOM_TYPE_STZ2, size, version, flags)
74 {
74 AP4_Atom(AP4_ATOM_TYPE_STZ2, size, version, flags),
75 m_FieldSize(0),
76 m_SampleCount(0)
77 {
78 if (size < AP4_FULL_ATOM_HEADER_SIZE + 8) {
79 return;
80 }
81
7582 AP4_UI08 reserved;
7683 stream.ReadUI08(reserved);
7784 stream.ReadUI08(reserved);
7885 stream.ReadUI08(reserved);
79 stream.ReadUI08(m_FieldSize);
80 stream.ReadUI32(m_SampleCount);
81 if (m_FieldSize != 4 && m_FieldSize != 8 && m_FieldSize != 16) {
82 // illegale field size
83 return;
84 }
85
86 AP4_Cardinal sample_count = m_SampleCount;
87 m_Entries.SetItemCount(sample_count);
88 unsigned int table_size = (sample_count*m_FieldSize+7)/8;
89 if ((table_size+8) > size) return;
86 AP4_UI08 field_size;
87 stream.ReadUI08(field_size);
88 if (field_size != 4 && field_size != 8 && field_size != 16) {
89 // illegal field size
90 return;
91 }
92 AP4_UI32 sample_count;
93 stream.ReadUI32(sample_count);
94
95 m_FieldSize = field_size;
96 m_SampleCount = sample_count;
97 unsigned int table_size = (sample_count * field_size + 7) / 8;
98 if (table_size > size - AP4_FULL_ATOM_HEADER_SIZE - 8) {
99 return;
100 }
90101 unsigned char* buffer = new unsigned char[table_size];
91102 AP4_Result result = stream.Read(buffer, table_size);
92103 if (AP4_FAILED(result)) {
93104 delete[] buffer;
94105 return;
95106 }
107 m_Entries.SetItemCount((AP4_Cardinal)sample_count);
96108 switch (m_FieldSize) {
97109 case 4:
98110 for (unsigned int i=0; i<sample_count; i++) {
241253 inspector.AddField("sample_count", m_Entries.ItemCount());
242254
243255 if (inspector.GetVerbosity() >= 2) {
244 char header[32];
256 inspector.StartArray("entries");
245257 for (AP4_Ordinal i=0; i<m_Entries.ItemCount(); i++) {
246 AP4_FormatString(header, sizeof(header), "entry %8d", i);
247 inspector.AddField(header, m_Entries[i]);
258 inspector.AddField(NULL, m_Entries[i]);
248259 }
260 inspector.EndArray();
249261 }
250262
251263 return AP4_SUCCESS;
11 |
22 | AP4 - tenc Atoms
33 |
4 | Copyright 2002-2011 Axiomatic Systems, LLC
4 | Copyright 2002-2016 Axiomatic Systems, LLC
55 |
66 |
77 | This file is part of Bento4/AP4 (MP4 Atom Processing Library).
4444 {
4545 AP4_UI08 version;
4646 AP4_UI32 flags;
47 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4748 if (AP4_FAILED(ReadFullHeader(stream, version, flags))) return NULL;
48 if (version != 0) return NULL;
49 return new AP4_TencAtom(size, version, flags, stream);
49 if (version > 1) return NULL;
50 AP4_TencAtom* tenc = new AP4_TencAtom(size, version, flags);
51 if (tenc == NULL) return NULL;
52 AP4_Result result = tenc->Parse(stream);
53 if (AP4_FAILED(result)) {
54 delete tenc;
55 return NULL;
56 }
57
58 return tenc;
5059 }
5160
5261 /*----------------------------------------------------------------------
5362 | AP4_TencAtom::AP4_TencAtom
5463 +---------------------------------------------------------------------*/
55 AP4_TencAtom::AP4_TencAtom(AP4_UI32 default_algorithm_id,
56 AP4_UI08 default_iv_size,
64 AP4_TencAtom::AP4_TencAtom(AP4_UI32 default_is_protected,
65 AP4_UI08 default_per_sample_iv_size,
5766 const AP4_UI08* default_kid) :
5867 AP4_Atom(AP4_ATOM_TYPE_TENC, AP4_FULL_ATOM_HEADER_SIZE+20, 0, 0),
59 AP4_CencTrackEncryption(default_algorithm_id,
60 default_iv_size,
68 AP4_CencTrackEncryption(0,
69 default_is_protected,
70 default_per_sample_iv_size,
6171 default_kid)
6272 {
6373 }
6575 /*----------------------------------------------------------------------
6676 | AP4_TencAtom::AP4_TencAtom
6777 +---------------------------------------------------------------------*/
68 AP4_TencAtom::AP4_TencAtom(AP4_UI32 size,
69 AP4_UI08 version,
70 AP4_UI32 flags,
71 AP4_ByteStream& stream) :
78 AP4_TencAtom::AP4_TencAtom(AP4_UI32 default_is_protected,
79 AP4_UI08 default_per_sample_iv_size,
80 const AP4_UI08* default_kid,
81 AP4_UI08 default_constant_iv_size,
82 const AP4_UI08* default_constant_iv,
83 AP4_UI08 default_crypt_byte_block,
84 AP4_UI08 default_skip_byte_block) :
85 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),
86 AP4_CencTrackEncryption(1,
87 default_is_protected,
88 default_per_sample_iv_size,
89 default_kid,
90 default_constant_iv_size,
91 default_constant_iv,
92 default_crypt_byte_block,
93 default_skip_byte_block)
94 {
95 }
96
97 /*----------------------------------------------------------------------
98 | AP4_TencAtom::Create
99 +---------------------------------------------------------------------*/
100 AP4_TencAtom::AP4_TencAtom(AP4_UI32 size,
101 AP4_UI08 version,
102 AP4_UI32 flags) :
72103 AP4_Atom(AP4_ATOM_TYPE_TENC, size, version, flags),
73 AP4_CencTrackEncryption(stream)
104 AP4_CencTrackEncryption(version)
74105 {
75106 }
76107
4646 static AP4_TencAtom* Create(AP4_Size size, AP4_ByteStream& stream);
4747
4848 // constructors
49 AP4_TencAtom(AP4_UI32 default_algorithm_id,
50 AP4_UI08 default_iv_size,
49 AP4_TencAtom(AP4_UI32 default_is_protected,
50 AP4_UI08 default_per_sample_iv_size,
5151 const AP4_UI08* default_kid);
5252
53 AP4_TencAtom(AP4_UI32 default_is_protected,
54 AP4_UI08 default_per_sample_iv_size,
55 const AP4_UI08* default_kid,
56 AP4_UI08 default_constant_iv_size,
57 const AP4_UI08* default_constant_iv,
58 AP4_UI08 default_crypt_byte_block,
59 AP4_UI08 default_skip_byte_block);
60
5361 // methods
5462 virtual AP4_Result InspectFields(AP4_AtomInspector& inspector);
5563 virtual AP4_Result WriteFields(AP4_ByteStream& stream);
5664
5765 private:
5866 // methods
59 AP4_TencAtom(AP4_UI32 size,
60 AP4_UI08 version,
61 AP4_UI32 flags,
62 AP4_ByteStream& stream);
67 AP4_TencAtom(AP4_UI32 size,
68 AP4_UI08 version,
69 AP4_UI32 flags);
6370 };
6471
6572 #endif // _AP4_TENC_ATOM_H_
4444 {
4545 AP4_UI08 version;
4646 AP4_UI32 flags;
47 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4748 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4849 if (version > 1) return NULL;
4950 return new AP4_TfdtAtom(size, version, flags, stream);
4444 {
4545 AP4_UI08 version;
4646 AP4_UI32 flags;
47 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4748 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4849 if (version > 0) return NULL;
4950 if (size < ComputeSize(flags)) return NULL;
123124 }
124125
125126 /*----------------------------------------------------------------------
127 | AP4_TfhdAtom::UpdateFlags
128 +---------------------------------------------------------------------*/
129 void
130 AP4_TfhdAtom::UpdateFlags(AP4_UI32 flags)
131 {
132 m_Flags = flags;
133 m_Size32 = ComputeSize(flags);
134 }
135
136 /*----------------------------------------------------------------------
126137 | AP4_TfhdAtom::WriteFields
127138 +---------------------------------------------------------------------*/
128139 AP4_Result
8080 AP4_UI32 GetDefaultSampleFlags() { return m_DefaultSampleFlags; }
8181 void SetDefaultSampleFlags(AP4_UI32 flags) { m_DefaultSampleFlags = flags; }
8282
83 void UpdateFlags(AP4_UI32 flags);
84
8385 private:
8486 // methods
8587 AP4_TfhdAtom(AP4_UI32 size,
4545 {
4646 AP4_UI08 version = 0;
4747 AP4_UI32 flags = 0;
48 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4849 AP4_Result result = ReadFullHeader(stream, version, flags);
4950 if (AP4_FAILED(result)) return NULL;
5051 if (version > 1) return NULL;
313314 inspector.AddField("length_size_of_trun_num", m_LengthSizeOfTrunNumber);
314315 inspector.AddField("length_size_of_sample_num", m_LengthSizeOfSampleNumber);
315316 if (inspector.GetVerbosity() >= 1) {
317 inspector.StartArray("entries", m_Entries.ItemCount());
316318 for (unsigned int i=0; i<m_Entries.ItemCount(); i++) {
317 char name[16];
318 char value[256];
319 AP4_FormatString(name, sizeof(name), "entry %04d", i);
320 AP4_FormatString(value, sizeof(value),
321 "time=%lld, moof_offset=%lld, traf_number=%d, trun_number=%d, sample_number=%d",
322 m_Entries[i].m_Time,
323 m_Entries[i].m_MoofOffset,
324 m_Entries[i].m_TrafNumber,
325 m_Entries[i].m_TrunNumber,
326 m_Entries[i].m_SampleNumber);
327 inspector.AddField(name, value);
328 }
319 inspector.StartObject(NULL, 5, true);
320 inspector.AddField("time", m_Entries[i].m_Time);
321 inspector.AddField("moof_offset", m_Entries[i].m_MoofOffset);
322 inspector.AddField("traf_number", m_Entries[i].m_TrafNumber);
323 inspector.AddField("trun_number", m_Entries[i].m_TrunNumber);
324 inspector.AddField("sample_number", m_Entries[i].m_SampleNumber);
325 inspector.EndObject();
326 }
327 inspector.EndArray();
329328 }
330329
331330 return AP4_SUCCESS;
4545 {
4646 AP4_UI08 version;
4747 AP4_UI32 flags;
48 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4849 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4950 if (version > 1) return NULL;
5051 return new AP4_TkhdAtom(size, version, flags, stream);
5354 /*----------------------------------------------------------------------
5455 | AP4_TkhdAtom::AP4_TkhdAtom
5556 +---------------------------------------------------------------------*/
56 AP4_TkhdAtom::AP4_TkhdAtom(AP4_UI32 creation_time,
57 AP4_UI32 modification_time,
57 AP4_TkhdAtom::AP4_TkhdAtom(AP4_UI64 creation_time,
58 AP4_UI64 modification_time,
5859 AP4_UI32 track_id,
5960 AP4_UI64 duration,
6061 AP4_UI16 volume,
9899 m_Reserved2[0] = 0;
99100 m_Reserved2[1] = 0;
100101
101 if (duration > 0xFFFFFFFF) {
102 if (duration > 0xFFFFFFFFULL ||
103 creation_time > 0xFFFFFFFFULL ||
104 modification_time > 0xFFFFFFFFULL) {
102105 m_Version = 1;
103106 m_Size32 += 12;
104107 }
5555 static AP4_TkhdAtom* Create(AP4_Size size, AP4_ByteStream& stream);
5656
5757 // methods
58 AP4_TkhdAtom(AP4_UI32 creation_time,
59 AP4_UI32 modification_time,
58 AP4_TkhdAtom(AP4_UI64 creation_time,
59 AP4_UI64 modification_time,
6060 AP4_UI32 track_id,
6161 AP4_UI64 duration,
6262 AP4_UI16 volume,
5555 AP4_UI64 media_duration,
5656 const char* language,
5757 AP4_UI32 width,
58 AP4_UI32 height) :
58 AP4_UI32 height,
59 AP4_UI64 creation_time,
60 AP4_UI64 modification_time) :
5961 m_TrakAtomIsOwned(true),
6062 m_Type(type),
6163 m_SampleTable(sample_table),
107109 m_TrakAtom = new AP4_TrakAtom(sample_table,
108110 hdlr_type,
109111 hdlr_name,
110 track_id,
111 0,
112 0,
112 track_id,
113 creation_time,
114 modification_time,
113115 track_duration,
114116 media_time_scale,
115117 media_duration,
130132 AP4_UI64 media_duration, // in the media timescale
131133 const AP4_Track* track_prototype) :
132134 m_TrakAtomIsOwned(true),
135 m_Type(track_prototype->m_Type),
133136 m_SampleTable(sample_table),
134137 m_SampleTableIsOwned(true),
135138 m_MovieTimeScale(movie_time_scale ?
180183 hdlr_type,
181184 hdlr_name,
182185 track_id,
183 0,
184 0,
186 tkhd?tkhd->GetCreationTime():0,
187 tkhd?tkhd->GetModificationTime():0,
185188 track_duration,
186189 media_time_scale,
187190 media_duration,
554557 }
555558 return NULL;
556559 }
560
561 /*----------------------------------------------------------------------
562 | AP4_Track::SetTrackLanguage
563 +---------------------------------------------------------------------*/
564 AP4_Result
565 AP4_Track::SetTrackLanguage(const char* language)
566 {
567 if (strlen(language) != 3) {
568 return AP4_ERROR_INVALID_PARAMETERS;
569 }
570
571 if (AP4_MdhdAtom* mdhd = AP4_DYNAMIC_CAST(AP4_MdhdAtom, m_TrakAtom->FindChild("mdia/mdhd"))) {
572 return mdhd->SetLanguage(language);
573 }
574 return AP4_ERROR_INVALID_STATE;
575 }
7676 // methods
7777 AP4_Track(Type type,
7878 AP4_SampleTable* sample_table, // ownership is transfered to the AP4_Track object
79 AP4_UI32 track_id,
79 AP4_UI32 track_id,
8080 AP4_UI32 movie_time_scale, // 0 = use default
8181 AP4_UI64 track_duration, // in the movie timescale
8282 AP4_UI32 media_time_scale,
8383 AP4_UI64 media_duration, // in the media timescale
8484 const char* language,
8585 AP4_UI32 width, // in 16.16 fixed point
86 AP4_UI32 height); // in 16.16 fixed point
87 AP4_Track(AP4_SampleTable* sample_table, // ownership is transfered to the AP4_Track object
88 AP4_UI32 track_id,
86 AP4_UI32 height, // in 16.16 fixed point
87 AP4_UI64 creation_time = 0,
88 AP4_UI64 modification_time = 0);
89 AP4_Track(AP4_SampleTable* sample_table, // ownership is transferred to the AP4_Track object
90 AP4_UI32 track_id,
8991 AP4_UI32 movie_time_scale, // 0 = use default
9092 AP4_UI64 track_duration, // in the movie timescale
9193 AP4_UI32 media_time_scale,
9597 AP4_ByteStream& sample_stream,
9698 AP4_UI32 movie_time_scale);
9799 virtual ~AP4_Track();
98
99 /**
100 * Clone a track. This is useful if you want to create a track from
101 * a non-synthetic track (parsed from a file for example) and
100
101 /**
102 * Clone a track. This is useful if you want to create a track from
103 * a non-synthetic track (parsed from a file for example) and
102104 * write it out
103105 */
104106 AP4_Track* Clone(AP4_Result* result = NULL);
105
107
106108 AP4_UI32 GetFlags() const;
107109 AP4_Result SetFlags(AP4_UI32 flags);
108110 AP4_Track::Type GetType() const { return m_Type; }
113115 AP4_UI32 GetHeight() const; // in 16.16 fixed point
114116 AP4_Cardinal GetSampleCount() const;
115117 AP4_Result GetSample(AP4_Ordinal index, AP4_Sample& sample);
116 AP4_Result ReadSample(AP4_Ordinal index,
118 AP4_Result ReadSample(AP4_Ordinal index,
117119 AP4_Sample& sample,
118120 AP4_DataBuffer& data);
119 AP4_Result GetSampleIndexForTimeStampMs(AP4_UI32 ts_ms,
121 AP4_Result GetSampleIndexForTimeStampMs(AP4_UI32 ts_ms,
120122 AP4_Ordinal& index);
121123 AP4_Ordinal GetNearestSyncSampleIndex(AP4_Ordinal index, bool before=true);
122124 AP4_SampleDescription* GetSampleDescription(AP4_Ordinal index);
132134 AP4_UI64 GetMediaDuration() const; // in the timescale of the media
133135 const char* GetTrackName() const;
134136 const char* GetTrackLanguage() const;
137 AP4_Result SetTrackLanguage(const char* language);
135138 AP4_Result Attach(AP4_MoovAtom* moov);
136139
137140 protected:
+0
-73
lib/libbento4/Core/Ap4TrafAtom.h less more
0 /*****************************************************************
1 |
2 | AP4 - mvhd Atoms
3 |
4 | Copyright 2002-2008 Axiomatic Systems, LLC
5 |
6 |
7 | This file is part of Bento4/AP4 (MP4 Atom Processing Library).
8 |
9 | Unless you have obtained Bento4 under a difference license,
10 | this version of Bento4 is Bento4|GPL.
11 | Bento4|GPL is free software; you can redistribute it and/or modify
12 | it under the terms of the GNU General Public License as published by
13 | the Free Software Foundation; either version 2, or (at your option)
14 | any later version.
15 |
16 | Bento4|GPL is distributed in the hope that it will be useful,
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | GNU General Public License for more details.
20 |
21 | You should have received a copy of the GNU General Public License
22 | along with Bento4|GPL; see the file COPYING. If not, write to the
23 | Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
24 | 02111-1307, USA.
25 |
26 ****************************************************************/
27
28 #ifndef _AP4_TRAF_ATOM_H_
29 #define _AP4_TRAF_ATOM_H_
30
31 /*----------------------------------------------------------------------
32 | includes
33 +---------------------------------------------------------------------*/
34 #include "Ap4ContainerAtom.h"
35
36 /*----------------------------------------------------------------------
37 | AP4_TrafAtom
38 +---------------------------------------------------------------------*/
39 class AP4_TrafAtom : public AP4_ContainerAtom
40 {
41 public:
42 AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_TrafAtom, AP4_ContainerAtom)
43
44 static AP4_TrafAtom* Create(
45 Type type,
46 AP4_UI64 size,
47 bool force_64,
48 AP4_ByteStream& stream,
49 AP4_AtomFactory& atom_factory)
50 {
51 return new AP4_TrafAtom(type, size, force_64, stream, atom_factory);
52 };
53
54 AP4_Atom* Clone();
55
56 void SetInternalTrackId(AP4_UI32 id){ m_InternalTrackId = id;};
57 AP4_UI32 GetInternalTrackId()const{ return m_InternalTrackId; };
58 private:
59 AP4_TrafAtom(Type type);
60
61 AP4_TrafAtom(Type type,
62 AP4_UI64 size,
63 bool force_64,
64 AP4_ByteStream& stream,
65 AP4_AtomFactory& atom_factory)
66 :AP4_ContainerAtom(type, size, force_64, stream, atom_factory)
67 {};
68
69 AP4_UI32 m_InternalTrackId;
70 };
71
72 #endif // _AP4_TRAF_ATOM_H_
5757 AP4_Atom::Type hdlr_type,
5858 const char* hdlr_name,
5959 AP4_UI32 track_id,
60 AP4_UI32 creation_time,
61 AP4_UI32 modification_time,
60 AP4_UI64 creation_time,
61 AP4_UI64 modification_time,
6262 AP4_UI64 track_duration,
6363 AP4_UI32 media_time_scale,
6464 AP4_UI64 media_duration,
314314 AP4_Atom* atom;
315315 if ((atom = FindChild("mdia/minf/stbl/stco")) != NULL) {
316316 AP4_StcoAtom* stco = AP4_DYNAMIC_CAST(AP4_StcoAtom, atom);
317 if (stco == NULL) return AP4_ERROR_INVALID_FORMAT;
317318 return stco->AdjustChunkOffsets((int)delta);
318319 } else if ((atom = FindChild("mdia/minf/stbl/co64")) != NULL) {
319320 AP4_Co64Atom* co64 = AP4_DYNAMIC_CAST(AP4_Co64Atom, atom);
321 if (co64 == NULL) return AP4_ERROR_INVALID_FORMAT;
320322 return co64->AdjustChunkOffsets(delta);
321323 } else {
322324 return AP4_ERROR_INVALID_STATE;
6262 AP4_Atom::Type hdlr_type,
6363 const char* hdlr_name,
6464 AP4_UI32 track_id,
65 AP4_UI32 creation_time,
66 AP4_UI32 modification_time,
65 AP4_UI64 creation_time,
66 AP4_UI64 modification_time,
6767 AP4_UI64 track_duration,
6868 AP4_UI32 media_time_scale,
6969 AP4_UI64 media_duration,
9191 AP4_Result SetWidth(AP4_UI32 width);
9292 AP4_UI32 GetHeight();
9393 AP4_Result SetHeight(AP4_UI32 height);
94 AP4_Atom* Clone(){
95 return AP4_Atom::Clone();
96 };
9794
9895 private:
9996 // methods
4545 {
4646 AP4_UI08 version;
4747 AP4_UI32 flags;
48 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4849 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4950 if (version != 0) return NULL;
5051 return new AP4_TrexAtom(size, version, flags, stream);
6161
6262 // accessors
6363 AP4_UI32 GetTrackId() { return m_TrackId; }
64 void SetTrackId(AP4_UI32 id) { m_TrackId = id; }
65 AP4_UI32 GetDefaultSampleDescriptionIndex() { return m_DefaultSampleDescriptionIndex; }
64 AP4_UI32 GetDefaultSampleDescriptionIndex() { return m_DefaultSampleDescriptionIndex; }
6665 AP4_UI32 GetDefaultSampleDuration() { return m_DefaultSampleDuration; }
6766 AP4_UI32 GetDefaultSampleSize() { return m_DefaultSampleSize; }
6867 AP4_UI32 GetDefaultSampleFlags() { return m_DefaultSampleFlags; }
4444 {
4545 AP4_UI08 version;
4646 AP4_UI32 flags;
47 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4748 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4849 if (version > 1) return NULL;
4950 return new AP4_TrunAtom(size, version, flags, stream);
129130 // Workaround for dazn streams, which provide 24 -> 1 sequences
130131 if (i && m_Entries[i].sample_duration == 1 && m_Entries[i - 1].sample_duration > 1)
131132 {
132 m_Entries[i].sample_duration = m_Entries[i - 1].sample_duration >> 1;
133 m_Entries[i - 1].sample_duration -= m_Entries[i].sample_duration;
133 m_Entries[i].sample_duration = m_Entries[i - 1].sample_duration >> 1;
134 m_Entries[i - 1].sample_duration -= m_Entries[i].sample_duration;
134135 }
135136 --record_fields_count;
136137 }
234235 if (m_Flags & AP4_TRUN_FLAG_FIRST_SAMPLE_FLAGS_PRESENT) {
235236 inspector.AddField("first sample flags", m_FirstSampleFlags, AP4_AtomInspector::HINT_HEX);
236237 }
237 if (inspector.GetVerbosity() == 1) {
238 if (inspector.GetVerbosity() > 0) {
239 inspector.StartArray("entries");
240
238241 AP4_UI32 sample_count = m_Entries.ItemCount();
239 for (unsigned int i=0; i<sample_count; i++) {
240 char header[32];
241 AP4_FormatString(header, sizeof(header), "%04d", i);
242 char v0[32];
243 char v1[32];
244 char v2[32];
245 char v3[64];
246 const char* s0 = "";
247 const char* s1 = "";
248 const char* s2 = "";
249 const char* s3 = "";
250 const char* sep = "";
242 for (unsigned int i = 0; i < sample_count; i++) {
243 inspector.StartObject(NULL, 0, true);
244
251245 if (m_Flags & AP4_TRUN_FLAG_SAMPLE_DURATION_PRESENT) {
252 AP4_FormatString(v0, sizeof(v0), "d:%u", m_Entries[i].sample_duration);
253 s0 = v0;
254 sep = ",";
246 inspector.AddField(inspector.GetVerbosity() >= 2 ? "sample_duration" : "d",
247 m_Entries[i].sample_duration);
255248 }
256249 if (m_Flags & AP4_TRUN_FLAG_SAMPLE_SIZE_PRESENT) {
257 AP4_FormatString(v1, sizeof(v1), "%ss:%u", sep, m_Entries[i].sample_size);
258 s1 = v1;
259 sep = ",";
250 inspector.AddField(inspector.GetVerbosity() >= 2 ? "sample_size" : "s",
251 m_Entries[i].sample_size);
260252 }
261253 if (m_Flags & AP4_TRUN_FLAG_SAMPLE_FLAGS_PRESENT) {
262 AP4_FormatString(v2, sizeof(v2), "%sf:%x", sep, m_Entries[i].sample_flags);
263 s2 = v2;
264 sep = ",";
254 inspector.AddField(inspector.GetVerbosity() >= 2 ? "sample_flags" : "f",
255 m_Entries[i].sample_flags);
265256 }
266257 if (m_Flags & AP4_TRUN_FLAG_SAMPLE_COMPOSITION_TIME_OFFSET_PRESENT) {
267 AP4_FormatString(v3, sizeof(v3), "%sc:%u", sep, m_Entries[i].sample_composition_time_offset);
268 s3 = v3;
269 }
270 char value[128];
271 AP4_FormatString(value, sizeof(value), "%s%s%s%s", s0, s1, s2, s3);
272 inspector.AddField(header, value);
273 }
274 } else if (inspector.GetVerbosity() >= 2) {
275 AP4_UI32 sample_count = m_Entries.ItemCount();
276 for (unsigned int i=0; i<sample_count; i++) {
277 char header[32];
278 AP4_FormatString(header, sizeof(header), "entry %04d", i);
279 char v0[32];
280 char v1[32];
281 char v2[32];
282 char v3[64];
283 const char* s0 = "";
284 const char* s1 = "";
285 const char* s2 = "";
286 const char* s3 = "";
287 const char* sep = "";
288 if (m_Flags & AP4_TRUN_FLAG_SAMPLE_DURATION_PRESENT) {
289 AP4_FormatString(v0, sizeof(v0), "sample_duration:%u", m_Entries[i].sample_duration);
290 s0 = v0;
291 sep = ", ";
292 }
293 if (m_Flags & AP4_TRUN_FLAG_SAMPLE_SIZE_PRESENT) {
294 AP4_FormatString(v1, sizeof(v1), "%ssample_size:%u", sep, m_Entries[i].sample_size);
295 s1 = v1;
296 sep = ", ";
297 }
298 if (m_Flags & AP4_TRUN_FLAG_SAMPLE_FLAGS_PRESENT) {
299 AP4_FormatString(v2, sizeof(v2), "%ssample_flags:%x", sep, m_Entries[i].sample_flags);
300 s2 = v2;
301 sep = ", ";
302 }
303 if (m_Flags & AP4_TRUN_FLAG_SAMPLE_COMPOSITION_TIME_OFFSET_PRESENT) {
304 AP4_FormatString(v3, sizeof(v3), "%ssample_composition_time_offset:%u", sep, m_Entries[i].sample_composition_time_offset);
305 s3 = v3;
306 }
307 char value[128];
308 AP4_FormatString(value, sizeof(value), "%s%s%s%s", s0, s1, s2, s3);
309 inspector.AddField(header, value);
310 }
258 inspector.AddField(inspector.GetVerbosity() >= 2 ? "sample_composition_time_offset" : "c",
259 m_Entries[i].sample_composition_time_offset);
260 }
261
262 inspector.EndObject();
263 }
264
265 inspector.EndArray();
311266 }
312267
313268 return AP4_SUCCESS;
4040 {
4141 AP4_UI08 version;
4242 AP4_UI32 flags;
43 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4344 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4445 if (version != 0) return NULL;
4546 return new AP4_UrlAtom(size, version, flags, stream);
2929 | includes
3030 +---------------------------------------------------------------------*/
3131 #include "Ap4Utils.h"
32 #include "Ap4Debug.h"
3233
3334 /*----------------------------------------------------------------------
3435 | AP4_GlobalOptions::g_Entry
4950 item = item->GetNext()) {
5051 if (item->GetData()->m_Name == name) return item->GetData();
5152 }
52
53
5354 if (autocreate) {
5455 Entry* new_entry = new Entry();
5556 new_entry->m_Name = name;
6768 AP4_GlobalOptions::SetBool(const char* name, bool value)
6869 {
6970 Entry* entry = GetEntry(name, true);
70 entry->m_BoolValue = value;
71 entry->m_Value = value?"true":"false";
7172 }
7273
7374 /*----------------------------------------------------------------------
7879 {
7980 Entry* entry = GetEntry(name, false);
8081 if (entry) {
81 return entry->m_BoolValue;
82 return entry->m_Value == "true";
8283 } else {
8384 return false;
85 }
86 }
87
88 /*----------------------------------------------------------------------
89 | AP4_GlobalOptions::SetString
90 +---------------------------------------------------------------------*/
91 void
92 AP4_GlobalOptions::SetString(const char* name, const char* value)
93 {
94 Entry* entry = GetEntry(name, true);
95 entry->m_Value = value;
96 }
97
98 /*----------------------------------------------------------------------
99 | AP4_GlobalOptions::GetString
100 +---------------------------------------------------------------------*/
101 const char*
102 AP4_GlobalOptions::GetString(const char* name)
103 {
104 Entry* entry = GetEntry(name, false);
105 if (entry) {
106 return entry->m_Value.GetChars();
107 } else {
108 return NULL;
84109 }
85110 }
86111
93118 AP4_UI64 i_value = AP4_BytesToUInt64BE(bytes);
94119 void* v_value = reinterpret_cast<void*>(&i_value);
95120 double* d_value = reinterpret_cast<double*>(v_value);
96
121
97122 return *d_value;
98123 }
99124
103128 AP4_UI64
104129 AP4_BytesToUInt64BE(const unsigned char* bytes)
105130 {
106 return
131 return
107132 ( ((AP4_UI64)bytes[0])<<56 ) |
108133 ( ((AP4_UI64)bytes[1])<<48 ) |
109134 ( ((AP4_UI64)bytes[2])<<40 ) |
111136 ( ((AP4_UI64)bytes[4])<<24 ) |
112137 ( ((AP4_UI64)bytes[5])<<16 ) |
113138 ( ((AP4_UI64)bytes[6])<<8 ) |
114 ( ((AP4_UI64)bytes[7]) );
139 ( ((AP4_UI64)bytes[7]) );
115140 }
116141
117142 /*----------------------------------------------------------------------
122147 {
123148 void* v_value = reinterpret_cast<void*>(&value);
124149 AP4_UI64* i_value = reinterpret_cast<AP4_UI64*>(v_value);
125
150
126151 AP4_BytesFromUInt64BE(bytes, *i_value);
127152 }
128153
143168 }
144169
145170 /*----------------------------------------------------------------------
171 | AP4_ByteSwap16
172 +---------------------------------------------------------------------*/
173 void
174 AP4_ByteSwap16(unsigned char* bytes, unsigned int count) {
175 AP4_ASSERT((count & 1) == 0);
176
177 for (unsigned int i = 0; i < count / 2; i++) {
178 unsigned char tmp = bytes[0];
179 bytes[0] = bytes[1];
180 bytes[1] = tmp;
181 bytes += 2;
182 }
183 }
184
185 /*----------------------------------------------------------------------
146186 | AP4_DurationMsFromUnits
147187 +---------------------------------------------------------------------*/
148188 AP4_UI32
155195 /*----------------------------------------------------------------------
156196 | AP4_ConvertTime
157197 +---------------------------------------------------------------------*/
158 AP4_UI64
198 AP4_UI64
159199 AP4_ConvertTime(AP4_UI64 time_value,
160200 AP4_UI32 from_time_scale,
161201 AP4_UI32 to_time_scale)
252292 | AP4_NibbleHex
253293 +---------------------------------------------------------------------*/
254294 char
255 AP4_NibbleHex(unsigned int nibble)
295 AP4_NibbleHex(unsigned int nibble)
256296 {
257297 if (nibble < 10) {
258298 return (char)('0'+nibble);
286326 *hex++ = AP4_NibbleHex(data[i]>>4);
287327 *hex++ = AP4_NibbleHex(data[i]&0x0F);
288328 }
289
329
290330 return AP4_SUCCESS;
291331 }
292332
293333 /*----------------------------------------------------------------------
294334 | AP4_BitWriter::Write
295335 +---------------------------------------------------------------------*/
296 void
336 void
297337 AP4_BitWriter::Write(AP4_UI32 bits, unsigned int bit_count)
298338 {
299339 unsigned char* data = m_Data;
333373 value = 10*value + (c-'0');
334374 } else {
335375 return 0;
336 }
376 }
337377 }
338378
339379 return value;
388428 }
389429
390430 /*----------------------------------------------------------------------
431 | AP4_BitReader::GetBitsRead
432 +---------------------------------------------------------------------*/
433 unsigned int
434 AP4_BitReader::GetBitsRead()
435 {
436 return 8*m_Position - m_BitsCached;
437 }
438
439 /*----------------------------------------------------------------------
391440 | AP4_BitReader::ReadCache
392441 +---------------------------------------------------------------------*/
393442 AP4_BitReader::BitsWord
406455 AP4_UI32
407456 AP4_BitReader::ReadBits(unsigned int n)
408457 {
458 if (n == 0) return 0;
409459 AP4_BitReader::BitsWord result;
410460 if (m_BitsCached >= n) {
411461 /* we have enough bits in the cache to satisfy the request */
420470 AP4_BitReader::BitsWord cache = m_Cache & AP4_BIT_MASK(m_BitsCached);
421471 n -= m_BitsCached;
422472 m_BitsCached = AP4_WORD_BITS - n;
423 result = (word >> m_BitsCached) | (cache << n);
473 result = m_BitsCached ? (word >> m_BitsCached) | (cache << n) : word;
424474 m_Cache = word;
425475 }
426476
530580 }
531581 }
532582
583 /*----------------------------------------------------------------------
584 | AP4_BitReader::BitsLeft
585 +---------------------------------------------------------------------*/
533586 AP4_UI32
534587 AP4_BitReader::BitsLeft()
535588 {
536 return (m_Buffer.GetDataSize() - m_Position) * 8 + m_BitsCached;
537 }
589 return (m_Buffer.GetDataSize() - m_Position) * 8 + m_BitsCached;
590 }
591
4545 class AP4_GlobalOptions
4646 {
4747 public:
48 static bool GetBool(const char* name);
49 static void SetBool(const char* name, bool value);
50
48 static bool GetBool(const char* name);
49 static void SetBool(const char* name, bool value);
50 static const char* GetString(const char* name);
51 static void SetString(const char* name, const char* value);
52
5153 private:
5254 struct Entry {
5355 AP4_String m_Name;
54 bool m_BoolValue;
56 AP4_String m_Value;
5557 };
5658 static Entry* GetEntry(const char* name, bool autocreate);
5759 static AP4_List<Entry>* g_Entries;
6466 AP4_UI64 AP4_BytesToUInt64BE(const unsigned char* bytes);
6567 void AP4_BytesFromDoubleBE(unsigned char* bytes, double value);
6668 void AP4_BytesFromUInt64BE(unsigned char* bytes, AP4_UI64 value);
69 void AP4_ByteSwap16(unsigned char* bytes, unsigned int count);
6770
6871 /*----------------------------------------------------------------------
6972 | AP4_BytesToUInt32BE
7174 inline AP4_UI32
7275 AP4_BytesToUInt32BE(const unsigned char* bytes)
7376 {
74 return
77 return
7578 ( ((AP4_UI32)bytes[0])<<24 ) |
7679 ( ((AP4_UI32)bytes[1])<<16 ) |
7780 ( ((AP4_UI32)bytes[2])<<8 ) |
78 ( ((AP4_UI32)bytes[3]) );
81 ( ((AP4_UI32)bytes[3]) );
7982 }
8083
8184 /*----------------------------------------------------------------------
9396 inline AP4_UI32
9497 AP4_BytesToUInt24BE(const unsigned char* bytes)
9598 {
96 return
99 return
97100 ( ((AP4_UI32)bytes[0])<<16 ) |
98101 ( ((AP4_UI32)bytes[1])<<8 ) |
99 ( ((AP4_UI32)bytes[2]) );
102 ( ((AP4_UI32)bytes[2]) );
100103 }
101104
102105 /*----------------------------------------------------------------------
105108 inline AP4_UI16
106109 AP4_BytesToUInt16BE(const unsigned char* bytes)
107110 {
108 return
111 return
109112 ( ((AP4_UI16)bytes[0])<<8 ) |
110 ( ((AP4_UI16)bytes[1]) );
113 ( ((AP4_UI16)bytes[1]) );
111114 }
112115
113116 /*----------------------------------------------------------------------
224227 }
225228 }
226229 ~AP4_BitWriter() { delete[] m_Data; }
227
230
228231 void Write(AP4_UI32 bits, unsigned int bit_count);
229
232
230233 unsigned int GetBitCount() { return m_BitCount; }
231234 const unsigned char* GetData() { return m_Data; }
232
235
233236 private:
234237 unsigned char* m_Data;
235238 unsigned int m_DataSize;
259262 void SkipBit();
260263 void SkipBits(unsigned int bit_count);
261264 AP4_UI32 BitsLeft();
265 unsigned int GetBitsRead();
262266
263267 private:
264268 // methods
270274 BitsWord m_Cache;
271275 unsigned int m_BitsCached;
272276 };
273
277
274278 #endif // _AP4_UTILS_H_
3636 /**
3737 * Version number of the SDK
3838 */
39 #define AP4_VERSION 0x01040300
40 #define AP4_VERSION_STRING "1.4.3.0"
39 #define AP4_VERSION 0x01060000
40 #define AP4_VERSION_STRING "1.6.0.0"
4141
4242 #endif // _AP4_VERSION_H_
4141 {
4242 AP4_UI08 version;
4343 AP4_UI32 flags;
44 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
4445 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
4546 if (version != 0) return NULL;
4647 return new AP4_VmhdAtom(size, version, flags, stream);
+0
-71
lib/libbento4/Core/Ap4VpcCAtom.cpp less more
0 /*****************************************************************
1 |
2 | AP4 - VpcC Atom
3 |
4 | Copyright 2018 peak3d
5 |
6 |
7 | This file is part of Bento4/AP4 (MP4 Atom Processing Library).
8 |
9 | Unless you have obtained Bento4 under a difference license,
10 | this version of Bento4 is Bento4|GPL.
11 | Bento4|GPL is free software; you can redistribute it and/or modify
12 | it under the terms of the GNU General Public License as published by
13 | the Free Software Foundation; either version 2, or (at your option)
14 | any later version.
15 |
16 | Bento4|GPL is distributed in the hope that it will be useful,
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | GNU General Public License for more details.
20 |
21 | You should have received a copy of the GNU General Public License
22 | along with Bento4|GPL; see the file COPYING. If not, write to the
23 | Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
24 | 02111-1307, USA.
25 |
26 ****************************************************************/
27
28 /*----------------------------------------------------------------------
29 | includes
30 +---------------------------------------------------------------------*/
31 #include "Ap4Types.h"
32 #include "Ap4VpcCAtom.h"
33 #include "Ap4Utils.h"
34
35 /*----------------------------------------------------------------------
36 | AP4_UuidAtom Dynamic Cast Anchor
37 +---------------------------------------------------------------------*/
38 AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_VpcCAtom)
39
40 /*----------------------------------------------------------------------
41 | AP4_SgpdAtom::Create
42 +---------------------------------------------------------------------*/
43 AP4_VpcCAtom*
44 AP4_VpcCAtom::Create(AP4_Size size, AP4_ByteStream& stream)
45 {
46 AP4_UI08 version;
47 AP4_UI32 flags;
48 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
49 if (version > 1) return NULL;
50 return new AP4_VpcCAtom(size, version, flags, stream);
51 }
52
53 /*----------------------------------------------------------------------
54 | AP4_VpcCAtom::AP4_VpcCAtom
55 +---------------------------------------------------------------------*/
56 AP4_VpcCAtom::AP4_VpcCAtom(AP4_UI64 size, AP4_UI08 version, AP4_UI32 flags, AP4_ByteStream& stream) :
57 AP4_Atom(AP4_ATOM_TYPE_VPCC, size, version, flags)
58 {
59 // store the data
60 m_Data.SetDataSize((AP4_Size)size - GetHeaderSize());
61 stream.Read(m_Data.UseData(), m_Data.GetDataSize());
62 }
63
64 /*----------------------------------------------------------------------
65 | AP4_VpcCAtom::WriteFields
66 +---------------------------------------------------------------------*/
67 AP4_Result AP4_VpcCAtom::WriteFields(AP4_ByteStream& stream)
68 {
69 return stream.Write(m_Data.GetData(), m_Data.GetDataSize());
70 }
+0
-72
lib/libbento4/Core/Ap4VpcCAtom.h less more
0 /*****************************************************************
1 |
2 | AP4 - VpcC Atom
3 |
4 | Copyright 2018 peak3d
5 |
6 |
7 | This file is part of Bento4/AP4 (MP4 Atom Processing Library).
8 |
9 | Unless you have obtained Bento4 under a difference license,
10 | this version of Bento4 is Bento4|GPL.
11 | Bento4|GPL is free software; you can redistribute it and/or modify
12 | it under the terms of the GNU General Public License as published by
13 | the Free Software Foundation; either version 2, or (at your option)
14 | any later version.
15 |
16 | Bento4|GPL is distributed in the hope that it will be useful,
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | GNU General Public License for more details.
20 |
21 | You should have received a copy of the GNU General Public License
22 | along with Bento4|GPL; see the file COPYING. If not, write to the
23 | Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
24 | 02111-1307, USA.
25 |
26 ****************************************************************/
27 /**
28 * @file
29 * @brief UUID Atoms
30 */
31
32 #ifndef _AP4_VPCC_ATOM_H_
33 #define _AP4_VPCC_ATOM_H_
34
35 /*----------------------------------------------------------------------
36 | includes
37 +---------------------------------------------------------------------*/
38 #include "Ap4Atom.h"
39 #include "Ap4ByteStream.h"
40
41 /*----------------------------------------------------------------------
42 | AP4_VpcCAtom
43 +---------------------------------------------------------------------*/
44 /**
45 * Base class for uuid atoms.
46 */
47 class AP4_VpcCAtom : public AP4_Atom {
48 public:
49 AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_VpcCAtom, AP4_Atom)
50
51 // class methods
52 static AP4_VpcCAtom* Create(AP4_Size size, AP4_ByteStream& stream);
53
54 // constructor and destructor
55 virtual ~AP4_VpcCAtom() {};
56
57 // accessors
58 const AP4_DataBuffer &GetData() { return m_Data; }
59
60 // methods
61 virtual AP4_Result InspectFields(AP4_AtomInspector& inspector) { return AP4_ERROR_NOT_SUPPORTED; };
62 virtual AP4_Result WriteFields(AP4_ByteStream& stream);
63
64 protected:
65 // members
66 AP4_VpcCAtom(AP4_UI64 size, AP4_UI08 version, AP4_UI32 flags, AP4_ByteStream& stream);
67
68 AP4_DataBuffer m_Data;
69 };
70
71 #endif // _AP4_UUID_ATOM_H_
0 /*****************************************************************
1 |
2 | AP4 - vpcC Atoms
3 |
4 | Copyright 2002-2020 Axiomatic Systems, LLC
5 |
6 |
7 | This file is part of Bento4/AP4 (MP4 Atom Processing Library).
8 |
9 | Unless you have obtained Bento4 under a difference license,
10 | this version of Bento4 is Bento4|GPL.
11 | Bento4|GPL is free software; you can redistribute it and/or modify
12 | it under the terms of the GNU General Public License as published by
13 | the Free Software Foundation; either version 2, or (at your option)
14 | any later version.
15 |
16 | Bento4|GPL is distributed in the hope that it will be useful,
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | GNU General Public License for more details.
20 |
21 | You should have received a copy of the GNU General Public License
22 | along with Bento4|GPL; see the file COPYING. If not, write to the
23 | Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
24 | 02111-1307, USA.
25 |
26 ****************************************************************/
27
28 /*----------------------------------------------------------------------
29 | includes
30 +---------------------------------------------------------------------*/
31 #include "Ap4VpccAtom.h"
32 #include "Ap4AtomFactory.h"
33 #include "Ap4Utils.h"
34 #include "Ap4Types.h"
35 #include "Ap4DataBuffer.h"
36 #include "Ap4Utils.h"
37
38 /*----------------------------------------------------------------------
39 | dynamic cast support
40 +---------------------------------------------------------------------*/
41 AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_VpccAtom)
42
43 /*----------------------------------------------------------------------
44 | AP4_VpccAtom::Create
45 +---------------------------------------------------------------------*/
46 AP4_VpccAtom*
47 AP4_VpccAtom::Create(AP4_Size size, AP4_ByteStream& stream)
48 {
49 AP4_UI08 version;
50 AP4_UI32 flags;
51 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
52 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
53
54 unsigned int payload_size = size - AP4_FULL_ATOM_HEADER_SIZE;
55 if (payload_size < 8) {
56 return NULL;
57 }
58
59 AP4_UI08 profile;
60 stream.ReadUI08(profile);
61 AP4_UI08 level;
62 stream.ReadUI08(level);
63 AP4_UI08 byte;
64 stream.ReadUI08(byte);
65 AP4_UI08 bit_depth = (byte >> 4) & 0XF;
66 AP4_UI08 chroma_subsampling = (byte >> 1) & 7;
67 bool video_full_range_flag = (byte & 1) != 0;
68 AP4_UI08 colour_primaries;
69 stream.ReadUI08(colour_primaries);
70 AP4_UI08 transfer_characteristics;
71 stream.ReadUI08(transfer_characteristics);
72 AP4_UI08 matrix_coefficients;
73 stream.ReadUI08(matrix_coefficients);
74 AP4_UI16 codec_initialization_data_size = 0;
75 stream.ReadUI16(codec_initialization_data_size);
76 if (codec_initialization_data_size > payload_size - 8) {
77 return NULL;
78 }
79 AP4_DataBuffer codec_initialization_data;
80 AP4_Result result = codec_initialization_data.SetDataSize(codec_initialization_data_size);
81 if (AP4_FAILED(result)) {
82 return NULL;
83 }
84 return new AP4_VpccAtom(profile,
85 level,
86 bit_depth,
87 chroma_subsampling,
88 video_full_range_flag,
89 colour_primaries,
90 transfer_characteristics,
91 matrix_coefficients,
92 codec_initialization_data.GetData(),
93 codec_initialization_data.GetDataSize());
94 }
95
96 /*----------------------------------------------------------------------
97 | AP4_VpccAtom::AP4_VpccAtom
98 +---------------------------------------------------------------------*/
99 AP4_VpccAtom::AP4_VpccAtom(AP4_UI08 profile,
100 AP4_UI08 level,
101 AP4_UI08 bit_depth,
102 AP4_UI08 chroma_subsampling,
103 bool videofull_range_flag,
104 AP4_UI08 colour_primaries,
105 AP4_UI08 transfer_characteristics,
106 AP4_UI08 matrix_coefficients,
107 const AP4_UI08* codec_initialization_data,
108 unsigned int codec_initialization_data_size) :
109 AP4_Atom(AP4_ATOM_TYPE_VPCC, AP4_FULL_ATOM_HEADER_SIZE + 8 + codec_initialization_data_size, 1, 0),
110 m_Profile(profile),
111 m_Level(level),
112 m_BitDepth(bit_depth),
113 m_ChromaSubsampling(chroma_subsampling),
114 m_VideoFullRangeFlag(videofull_range_flag),
115 m_ColourPrimaries(colour_primaries),
116 m_TransferCharacteristics(transfer_characteristics),
117 m_MatrixCoefficients(matrix_coefficients)
118 {
119 if (codec_initialization_data && codec_initialization_data_size) {
120 m_CodecIntializationData.SetData(codec_initialization_data, codec_initialization_data_size);
121 }
122 }
123
124 /*----------------------------------------------------------------------
125 | AP4_VpccAtom::GetCodecString
126 +---------------------------------------------------------------------*/
127 AP4_Result
128 AP4_VpccAtom::GetCodecString(AP4_UI32 container_type, AP4_String& codec)
129 {
130 char type_name[5];
131 AP4_FormatFourChars(type_name, container_type);
132 char string[64];
133 AP4_FormatString(string,
134 sizeof(string),
135 "%s.%02d.%02d.%02d.%02d.%02d.%02d.%02d.%02d",
136 type_name,
137 m_Profile,
138 m_Level,
139 m_BitDepth,
140 m_ChromaSubsampling,
141 m_ColourPrimaries,
142 m_TransferCharacteristics,
143 m_MatrixCoefficients,
144 m_VideoFullRangeFlag ? 1 : 0);
145 codec = string;
146
147 return AP4_SUCCESS;
148 }
149
150 /*----------------------------------------------------------------------
151 | AP4_VpccAtom::WriteFields
152 +---------------------------------------------------------------------*/
153 AP4_Result
154 AP4_VpccAtom::WriteFields(AP4_ByteStream& stream)
155 {
156 stream.WriteUI08(m_Profile);
157 stream.WriteUI08(m_Level);
158 stream.WriteUI08((m_BitDepth << 4) | (m_ChromaSubsampling << 1) | (m_VideoFullRangeFlag ? 1 : 0));
159 stream.WriteUI08(m_ColourPrimaries);
160 stream.WriteUI08(m_TransferCharacteristics);
161 stream.WriteUI08(m_MatrixCoefficients);
162 stream.WriteUI16((AP4_UI16)m_CodecIntializationData.GetDataSize());
163 stream.Write(m_CodecIntializationData.GetData(), m_CodecIntializationData.GetDataSize());
164
165 return AP4_SUCCESS;
166 }
167
168 /*----------------------------------------------------------------------
169 | AP4_VpccAtom::InspectFields
170 +---------------------------------------------------------------------*/
171 AP4_Result
172 AP4_VpccAtom::InspectFields(AP4_AtomInspector& inspector)
173 {
174 inspector.AddField("profile", m_Profile);
175 inspector.AddField("level", m_Level);
176 inspector.AddField("bit depth", m_BitDepth);
177 inspector.AddField("chroma subsampling", m_ChromaSubsampling);
178 inspector.AddField("video full range flag", m_VideoFullRangeFlag);
179 inspector.AddField("colour primaries", m_ColourPrimaries);
180 inspector.AddField("matrix coefficients", m_MatrixCoefficients);
181 inspector.AddField("codec initialization data",
182 m_CodecIntializationData.GetData(),
183 m_CodecIntializationData.GetDataSize());
184 return AP4_SUCCESS;
185 }
0 /*****************************************************************
1 |
2 | AP4 - vpcC Atoms
3 |
4 | Copyright 2002-2020 Axiomatic Systems, LLC
5 |
6 |
7 | This file is part of Bento4/AP4 (MP4 Atom Processing Library).
8 |
9 | Unless you have obtained Bento4 under a difference license,
10 | this version of Bento4 is Bento4|GPL.
11 | Bento4|GPL is free software; you can redistribute it and/or modify
12 | it under the terms of the GNU General Public License as published by
13 | the Free Software Foundation; either version 2, or (at your option)
14 | any later version.
15 |
16 | Bento4|GPL is distributed in the hope that it will be useful,
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | GNU General Public License for more details.
20 |
21 | You should have received a copy of the GNU General Public License
22 | along with Bento4|GPL; see the file COPYING. If not, write to the
23 | Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
24 | 02111-1307, USA.
25 |
26 ****************************************************************/
27
28 #ifndef _AP4_VPCC_ATOM_H_
29 #define _AP4_VPCC_ATOM_H_
30
31 /*----------------------------------------------------------------------
32 | includes
33 +---------------------------------------------------------------------*/
34 #include "Ap4Atom.h"
35 #include "Ap4Array.h"
36 #include "Ap4DataBuffer.h"
37
38 /*----------------------------------------------------------------------
39 | constants
40 +---------------------------------------------------------------------*/
41
42
43 /*----------------------------------------------------------------------
44 | AP4_VpccAtom
45 +---------------------------------------------------------------------*/
46 class AP4_VpccAtom : public AP4_Atom
47 {
48 public:
49 AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_VpccAtom, AP4_Atom)
50
51 // class methods
52 static AP4_VpccAtom* Create(AP4_Size size, AP4_ByteStream& stream);
53
54 // constructors
55 AP4_VpccAtom(AP4_UI08 profile,
56 AP4_UI08 level,
57 AP4_UI08 bit_depth,
58 AP4_UI08 chroma_subsampling,
59 bool videofull_range_flag,
60 AP4_UI08 colour_primaries,
61 AP4_UI08 transfer_characteristics,
62 AP4_UI08 matrix_coefficients,
63 const AP4_UI08* codec_initialization_data,
64 unsigned int codec_initialization_data_size
65 );
66
67 // methods
68 virtual AP4_Result InspectFields(AP4_AtomInspector& inspector);
69 virtual AP4_Result WriteFields(AP4_ByteStream& stream);
70
71 // accessors
72 AP4_UI08 GetProfile() { return m_Profile; }
73 AP4_UI08 GetLevel() { return m_Level; }
74 AP4_UI08 GetBitDepth() { return m_BitDepth; }
75 AP4_UI08 GetChromaSubsampling() { return m_ChromaSubsampling; }
76 bool GetVideoFullRangeFlag() { return m_VideoFullRangeFlag; }
77 AP4_UI08 GetColourPrimaries() { return m_ColourPrimaries; }
78 AP4_UI08 GetTransferCharacteristics() { return m_TransferCharacteristics; }
79 AP4_UI08 GetMatrixCoefficients() { return m_MatrixCoefficients; }
80 const AP4_DataBuffer& GetCodecInitializationData() { return m_CodecIntializationData; }
81 const AP4_DataBuffer& GetData() { return m_Data; }
82
83 // helpers
84 AP4_Result GetCodecString(AP4_UI32 container_type, AP4_String& codec);
85
86 protected:
87 AP4_DataBuffer m_Data;
88 private:
89 // methods
90 AP4_VpccAtom(AP4_UI32 size, const AP4_UI08* payload);
91
92 // members
93 AP4_UI08 m_Profile;
94 AP4_UI08 m_Level;
95 AP4_UI08 m_BitDepth;
96 AP4_UI08 m_ChromaSubsampling;
97 bool m_VideoFullRangeFlag;
98 AP4_UI08 m_ColourPrimaries;
99 AP4_UI08 m_TransferCharacteristics;
100 AP4_UI08 m_MatrixCoefficients;
101 AP4_DataBuffer m_CodecIntializationData;
102 };
103
104 #endif // _AP4_VPCC_ATOM_H_
1010
1111 LICENSE TERMS
1212
13 The free distribution and use of this software in both source and binary
13 The free distribution and use of this software in both source and binary
1414 form is allowed (with or without changes) provided that:
1515
16 1. distributions of this source code include the above copyright
16 1. distributions of this source code include the above copyright
1717 notice, this list of conditions and the following disclaimer;
1818
1919 2. distributions in binary form include the above copyright
2020 notice, this list of conditions and the following disclaimer
2121 in the documentation and/or other associated materials;
2222
23 3. the copyright holder's name is not used to endorse products
24 built using this software without specific written permission.
23 3. the copyright holder's name is not used to endorse products
24 built using this software without specific written permission.
2525
2626 DISCLAIMER
2727
2828 This software is provided 'as is' with no explicit or implied warranties
29 in respect of its properties, including, but not limited to, correctness
29 in respect of its properties, including, but not limited to, correctness
3030 and fitness for purpose.
3131 -------------------------------------------------------------------------
3232 Issue Date: 29/07/2002
3838 #include "Ap4AesBlockCipher.h"
3939 #include "Ap4Results.h"
4040 #include "Ap4Utils.h"
41 #include "Ap4Config.h"
4142
4243 /*----------------------------------------------------------------------
4344 | AES types
6869 /* START OF CONFIGURATION OPTIONS
6970
7071 USE OF DEFINES
71
72 Later in this section there are a number of defines that control the
73 operation of the code. In each section, the purpose of each define is
74 explained so that the relevant form can be included or excluded by
75 setting either 1's or 0's respectively on the branches of the related
72
73 Later in this section there are a number of defines that control the
74 operation of the code. In each section, the purpose of each define is
75 explained so that the relevant form can be included or excluded by
76 setting either 1's or 0's respectively on the branches of the related
7677 #if clauses.
7778 */
7879
7980 /* 1. BYTE ORDER IN 32-BIT WORDS
8081
81 To obtain the highest speed on processors with 32-bit words, this code
82 To obtain the highest speed on processors with 32-bit words, this code
8283 needs to determine the order in which bytes are packed into such words.
83 The following block of code is an attempt to capture the most obvious
84 ways in which various environemnts define byte order. It may well fail,
85 in which case the definitions will need to be set by editing at the
84 The following block of code is an attempt to capture the most obvious
85 ways in which various environments define byte order. It may well fail,
86 in which case the definitions will need to be set by editing at the
8687 points marked **** EDIT HERE IF NECESSARY **** below.
8788 */
8889 #define AES_LITTLE_ENDIAN 1234 /* byte 0 is least significant (i386) */
104105
105106 /* 2. BYTE ORDER WITHIN 32 BIT WORDS
106107
107 The fundamental data processing units in Rijndael are 8-bit bytes. The
108 input, output and key input are all enumerated arrays of bytes in which
109 bytes are numbered starting at zero and increasing to one less than the
110 number of bytes in the array in question. This enumeration is only used
111 for naming bytes and does not imply any adjacency or order relationship
112 from one byte to another. When these inputs and outputs are considered
113 as bit sequences, bits 8*n to 8*n+7 of the bit sequence are mapped to
114 byte[n] with bit 8n+i in the sequence mapped to bit 7-i within the byte.
115 In this implementation bits are numbered from 0 to 7 starting at the
108 The fundamental data processing units in Rijndael are 8-bit bytes. The
109 input, output and key input are all enumerated arrays of bytes in which
110 bytes are numbered starting at zero and increasing to one less than the
111 number of bytes in the array in question. This enumeration is only used
112 for naming bytes and does not imply any adjacency or order relationship
113 from one byte to another. When these inputs and outputs are considered
114 as bit sequences, bits 8*n to 8*n+7 of the bit sequence are mapped to
115 byte[n] with bit 8n+i in the sequence mapped to bit 7-i within the byte.
116 In this implementation bits are numbered from 0 to 7 starting at the
116117 numerically least significant end of each byte (bit n represents 2^n).
117118
118 However, Rijndael can be implemented more efficiently using 32-bit
119 However, Rijndael can be implemented more efficiently using 32-bit
119120 words by packing bytes into words so that bytes 4*n to 4*n+3 are placed
120 into word[n]. While in principle these bytes can be assembled into words
121 in any positions, this implementation only supports the two formats in
121 into word[n]. While in principle these bytes can be assembled into words
122 in any positions, this implementation only supports the two formats in
122123 which bytes in adjacent positions within words also have adjacent byte
123 numbers. This order is called big-endian if the lowest numbered bytes
124 in words have the highest numeric significance and little-endian if the
125 opposite applies.
126
127 This code can work in either order irrespective of the order used by the
124 numbers. This order is called big-endian if the lowest numbered bytes
125 in words have the highest numeric significance and little-endian if the
126 opposite applies.
127
128 This code can work in either order irrespective of the order used by the
128129 machine on which it runs. Normally the internal byte order will be set
129130 to the order of the processor on which the code is to be run but this
130131 define can be used to reverse this in special situations
137138 #define INTERNAL_BYTE_ORDER AES_BIG_ENDIAN
138139 #endif
139140
140 /* 3. FAST INPUT/OUTPUT OPERATIONS.
141
142 On some machines it is possible to improve speed by transferring the
143 bytes in the input and output arrays to and from the internal 32-bit
144 variables by addressing these arrays as if they are arrays of 32-bit
145 words. On some machines this will always be possible but there may
146 be a large performance penalty if the byte arrays are not aligned on
147 the normal word boundaries. On other machines this technique will
141 /* 3. FAST INPUT/OUTPUT OPERATIONS.
142
143 On some machines it is possible to improve speed by transferring the
144 bytes in the input and output arrays to and from the internal 32-bit
145 variables by addressing these arrays as if they are arrays of 32-bit
146 words. On some machines this will always be possible but there may
147 be a large performance penalty if the byte arrays are not aligned on
148 the normal word boundaries. On other machines this technique will
148149 lead to memory access errors when such 32-bit word accesses are not
149 properly aligned. The option SAFE_IO avoids such problems but will
150 often be slower on those machines that support misaligned access
151 (especially so if care is taken to align the input and output byte
152 arrays on 32-bit word boundaries). If SAFE_IO is not defined it is
153 assumed that access to byte arrays as if they are arrays of 32-bit
150 properly aligned. The option SAFE_IO avoids such problems but will
151 often be slower on those machines that support misaligned access
152 (especially so if care is taken to align the input and output byte
153 arrays on 32-bit word boundaries). If SAFE_IO is not defined it is
154 assumed that access to byte arrays as if they are arrays of 32-bit
154155 words will not cause problems when such accesses are misaligned.
155156 */
156157 #if 1
160161 /* 4. LOOP UNROLLING
161162
162163 The code for encryption and decrytpion cycles through a number of rounds
163 that can be implemented either in a loop or by expanding the code into a
164 that can be implemented either in a loop or by expanding the code into a
164165 long sequence of instructions, the latter producing a larger program but
165166 one that will often be much faster. The latter is called loop unrolling.
166167 There are also potential speed advantages in expanding two iterations in
167168 a loop with half the number of iterations, which is called partial loop
168 unrolling. The following options allow partial or full loop unrolling
169 unrolling. The following options allow partial or full loop unrolling
169170 to be set independently for encryption and decryption
170171 */
171172 #if 0
186187
187188 /* 5. FIXED OR DYNAMIC TABLES
188189
189 When this section is included the tables used by the code are comipled
190 statically into the binary file. Otherwise they are computed once when
190 When this section is included the tables used by the code are comipled
191 statically into the binary file. Otherwise they are computed once when
191192 the code is first used.
192193 */
193194 #if 1
196197
197198 /* 6. FAST FINITE FIELD OPERATIONS
198199
199 If this section is included, tables are used to provide faster finite
200 If this section is included, tables are used to provide faster finite
200201 field arithmetic (this has no effect if FIXED_TABLES is defined).
201202 */
202203 #if 1
205206
206207 /* 7. INTERNAL STATE VARIABLE FORMAT
207208
208 The internal state of Rijndael is stored in a number of local 32-bit
209 word varaibles which can be defined either as an array or as individual
209 The internal state of Rijndael is stored in a number of local 32-bit
210 word varaibles which can be defined either as an array or as individual
210211 names variables. Include this section if you want to store these local
211212 variables in arrays. Otherwise individual local variables will be used.
212213 */
216217
217218 /* In this implementation the columns of the state array are each held in
218219 32-bit words. The state array can be held in various ways: in an array
219 of words, in a number of individual word variables or in a number of
220 of words, in a number of individual word variables or in a number of
220221 processor registers. The following define maps a variable name x and
221222 a column number c to the way the state array variable is to be held.
222 The first define below maps the state into an array x[c] whereas the
223 The first define below maps the state into an array x[c] whereas the
223224 second form maps the state into a number of individual variables x0,
224225 x1, etc. Another form could map individual state colums to machine
225226 register names.
245246
246247 This cipher proceeds by repeating in a number of cycles known as 'rounds'
247248 which are implemented by a round function which can optionally be speeded
248 up using tables. The basic tables are each 256 32-bit words, with either
249 up using tables. The basic tables are each 256 32-bit words, with either
249250 one or four tables being required for each round function depending on
250251 how much speed is required. The encryption and decryption round functions
251252 are different and the last encryption and decrytpion round functions are
252253 different again making four different round functions in all.
253254
254255 This means that:
255 1. Normal encryption and decryption rounds can each use either 0, 1
256 1. Normal encryption and decryption rounds can each use either 0, 1
256257 or 4 tables and table spaces of 0, 1024 or 4096 bytes each.
257 2. The last encryption and decryption rounds can also use either 0, 1
258 2. The last encryption and decryption rounds can also use either 0, 1
258259 or 4 tables and table spaces of 0, 1024 or 4096 bytes each.
259260
260261 Include or exclude the appropriate definitions below to set the number
294295 #endif
295296
296297 /* The decryption key schedule can be speeded up with tables in the same
297 way that the round functions can. Include or exclude the following
298 way that the round functions can. Include or exclude the following
298299 defines to set this requirement.
299300 */
300301 #if 1
316317
317318 #if defined(BLOCK_SIZE) && ((BLOCK_SIZE & 3) || BLOCK_SIZE < 16 || BLOCK_SIZE > 32)
318319 #error An illegal block size has been specified.
319 #endif
320 #endif
320321
321322 #if !defined(BLOCK_SIZE)
322323 #define RC_LENGTH 29
331332 #define LAST_ENC_ROUND NO_TABLES
332333 #elif ENC_ROUND == ONE_TABLE && LAST_ENC_ROUND == FOUR_TABLES
333334 #undef LAST_ENC_ROUND
334 #define LAST_ENC_ROUND ONE_TABLE
335 #define LAST_ENC_ROUND ONE_TABLE
335336 #endif
336337
337338 #if ENC_ROUND == NO_TABLES && ENC_UNROLL != NONE
344345 #define LAST_DEC_ROUND NO_TABLES
345346 #elif DEC_ROUND == ONE_TABLE && LAST_DEC_ROUND == FOUR_TABLES
346347 #undef LAST_DEC_ROUND
347 #define LAST_DEC_ROUND ONE_TABLE
348 #define LAST_DEC_ROUND ONE_TABLE
348349 #endif
349350
350351 #if DEC_ROUND == NO_TABLES && DEC_UNROLL != NONE
354355
355356 /* upr(x,n): rotates bytes within words by n positions, moving bytes to
356357 higher index positions with wrap around into low positions
357 ups(x,n): moves bytes by n positions to higher index positions in
358 ups(x,n): moves bytes by n positions to higher index positions in
358359 words but without wrap around
359360 bval(x,n): extracts a byte from a word
360361
361 NOTE: The definitions given here are intended only for use with
362 NOTE: The definitions given here are intended only for use with
362363 unsigned variables and with shift counts that are compile
363364 time constants
364365 */
400401 #if !defined(_MSC_VER)
401402 #define _lrotl(x,n) ((((aes_32t)(x)) << n) | (((aes_32t)(x)) >> (32 - n)))
402403 #endif
403 #define bswap_32(x) ((_lrotl((x),8) & 0x00ff00ff) | (_lrotl((x),24) & 0xff00ff00))
404 #define bswap_32(x) ((_lrotl((x),8) & 0x00ff00ff) | (_lrotl((x),24) & 0xff00ff00))
404405 #endif
405406
406407 #define word_in(x) bswap_32(*(aes_32t*)(x))
423424 give improved performance if a fast 32-bit multiply is not available. Note
424425 that a temporary variable u needs to be defined where FFmulX is used.
425426
426 #define FFmulX(x) (u = (x) & m1, u |= (u >> 1), ((x) & m2) << 1) ^ ((u >> 3) | (u >> 6))
427 #define FFmulX(x) (u = (x) & m1, u |= (u >> 1), ((x) & m2) << 1) ^ ((u >> 3) | (u >> 6))
427428 #define m4 (0x01010101 * BPOLY)
428 #define FFmulX(x) (u = (x) & m1, ((x) & m2) << 1) ^ ((u - (u >> 7)) & m4)
429 #define FFmulX(x) (u = (x) & m1, ((x) & m2) << 1) ^ ((u - (u >> 7)) & m4)
429430 */
430431
431432 /* Work out which tables are needed for the different options */
650651 /*----------------------------------------------------------------------
651652 | tables
652653 +---------------------------------------------------------------------*/
653 #if defined(FIXED_TABLES) || !defined(FF_TABLES)
654 #if defined(FIXED_TABLES) || !defined(FF_TABLES)
654655
655656 /* finite field arithmetic operations */
656657
772773
773774 #define h0(x) (x)
774775
775 /* These defines are used to ensure tables are generated in the
776 /* These defines are used to ensure tables are generated in the
776777 right format depending on the internal byte order required
777778 */
778779
830831 static const aes_32t ft_tab[256] = { sb_data(u0) };
831832 #endif
832833 #ifdef FT4_SET
833 static const aes_32t ft_tab[4][256] =
834 static const aes_32t ft_tab[4][256] =
834835 { { sb_data(u0) }, { sb_data(u1) }, { sb_data(u2) }, { sb_data(u3) } };
835836 #endif
836837
838839 static const aes_32t fl_tab[256] = { sb_data(w0) };
839840 #endif
840841 #ifdef FL4_SET
841 static const aes_32t fl_tab[4][256] =
842 static const aes_32t fl_tab[4][256] =
842843 { { sb_data(w0) }, { sb_data(w1) }, { sb_data(w2) }, { sb_data(w3) } };
843844 #endif
844845
854855 static const aes_32t il_tab[256] = { isb_data(w0) };
855856 #endif
856857 #ifdef IL4_SET
857 static const aes_32t il_tab[4][256] =
858 static const aes_32t il_tab[4][256] =
858859 { { isb_data(w0) }, { isb_data(w1) }, { isb_data(w2) }, { isb_data(w3) } };
859860 #endif
860861
862863 static const aes_32t ls_tab[256] = { sb_data(w0) };
863864 #endif
864865 #ifdef LS4_SET
865 /* GBG: unused?
866 /* GBG: unused?
866867 static const aes_32t ls_tab[4][256] =
867868 { { sb_data(w0) }, { sb_data(w1) }, { sb_data(w2) }, { sb_data(w3) } };
868869 */
872873 static const aes_32t im_tab[256] = { mm_data(v0) };
873874 #endif
874875 #ifdef IM4_SET
875 static const aes_32t im_tab[4][256] =
876 static const aes_32t im_tab[4][256] =
876877 { { mm_data(v0) }, { mm_data(v1) }, { mm_data(v2) }, { mm_data(v3) } };
877878 #endif
878879
937938
938939 /* Generate the tables for the dynamic table option
939940
940 It will generally be sensible to use tables to compute finite
941 field multiplies and inverses but where memory is scarse this
941 It will generally be sensible to use tables to compute finite
942 field multiplies and inverses but where memory is scarse this
942943 code might sometimes be better. But it only has effect during
943944 initialisation so its pretty unimportant in overall terms.
944945 */
950951
951952 static aes_08t hibit(const aes_32t x)
952953 { aes_08t r = (aes_08t)((x >> 1) | (x >> 2));
953
954
954955 r |= (r >> 2);
955956 r |= (r >> 4);
956957 return (r + 1) >> 1;
968969 if(!n1) return v1;
969970
970971 while(n2 >= n1)
971 {
972 {
972973 n2 /= n1; p2 ^= p1 * n2; v2 ^= v1 * n2; n2 = hibit(p2);
973974 }
974
975
975976 if(!n2) return v2;
976977
977978 while(n1 >= n2)
978 {
979 {
979980 n1 /= n2; p1 ^= p2 * n1; v1 ^= v2 * n1; n1 = hibit(p1);
980981 }
981982 }
10151016 root is 0x03, used here to generate the tables
10161017 */
10171018
1018 i = 0; w = 1;
1019 i = 0; w = 1;
10191020 do
1020 {
1021 {
10211022 pow[i] = (aes_08t)w;
10221023 pow[i + 255] = (aes_08t)w;
10231024 log[w] = (aes_08t)i++;
11271128 if(!tab_init) gen_tabs();
11281129 #endif
11291130
1130 if((blen & 7) || blen < 16 || blen > 32)
1131 {
1131 if((blen & 7) || blen < 16 || blen > 32)
1132 {
11321133 cx->n_blk = 0; return aes_bad;
11331134 }
11341135
11431144 This corresponds to bit lengths of 128, 192 and 256 bits, and
11441145 to Nk values of 4, 6 and 8 respectively.
11451146
1146 The following macros implement a single cycle in the key
1147 schedule generation process. The number of cycles needed
1147 The following macros implement a single cycle in the key
1148 schedule generation process. The number of cycles needed
11481149 for each cx->n_col and nk value is:
1149
1150
11501151 nk = 4 5 6 7 8
11511152 ------------------------------
11521153 cx->n_col = 4 10 9 8 7 7
11891190 #if defined(ENCRYPTION_KEY_SCHEDULE)
11901191
11911192 static aes_rval aes_enc_key(const unsigned char in_key[], unsigned int klen, aes_ctx cx[1])
1192 { aes_32t ss[8];
1193 { aes_32t ss[8];
11931194
11941195 #if !defined(FIXED_TABLES)
11951196 if(!tab_init) gen_tabs();
12001201 #else
12011202 cx->n_blk = BLOCK_SIZE;
12021203 #endif
1203
1204
12041205 cx->n_blk = (cx->n_blk & ~3) | 1;
12051206
12061207 cx->k_sch[0] = ss[0] = word_in(in_key );
12121213
12131214 switch(klen)
12141215 {
1215 case 16: ke4(cx->k_sch, 0); ke4(cx->k_sch, 1);
1216 case 16: ke4(cx->k_sch, 0); ke4(cx->k_sch, 1);
12161217 ke4(cx->k_sch, 2); ke4(cx->k_sch, 3);
1217 ke4(cx->k_sch, 4); ke4(cx->k_sch, 5);
1218 ke4(cx->k_sch, 4); ke4(cx->k_sch, 5);
12181219 ke4(cx->k_sch, 6); ke4(cx->k_sch, 7);
1219 ke4(cx->k_sch, 8); kel4(cx->k_sch, 9);
1220 ke4(cx->k_sch, 8); kel4(cx->k_sch, 9);
12201221 cx->n_rnd = 10; break;
12211222 case 24: cx->k_sch[4] = ss[4] = word_in(in_key + 16);
12221223 cx->k_sch[5] = ss[5] = word_in(in_key + 20);
1223 ke6(cx->k_sch, 0); ke6(cx->k_sch, 1);
1224 ke6(cx->k_sch, 0); ke6(cx->k_sch, 1);
12241225 ke6(cx->k_sch, 2); ke6(cx->k_sch, 3);
1225 ke6(cx->k_sch, 4); ke6(cx->k_sch, 5);
1226 ke6(cx->k_sch, 6); kel6(cx->k_sch, 7);
1226 ke6(cx->k_sch, 4); ke6(cx->k_sch, 5);
1227 ke6(cx->k_sch, 6); kel6(cx->k_sch, 7);
12271228 cx->n_rnd = 12; break;
12281229 case 32: cx->k_sch[4] = ss[4] = word_in(in_key + 16);
12291230 cx->k_sch[5] = ss[5] = word_in(in_key + 20);
12301231 cx->k_sch[6] = ss[6] = word_in(in_key + 24);
12311232 cx->k_sch[7] = ss[7] = word_in(in_key + 28);
1232 ke8(cx->k_sch, 0); ke8(cx->k_sch, 1);
1233 ke8(cx->k_sch, 0); ke8(cx->k_sch, 1);
12331234 ke8(cx->k_sch, 2); ke8(cx->k_sch, 3);
1234 ke8(cx->k_sch, 4); ke8(cx->k_sch, 5);
1235 kel8(cx->k_sch, 6);
1235 ke8(cx->k_sch, 4); ke8(cx->k_sch, 5);
1236 kel8(cx->k_sch, 6);
12361237 cx->n_rnd = 14; break;
1237 default: cx->n_rnd = 0; return aes_bad;
1238 default: cx->n_rnd = 0; return aes_bad;
12381239 }
12391240 #else
12401241 { aes_32t i, l;
12581259 for(i = 0; i < l; ++i)
12591260 ke8(cx->k_sch, i);
12601261 break;
1261 default: cx->n_rnd = 0; return aes_bad;
1262 default: cx->n_rnd = 0; return aes_bad;
12621263 }
12631264 }
12641265 #endif
13561357 }
13571358
13581359 static aes_rval aes_dec_key(const unsigned char in_key[], unsigned int klen, aes_ctx cx[1])
1359 { aes_32t ss[8];
1360 { aes_32t ss[8];
13601361 d_vars
13611362
13621363 #if !defined(FIXED_TABLES)
13801381
13811382 switch(klen)
13821383 {
1383 case 16: kdf4(cx->k_sch, 0); kd4(cx->k_sch, 1);
1384 case 16: kdf4(cx->k_sch, 0); kd4(cx->k_sch, 1);
13841385 kd4(cx->k_sch, 2); kd4(cx->k_sch, 3);
1385 kd4(cx->k_sch, 4); kd4(cx->k_sch, 5);
1386 kd4(cx->k_sch, 4); kd4(cx->k_sch, 5);
13861387 kd4(cx->k_sch, 6); kd4(cx->k_sch, 7);
1387 kd4(cx->k_sch, 8); kdl4(cx->k_sch, 9);
1388 kd4(cx->k_sch, 8); kdl4(cx->k_sch, 9);
13881389 cx->n_rnd = 10; break;
13891390 case 24: cx->k_sch[4] = ff(ss[4] = word_in(in_key + 16));
13901391 cx->k_sch[5] = ff(ss[5] = word_in(in_key + 20));
1391 kdf6(cx->k_sch, 0); kd6(cx->k_sch, 1);
1392 kdf6(cx->k_sch, 0); kd6(cx->k_sch, 1);
13921393 kd6(cx->k_sch, 2); kd6(cx->k_sch, 3);
1393 kd6(cx->k_sch, 4); kd6(cx->k_sch, 5);
1394 kd6(cx->k_sch, 6); kdl6(cx->k_sch, 7);
1394 kd6(cx->k_sch, 4); kd6(cx->k_sch, 5);
1395 kd6(cx->k_sch, 6); kdl6(cx->k_sch, 7);
13951396 cx->n_rnd = 12; break;
13961397 case 32: cx->k_sch[4] = ff(ss[4] = word_in(in_key + 16));
13971398 cx->k_sch[5] = ff(ss[5] = word_in(in_key + 20));
13981399 cx->k_sch[6] = ff(ss[6] = word_in(in_key + 24));
13991400 cx->k_sch[7] = ff(ss[7] = word_in(in_key + 28));
1400 kdf8(cx->k_sch, 0); kd8(cx->k_sch, 1);
1401 kdf8(cx->k_sch, 0); kd8(cx->k_sch, 1);
14011402 kd8(cx->k_sch, 2); kd8(cx->k_sch, 3);
1402 kd8(cx->k_sch, 4); kd8(cx->k_sch, 5);
1403 kdl8(cx->k_sch, 6);
1403 kd8(cx->k_sch, 4); kd8(cx->k_sch, 5);
1404 kdl8(cx->k_sch, 6);
14041405 cx->n_rnd = 14; break;
1405 default: cx->n_rnd = 0; return aes_bad;
1406 default: cx->n_rnd = 0; return aes_bad;
14061407 }
14071408 #else
14081409 { aes_32t i, l;
14111412
14121413 switch(klen)
14131414 {
1414 case 16:
1415 case 16:
14151416 for(i = 0; i < l; ++i)
14161417 ke4(cx->k_sch, i);
14171418 break;
14271428 for(i = 0; i < l; ++i)
14281429 ke8(cx->k_sch, i);
14291430 break;
1430 default: cx->n_rnd = 0; return aes_bad;
1431 default: cx->n_rnd = 0; return aes_bad;
14311432 }
14321433 #if (DEC_ROUND != NO_TABLES)
14331434 for(i = nc; i < nc * cx->n_rnd; ++i)
14551456 #define locals(y,x) x[4],y[4]
14561457 #else
14571458 #define locals(y,x) x##0,x##1,x##2,x##3,y##0,y##1,y##2,y##3
1458 /*
1459 /*
14591460 the following defines prevent the compiler requiring the declaration
14601461 of generated but unused variables in the fwd_var and inv_var macros
14611462 */
15691570 #if defined(ENCRYPTION)
15701571
15711572 /* I am grateful to Frank Yellin for the following construction
1572 (and that for decryption) which, given the column (c) of the
1573 output state variable, gives the input state variables which
1573 (and that for decryption) which, given the column (c) of the
1574 output state variable, gives the input state variables which
15741575 are needed in its computation for each row (r) of the state.
15751576
1576 For the fixed block size options, compilers should be able to
1577 reduce this complex expression (and the equivalent one for
1578 decryption) to a static variable reference at compile time.
1577 For the fixed block size options, compilers should be able to
1578 reduce this complex expression (and the equivalent one for
1579 decryption) to a static variable reference at compile time.
15791580 But for variable block size code, there will be some limbs on
15801581 which conditional clauses will be returned.
15811582 */
15821583
1583 /* y = output word, x = input word, r = row, c = column for r = 0,
1584 /* y = output word, x = input word, r = row, c = column for r = 0,
15841585 1, 2 and 3 = column accessed for row r.
15851586 */
15861587
16491650
16501651 if(!(cx->n_blk & 1)) return aes_bad;
16511652
1652 state_in(b0, in_blk, kp);
1653 state_in(b0, in_blk, kp);
16531654
16541655 #if (ENC_UNROLL == FULL)
16551656
16571658
16581659 switch(cx->n_rnd)
16591660 {
1660 case 14: round(fwd_rnd, b1, b0, kp - 4 * nc);
1661 case 14: round(fwd_rnd, b1, b0, kp - 4 * nc);
16611662 round(fwd_rnd, b0, b1, kp - 3 * nc);
1662 case 12: round(fwd_rnd, b1, b0, kp - 2 * nc);
1663 case 12: round(fwd_rnd, b1, b0, kp - 2 * nc);
16631664 round(fwd_rnd, b0, b1, kp - nc);
1664 case 10: round(fwd_rnd, b1, b0, kp );
1665 case 10: round(fwd_rnd, b1, b0, kp );
16651666 round(fwd_rnd, b0, b1, kp + nc);
1666 round(fwd_rnd, b1, b0, kp + 2 * nc);
1667 round(fwd_rnd, b1, b0, kp + 2 * nc);
16671668 round(fwd_rnd, b0, b1, kp + 3 * nc);
1668 round(fwd_rnd, b1, b0, kp + 4 * nc);
1669 round(fwd_rnd, b1, b0, kp + 4 * nc);
16691670 round(fwd_rnd, b0, b1, kp + 5 * nc);
1670 round(fwd_rnd, b1, b0, kp + 6 * nc);
1671 round(fwd_rnd, b1, b0, kp + 6 * nc);
16711672 round(fwd_rnd, b0, b1, kp + 7 * nc);
16721673 round(fwd_rnd, b1, b0, kp + 8 * nc);
16731674 round(fwd_lrnd, b0, b1, kp + 9 * nc);
16741675 }
16751676 #else
1676
1677
16771678 #if (ENC_UNROLL == PARTIAL)
16781679 { aes_32t rnd;
16791680 for(rnd = 0; rnd < (cx->n_rnd >> 1) - 1; ++rnd)
16801681 {
16811682 kp += nc;
1682 round(fwd_rnd, b1, b0, kp);
1683 round(fwd_rnd, b1, b0, kp);
16831684 kp += nc;
1684 round(fwd_rnd, b0, b1, kp);
1685 round(fwd_rnd, b0, b1, kp);
16851686 }
16861687 kp += nc;
16871688 round(fwd_rnd, b1, b0, kp);
16901691 for(rnd = 0; rnd < cx->n_rnd - 1; ++rnd)
16911692 {
16921693 kp += nc;
1693 round(fwd_rnd, p1, p0, kp);
1694 pt = p0, p0 = p1, p1 = pt;
1694 round(fwd_rnd, p1, p0, kp);
1695 pt = p0; p0 = p1; p1 = pt;
16951696 }
16961697 #endif
16971698 kp += nc;
17831784 round(inv_rnd, b0, b1, kp + 3 * nc);
17841785 case 12: round(inv_rnd, b1, b0, kp + 2 * nc);
17851786 round(inv_rnd, b0, b1, kp + nc );
1786 case 10: round(inv_rnd, b1, b0, kp );
1787 case 10: round(inv_rnd, b1, b0, kp );
17871788 round(inv_rnd, b0, b1, kp - nc);
1788 round(inv_rnd, b1, b0, kp - 2 * nc);
1789 round(inv_rnd, b1, b0, kp - 2 * nc);
17891790 round(inv_rnd, b0, b1, kp - 3 * nc);
1790 round(inv_rnd, b1, b0, kp - 4 * nc);
1791 round(inv_rnd, b1, b0, kp - 4 * nc);
17911792 round(inv_rnd, b0, b1, kp - 5 * nc);
1792 round(inv_rnd, b1, b0, kp - 6 * nc);
1793 round(inv_rnd, b1, b0, kp - 6 * nc);
17931794 round(inv_rnd, b0, b1, kp - 7 * nc);
17941795 round(inv_rnd, b1, b0, kp - 8 * nc);
17951796 round(inv_lrnd, b0, b1, kp - 9 * nc);
17961797 }
17971798 #else
1798
1799
17991800 #if (DEC_UNROLL == PARTIAL)
18001801 { aes_32t rnd;
18011802 for(rnd = 0; rnd < (cx->n_rnd >> 1) - 1; ++rnd)
18021803 {
1803 kp -= nc;
1804 round(inv_rnd, b1, b0, kp);
1805 kp -= nc;
1806 round(inv_rnd, b0, b1, kp);
1804 kp -= nc;
1805 round(inv_rnd, b1, b0, kp);
1806 kp -= nc;
1807 round(inv_rnd, b0, b1, kp);
18071808 }
18081809 kp -= nc;
18091810 round(inv_rnd, b1, b0, kp);
18121813 for(rnd = 0; rnd < cx->n_rnd - 1; ++rnd)
18131814 {
18141815 kp -= nc;
1815 round(inv_rnd, p1, p0, kp);
1816 pt = p0, p0 = p1, p1 = pt;
1816 round(inv_rnd, p1, p0, kp);
1817 pt = p0; p0 = p1; p1 = pt;
18171818 }
18181819 #endif
18191820 kp -= nc;
18361837 AP4_AesCbcBlockCipher(CipherDirection direction,
18371838 aes_ctx* context) :
18381839 AP4_AesBlockCipher(direction, CBC, context) {}
1839
1840
18401841 // AP4_BlockCipher methods
1841 virtual AP4_Result Process(const AP4_UI08* input,
1842 virtual AP4_Result Process(const AP4_UI08* input,
18421843 AP4_Size input_size,
18431844 AP4_UI08* output,
18441845 const AP4_UI08* iv);
18471848 /*----------------------------------------------------------------------
18481849 | AP4_AesCbcBlockCipher::Process
18491850 +---------------------------------------------------------------------*/
1850 AP4_Result
1851 AP4_AesCbcBlockCipher::Process(const AP4_UI08* input,
1851 AP4_Result
1852 AP4_AesCbcBlockCipher::Process(const AP4_UI08* input,
18521853 AP4_Size input_size,
18531854 AP4_UI08* output,
18541855 const AP4_UI08* iv)
18571858 if (input_size%AP4_AES_BLOCK_SIZE) {
18581859 return AP4_ERROR_INVALID_PARAMETERS;
18591860 }
1860
1861
18611862 // setup the chaining block from the IV
18621863 AP4_UI08 chaining_block[AP4_AES_BLOCK_SIZE];
18631864 if (iv) {
18651866 } else {
18661867 AP4_SetMemory(chaining_block, 0, AP4_AES_BLOCK_SIZE);
18671868 }
1868
1869
18691870 // process all blocks
18701871 unsigned int block_count = input_size/AP4_AES_BLOCK_SIZE;
18711872 if (m_Direction == ENCRYPT) {
18791880 input += AP4_AES_BLOCK_SIZE;
18801881 output += AP4_AES_BLOCK_SIZE;
18811882 }
1882 } else {
1883 } else {
18831884 for (unsigned int i=0; i<block_count; i++) {
18841885 aes_dec_blk(input, output, m_Context);
18851886 for (unsigned int j=0; j<AP4_AES_BLOCK_SIZE; j++) {
18901891 output += AP4_AES_BLOCK_SIZE;
18911892 }
18921893 }
1893
1894
18941895 return AP4_SUCCESS;
18951896 }
18961897
19051906 aes_ctx* context) :
19061907 AP4_AesBlockCipher(direction, CTR, context)
19071908 /*m_CounterSize(counter_size)*/ {}
1908
1909
19091910 // AP4_BlockCipher methods
1910 virtual AP4_Result Process(const AP4_UI08* input,
1911 virtual AP4_Result Process(const AP4_UI08* input,
19111912 AP4_Size input_size,
19121913 AP4_UI08* output,
19131914 const AP4_UI08* iv);
19191920 /*----------------------------------------------------------------------
19201921 | AP4_AesCtrBlockCipher::Process
19211922 +---------------------------------------------------------------------*/
1922 AP4_Result
1923 AP4_AesCtrBlockCipher::Process(const AP4_UI08* input,
1923 AP4_Result
1924 AP4_AesCtrBlockCipher::Process(const AP4_UI08* input,
19241925 AP4_Size input_size,
19251926 AP4_UI08* output,
19261927 const AP4_UI08* iv)
19321933 } else {
19331934 AP4_SetMemory(counter, 0, AP4_AES_BLOCK_SIZE);
19341935 }
1935
1936
19361937 // process all blocks
19371938 while (input_size) {
19381939 AP4_UI08 block[AP4_AES_BLOCK_SIZE];
19531954 break;
19541955 }
19551956 }
1956
1957
19571958 // move to the next block
19581959 input += AP4_AES_BLOCK_SIZE;
19591960 output += AP4_AES_BLOCK_SIZE;
19661967 | AP4_AesBlockCipher::Create
19671968 +---------------------------------------------------------------------*/
19681969 AP4_Result
1969 AP4_AesBlockCipher::Create(const AP4_UI08* key,
1970 AP4_AesBlockCipher::Create(const AP4_UI08* key,
19701971 CipherDirection direction,
19711972 CipherMode mode,
19721973 const void* mode_params,
19751976 cipher = NULL;
19761977
19771978 aes_ctx* context = new aes_ctx();
1978
1979
19791980 switch (mode) {
19801981 case AP4_BlockCipher::CBC:
19811982 if (direction == AP4_BlockCipher::ENCRYPT) {
19851986 }
19861987 cipher = new AP4_AesCbcBlockCipher(direction, context);
19871988 break;
1988
1989
19891990 case AP4_BlockCipher::CTR: {
19901991 aes_enc_key(key, AP4_AES_KEY_LENGTH, context);
19911992 const AP4_BlockCipher::CtrParams* ctr_params = (const AP4_BlockCipher::CtrParams*)mode_params;
19961997 cipher = new AP4_AesCtrBlockCipher(direction, counter_size, context);
19971998 break;
19981999 }
1999
2000
20002001 default:
20012002 return AP4_ERROR_INVALID_PARAMETERS;
20022003 }
518518 return DecryptBuffer(in, in_size, out, out_size, is_last_buffer);
519519 }
520520 }
521
522 /*----------------------------------------------------------------------
523 | AP4_PatternStreamCipher
524 +---------------------------------------------------------------------*/
525 AP4_PatternStreamCipher::AP4_PatternStreamCipher(AP4_StreamCipher* cipher,
526 AP4_UI08 crypt_byte_block,
527 AP4_UI08 skip_byte_block) :
528 m_Cipher(cipher),
529 m_CryptByteBlock(crypt_byte_block),
530 m_SkipByteBlock(skip_byte_block),
531 m_StreamOffset(0)
532 {
533 }
534
535 /*----------------------------------------------------------------------
536 | AP4_PatternStreamCipher::~AP4_PatternStreamCipher
537 +---------------------------------------------------------------------*/
538 AP4_PatternStreamCipher::~AP4_PatternStreamCipher()
539 {
540 delete m_Cipher;
541 }
542
543 /*----------------------------------------------------------------------
544 | AP4_PatternStreamCipher::SetStreamOffset
545 +---------------------------------------------------------------------*/
546 AP4_Result
547 AP4_PatternStreamCipher::SetStreamOffset(AP4_UI64 /*offset*/,
548 AP4_Cardinal* /*preroll*/)
549 {
550 return AP4_ERROR_NOT_SUPPORTED;
551 }
552
553 /*----------------------------------------------------------------------
554 | AP4_PatternStreamCipher
555 +---------------------------------------------------------------------*/
556 AP4_Result
557 AP4_PatternStreamCipher::ProcessBuffer(const AP4_UI08* in,
558 AP4_Size in_size,
559 AP4_UI08* out,
560 AP4_Size* out_size,
561 bool /* is_last_buffer */)
562 {
563 // set default return values
564 *out_size = 0;
565
566 // check that the range is block-aligned (required by the spec for pattern encryption)
567 if (m_StreamOffset % 16) return AP4_ERROR_INVALID_FORMAT;
568
569 // compute where we are in the pattern
570 unsigned int pattern_span = m_CryptByteBlock+m_SkipByteBlock;
571 unsigned int block_position = (unsigned int)(m_StreamOffset/16);
572 unsigned int pattern_position = block_position % pattern_span;
573
574 // process the range
575 while (*out_size < in_size) {
576 unsigned int crypt_size = 0;
577 unsigned int skip_size = m_SkipByteBlock*16;
578 if (pattern_position < m_CryptByteBlock) {
579 // in the encrypted part
580 crypt_size = (m_CryptByteBlock-pattern_position)*16;
581 } else {
582 // in the skipped part
583 skip_size = (pattern_span-pattern_position)*16;
584 }
585
586 // clip
587 AP4_Size remain = in_size-*out_size;
588 if (crypt_size > remain) {
589 crypt_size = 16*(remain/16);
590 skip_size = remain-crypt_size;
591 }
592 if (crypt_size+skip_size > remain) {
593 skip_size = remain-crypt_size;
594 }
595
596 // encrypted part
597 if (crypt_size) {
598 AP4_Size in_chunk_size = crypt_size;
599 AP4_Size out_chunk_size = crypt_size;
600
601 AP4_Result result = m_Cipher->ProcessBuffer(in, in_chunk_size, out, &out_chunk_size);
602 if (AP4_FAILED(result)) return result;
603 // check that we got back what we expectected
604 if (out_chunk_size != in_chunk_size) {
605 return AP4_ERROR_INTERNAL;
606 }
607 in += crypt_size;
608 out += crypt_size;
609 *out_size += crypt_size;
610 m_StreamOffset += crypt_size;
611 }
612
613 // skipped part
614 if (skip_size) {
615 AP4_CopyMemory(out, in, skip_size);
616 in += skip_size;
617 out += skip_size;
618 *out_size += skip_size;
619 m_StreamOffset += skip_size;
620 }
621
622 // we're now at the start of a new pattern
623 pattern_position = 0;
624 }
625
626 return AP4_SUCCESS;
627 }
628
629 /*----------------------------------------------------------------------
630 | AP4_PatternStreamCipher
631 +---------------------------------------------------------------------*/
632 AP4_Result
633 AP4_PatternStreamCipher::SetIV(const AP4_UI08* iv)
634 {
635 m_StreamOffset = 0;
636 return m_Cipher->SetIV(iv);
637 }
638
639 /*----------------------------------------------------------------------
640 | AP4_PatternStreamCipher
641 +---------------------------------------------------------------------*/
642 const AP4_UI08*
643 AP4_PatternStreamCipher::GetIV()
644 {
645 return m_Cipher->GetIV();
646 }
164164 bool is_last_buffer);
165165 };
166166
167 /*----------------------------------------------------------------------
168 | AP4_PatternStreamCipher
169 +---------------------------------------------------------------------*/
170 class AP4_PatternStreamCipher : public AP4_StreamCipher
171 {
172 public:
173 // methods
174
175 /**
176 * The stream cipher is passed with transfer of ownership (it will
177 * be destroyed when this object is destroyed).
178 */
179 AP4_PatternStreamCipher(AP4_StreamCipher* cipher, AP4_UI08 crypt_byte_block, AP4_UI08 skip_byte_block);
180 ~AP4_PatternStreamCipher();
181
182 // AP4_StreamCipher implementation
183 virtual AP4_Result SetStreamOffset(AP4_UI64 offset,
184 AP4_Cardinal* preroll);
185 virtual AP4_UI64 GetStreamOffset() { return m_StreamOffset; }
186 virtual AP4_Result ProcessBuffer(const AP4_UI08* in,
187 AP4_Size in_size,
188 AP4_UI08* out,
189 AP4_Size* out_size,
190 bool is_last_buffer = false);
191 virtual AP4_Result SetIV(const AP4_UI08* iv);
192 virtual const AP4_UI08* GetIV();
193
194 private:
195 // members
196 AP4_StreamCipher* m_Cipher;
197 AP4_UI08 m_CryptByteBlock;
198 AP4_UI08 m_SkipByteBlock;
199 AP4_UI64 m_StreamOffset;
200 };
201
167202 #endif // _AP4_STREAM_CIPHER_H_
782782
783783 // not supported
784784 return AP4_ERROR_NOT_SUPPORTED;
785 } else if (m_Key.GetNamespace() == "3gpp") {
786 // convert the name into an atom type
787 if (m_Key.GetName().GetLength() != 4) {
788 // the name is not in the right format
789 return AP4_ERROR_INVALID_PARAMETERS;
790 }
791 AP4_Atom::Type atom_type = AP4_Atom::TypeFromString(m_Key.GetName().GetChars());
792
793 if (AP4_MetaDataAtomTypeHandler::IsTypeInList(atom_type,
794 AP4_MetaDataAtomTypeHandler::_3gppLocalizedStringTypeList)) {
795 AP4_String atom_value = m_Value->ToString();
796 const char* language = "eng"; // default
797 if (m_Value->GetLanguage().GetLength() != 0) {
798 language = m_Value->GetLanguage().GetChars();
799 }
800 atom = new AP4_3GppLocalizedStringAtom(atom_type, language, atom_value.GetChars());
801 return AP4_SUCCESS;
802 }
803
804 // not supported
805 return AP4_ERROR_NOT_SUPPORTED;
785806 } else {
786807 // create a '----' atom
787808 AP4_ContainerAtom* container = new AP4_ContainerAtom(AP4_ATOM_TYPE_dddd);
846867 AP4_Atom* atom;
847868 AP4_Result result = ToAtom(atom);
848869 if (AP4_FAILED(result)) return result;
849 AP4_ContainerAtom* entry_atom = AP4_DYNAMIC_CAST(AP4_ContainerAtom, atom);
850 if (entry_atom == NULL) {
851 return AP4_ERROR_INVALID_FORMAT;
852 }
853870
854871 // look for the 'moov'
855872 AP4_Movie* movie = file.GetMovie();
856 if (movie == NULL) return AP4_ERROR_INVALID_FORMAT;
873 if (movie == NULL) {
874 delete atom;
875 return AP4_ERROR_INVALID_FORMAT;
876 }
857877 AP4_MoovAtom* moov = movie->GetMoovAtom();
858 if (moov == NULL) return AP4_ERROR_INVALID_FORMAT;
878 if (moov == NULL) {
879 delete atom;
880 return AP4_ERROR_INVALID_FORMAT;
881 }
859882
860883 // look for 'udta', and create if it does not exist
861884 AP4_ContainerAtom* udta = AP4_DYNAMIC_CAST(AP4_ContainerAtom, moov->FindChild("udta", true));
883906 // look if there is already a container for this entry
884907 AP4_ContainerAtom* existing = FindInIlst(ilst);
885908 if (existing == NULL) {
909 // look for a simple entry with the same type
910 AP4_Atom* previous = ilst->GetChild(atom->GetType());
911 if (previous) {
912 ilst->RemoveChild(previous);
913 }
914
886915 // just add the one we have
887 ilst->AddChild(entry_atom);
916 ilst->AddChild(atom);
888917 } else {
889918 // add the entry's data to the existing entry
919 AP4_ContainerAtom* entry_atom = AP4_DYNAMIC_CAST(AP4_ContainerAtom, atom);
920 if (entry_atom == NULL) {
921 return AP4_ERROR_INVALID_FORMAT;
922 }
923
890924 AP4_DataAtom* data_atom = AP4_DYNAMIC_CAST(AP4_DataAtom, entry_atom->GetChild(AP4_ATOM_TYPE_DATA));
891925 if (data_atom == NULL) return AP4_ERROR_INTERNAL;
892926 entry_atom->RemoveChild(data_atom);
917951 // convert the entry into an atom
918952 AP4_Atom* data_atom;
919953 AP4_Result result = ToAtom(data_atom);
954 if (AP4_FAILED(result)) return result;
955
956 // add the entry's data to the container
957 return udta->AddChild(data_atom, index);
958 }
959
960 /*----------------------------------------------------------------------
961 | AP4_MetaData::Entry::AddToFileUdta
962 +---------------------------------------------------------------------*/
963 AP4_Result
964 AP4_MetaData::Entry::AddToFileUdta(AP4_File& file, AP4_Ordinal index)
965 {
966 // check that we have a correct entry
967 if (m_Value == NULL) return AP4_ERROR_INVALID_STATE;
968
969 // convert the entry into an atom
970 AP4_Atom* atom;
971 AP4_Result result = ToAtom(atom);
972 if (AP4_FAILED(result)) return result;
973
974 // look for the 'moov'
975 AP4_Movie* movie = file.GetMovie();
976 if (movie == NULL) return AP4_ERROR_INVALID_FORMAT;
977 AP4_MoovAtom* moov = movie->GetMoovAtom();
978 if (moov == NULL) return AP4_ERROR_INVALID_FORMAT;
979
980 // look for 'udta', and create if it does not exist
981 AP4_ContainerAtom* udta = AP4_DYNAMIC_CAST(AP4_ContainerAtom, moov->FindChild("udta", true));
982 if (udta == NULL) return AP4_ERROR_INTERNAL;
983
984 // convert the entry into an atom
985 AP4_Atom* data_atom;
986 result = ToAtom(data_atom);
920987 if (AP4_FAILED(result)) return result;
921988
922989 // add the entry's data to the container
9371004 return AddToFileIlst(file, index);
9381005 } else if (m_Key.GetNamespace() == "dcf") {
9391006 return AddToFileDcf(file, index);
1007 } else if (m_Key.GetNamespace() == "3gpp") {
1008 return AddToFileUdta(file, index);
9401009 } else {
9411010 // custom namespace
9421011 return AddToFileIlst(file, index);
10041073 }
10051074
10061075 /*----------------------------------------------------------------------
1076 | AP4_MetaData::Entry::RemoveFromFileUdta
1077 +---------------------------------------------------------------------*/
1078 AP4_Result
1079 AP4_MetaData::Entry::RemoveFromFileUdta(AP4_File& file, AP4_Ordinal index)
1080 {
1081 // look for the 'moov'
1082 AP4_Movie* movie = file.GetMovie();
1083 if (movie == NULL) return AP4_ERROR_INVALID_FORMAT;
1084 AP4_MoovAtom* moov = movie->GetMoovAtom();
1085 if (moov == NULL) return AP4_ERROR_INVALID_FORMAT;
1086
1087 // look for 'udta'
1088 AP4_ContainerAtom* udta = AP4_DYNAMIC_CAST(AP4_ContainerAtom, moov->FindChild("udta"));
1089 if (udta == NULL) return AP4_ERROR_NO_SUCH_ITEM;
1090
1091 // remove the data atom in the entry
1092 AP4_UI32 type = AP4_BytesToUInt32BE((const unsigned char*)m_Key.GetName().GetChars());
1093 AP4_Result result = udta->DeleteChild(type, index);
1094 if (AP4_FAILED(result)) return result;
1095
1096 return AP4_SUCCESS;
1097 }
1098
1099 /*----------------------------------------------------------------------
10071100 | AP4_MetaData::Entry::RemoveFromFile
10081101 +---------------------------------------------------------------------*/
10091102 AP4_Result
10141107 return RemoveFromFileIlst(file, index);
10151108 } else if (m_Key.GetNamespace() == "dcf") {
10161109 return RemoveFromFileDcf(file, index);
1110 } else if (m_Key.GetNamespace() == "3gpp") {
1111 return RemoveFromFileUdta(file, index);
10171112 } else {
10181113 // custom namespace
10191114 return RemoveFromFileIlst(file, index);
12571352 +---------------------------------------------------------------------*/
12581353 AP4_DataAtom::AP4_DataAtom(const AP4_MetaData::Value& value) :
12591354 AP4_Atom(AP4_ATOM_TYPE_DATA, AP4_ATOM_HEADER_SIZE),
1260 m_DataType(DATA_TYPE_BINARY)
1261 {
1262 AP4_MemoryByteStream* memory = new AP4_MemoryByteStream(256);
1355 m_DataType(DATA_TYPE_BINARY),
1356 m_Source(NULL)
1357 {
1358 AP4_MemoryByteStream* memory = new AP4_MemoryByteStream();
12631359 AP4_Size payload_size = 8;
12641360 m_Source = memory;
12651361
13331429 | AP4_DataAtom::AP4_DataAtom
13341430 +---------------------------------------------------------------------*/
13351431 AP4_DataAtom::AP4_DataAtom(AP4_UI32 size, AP4_ByteStream& stream) :
1336 AP4_Atom(AP4_ATOM_TYPE_DATA, size)
1432 AP4_Atom(AP4_ATOM_TYPE_DATA, size),
1433 m_Source(NULL)
13371434 {
13381435 if (size < AP4_ATOM_HEADER_SIZE+8) return;
13391436
15671664 {
15681665 AP4_UI08 version;
15691666 AP4_UI32 flags;
1667 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
15701668 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
15711669 if (version != 0) return NULL;
15721670 return new AP4_3GppLocalizedStringAtom(type, size, version, flags, stream);
16601758 {
16611759 AP4_UI08 version;
16621760 AP4_UI32 flags;
1761 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
16631762 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
16641763 if (version != 0) return NULL;
16651764 return new AP4_DcfStringAtom(type, size, version, flags, stream);
17221821 {
17231822 AP4_UI08 version;
17241823 AP4_UI32 flags;
1824 if (size < AP4_FULL_ATOM_HEADER_SIZE) return NULL;
17251825 if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
17261826 if (version != 0) return NULL;
17271827 if (size != AP4_FULL_ATOM_HEADER_SIZE+4) return NULL;
225225 AP4_Result AddToFile(AP4_File& file, AP4_Ordinal index = 0);
226226 AP4_Result AddToFileIlst(AP4_File& file, AP4_Ordinal index = 0);
227227 AP4_Result AddToFileDcf(AP4_File& file, AP4_Ordinal index = 0);
228 AP4_Result AddToFileUdta(AP4_File& file, AP4_Ordinal index = 0);
228229 AP4_Result RemoveFromFile(AP4_File& file, AP4_Ordinal index);
229230 AP4_Result RemoveFromFileIlst(AP4_File& file, AP4_Ordinal index);
230231 AP4_Result RemoveFromFileDcf(AP4_File& file, AP4_Ordinal index);
232 AP4_Result RemoveFromFileUdta(AP4_File& file, AP4_Ordinal index);
231233 AP4_ContainerAtom* FindInIlst(AP4_ContainerAtom* ilst) const;
232234 AP4_Result ToAtom(AP4_Atom*& atom) const;
233235
0 /*****************************************************************
1 |
2 | AP4 - Android File Byte Stream implementation
3 |
4 | Copyright 2002-2016 Axiomatic Systems, LLC
5 |
6 |
7 | This file is part of Bento4/AP4 (MP4 Atom Processing Library).
8 |
9 | Unless you have obtained Bento4 under a difference license,
10 | this version of Bento4 is Bento4|GPL.
11 | Bento4|GPL is free software; you can redistribute it and/or modify
12 | it under the terms of the GNU General Public License as published by
13 | the Free Software Foundation; either version 2, or (at your option)
14 | any later version.
15 |
16 | Bento4|GPL is distributed in the hope that it will be useful,
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | GNU General Public License for more details.
20 |
21 | You should have received a copy of the GNU General Public License
22 | along with Bento4|GPL; see the file COPYING. If not, write to the
23 | Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
24 | 02111-1307, USA.
25 |
26 ****************************************************************/
27
28 /*----------------------------------------------------------------------
29 | includes
30 +---------------------------------------------------------------------*/
31 #include <stdio.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <sys/stat.h>
35 #include <unistd.h>
36 #include <fcntl.h>
37
38 #include "Ap4FileByteStream.h"
39
40 /*----------------------------------------------------------------------
41 | AP4_AndroidFileByteStream
42 +---------------------------------------------------------------------*/
43 class AP4_AndroidFileByteStream: public AP4_ByteStream
44 {
45 public:
46 // class methods
47 static AP4_Result Create(AP4_FileByteStream* delegator,
48 const char* name,
49 AP4_FileByteStream::Mode mode,
50 AP4_ByteStream*& stream);
51
52 // methods
53 AP4_AndroidFileByteStream(AP4_FileByteStream* delegator,
54 int fd,
55 AP4_LargeSize size);
56
57 ~AP4_AndroidFileByteStream();
58
59 // AP4_ByteStream methods
60 AP4_Result ReadPartial(void* buffer,
61 AP4_Size bytesToRead,
62 AP4_Size& bytesRead);
63 AP4_Result WritePartial(const void* buffer,
64 AP4_Size bytesToWrite,
65 AP4_Size& bytesWritten);
66 AP4_Result Seek(AP4_Position position);
67 AP4_Result Tell(AP4_Position& position);
68 AP4_Result GetSize(AP4_LargeSize& size);
69 AP4_Result Flush();
70
71 // AP4_Referenceable methods
72 void AddReference();
73 void Release();
74
75 private:
76 // members
77 AP4_ByteStream* m_Delegator;
78 AP4_Cardinal m_ReferenceCount;
79 int m_FD;
80 AP4_Position m_Position;
81 AP4_LargeSize m_Size;
82 };
83
84 /*----------------------------------------------------------------------
85 | AP4_AndroidFileByteStream::Create
86 +---------------------------------------------------------------------*/
87 AP4_Result
88 AP4_AndroidFileByteStream::Create(AP4_FileByteStream* delegator,
89 const char* name,
90 AP4_FileByteStream::Mode mode,
91 AP4_ByteStream*& stream)
92 {
93 // default value
94 stream = NULL;
95
96 // check arguments
97 if (name == NULL) return AP4_ERROR_INVALID_PARAMETERS;
98
99 // open the file
100 int fd = 0;
101 AP4_Position size = 0;
102 if (!strcmp(name, "-stdin")) {
103 fd = STDIN_FILENO;
104 } else if (!strcmp(name, "-stdout")) {
105 fd = STDOUT_FILENO;
106 } else if (!strcmp(name, "-stderr")) {
107 fd = STDERR_FILENO;
108 } else {
109 int open_flags = 0;
110 int create_perm = 0;
111 switch (mode) {
112 case AP4_FileByteStream::STREAM_MODE_READ:
113 open_flags = O_RDONLY;
114 break;
115
116 case AP4_FileByteStream::STREAM_MODE_WRITE:
117 open_flags = O_RDWR | O_CREAT | O_TRUNC;
118 break;
119
120 case AP4_FileByteStream::STREAM_MODE_READ_WRITE:
121 open_flags = O_RDWR;
122 break;
123
124 default:
125 return AP4_ERROR_INVALID_PARAMETERS;
126 }
127
128 fd = open(name, open_flags, create_perm);
129 if (fd < 0) {
130 if (errno == ENOENT) {
131 return AP4_ERROR_NO_SUCH_FILE;
132 } else if (errno == EACCES) {
133 return AP4_ERROR_PERMISSION_DENIED;
134 } else {
135 return AP4_ERROR_CANNOT_OPEN_FILE;
136 }
137 }
138
139 // get the size
140 struct stat info;
141 if (stat(name, &info) == 0) {
142 size = info.st_size;
143 }
144 }
145
146 stream = new AP4_AndroidFileByteStream(delegator, fd, size);
147 return AP4_SUCCESS;
148 }
149
150 /*----------------------------------------------------------------------
151 | AP4_AndroidFileByteStream::AP4_AndroidFileByteStream
152 +---------------------------------------------------------------------*/
153 AP4_AndroidFileByteStream::AP4_AndroidFileByteStream(AP4_FileByteStream* delegator,
154 int fd,
155 AP4_LargeSize size) :
156 m_Delegator(delegator),
157 m_ReferenceCount(1),
158 m_FD(fd),
159 m_Position(0),
160 m_Size(size)
161 {
162 }
163
164 /*----------------------------------------------------------------------
165 | AP4_AndroidFileByteStream::~AP4_AndroidFileByteStream
166 +---------------------------------------------------------------------*/
167 AP4_AndroidFileByteStream::~AP4_AndroidFileByteStream()
168 {
169 if (m_FD && m_FD != STDERR_FILENO && m_FD != STDOUT_FILENO && m_FD != STDERR_FILENO) {
170 close(m_FD);
171 }
172 }
173
174 /*----------------------------------------------------------------------
175 | AP4_AndroidFileByteStream::AddReference
176 +---------------------------------------------------------------------*/
177 void
178 AP4_AndroidFileByteStream::AddReference()
179 {
180 m_ReferenceCount++;
181 }
182
183 /*----------------------------------------------------------------------
184 | AP4_AndroidFileByteStream::Release
185 +---------------------------------------------------------------------*/
186 void
187 AP4_AndroidFileByteStream::Release()
188 {
189 if (--m_ReferenceCount == 0) {
190 if (m_Delegator) {
191 delete m_Delegator;
192 } else {
193 delete this;
194 }
195 }
196 }
197
198 /*----------------------------------------------------------------------
199 | AP4_AndroidFileByteStream::ReadPartial
200 +---------------------------------------------------------------------*/
201 AP4_Result
202 AP4_AndroidFileByteStream::ReadPartial(void* buffer,
203 AP4_Size bytes_to_read,
204 AP4_Size& bytes_read)
205 {
206 ssize_t nb_read = read(m_FD, buffer, bytes_to_read);
207
208 if (nb_read > 0) {
209 bytes_read = (AP4_Size)nb_read;
210 m_Position += nb_read;
211 return AP4_SUCCESS;
212 } else if (nb_read == 0) {
213 bytes_read = 0;
214 return AP4_ERROR_EOS;
215 } else {
216 bytes_read = 0;
217 return AP4_ERROR_READ_FAILED;
218 }
219 }
220
221 /*----------------------------------------------------------------------
222 | AP4_AndroidFileByteStream::WritePartial
223 +---------------------------------------------------------------------*/
224 AP4_Result
225 AP4_AndroidFileByteStream::WritePartial(const void* buffer,
226 AP4_Size bytes_to_write,
227 AP4_Size& bytes_written)
228 {
229 if (bytes_to_write == 0) {
230 bytes_written = 0;
231 return AP4_SUCCESS;
232 }
233 ssize_t nb_written = write(m_FD, buffer, bytes_to_write);
234
235 if (nb_written > 0) {
236 bytes_written = (AP4_Size)nb_written;
237 m_Position += nb_written;
238 return AP4_SUCCESS;
239 } else {
240 bytes_written = 0;
241 return AP4_ERROR_WRITE_FAILED;
242 }
243 }
244
245 /*----------------------------------------------------------------------
246 | AP4_AndroidFileByteStream::Seek
247 +---------------------------------------------------------------------*/
248 AP4_Result
249 AP4_AndroidFileByteStream::Seek(AP4_Position position)
250 {
251 // shortcut
252 if (position == m_Position) return AP4_SUCCESS;
253
254 off64_t result = lseek64(m_FD, position, SEEK_SET);
255 if (result >= 0) {
256 m_Position = position;
257 return AP4_SUCCESS;
258 } else {
259 return AP4_FAILURE;
260 }
261 }
262
263 /*----------------------------------------------------------------------
264 | AP4_AndroidFileByteStream::Tell
265 +---------------------------------------------------------------------*/
266 AP4_Result
267 AP4_AndroidFileByteStream::Tell(AP4_Position& position)
268 {
269 position = m_Position;
270 return AP4_SUCCESS;
271 }
272
273 /*----------------------------------------------------------------------
274 | AP4_AndroidFileByteStream::GetSize
275 +---------------------------------------------------------------------*/
276 AP4_Result
277 AP4_AndroidFileByteStream::GetSize(AP4_LargeSize& size)
278 {
279 size = m_Size;
280 return AP4_SUCCESS;
281 }
282
283 /*----------------------------------------------------------------------
284 | AP4_AndroidFileByteStream::Flush
285 +---------------------------------------------------------------------*/
286 AP4_Result
287 AP4_AndroidFileByteStream::Flush()
288 {
289 return AP4_SUCCESS;
290 }
291
292 /*----------------------------------------------------------------------
293 | AP4_FileByteStream::Create
294 +---------------------------------------------------------------------*/
295 AP4_Result
296 AP4_FileByteStream::Create(const char* name,
297 AP4_FileByteStream::Mode mode,
298 AP4_ByteStream*& stream)
299 {
300 return AP4_AndroidFileByteStream::Create(NULL, name, mode, stream);
301 }
302
303 #if !defined(AP4_CONFIG_NO_EXCEPTIONS)
304 /*----------------------------------------------------------------------
305 | AP4_FileByteStream::AP4_FileByteStream
306 +---------------------------------------------------------------------*/
307 AP4_FileByteStream::AP4_FileByteStream(const char* name,
308 AP4_FileByteStream::Mode mode)
309 {
310 AP4_ByteStream* stream = NULL;
311 AP4_Result result = AP4_AndroidFileByteStream::Create(this, name, mode, stream);
312 if (AP4_FAILED(result)) throw AP4_Exception(result);
313
314 m_Delegate = stream;
315 }
316 #endif
317
318
319
320
321
322
323
324
325
326
327
2929 | includes
3030 +---------------------------------------------------------------------*/
3131 #define _LARGEFILE_SOURCE
32 #define _LARGEFILE_SOURCE64
3233 #define _FILE_OFFSET_BITS 64
3334
3435 #include <stdio.h>
3738 #include <errno.h>
3839 #include <sys/stat.h>
3940 #endif
40
41 #if defined(_WIN32)
42 #include <io.h>
43 #include <fcntl.h>
44 #endif
4145 #include "Ap4FileByteStream.h"
4246
4347 /*----------------------------------------------------------------------
6468 return 0;
6569 }
6670 #endif // defined(AP4_CONFIG_HAVE_FOPEN_S
71
72 #if defined(_WIN32)
73
74 #include <windows.h>
75 #include <malloc.h>
76 #include <limits.h>
77 #include <assert.h>
78
79 #define AP4_WIN32_USE_CHAR_CONVERSION \
80 int _convert = 0; \
81 LPCWSTR _lpw = NULL; \
82 LPCSTR _lpa = NULL
83
84 /*----------------------------------------------------------------------
85 | A2WHelper
86 +---------------------------------------------------------------------*/
87 static LPWSTR
88 A2WHelper(LPWSTR lpw, LPCSTR lpa, int nChars, UINT acp)
89 {
90 int ret;
91
92 assert(lpa != NULL);
93 assert(lpw != NULL);
94 if (lpw == NULL || lpa == NULL) return NULL;
95
96 lpw[0] = '\0';
97 ret = MultiByteToWideChar(acp, 0, lpa, -1, lpw, nChars);
98 if (ret == 0) {
99 assert(0);
100 return NULL;
101 }
102 return lpw;
103 }
104
105 /*----------------------------------------------------------------------
106 | W2AHelper
107 +---------------------------------------------------------------------*/
108 static LPSTR
109 W2AHelper(LPSTR lpa, LPCWSTR lpw, int nChars, UINT acp)
110 {
111 int ret;
112
113 assert(lpw != NULL);
114 assert(lpa != NULL);
115 if (lpa == NULL || lpw == NULL) return NULL;
116
117 lpa[0] = '\0';
118 ret = WideCharToMultiByte(acp, 0, lpw, -1, lpa, nChars, NULL, NULL);
119 if (ret == 0) {
120 int error = GetLastError();
121 assert(error);
122 return NULL;
123 }
124 return lpa;
125 }
126
127 /*----------------------------------------------------------------------
128 | conversion macros
129 +---------------------------------------------------------------------*/
130 #define AP4_WIN32_A2W(lpa) \
131 (((_lpa = lpa) == NULL) ? \
132 NULL : \
133 (_convert = (int)(strlen(_lpa) + 1), \
134 (INT_MAX / 2 < _convert) ? \
135 NULL : \
136 A2WHelper((LPWSTR)alloca(_convert * sizeof(WCHAR)), _lpa, _convert, CP_UTF8)))
137
138 /* +2 instead of +1 temporary fix for Chinese characters */
139 #define AP4_WIN32_W2A(lpw) \
140 (((_lpw = lpw) == NULL) ? \
141 NULL : \
142 ((_convert = (lstrlenW(_lpw) + 2), \
143 (_convert > INT_MAX / 2) ? \
144 NULL : \
145 W2AHelper((LPSTR)alloca(_convert * sizeof(WCHAR)), _lpw, _convert * sizeof(WCHAR), CP_UTF8))))
146
147 /*----------------------------------------------------------------------
148 | AP4_fopen_s_utf8
149 +---------------------------------------------------------------------*/
150 static errno_t
151 AP4_fopen_s_utf8(FILE** file, const char* path, const char* mode)
152 {
153 AP4_WIN32_USE_CHAR_CONVERSION;
154 return _wfopen_s(file, AP4_WIN32_A2W(path), AP4_WIN32_A2W(mode));
155 }
156
157 /*----------------------------------------------------------------------
158 | remap some functions
159 +---------------------------------------------------------------------*/
160 #define fopen_s AP4_fopen_s_utf8
161
162 #endif /* _WIN32 */
67163
68164 /*----------------------------------------------------------------------
69165 | AP4_StdcFileByteStream
127223 // open the file
128224 FILE* file = NULL;
129225 AP4_Position size = 0;
130 if (!strcmp(name, "-stdin")) {
226 if (!strcmp(name, "-stdin") || !strcmp(name, "-stdin#")) {
131227 file = stdin;
132 } else if (!strcmp(name, "-stdout")) {
228 #if defined(_WIN32)
229 if (name[6] == '#') {
230 _setmode(fileno(stdin), O_BINARY);
231 }
232 #endif
233 } else if (!strcmp(name, "-stdout") || !strcmp(name, "-stdout#")) {
133234 file = stdout;
235 #if defined(_WIN32)
236 if (name[7] == '#') {
237 _setmode(fileno(stdout), O_BINARY);
238 }
239 #endif
134240 } else if (!strcmp(name, "-stderr")) {
135241 file = stderr;
136242 } else {
137243 int open_result;
138244 switch (mode) {
139245 case AP4_FileByteStream::STREAM_MODE_READ:
140 open_result = ::fopen_s(&file, name, "rb");
246 open_result = fopen_s(&file, name, "rb");
141247 break;
142248
143249 case AP4_FileByteStream::STREAM_MODE_WRITE:
144 open_result = ::fopen_s(&file, name, "wb+");
250 open_result = fopen_s(&file, name, "wb+");
145251 break;
146252
147253 case AP4_FileByteStream::STREAM_MODE_READ_WRITE:
148 open_result = ::fopen_s(&file, name, "r+b");
254 open_result = fopen_s(&file, name, "r+b");
149255 break;
150256
151257 default:
263369 if (nbWritten > 0) {
264370 bytesWritten = (AP4_Size)nbWritten;
265371 m_Position += nbWritten;
372 if (m_Position > m_Size) {
373 m_Size = m_Position;
374 }
266375 return AP4_SUCCESS;
267376 } else {
268377 bytesWritten = 0;
316425 AP4_StdcFileByteStream::Flush()
317426 {
318427 int ret_val = fflush(m_File);
319 AP4_Result result((ret_val > 0) ? AP4_FAILURE : AP4_SUCCESS);
320 if (AP4_SUCCEEDED(result) && GetObserver())
321 return GetObserver()->OnFlush(this);
322 return result;
428 return (ret_val > 0) ? AP4_FAILURE: AP4_SUCCESS;
323429 }
324430
325431 /*----------------------------------------------------------------------
2020 #include "../log.h"
2121 #include "../oscompat.h"
2222
23 #include <algorithm>
2324 #include <cstring>
2425 #include <iostream>
25 #include <math.h>
26 #include <cmath>
2627
2728 using namespace adaptive;
2829
29 AdaptiveStream::AdaptiveStream(AdaptiveTree& tree, AdaptiveTree::StreamType type)
30 const size_t AdaptiveStream::MAXSEGMENTBUFFER = 10;
31
32 AdaptiveStream::AdaptiveStream(AdaptiveTree& tree,
33 AdaptiveTree::AdaptationSet* adp,
34 const std::map<std::string, std::string>& media_headers,
35 bool play_timeshift_buffer,
36 size_t repId,
37 bool choose_rep)
3038 : thread_data_(nullptr),
3139 tree_(tree),
32 type_(type),
3340 observer_(nullptr),
3441 current_period_(tree_.current_period_),
35 current_adp_(nullptr),
36 current_rep_(nullptr),
42 current_adp_(adp),
43 current_rep_(repId ? adp->representations_[adp->representations_.size() - repId]
44 : tree.ChooseRepresentation(adp)),
45 available_segment_buffers_(0),
46 valid_segment_buffers_(0),
47 media_headers_(media_headers),
3748 segment_read_pos_(0),
3849 currentPTSOffset_(0),
3950 absolutePTSOffset_(0),
4051 lastUpdated_(std::chrono::system_clock::now()),
4152 m_fixateInitialization(false),
4253 m_segmentFileOffset(0),
43 play_timeshift_buffer_(false)
44 {
54 play_timeshift_buffer_(play_timeshift_buffer),
55 choose_rep_(choose_rep),
56 rep_counter_(1),
57 prev_rep_(0),
58 last_rep_(0),
59 assured_buffer_length_(5),
60 max_buffer_length_(10)
61 {
62 segment_buffers_.resize(MAXSEGMENTBUFFER + 1);
63 current_rep_->current_segment_ = nullptr;
4564 }
4665
4766 AdaptiveStream::~AdaptiveStream()
4867 {
4968 stop();
5069 clear();
51 }
52
53 void AdaptiveStream::ResetSegment()
54 {
55 segment_buffer_.clear();
70
71 for (SEGMENTBUFFER& buf : segment_buffers_)
72 delete[] buf.segment.url;
73 }
74
75 void AdaptiveStream::Reset()
76 {
5677 segment_read_pos_ = 0;
57
58 if (current_rep_->current_segment_ &&
78 currentPTSOffset_ = 0;
79 absolutePTSOffset_ = 0;
80 }
81
82 void AdaptiveStream::ResetSegment(const AdaptiveTree::Segment* segment)
83 {
84 segment_read_pos_ = 0;
85
86 if (segment &&
5987 !(current_rep_->flags_ &
60 (AdaptiveTree::Representation::SEGMENTBASE | AdaptiveTree::Representation::TEMPLATE |
61 AdaptiveTree::Representation::URLSEGMENTS)))
62 absolute_position_ = current_rep_->current_segment_->range_begin_;
88 (AdaptiveTree::Representation::SEGMENTBASE |
89 AdaptiveTree::Representation::TEMPLATE |
90 AdaptiveTree::Representation::URLSEGMENTS)) &&
91 current_rep_->containerType_ != AdaptiveTree::ContainerType::CONTAINERTYPE_TS)
92 absolute_position_ = segment->range_begin_;
93 }
94
95 void AdaptiveStream::ResetActiveBuffer(bool oneValid)
96 {
97 valid_segment_buffers_ = oneValid ? 1 : 0;
98 available_segment_buffers_ = valid_segment_buffers_;
99 absolute_position_ = 0;
100 segment_buffers_[0].buffer.clear();
101 segment_read_pos_ = 0;
102 }
103
104 // Make sure worker is in CV wait state.
105 void AdaptiveStream::StopWorker(STATE state)
106 {
107 // stop downloading chunks
108 state_ = state;
109 // wait until last reading operation stopped
110 // make sure download section in worker thread is done.
111 std::unique_lock<std::mutex> lckrw(thread_data_->mutex_rw_);
112 while (worker_processing_)
113 thread_data_->signal_rw_.wait(lckrw);
114 // Now the worker thread should keep the lock until it starts waiting
115 // to get CV signaled - make sure we are at this point.
116 std::lock_guard<std::mutex> lckdl(thread_data_->mutex_dl_);
117 // Make sure that worker continues at next notify
118 state_ = RUNNING;
63119 }
64120
65121 bool AdaptiveStream::download_segment()
67123 if (download_url_.empty())
68124 return false;
69125
70 return download(download_url_.c_str(), download_headers_);
126 return download(download_url_.c_str(), download_headers_, nullptr);
71127 }
72128
73129 void AdaptiveStream::worker()
74130 {
75131 std::unique_lock<std::mutex> lckdl(thread_data_->mutex_dl_);
132 worker_processing_ = false;
76133 thread_data_->signal_dl_.notify_one();
77134 do
78135 {
79 thread_data_->signal_dl_.wait(lckdl);
80
81 bool ret(download_segment());
82 unsigned int retryCount(10);
83
84 //Some streaming software offers subtitle tracks with missing fragments, usually live tv
85 //When a programme is broadcasted that has subtitles, subtitles fragments are offered
86 //TODO: Ensure we continue with the next segment after one retry on errors
87 if (type_ == AdaptiveTree::SUBTITLE)
88 retryCount = 1;
89
90 while (!ret && !stopped_ && retryCount--)
91 {
92 std::this_thread::sleep_for(std::chrono::seconds(1));
93 Log(LOGLEVEL_DEBUG, "AdaptiveStream: trying to reload segment ...");
94 ret = download_segment();
95 }
96
97 //Signal finished download
98 {
99 std::lock_guard<std::mutex> lckrw(thread_data_->mutex_rw_);
100 download_url_.clear();
101 if (!ret)
102 stopped_ = true;
103 }
104 thread_data_->signal_rw_.notify_one();
105
136 while (!thread_data_->thread_stop_ &&
137 (state_ != RUNNING || valid_segment_buffers_ >= available_segment_buffers_))
138 thread_data_->signal_dl_.wait(lckdl);
139
140 if (!thread_data_->thread_stop_)
141 {
142 worker_processing_ = true;
143
144 prepareNextDownload();
145
146 // tell the main thread that we have processed prepare_download;
147 thread_data_->signal_dl_.notify_one();
148 lckdl.unlock();
149
150 bool ret(download_segment());
151 unsigned int retryCount(10);
152
153 //Some streaming software offers subtitle tracks with missing fragments, usually live tv
154 //When a programme is broadcasted that has subtitles, subtitles fragments are offered
155 //TODO: Ensure we continue with the next segment after one retry on errors
156 if (current_adp_->type_ == AdaptiveTree::SUBTITLE)
157 retryCount = 1;
158
159 while (!ret && state_ == RUNNING && retryCount-- && tree_.has_timeshift_buffer_)
160 {
161 std::this_thread::sleep_for(std::chrono::seconds(1));
162 Log(LOGLEVEL_DEBUG, "AdaptiveStream: trying to reload segment ...");
163 ret = download_segment();
164 }
165
166 lckdl.lock();
167
168 //Signal finished download
169 {
170 std::lock_guard<std::mutex> lckrw(thread_data_->mutex_rw_);
171 download_url_.clear();
172 if (!ret)
173 state_ = STOPPED;
174 }
175 worker_processing_ = false;
176
177 thread_data_->signal_rw_.notify_one();
178 }
106179 } while (!thread_data_->thread_stop_);
107180 }
108181
115188 .count());
116189 }
117190
118 bool AdaptiveStream::write_data(const void* buffer, size_t buffer_size)
119 {
191
192 bool AdaptiveStream::write_data(const void* buffer, size_t buffer_size, std::string* lockfreeBuffer)
193 {
194 if (lockfreeBuffer)
195 {
196 size_t insertPos(lockfreeBuffer->size());
197 lockfreeBuffer->resize(insertPos + buffer_size);
198 memcpy(&(*lockfreeBuffer)[insertPos], buffer, buffer_size);
199 return true;
200 }
201
120202 {
121203 std::lock_guard<std::mutex> lckrw(thread_data_->mutex_rw_);
122204
123 if (stopped_)
205 if (state_ == STOPPED)
124206 return false;
125207
126 size_t insertPos(segment_buffer_.size());
127 segment_buffer_.resize(insertPos + buffer_size);
208 // we write always into the last active segment
209 std::string& segment_buffer = segment_buffers_[valid_segment_buffers_ - 1].buffer;
210
211 size_t insertPos(segment_buffer.size());
212 segment_buffer.resize(insertPos + buffer_size);
128213 tree_.OnDataArrived(download_segNum_, download_pssh_set_, m_iv,
129214 reinterpret_cast<const uint8_t*>(buffer),
130 reinterpret_cast<uint8_t*>(&segment_buffer_[0]), insertPos, buffer_size);
215 reinterpret_cast<uint8_t*>(&segment_buffer[0]), insertPos, buffer_size);
131216 }
132217 thread_data_->signal_rw_.notify_one();
133218 return true;
134219 }
135220
136 bool AdaptiveStream::prepare_stream(AdaptiveTree::AdaptationSet* adp,
137 const uint32_t width,
138 const uint32_t height,
139 uint32_t hdcpLimit,
140 uint16_t hdcpVersion,
141 uint32_t min_bandwidth,
142 uint32_t max_bandwidth,
143 unsigned int repId,
144 const std::map<std::string, std::string>& media_headers)
145 {
146 width_ = type_ == AdaptiveTree::VIDEO ? width : 0;
147 height_ = type_ == AdaptiveTree::VIDEO ? height : 0;
148 hdcpLimit_ = hdcpLimit;
149 hdcpVersion_ = hdcpVersion;
150
151 uint32_t avg_bandwidth = tree_.bandwidth_;
152
153 bandwidth_ = min_bandwidth;
154 if (avg_bandwidth > bandwidth_)
155 bandwidth_ = avg_bandwidth;
156 if (max_bandwidth && bandwidth_ > max_bandwidth)
157 bandwidth_ = max_bandwidth;
158
159 stopped_ = false;
160
161 bandwidth_ = static_cast<uint32_t>(bandwidth_ * (type_ == AdaptiveTree::VIDEO ? 0.9 : 0.1));
162
163 current_adp_ = adp;
164
165 media_headers_ = media_headers;
166
167 return select_stream(false, true, repId);
168 }
169
170 bool AdaptiveStream::start_stream(const uint32_t seg_offset,
171 uint16_t width,
172 uint16_t height,
173 bool play_timeshift_buffer)
174 {
175 if (!play_timeshift_buffer && !~seg_offset && tree_.has_timeshift_buffer_ &&
176 current_rep_->segments_.data.size() > 1 && tree_.periods_.size() == 1)
177 {
178 std::int32_t pos;
179 if (tree_.has_timeshift_buffer_ || tree_.available_time_ >= tree_.stream_start_)
180 pos = static_cast<int32_t>(current_rep_->segments_.data.size() - 1);
181 else
182 {
183 pos = static_cast<int32_t>(
184 ((tree_.stream_start_ - tree_.available_time_) * current_rep_->timescale_) /
185 current_rep_->duration_);
186 if (!pos)
187 pos = 1;
188 }
189 //go at least 12 secs back
190 uint64_t duration(current_rep_->get_segment(pos)->startPTS_ -
191 current_rep_->get_segment(pos - 1)->startPTS_);
192 pos -= static_cast<uint32_t>((12 * current_rep_->timescale_) / duration) + 1;
193 current_rep_->current_segment_ = current_rep_->get_segment(pos < 0 ? 0 : pos);
194 }
195 else
196 current_rep_->current_segment_ = ~seg_offset ? current_rep_->get_segment(seg_offset) : 0;
197
198 segment_buffer_.clear();
199 segment_read_pos_ = 0;
200
201 if (!current_rep_->get_next_segment(current_rep_->current_segment_))
202 {
203 absolute_position_ = ~0;
204 stopped_ = true;
205 }
206 else
207 {
208 width_ = type_ == AdaptiveTree::VIDEO ? width : 0;
209 height_ = type_ == AdaptiveTree::VIDEO ? height : 0;
210 play_timeshift_buffer_ = play_timeshift_buffer;
211
212 if (!(current_rep_->flags_ &
213 (AdaptiveTree::Representation::SEGMENTBASE | AdaptiveTree::Representation::TEMPLATE |
214 AdaptiveTree::Representation::URLSEGMENTS)))
215 absolute_position_ =
216 current_rep_->get_next_segment(current_rep_->current_segment_)->range_begin_;
217 else
218 absolute_position_ = 0;
219
220 stopped_ = false;
221 }
221 bool AdaptiveStream::start_stream()
222 {
223 if (!current_rep_)
224 return false;
225
226 if (choose_rep_)
227 {
228 choose_rep_ = false;
229 current_rep_ = tree_.ChooseNextRepresentation(
230 current_adp_, segment_buffers_[valid_segment_buffers_].rep, &valid_segment_buffers_,
231 &available_segment_buffers_, &assured_buffer_length_, &max_buffer_length_, rep_counter_);
232 }
233
234 if (!(current_rep_->flags_ & AdaptiveTree::Representation::INITIALIZED))
235 {
236 tree_.prepareRepresentation(current_period_, current_adp_, current_rep_,
237 false);
238 }
239
240 assured_buffer_length_=current_rep_ ->assured_buffer_duration_;
241 assured_buffer_length_ = std::ceil( (assured_buffer_length_ * current_rep_->segtpl_.timescale)/ (float)current_rep_->segtpl_.duration );
242
243 max_buffer_length_=current_rep_ ->max_buffer_duration_;
244 max_buffer_length_ = std::ceil( (max_buffer_length_ * current_rep_->segtpl_.timescale)/ (float)current_rep_->segtpl_.duration );
245 assured_buffer_length_ = assured_buffer_length_ <4 ? 4:assured_buffer_length_;//for incorrect settings input
246 if(max_buffer_length_<=assured_buffer_length_)//for incorrect settings input
247 max_buffer_length_=assured_buffer_length_+4u;
248
249 segment_buffers_.resize(max_buffer_length_+ 1);//TTHR
222250
223251 if (!thread_data_)
224252 {
253 state_ = STOPPED;
225254 thread_data_ = new THREADDATA();
226255 std::unique_lock<std::mutex> lckdl(thread_data_->mutex_dl_);
227256 thread_data_->Start(this);
229258 thread_data_->signal_dl_.wait(lckdl);
230259 }
231260
232 return true;
233 }
234
235 bool AdaptiveStream::restart_stream()
236 {
237 if (!start_stream(~0, width_, height_, play_timeshift_buffer_))
238 return false;
239
240 /* lets download the initialization */
241 if (prepareDownload(current_rep_->get_initialization()) && !download_segment())
242 return false;
243 download_url_.clear();
244
245 return true;
261 {
262 // ResolveSegmentbase assumes mutex_dl locked
263 std::lock_guard<std::mutex> lck(thread_data_->mutex_dl_);
264 if (!ResolveSegmentBase(current_rep_, true))
265 {
266 state_ = STOPPED;
267 return false;
268 }
269 }
270
271 if (!current_rep_->current_segment_)
272 {
273 if (!play_timeshift_buffer_ && tree_.has_timeshift_buffer_ &&
274 current_rep_->segments_.data.size() > 1 && tree_.periods_.size() == 1)
275 {
276 if (!last_rep_)
277 {
278 std::int32_t pos;
279 if (tree_.has_timeshift_buffer_ || tree_.available_time_ >= tree_.stream_start_)
280 pos = static_cast<int32_t>(current_rep_->segments_.data.size() - 1);
281 else
282 {
283 pos = static_cast<int32_t>(
284 ((tree_.stream_start_ - tree_.available_time_) * current_rep_->timescale_) /
285 current_rep_->duration_);
286 if (!pos)
287 pos = 1;
288 }
289 uint64_t duration(current_rep_->get_segment(pos)->startPTS_ -
290 current_rep_->get_segment(pos - 1)->startPTS_);
291 pos -= static_cast<uint32_t>((tree_.live_delay_ * current_rep_->timescale_) / duration);
292 current_rep_->current_segment_ = current_rep_->get_segment(pos < 0 ? 0 : pos);
293 }
294 else // switching streams, align new stream segment no.
295 {
296 std::int32_t segmentId = segment_buffers_[0].segment_number;
297 if (segmentId >= current_rep_->startNumber_ + current_rep_->segments_.size())
298 segmentId = current_rep_->startNumber_ + current_rep_->segments_.size() - 1;
299 current_rep_->current_segment_ = current_rep_->get_segment(segmentId - current_rep_->startNumber_);
300 }
301 }
302 else
303 current_rep_->current_segment_ = nullptr; // start from beginning
304 }
305
306 const AdaptiveTree::Segment* next_segment =
307 current_rep_->get_next_segment(current_rep_->current_segment_);
308
309 if (!next_segment)
310 {
311 absolute_position_ = ~0;
312 state_ = STOPPED;
313 return true;
314 }
315
316 state_ = RUNNING;
317 absolute_position_ = 0;
318
319 // load the initialization segment
320 const AdaptiveTree::Segment* loadingSeg = current_rep_->get_initialization();
321 if (loadingSeg)
322 {
323 StopWorker(PAUSED);
324
325 if (available_segment_buffers_)
326 std::rotate(segment_buffers_.rend() - (available_segment_buffers_ + 1),
327 segment_buffers_.rend() - available_segment_buffers_, segment_buffers_.rend());
328 segment_buffers_[0].segment.url = nullptr;
329 ++available_segment_buffers_;
330
331 segment_buffers_[0].segment.Copy(loadingSeg);
332 segment_buffers_[0].rep = current_rep_;
333 segment_buffers_[0].segment_number = ~0U;
334 segment_buffers_[0].buffer.clear();
335 segment_read_pos_ = 0;
336
337 // Force writing the data into segment_buffers_[0]
338 // Store the # of valid buffers so we can resore later
339 size_t valid_segment_buffers = valid_segment_buffers_;
340 valid_segment_buffers_ = 0;
341
342 if (!prepareNextDownload() || !download_segment())
343 state_ = STOPPED;
344
345 valid_segment_buffers_ = valid_segment_buffers + 1;
346 }
347
348 currentPTSOffset_ = (next_segment->startPTS_ * current_rep_->timescale_ext_) /
349 current_rep_->timescale_int_;
350 absolutePTSOffset_ = (current_rep_->segments_[0]->startPTS_ * current_rep_->timescale_ext_) /
351 current_rep_->timescale_int_;
352
353 if (state_ == RUNNING)
354 {
355 const_cast<adaptive::AdaptiveTree::Representation*>(current_rep_)->flags_ |=
356 adaptive::AdaptiveTree::Representation::ENABLED;
357 return true;
358 }
359 return false;
246360 }
247361
248362 void AdaptiveStream::ReplacePlaceholder(std::string& url, const std::string placeholder, uint64_t value)
268382 url.replace(np - lenReplace, npe - np + lenReplace + 1, rangebuf);
269383 }
270384
271 bool AdaptiveStream::prepareDownload(const AdaptiveTree::Segment* seg)
385 bool AdaptiveStream::prepareNextDownload()
386 {
387 // We assume, that we find the next segment to load in the next valid_segment_buffers_
388 if (valid_segment_buffers_ >= available_segment_buffers_)
389 return false;
390
391 const AdaptiveTree::Representation* rep = segment_buffers_[valid_segment_buffers_].rep;
392 const AdaptiveTree::Segment* seg = &segment_buffers_[valid_segment_buffers_].segment;
393 // segNum == ~0U is initialization segment!
394 unsigned int segNum = segment_buffers_[valid_segment_buffers_].segment_number;
395 segment_buffers_[valid_segment_buffers_].buffer.clear();
396 ++valid_segment_buffers_;
397
398 return prepareDownload(rep, seg, segNum);
399 }
400
401 bool AdaptiveStream::prepareDownload(const AdaptiveTree::Representation* rep,
402 const AdaptiveTree::Segment* seg,
403 unsigned int segNum)
272404 {
273405 if (!seg)
274406 return false;
275407
276 if (!current_rep_->segments_.empty())
277 {
278 currentPTSOffset_ =
279 (seg->startPTS_ * current_rep_->timescale_ext_) / current_rep_->timescale_int_;
280 absolutePTSOffset_ = (current_rep_->segments_[0]->startPTS_ * current_rep_->timescale_ext_) /
281 current_rep_->timescale_int_;
282 }
283
284 if (observer_ && seg != &current_rep_->initialization_ && ~seg->startPTS_)
285 observer_->OnSegmentChanged(this);
286
287408 char rangebuf[128], *rangeHeader(0);
288409
289 if (!(current_rep_->flags_ & AdaptiveTree::Representation::SEGMENTBASE))
290 {
291 if (!(current_rep_->flags_ & AdaptiveTree::Representation::TEMPLATE))
292 {
293 if (current_rep_->flags_ & AdaptiveTree::Representation::URLSEGMENTS)
410 if (!(rep->flags_ & AdaptiveTree::Representation::SEGMENTBASE))
411 {
412 if (!(rep->flags_ & AdaptiveTree::Representation::TEMPLATE))
413 {
414 if (rep->flags_ & AdaptiveTree::Representation::URLSEGMENTS)
294415 {
295416 download_url_ = seg->url;
296417 if (download_url_.find("://") == std::string::npos)
297 download_url_ = current_rep_->url_ + download_url_;
418 download_url_ = rep->url_ + download_url_;
298419 }
299420 else
300 download_url_ = current_rep_->url_;
421 download_url_ = rep->url_;
301422 if (~seg->range_begin_)
302423 {
303 uint64_t fileOffset = seg != &current_rep_->initialization_ ? m_segmentFileOffset : 0;
424 uint64_t fileOffset = ~segNum ? m_segmentFileOffset : 0;
304425 if (~seg->range_end_)
305426 sprintf(rangebuf, "bytes=%" PRIu64 "-%" PRIu64, seg->range_begin_ + fileOffset,
306427 seg->range_end_ + fileOffset);
309430 rangeHeader = rangebuf;
310431 }
311432 }
312 else if (seg != &current_rep_->initialization_) //templated segment
313 {
314 download_url_ = current_rep_->segtpl_.media;
433 else if (~segNum) //templated segment
434 {
435 download_url_ = rep->segtpl_.media;
315436 ReplacePlaceholder(download_url_, "$Number", seg->range_end_);
316437 ReplacePlaceholder(download_url_, "$Time", seg->range_begin_);
317438 }
318439 else //templated initialization segment
319 download_url_ = current_rep_->url_;
440 download_url_ = rep->url_;
320441 }
321442 else
322443 {
323 if (current_rep_->flags_ & AdaptiveTree::Representation::TEMPLATE &&
324 seg != &current_rep_->initialization_)
325 {
326 download_url_ = current_rep_->segtpl_.media;
327 ReplacePlaceholder(download_url_, "$Number", current_rep_->startNumber_);
444 if (rep->flags_ & AdaptiveTree::Representation::TEMPLATE && ~segNum)
445 {
446 download_url_ = rep->segtpl_.media;
447 ReplacePlaceholder(download_url_, "$Number", rep->startNumber_);
328448 ReplacePlaceholder(download_url_, "$Time", 0);
329449 }
330450 else
331 download_url_ = current_rep_->url_;
451 download_url_ = rep->url_;
332452 if (~seg->range_begin_)
333453 {
334 uint64_t fileOffset = seg != &current_rep_->initialization_ ? m_segmentFileOffset : 0;
454 uint64_t fileOffset = ~segNum ? m_segmentFileOffset : 0;
335455 if (~seg->range_end_)
336456 sprintf(rangebuf, "bytes=%" PRIu64 "-%" PRIu64, seg->range_begin_ + fileOffset,
337457 seg->range_end_ + fileOffset);
341461 }
342462 }
343463
344 download_segNum_ = current_rep_->startNumber_ + current_rep_->get_segment_pos(seg);
464 download_segNum_ = segNum;
345465 download_pssh_set_ = seg->pssh_set_;
346466 download_headers_ = media_headers_;
347467 if (rangeHeader)
356476
357477 bool AdaptiveStream::ensureSegment()
358478 {
359 if (stopped_)
479 if (state_ != RUNNING)
360480 return false;
361481
362 if (download_url_.empty() && segment_read_pos_ >= segment_buffer_.size())
363 {
364 //wait until worker is ready for new segment
365 std::lock_guard<std::mutex> lck(thread_data_->mutex_dl_);
482 // We an only switch to the next segment, if the current (== segment_buffers_[0]) is finished.
483 // This is the case if we have more than 1 valid segments, or worker is not processing anymore.
484 if ((!worker_processing_ || valid_segment_buffers_ > 1) &&
485 segment_read_pos_ >= segment_buffers_[0].buffer.size())
486 {
487 // wait until worker is ready for new segment
488 std::unique_lock<std::mutex> lck(thread_data_->mutex_dl_);
489 // lock live segment updates
366490 std::lock_guard<std::mutex> lckTree(tree_.GetTreeMutex());
367491
368492 if (tree_.HasUpdateThread() && SecondsSinceUpdate() > 1)
374498 if (m_fixateInitialization)
375499 return false;
376500
377 const AdaptiveTree::Segment* nextSegment =
378 current_rep_->get_next_segment(current_rep_->current_segment_);
501 stream_changed_ = false;
502 const AdaptiveTree::Segment* nextSegment;
503 last_rep_ = current_rep_;
504 if (valid_segment_buffers_)
505 {
506 // rotate element 0 to the end
507 std::rotate(segment_buffers_.begin(), segment_buffers_.begin() + 1,
508 segment_buffers_.begin() + available_segment_buffers_);
509 --valid_segment_buffers_;
510 --available_segment_buffers_;
511
512 if (segment_buffers_[0].rep != current_rep_)
513 {
514 current_rep_->flags_ &= ~adaptive::AdaptiveTree::Representation::ENABLED;
515 current_rep_ = segment_buffers_[0].rep;
516 current_rep_->flags_ |= adaptive::AdaptiveTree::Representation::ENABLED;
517 stream_changed_ = true;
518 }
519 }
520 if (valid_segment_buffers_)
521 nextSegment = ~segment_buffers_[0].segment_number
522 ? current_rep_->get_segment(segment_buffers_[0].segment_number -
523 current_rep_->startNumber_)
524 : nullptr;
525 else
526 nextSegment = current_rep_->get_next_segment(current_rep_->current_segment_);
527
528 if(prev_rep_== current_rep_)
529 rep_counter_++;
530 else
531 {
532 rep_counter_=1;
533 prev_rep_=current_rep_;
534 }
535
379536 if (nextSegment)
380537 {
538 currentPTSOffset_ =
539 (nextSegment->startPTS_ * current_rep_->timescale_ext_) / current_rep_->timescale_int_;
540
541 absolutePTSOffset_ = (current_rep_->segments_[0]->startPTS_ * current_rep_->timescale_ext_) /
542 current_rep_->timescale_int_;
543
381544 current_rep_->current_segment_ = nextSegment;
382 prepareDownload(nextSegment);
383 ResetSegment();
545 ResetSegment(nextSegment);
546
547 if (observer_ && nextSegment != &current_rep_->initialization_ && ~nextSegment->startPTS_)
548 observer_->OnSegmentChanged(this);
549
550 uint32_t nextsegmentPosold = current_rep_->get_segment_pos(nextSegment);
551 uint32_t nextsegno = current_rep_->getSegmentNumber(nextSegment);
552 AdaptiveTree::Representation* newRep;
553 bool lastSeg =
554 (current_period_ != tree_.periods_.back() &&
555 nextsegmentPosold + available_segment_buffers_ == current_rep_->segments_.size() - 1);
556
557 if (segment_buffers_[0].segment_number == ~0L || valid_segment_buffers_ == 0 ||
558 current_adp_->type_ != AdaptiveTree::VIDEO)
559 {
560 newRep = current_rep_;
561 }
562 else if (lastSeg) // Don't change reps on last segment of period, use the rep of preceeding seg
563 {
564 newRep = segment_buffers_[valid_segment_buffers_ - 1].rep;
565 }
566 else
567 {
568 newRep = tree_.ChooseNextRepresentation(current_adp_,
569 segment_buffers_[valid_segment_buffers_].rep,
570 &valid_segment_buffers_,&available_segment_buffers_,
571 &assured_buffer_length_,
572 &max_buffer_length_,
573 rep_counter_);
574 }
575 // Make sure, new representation has segments!
576 ResolveSegmentBase(newRep, false); // For DASH
577 if (tree_.SecondsSinceRepUpdate(newRep) > 1)
578 {
579 tree_.prepareRepresentation(
580 current_period_, current_adp_, newRep, tree_.has_timeshift_buffer_);
581 }
582
583 uint32_t nextsegmentPos = nextsegno - newRep->startNumber_;
584 if (nextsegmentPos + available_segment_buffers_ >= newRep->segments_.size())
585 {
586 nextsegmentPos = newRep->segments_.size() - available_segment_buffers_;
587 }
588 for (size_t updPos(available_segment_buffers_); updPos < max_buffer_length_ ; ++updPos)
589 {
590 const AdaptiveTree::Segment* futureSegment = newRep->get_segment(nextsegmentPos + updPos);
591
592 if (futureSegment)
593 {
594 segment_buffers_[updPos].segment.Copy(futureSegment);
595 segment_buffers_[updPos].segment_number = newRep->startNumber_ + nextsegmentPos + updPos;
596 segment_buffers_[updPos].rep = newRep;
597 ++available_segment_buffers_;
598 }
599 else
600 break;
601 }
602
384603 thread_data_->signal_dl_.notify_one();
604 // Make sure that we have at least one segment filling
605 // Otherwise we lead into a deadlock because first condition is false.
606 if (!valid_segment_buffers_)
607 thread_data_->signal_dl_.wait(lck);
608
609 if (stream_changed_)
610 {
611 if (observer_)
612 observer_->OnStreamChange(this);
613 return false;
614 }
385615 }
386616 else if (tree_.HasUpdateThread() && current_period_ == tree_.periods_.back())
387617 {
392622 }
393623 else
394624 {
395 stopped_ = true;
625 state_ = STOPPED;
396626 return false;
397627 }
398628 }
402632
403633 uint32_t AdaptiveStream::read(void* buffer, uint32_t bytesToRead)
404634 {
405 if (stopped_)
635 if (state_ == STOPPED)
406636 return false;
407637
408638 std::unique_lock<std::mutex> lckrw(thread_data_->mutex_rw_);
412642 {
413643 while (true)
414644 {
415 uint32_t avail = segment_buffer_.size() - segment_read_pos_;
416 if (avail < bytesToRead && !download_url_.empty())
645 uint32_t avail = segment_buffers_[0].buffer.size() - segment_read_pos_;
646 if (avail < bytesToRead && worker_processing_)
417647 {
418648 thread_data_->signal_rw_.wait(lckrw);
419649 continue;
427657
428658 if (avail == bytesToRead)
429659 {
430 memcpy(buffer, segment_buffer_.data() + (segment_read_pos_ - avail), avail);
660 memcpy(buffer, segment_buffers_[0].buffer.data() + (segment_read_pos_ - avail), avail);
431661 return avail;
432662 }
433663 // If we call read after the last chunk was read but before worker finishes download, we end up here.
441671
442672 bool AdaptiveStream::seek(uint64_t const pos)
443673 {
444 if (stopped_)
674 if (state_ == STOPPED)
445675 return false;
446676
447677 std::unique_lock<std::mutex> lckrw(thread_data_->mutex_rw_);
448678
449679 // we seek only in the current segment
450 if (!stopped_ && pos >= absolute_position_ - segment_read_pos_)
680 if (state_ != STOPPED && pos >= absolute_position_ - segment_read_pos_)
451681 {
452682 segment_read_pos_ = static_cast<uint32_t>(pos - (absolute_position_ - segment_read_pos_));
453683
454 while (segment_read_pos_ > segment_buffer_.size() && !download_url_.empty())
684 while (segment_read_pos_ > segment_buffers_[0].buffer.size() && worker_processing_)
455685 thread_data_->signal_rw_.wait(lckrw);
456686
457 if (segment_read_pos_ > segment_buffer_.size())
458 {
459 segment_read_pos_ = static_cast<uint32_t>(segment_buffer_.size());
687 if (segment_read_pos_ > segment_buffers_[0].buffer.size())
688 {
689 segment_read_pos_ = static_cast<uint32_t>(segment_buffers_[0].buffer.size());
460690 return false;
461691 }
462692 absolute_position_ = pos;
467697
468698 bool AdaptiveStream::getSize(unsigned long long& sz)
469699 {
470 if (stopped_)
700 if (state_ == STOPPED)
471701 return false;
472702
473703 std::unique_lock<std::mutex> lckrw(thread_data_->mutex_rw_);
476706 {
477707 while (true)
478708 {
479 if (!download_url_.empty())
709 if (worker_processing_)
480710 {
481711 thread_data_->signal_rw_.wait(lckrw);
482712 continue;
483713 }
484 sz = segment_buffer_.size();
714 sz = segment_buffers_[0].buffer.size();
485715 return true;
486716 }
487717 }
515745 if (!current_rep_)
516746 return false;
517747
518 if (stopped_)
748 if (state_ == STOPPED)
519749 // For subtitles which come in one file we should return true!
520750 return current_rep_->segments_.empty();
521751
548778 choosen_seg = current_rep_->expired_segments_;
549779
550780 if (!preceeding && sec_in_ts > current_rep_->get_segment(choosen_seg)->startPTS_ &&
551 type_ == AdaptiveTree::VIDEO) //Assume that we have I-Frames only at segment start
781 current_adp_->type_ ==
782 AdaptiveTree::VIDEO) //Assume that we have I-Frames only at segment start
552783 ++choosen_seg;
553784
554785 const AdaptiveTree::Segment *old_seg(current_rep_->current_segment_),
558789 needReset = true;
559790 if (newSeg != old_seg)
560791 {
561 //stop downloading chunks
562 stopped_ = true;
563 //wait until last reading operation stopped
564 lckTree.unlock(); //writing downloadrate takes the tree lock / avoid dead-lock
565 std::lock_guard<std::mutex> lck(thread_data_->mutex_dl_);
566 lckTree.lock();
567 stopped_ = false;
568 current_rep_->current_segment_ = newSeg;
569 prepareDownload(newSeg);
570 absolute_position_ = 0;
571 ResetSegment();
572 thread_data_->signal_dl_.notify_one();
792 StopWorker(STOPPED);
793 // EnsureSegment loads always the next segment, so go back 1
794 current_rep_->current_segment_ =
795 current_rep_->get_segment(current_rep_->get_segment_pos(newSeg) - 1);
796 // TODO: if new segment is already prefetched, don't ResetActiveBuffer;
797 ResetActiveBuffer(false);
573798 }
574799 else if (!preceeding)
575800 {
604829 m_fixateInitialization = on && current_rep_->get_initialization() != nullptr;
605830 }
606831
607 bool AdaptiveStream::select_stream(bool force, bool justInit, unsigned int repId)
608 {
609 AdaptiveTree::Representation *new_rep(0), *min_rep(0);
610
611 if (!repId || repId > current_adp_->representations_.size())
612 {
613 unsigned int bestScore(~0);
614
615 for (std::vector<AdaptiveTree::Representation*>::const_iterator
616 br(current_adp_->representations_.begin()),
617 er(current_adp_->representations_.end());
618 br != er; ++br)
619 {
620 unsigned int score;
621 if ((*br)->bandwidth_ <= bandwidth_ && (*br)->hdcpVersion_ <= hdcpVersion_ &&
622 (!hdcpLimit_ || static_cast<uint32_t>((*br)->width_) * (*br)->height_ <= hdcpLimit_) &&
623 ((score = abs(static_cast<int>((*br)->width_ * (*br)->height_) -
624 static_cast<int>(width_ * height_)) +
625 static_cast<unsigned int>(sqrt(bandwidth_ - (*br)->bandwidth_))) < bestScore))
626 {
627 bestScore = score;
628 new_rep = (*br);
629 }
630 else if (!min_rep || (*br)->bandwidth_ < min_rep->bandwidth_)
631 min_rep = (*br);
632 }
633 }
634 else
635 new_rep = current_adp_->representations_[current_adp_->representations_.size() - repId];
636
637 if (!new_rep)
638 new_rep = min_rep;
639
640 if (justInit)
641 {
642 current_rep_ = new_rep;
643 return true;
644 }
645
646 if (!force && new_rep == current_rep_)
647 return false;
648
649 uint32_t segid(current_rep_ ? current_rep_->getCurrentSegmentPos() : 0);
650 if (current_rep_)
651 const_cast<adaptive::AdaptiveTree::Representation*>(current_rep_)->flags_ &=
652 ~adaptive::AdaptiveTree::Representation::ENABLED;
653
654 current_rep_ = new_rep;
655 current_rep_->current_segment_ = current_rep_->get_segment(segid);
656
657 const_cast<adaptive::AdaptiveTree::Representation*>(current_rep_)->flags_ |=
658 adaptive::AdaptiveTree::Representation::ENABLED;
659
660 if (observer_)
661 observer_->OnStreamChange(this);
662
663 stopped_ = false;
832 bool AdaptiveStream::ResolveSegmentBase(AdaptiveTree::Representation* rep, bool stopWorker)
833 {
664834 /* If we have indexRangeExact SegmentBase, update SegmentList from SIDX */
665 if (current_rep_->flags_ & AdaptiveTree::Representation::SEGMENTBASE)
666 {
835 if (rep->flags_ & AdaptiveTree::Representation::SEGMENTBASE)
836 {
837 // We assume mutex_dl is locked so we can safely call prepare_download
667838 AdaptiveTree::Segment seg;
668 const AdaptiveTree::Segment* downloadSeg;
669
670 // If indexRangeMin is set, we have a "real" SIDX stream position -> use it instead init segment
671 if (current_rep_->indexRangeMin_ || !(downloadSeg = current_rep_->get_initialization()))
672 {
673 seg.range_begin_ = current_rep_->indexRangeMin_;
674 seg.range_end_ = current_rep_->indexRangeMax_;
839 unsigned int segNum = ~0U;
840 if (rep->indexRangeMin_ || !(rep->get_initialization()))
841 {
842 seg.range_begin_ = rep->indexRangeMin_;
843 seg.range_end_ = rep->indexRangeMax_;
675844 seg.startPTS_ = ~0ULL;
676 downloadSeg = &seg;
677 }
678
679 if (prepareDownload(downloadSeg) && !download_segment())
680 {
681 stopped_ = true;
845 seg.pssh_set_ = 0;
846 segNum = 0; // It's no an initialization segment
847 }
848 else if (rep->get_initialization())
849 seg = *rep->get_initialization();
850 else
682851 return false;
683 }
684
685 // Signal that there is no data coming
686 download_url_.clear();
687
688 AdaptiveTree::Representation* rep(const_cast<AdaptiveTree::Representation*>(current_rep_));
689 absolute_position_ = 0;
690 if (!parseIndexRange())
691 {
692 stopped_ = true;
852
853 std::string sidxBuffer;
854 if (prepareDownload(rep, &seg, segNum) &&
855 download(download_url_.c_str(), download_headers_, &sidxBuffer) &&
856 parseIndexRange(rep, sidxBuffer))
857 const_cast<AdaptiveTree::Representation*>(rep)->flags_ &=
858 ~AdaptiveTree::Representation::SEGMENTBASE;
859 else
693860 return false;
694 }
695 rep->indexRangeMin_ = rep->indexRangeMax_ = 0;
696 absolute_position_ = 0;
697 segment_buffer_.clear();
698 segment_read_pos_ = 0;
699 rep->flags_ &= ~AdaptiveTree::Representation::SEGMENTBASE;
700 }
701
702 stopped_ = false;
703
704 /* lets download the initialization */
705 const AdaptiveTree::Segment* loadingSeg = current_rep_->get_initialization();
706 if (!loadingSeg && current_rep_->flags_ & AdaptiveTree::Representation::INITIALIZATION_PREFIXED)
707 loadingSeg = current_rep_->get_segment(segid);
708
709 if (prepareDownload(loadingSeg) && !download_segment())
710 {
711 stopped_ = true;
712 return false;
713 }
714
715 download_url_.clear();
716
861 }
717862 return true;
718863 }
719864
720865 void AdaptiveStream::info(std::ostream& s)
721866 {
722867 static const char* ts[4] = {"NoType", "Video", "Audio", "Text"};
723 s << ts[type_]
868 s << ts[current_adp_->type_]
724869 << " representation: " << current_rep_->url_.substr(current_rep_->url_.find_last_of('/') + 1)
725870 << " bandwidth: " << current_rep_->bandwidth_ << std::endl;
726871 }
727872
728873 void AdaptiveStream::stop()
729874 {
730 stopped_ = true;
731875 if (current_rep_)
732876 const_cast<adaptive::AdaptiveTree::Representation*>(current_rep_)->flags_ &=
733877 ~adaptive::AdaptiveTree::Representation::ENABLED;
734878 if (thread_data_)
735879 {
880 StopWorker(STOPPED);
736881 delete thread_data_;
737882 thread_data_ = nullptr;
738883 }
4141 class ATTRIBUTE_HIDDEN AdaptiveStream
4242 {
4343 public:
44 AdaptiveStream(AdaptiveTree &tree, AdaptiveTree::StreamType type);
44 AdaptiveStream(AdaptiveTree& tree,
45 AdaptiveTree::AdaptationSet* adp,
46 const std::map<std::string, std::string>& media_headers,
47 bool play_timeshift_buffer,
48 size_t repId,
49 bool choose_rep_);
4550 virtual ~AdaptiveStream();
4651 void set_observer(AdaptiveStreamObserver *observer){ observer_ = observer; };
47 bool prepare_stream(AdaptiveTree::AdaptationSet* adp,
48 const uint32_t width,
49 const uint32_t height,
50 uint32_t hdcpLimit,
51 uint16_t hdcpVersion,
52 uint32_t min_bandwidth,
53 uint32_t max_bandwidth,
54 unsigned int repId,
55 const std::map<std::string, std::string>& media_headers);
56 bool start_stream(const uint32_t seg_offset, uint16_t width, uint16_t height, bool play_timeshift_buffer);
57 bool restart_stream();
58 bool select_stream(bool force = false, bool justInit = false, unsigned int repId = 0);
52 void Reset();
53 bool start_stream();
5954 void stop();
6055 void clear();
6156 void info(std::ostream &s);
62 unsigned int getWidth() const { return width_; };
63 unsigned int getHeight() const { return height_; };
64 unsigned int getBandwidth() const { return bandwidth_; };
6557 uint64_t getMaxTimeMs();
6658
67 unsigned int get_type()const{ return type_; };
59 unsigned int get_type()const{ return current_adp_->type_; };
6860
6961 bool ensureSegment();
7062 uint32_t read(void* buffer, uint32_t bytesToRead);
7567 AdaptiveTree::Period* getPeriod() { return current_period_; };
7668 AdaptiveTree::AdaptationSet* getAdaptationSet() { return current_adp_; };
7769 AdaptiveTree::Representation* getRepresentation() { return current_rep_; };
78 double get_download_speed() const { return tree_.get_download_speed(); };
79 void set_download_speed(double speed) { tree_.set_download_speed(speed); };
8070 size_t getSegmentPos() { return current_rep_->getCurrentSegmentPos(); };
8171 uint64_t GetCurrentPTSOffset() { return currentPTSOffset_; };
8272 uint64_t GetAbsolutePTSOffset() { return absolutePTSOffset_; };
8373 bool waitingForSegment(bool checkTime = false) const;
8474 void FixateInitialization(bool on);
8575 void SetSegmentFileOffset(uint64_t offset) { m_segmentFileOffset = offset; };
76 bool StreamChanged() { return stream_changed_; }
8677 protected:
87 virtual bool download(const char* url, const std::map<std::string, std::string> &mediaHeaders){ return false; };
88 virtual bool parseIndexRange() { return false; };
89 bool write_data(const void *buffer, size_t buffer_size);
90 bool prepareDownload(const AdaptiveTree::Segment *seg);
91 adaptive::AdaptiveTree& GetTree() { return tree_; };
78 virtual bool download(const char* url,
79 const std::map<std::string, std::string>& mediaHeaders,
80 std::string* lockfreeBuffer)
81 {
82 return false;
83 };
84 virtual bool parseIndexRange(AdaptiveTree::Representation* rep, const std::string& buffer)
85 {
86 return false;
87 };
88 bool write_data(const void* buffer, size_t buffer_size, std::string* lockfreeBuffer);
9289 virtual void SetLastUpdated(std::chrono::system_clock::time_point tm) {};
9390 std::chrono::time_point<std::chrono::system_clock> lastUpdated_;
91 virtual bool download_segment();
92 std::string download_url_;
93 std::map<std::string, std::string> media_headers_, download_headers_;
94 struct SEGMENTBUFFER
95 {
96 std::string buffer;
97 AdaptiveTree::Segment segment;
98 unsigned int segment_number;
99 AdaptiveTree::Representation* rep;
100 };
101 std::vector<SEGMENTBUFFER> segment_buffers_;
102
94103
95104 private:
105 enum STATE
106 {
107 RUNNING,
108 STOPPED,
109 PAUSED
110 } state_;
111
96112 // Segment download section
97 void ResetSegment();
98 bool download_segment();
113 void ResetSegment(const AdaptiveTree::Segment* segment);
114 void ResetActiveBuffer(bool oneValid);
115 void StopWorker(STATE state);
99116 void worker();
117 bool prepareNextDownload();
118 bool prepareDownload(const AdaptiveTree::Representation* rep,
119 const AdaptiveTree::Segment* seg,
120 unsigned int segNum);
100121 int SecondsSinceUpdate() const;
101 static void ReplacePlaceholder(std::string &url, const std::string placeholder, uint64_t value);
122 static void ReplacePlaceholder(std::string& url, const std::string placeholder, uint64_t value);
123 bool ResolveSegmentBase(AdaptiveTree::Representation* rep, bool stopWorker);
102124
103125 struct THREADDATA
104126 {
116138 {
117139 thread_stop_ = true;
118140 signal_dl_.notify_one();
119 download_thread_.join();
141 if (download_thread_.joinable())
142 download_thread_.join();
120143 };
121144
122145 std::mutex mutex_rw_, mutex_dl_;
127150 THREADDATA *thread_data_;
128151
129152 AdaptiveTree &tree_;
130 AdaptiveTree::StreamType type_;
131153 AdaptiveStreamObserver *observer_;
132154 // Active configuration
133155 AdaptiveTree::Period* current_period_;
134156 AdaptiveTree::AdaptationSet* current_adp_;
135157 AdaptiveTree::Representation *current_rep_;
136 std::string download_url_;
137 //We assume that a single segment can build complete frames
138 std::string segment_buffer_;
139 std::map<std::string, std::string> media_headers_, download_headers_;
158
159 static const size_t MAXSEGMENTBUFFER;
160 // number of segmentbuffers whith valid segment, always >= valid_segment_buffers_
161 size_t available_segment_buffers_;
162 // number of segment_buffers which are downloaded / downloading
163 uint32_t assured_buffer_length_;
164 uint32_t max_buffer_length_;
165 size_t valid_segment_buffers_;
166 uint32_t rep_counter_;
167 AdaptiveTree::Representation *prev_rep_; // used for rep_counter_
168 AdaptiveTree::Representation* last_rep_; // used to align new live rep with old
169
140170 std::size_t segment_read_pos_;
141171 uint64_t absolute_position_;
142172 uint64_t currentPTSOffset_, absolutePTSOffset_;
143173
144 uint16_t width_, height_;
145 uint32_t bandwidth_;
146 uint32_t hdcpLimit_;
147 uint16_t hdcpVersion_;
148174 uint16_t download_pssh_set_;
149175 unsigned int download_segNum_;
150 bool stopped_;
176 bool worker_processing_;
151177 uint8_t m_iv[16];
152178 bool m_fixateInitialization;
153179 uint64_t m_segmentFileOffset;
154180 bool play_timeshift_buffer_;
181 bool stream_changed_ = false;
182 bool choose_rep_;
155183 };
156184 };
3636 range_begin_ = range_end_ = 0;
3737 }
3838
39 void AdaptiveTree::Segment::Copy(const Segment* src)
40 {
41 delete[] url, url = nullptr;
42 *this = *src;
43 if (src->url)
44 {
45 size_t len = strlen(src->url) + 1;
46 url = new char[len];
47 memcpy((void*)url, src->url, len);
48 }
49 }
50
3951 AdaptiveTree::AdaptiveTree()
4052 : current_period_(nullptr)
4153 , next_period_(nullptr)
4658 , stream_start_(0)
4759 , available_time_(0)
4860 , base_time_(0)
61 , live_delay_(0)
4962 , minPresentationOffset(0)
5063 , has_timeshift_buffer_(false)
5164 , has_overall_seconds_(false)
52 , download_speed_(0.0)
53 , average_download_speed_(0.0f)
5465 , updateInterval_(~0)
5566 , updateThread_(nullptr)
5667 , lastUpdated_(std::chrono::system_clock::now())
104115
105116 uint32_t AdaptiveTree::estimate_segcount(uint64_t duration, uint32_t timescale)
106117 {
118 Log(LOGLEVEL_DEBUG,"estimate_segcount duration=%llu , timescale=%u",duration , timescale);
119
107120 duration /= timescale;
108121 return static_cast<uint32_t>((overallSeconds_ / duration)*1.01);
109122 }
110123
111 void AdaptiveTree::set_download_speed(double speed)
112 {
113 std::lock_guard<std::mutex> lck(treeMutex_);
114
115 download_speed_ = speed;
116 if (!average_download_speed_)
117 average_download_speed_ = download_speed_;
118 else
119 average_download_speed_ = average_download_speed_*0.9 + download_speed_*0.1;
120 };
121
122124 void AdaptiveTree::SetFragmentDuration(const AdaptationSet* adp, const Representation* rep, size_t pos, uint64_t timestamp, uint32_t fragmentDuration, uint32_t movie_timescale)
123125 {
124 if (!has_timeshift_buffer_ || !update_parameter_.empty() ||
126 if (!has_timeshift_buffer_ || HasUpdateThread() ||
125127 (rep->flags_ & AdaptiveTree::Representation::URLSEGMENTS) != 0)
126128 return;
127129
382384 {
383385 for (std::vector<Period*>::const_iterator bp(periods_.begin()), ep(periods_.end()); bp != ep; ++bp)
384386 {
385 std::stable_sort((*bp)->adaptationSets_.begin(), (*bp)->adaptationSets_.end(), AdaptationSet::compare);
386
387 // Merge AUDIO streams, some provider pass everythng in own Audio sets
387 // Merge VIDEO & AUDIO adaption sets
388388 for (std::vector<AdaptationSet*>::iterator ba((*bp)->adaptationSets_.begin()), ea((*bp)->adaptationSets_.end()); ba != ea;)
389389 {
390 if ((*ba)->type_ == AUDIO && ba + 1 != ea && AdaptationSet::mergeable(*ba, *(ba + 1)))
390 if (((*ba)->type_ == AUDIO || (*ba)->type_ == VIDEO) && ba + 1 != ea && AdaptationSet::mergeable(*ba, *(ba + 1)))
391391 {
392392 for (size_t i(1); i < (*bp)->psshSets_.size(); ++i)
393393 if ((*bp)->psshSets_[i].adaptation_set_ == *ba)
402402 ++ba;
403403 }
404404
405 std::stable_sort((*bp)->adaptationSets_.begin(), (*bp)->adaptationSets_.end(), AdaptationSet::compare);
406
405407 for (std::vector<AdaptationSet*>::const_iterator ba((*bp)->adaptationSets_.begin()), ea((*bp)->adaptationSets_.end()); ba != ea; ++ba)
406408 {
407409 std::sort((*ba)->representations_.begin(), (*ba)->representations_.end(), Representation::compare);
134134 struct Segment
135135 {
136136 void SetRange(const char *range);
137 void Copy(const Segment* src);
137138 uint64_t range_begin_ = 0; //Either byterange start or timestamp or ~0
138139 uint64_t range_end_ = 0; //Either byterange end or sequence_id if range_begin is ~0
139140 const char *url = nullptr;
179180 uint16_t width_, height_;
180181 uint32_t fpsRate_, fpsScale_;
181182 float aspect_;
183
184 uint32_t assured_buffer_duration_;
185 uint32_t max_buffer_duration_;
182186 //Flags
183187 static const uint16_t BYTERANGE = 0;
184188 static const uint16_t INDEXRANGEEXACT = 1;
193197 static const uint16_t WAITFORSEGMENT = 512;
194198 static const uint16_t INITIALIZATION_PREFIXED = 1024;
195199 static const uint16_t DOWNLOADED = 2048;
200 static const uint16_t INITIALIZED = 4096;
196201
197202 uint16_t flags_;
198203 uint16_t hdcpVersion_;
212217 uint32_t timescale_ext_, timescale_int_;
213218 Segment initialization_;
214219 SPINCACHE<Segment> segments_;
220 std::chrono::time_point<std::chrono::system_clock> repLastUpdated_;
215221 const Segment *current_segment_;
216222 const Segment *get_initialization()const { return (flags_ & INITIALIZATION) ? &initialization_ : 0; };
217223 const Segment *get_next_segment(const Segment *seg)const
247253 uint32_t getCurrentSegmentNumber() const
248254 {
249255 return current_segment_ ? get_segment_pos(current_segment_) + startNumber_ : ~0U;
256 };
257
258 uint32_t getSegmentNumber(const Segment *segment) const
259 {
260 return segment ? get_segment_pos(segment) + startNumber_ : ~0U;
250261 };
251262
252263 void SetScaling()
274285
275286 struct AdaptationSet
276287 {
277 AdaptationSet() :type_(NOTYPE), timescale_(0), duration_(0), startPTS_(0), startNumber_(1), impaired_(false), original_(false), default_(false), forced_(false){ language_ = "unk"; };
288 AdaptationSet() :type_(NOTYPE), timescale_(0), duration_(0), startPTS_(0), best_rep_(0), min_rep_(0), startNumber_(1), impaired_(false), original_(false), default_(false), forced_(false) { language_ = "unk"; };
278289 ~AdaptationSet() { for (std::vector<Representation* >::const_iterator b(representations_.begin()), e(representations_.end()); b != e; ++b) delete *b; };
279290 void CopyBasicData(AdaptationSet* src);
280291 StreamType type_;
290301 std::string codecs_;
291302 std::string audio_track_id_;
292303 std::string name_;
304 std::vector<std::string> switching_ids_;
293305 std::vector<Representation*> representations_;
306 Representation* best_rep_;
307 Representation* min_rep_;
294308 SPINCACHE<uint32_t> segment_durations_;
295309 SegmentTemplate segtpl_;
296310
299313 return *segment_durations_[pos];
300314 };
301315
302 static bool compare(const AdaptationSet* a, const AdaptationSet *b)
316 static bool compare(const AdaptationSet* a, const AdaptationSet* b)
303317 {
304318 if (a->type_ != b->type_)
305 return a->type_ < b->type_;
306 if (a->language_ != b->language_)
307 return a->language_ < b->language_;
319 return false;
308320 if (a->default_ != b->default_)
309321 return a->default_;
310322
347359 return false;
348360 };
349361
350 static bool mergeable(const AdaptationSet* a, const AdaptationSet *b)
351 {
352 if (a->type_ == b->type_
353 && a->timescale_ == b->timescale_
354 && a->duration_ == b->duration_
355 && a->startPTS_ == b->startPTS_
356 && a->startNumber_ == b->startNumber_
357 && a->impaired_ == b->impaired_
358 && a->original_ == b->original_
359 && a->default_ == b->default_
360 && a->language_ == b->language_
361 && a->mimeType_ == b->mimeType_
362 && a->base_url_ == b->base_url_
363 && a->audio_track_id_ == b->audio_track_id_
364 && a->name_ == b->name_
365 && a->id_ == b->id_
366 && a->group_ == b->group_
367 && compareCodecs(a->codecs_, b->codecs_))
362 static bool mergeable(const AdaptationSet* a, const AdaptationSet* b)
363 {
364 if (a->type_ != b->type_)
365 return false;
366
367 if (a->type_ == VIDEO)
368368 {
369 return a->type_ == AUDIO
369 if (a->group_ == b->group_
370 && std::find(a->switching_ids_.begin(), a->switching_ids_.end(), b->id_) != a->switching_ids_.end()
371 && std::find(b->switching_ids_.begin(), b->switching_ids_.end(), a->id_) != b->switching_ids_.end())
372 {
373 return true;
374 }
375 }
376 else if (a->type_ == AUDIO)
377 {
378 if (a->timescale_ == b->timescale_
379 && a->duration_ == b->duration_
380 && a->startPTS_ == b->startPTS_
381 && a->startNumber_ == b->startNumber_
382 && a->impaired_ == b->impaired_
383 && a->original_ == b->original_
384 && a->default_ == b->default_
385 && a->language_ == b->language_
386 && a->mimeType_ == b->mimeType_
387 && a->base_url_ == b->base_url_
388 && a->audio_track_id_ == b->audio_track_id_
389 && a->name_ == b->name_
390 && a->id_ == b->id_
391 && a->group_ == b->group_
392 && compareCodecs(a->codecs_, b->codecs_)
370393 && a->representations_[0]->channelCount_ == b->representations_[0]->channelCount_
371 && compareCodecs(a->representations_[0]->codecs_, b->representations_[0]->codecs_);
394 && compareCodecs(a->representations_[0]->codecs_, b->representations_[0]->codecs_))
395 {
396 return true;
397 }
372398 }
399
373400 return false;
374401 };
375402 }*current_adaptationset_;
412439 SegmentTemplate segtpl_;
413440 }*current_period_, *next_period_;
414441
442 struct RepresentationChooser
443 {
444 virtual Representation* ChooseRepresentation(AdaptationSet* adp) = 0;
445 virtual Representation* ChooseNextRepresentation(AdaptationSet* adp ,
446 Representation* rep,
447 size_t *available_segment_buffers_,
448 size_t *valid_segment_buffers_,
449 uint32_t *assured_buffer_length_,
450 uint32_t * max_buffer_length_,
451 uint32_t rep_counter_) = 0;
452 } *representation_chooser_ = nullptr;
453
415454 std::vector<Period*> periods_;
416455 std::string manifest_url_;
417456 std::string base_url_;
426465 uint32_t currentNode_;
427466 uint32_t segcount_;
428467 uint32_t initial_sequence_ = ~0UL;
429 uint64_t overallSeconds_, stream_start_, available_time_, base_time_;
468 uint64_t overallSeconds_, stream_start_, available_time_, base_time_, live_delay_;
430469 uint64_t minPresentationOffset;
431470 bool has_timeshift_buffer_, has_overall_seconds_;
432471
433 uint32_t bandwidth_;
434472 std::map<std::string, std::string> manifest_headers_;
435
436 double download_speed_, average_download_speed_;
437473
438474 std::string supportedKeySystem_, location_;
439475
462498 {
463499 return PREPARE_RESULT_OK;
464500 };
501 virtual std::chrono::time_point<std::chrono::system_clock> GetRepLastUpdated(const Representation* rep) { return std::chrono::system_clock::now(); }
465502 virtual void OnDataArrived(unsigned int segNum, uint16_t psshSet, uint8_t iv[16], const uint8_t *src, uint8_t *dst, size_t dstOffset, size_t dataSize);
466503 virtual void RefreshSegments(Period* period,
467504 AdaptationSet* adp,
471508 bool has_type(StreamType t);
472509 void FreeSegments(Period* period, Representation* rep);
473510 uint32_t estimate_segcount(uint64_t duration, uint32_t timescale);
474 double get_download_speed() const { return download_speed_; };
475 double get_average_download_speed() const { return average_download_speed_; };
476 void set_download_speed(double speed);
477511 void SetFragmentDuration(const AdaptationSet* adp, const Representation* rep, size_t pos, uint64_t timestamp, uint32_t fragmentDuration, uint32_t movie_timescale);
478512 uint16_t insert_psshset(StreamType type, Period* period = nullptr, AdaptationSet* adp = nullptr);
479513
491525 bool HasUpdateThread() const { return updateThread_ != 0 && has_timeshift_buffer_ && updateInterval_ && !update_parameter_.empty(); };
492526 void RefreshUpdateThread();
493527 const std::chrono::time_point<std::chrono::system_clock> GetLastUpdated() const { return lastUpdated_; };
528
529 Representation* ChooseRepresentation(AdaptationSet* adp)
530 {
531 return representation_chooser_ ? representation_chooser_->ChooseRepresentation(adp) : nullptr;
532 };
533 Representation* ChooseNextRepresentation(AdaptationSet* adp,
534 Representation* rep,
535 size_t *available_segment_buffers_,
536 size_t *valid_segment_buffers_,
537 uint32_t *assured_buffer_length_,
538 uint32_t * max_buffer_length_,
539 uint32_t rep_counter_)
540 {
541 return representation_chooser_ ? representation_chooser_->ChooseNextRepresentation(adp,rep,available_segment_buffers_,
542 valid_segment_buffers_, assured_buffer_length_,
543 max_buffer_length_, rep_counter_) : nullptr;
544 };
545
546 int SecondsSinceRepUpdate(Representation* rep)
547 {
548 return static_cast<int>(
549 std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now() - GetRepLastUpdated(rep))
550 .count());
551 }
494552
495553 protected:
496554 virtual bool download(const char* url,
0 /*******************************************************
1 | RepresentationChooser
2 ********************************************************/
3
4 #include "RepresentationChooser.h"
5 #include "../log.h"
6
7
8 //Pending- The plan was to group representations, this will give an easier switching control.
9 //Streams will get filtered in 6 buckets: 240p, 480p, HD-720p, FHD-1080p, QHD-1440p, UHD-2160p
10 //This will help in better representation switching when lots of representations are provided by CDN
11 //HD-720p and above will opt for highest fps. Eg: 720p24, 720p30, 720p50, 720p60 are available, it will go for 720p60
12 //FHD-1080p and above will opt for HDR if available
13 /*enum GenRep
14 {
15 R240P,
16 R480P,
17 HD,
18 FHD,
19 QHD,
20 UHD
21 };*/
22 //vector<pair<int,int> > mapping_res_to_adp_; //mapping to < GenRep ,adp->representations_ index> . Will store 6 resolution buckets if available (90% match)
23 //This to be run during initialization function
24 //int GenRepPixel[6]={};
25 /*for(int i=0;i<6;i++)
26 {
27 uint32_t diff=INT_MAX, index=-1;
28 for (std::vector<adaptive::AdaptiveTree::Representation*>::const_iterator
29 br(adp->representations_.begin()),
30 er(adp->representations_.end());
31 br != er; ++br)
32 {
33 //Select for best match with error of 15%
34 int res= abs(static_cast<int>((*br)->width_ * (*br)->height_) - static_cast<int>(GenRepPixel[i]);
35 if( res < 0.15*GenRepPixel[i] && res < diff)
36 {
37 diff=res;
38 index= br- representations_.begin();
39 }
40 }
41 if(index!=-1)
42 mapping_res_to_adp_.push_back({i,index});
43 }
44 */
45
46 DefaultRepresentationChooser::~DefaultRepresentationChooser() {};
47
48 //SetDisplayDimensions will be called upon changed dimension only (will be filtered beforehand by xbmc api calls to SetVideoResolution)
49 void DefaultRepresentationChooser::SetDisplayDimensions(unsigned int w, unsigned int h)
50 {
51 if (res_to_be_changed_)
52 {
53 display_width_ = w;
54 display_height_ = h;
55 //Log(LOGLEVEL_DEBUG, "SetDisplayDimensions(unsigned int w=%u, unsigned int h=%u) ",w,h);
56
57 width_ = ignore_display_ ? 8192 : display_width_;
58 switch (secure_video_session_ ? max_secure_resolution_ : max_resolution_)
59 {
60 case 1:
61 if (width_ > 640)
62 width_ = 640;
63 break;
64 case 2:
65 if (width_ > 960)
66 width_ = 960;
67 break;
68 case 3:
69 if (width_ > 1280)
70 width_ = 1280;
71 break;
72 case 4:
73 if (width_ > 1920)
74 width_ = 1920;
75 break;
76 default:;
77 }
78
79 height_ = ignore_display_ ? 8192 : display_height_;
80 switch (secure_video_session_ ? max_secure_resolution_ : max_resolution_)
81 {
82 case 1:
83 if (height_ > 480)
84 height_ = 480;
85 break;
86 case 2:
87 if (height_ > 640)
88 height_ = 640;
89 break;
90 case 3:
91 if (height_ > 720)
92 height_ = 720;
93 break;
94 case 4:
95 if (height_ > 1080)
96 height_ = 1080;
97 break;
98 default:;
99 }
100 next_display_width_ = display_width_;
101 next_display_height_ = display_height_;
102 res_to_be_changed_ = false;
103 }
104 else
105 {
106 next_display_width_ = w;
107 next_display_height_ = h;
108 }
109 lastDimensionUpdated_ = std::chrono::steady_clock::now();
110 };
111
112 void DefaultRepresentationChooser::SetMaxUserBandwidth(uint32_t max_user_bandwidth)
113 {
114 if (max_bandwidth_ == 0 || (max_user_bandwidth && max_bandwidth_ > max_user_bandwidth))
115 max_bandwidth_ = max_user_bandwidth;
116 };
117
118 void DefaultRepresentationChooser::Prepare(bool secure_video_session)
119 {
120 secure_video_session_ = secure_video_session;
121 res_to_be_changed_ = true;
122 SetDisplayDimensions(display_width_, display_height_);
123
124 Log(LOGLEVEL_DEBUG, "Stream selection conditions: w: %u, h: %u, bw: %u", width_, height_,
125 bandwidth_);
126 };
127
128 adaptive::AdaptiveTree::Representation* DefaultRepresentationChooser::ChooseNextRepresentation(
129 adaptive::AdaptiveTree::AdaptationSet* adp,
130 adaptive::AdaptiveTree::Representation* rep,
131 size_t *valid_segment_buffers_,
132 size_t *available_segment_buffers_,
133 uint32_t *assured_buffer_length_,
134 uint32_t * max_buffer_length_,
135 uint32_t rep_counter_) //to be called from ensuresegment only, SEPERATED FOR FURTHER DEVELOPMENT, CAN BE MERGED AFTERWARDS
136 {
137 if ((std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - lastDimensionUpdated_).count() > 15)
138 && (!ignore_window_change_)
139 && (!ignore_display_)
140 && !(next_display_width_ == display_width_ && next_display_height_ == display_height_))
141 {
142 res_to_be_changed_ = true;
143 Log(LOGLEVEL_DEBUG, "Updating new display resolution to: (w X h) : (%u X %u)", next_display_width_, next_display_height_);
144 SetDisplayDimensions(next_display_width_, next_display_height_);
145 }
146
147 adaptive::AdaptiveTree::Representation *next_rep(0);//best_rep definition to be finalised
148 unsigned int bestScore(~0);
149 uint16_t hdcpVersion = 99;
150 uint32_t hdcpLimit = 0;
151
152
153 current_bandwidth_ = get_average_download_speed();
154 Log(LOGLEVEL_DEBUG, "current_bandwidth_: %u ", current_bandwidth_);
155
156 float buffer_hungry_factor = 1.0;// can be made as a sliding input
157 buffer_hungry_factor = ((float)*valid_segment_buffers_ / (float)*assured_buffer_length_);
158 buffer_hungry_factor = buffer_hungry_factor > 0.5 ? buffer_hungry_factor : 0.5;
159
160 uint32_t bandwidth = (uint32_t)(buffer_hungry_factor*7.0*current_bandwidth_);
161 Log(LOGLEVEL_DEBUG, "bandwidth set: %u ", bandwidth);
162
163 if (*valid_segment_buffers_ >= *assured_buffer_length_)
164 {
165 return adp->best_rep_;
166 }
167 if ((*valid_segment_buffers_ > 6) && (bandwidth >= rep->bandwidth_ * 2) && (rep != adp->best_rep_) && (adp->best_rep_->bandwidth_ <= bandwidth)) //overwrite case, more internet data
168 {
169 *valid_segment_buffers_ = std::max(*valid_segment_buffers_ / 2, *valid_segment_buffers_ - rep_counter_);
170 *available_segment_buffers_ = *valid_segment_buffers_; //so that ensure writes again with new rep
171 }
172
173 for (std::vector<adaptive::AdaptiveTree::Representation*>::const_iterator br(adp->representations_.begin()),
174 er(adp->representations_.end());
175 br != er; ++br)
176 {
177 unsigned int score;
178 if (!hdcp_override_)
179 {
180 hdcpVersion = decrypter_caps_[(*br)->pssh_set_].hdcpVersion;
181 hdcpLimit = decrypter_caps_[(*br)->pssh_set_].hdcpLimit;
182 }
183
184 if ((*br)->bandwidth_ <= bandwidth && (*br)->hdcpVersion_ <= hdcpVersion &&
185 (!hdcpLimit || static_cast<uint32_t>((*br)->width_) * (*br)->height_ <= hdcpLimit) &&
186 ((score = abs(static_cast<int>((*br)->width_ * (*br)->height_) -
187 static_cast<int>(width_ * height_)) +
188 static_cast<unsigned int>(sqrt(bandwidth - (*br)->bandwidth_))) < bestScore))
189 {
190 bestScore = score;
191 next_rep = (*br);
192 }
193 else if (!adp->min_rep_ || (*br)->bandwidth_ < adp->min_rep_->bandwidth_)
194 adp->min_rep_ = (*br);
195 }
196 if (!next_rep)
197 next_rep = adp->min_rep_;
198
199 //Log(LOGLEVEL_DEBUG, "NextRep bandwidth: %u ",next_rep->bandwidth_);
200
201 return next_rep;
202 };
203
204 adaptive::AdaptiveTree::Representation* DefaultRepresentationChooser::ChooseRepresentation(adaptive::AdaptiveTree::AdaptationSet* adp) //to be called single time
205 {
206 adaptive::AdaptiveTree::Representation *new_rep(0);
207 unsigned int bestScore(~0), valScore(~0);
208 uint16_t hdcpVersion = 99;
209 uint32_t hdcpLimit = 0;
210
211
212 uint32_t bandwidth = min_bandwidth_;
213 if (current_bandwidth_ > bandwidth_)
214 bandwidth = current_bandwidth_;
215 if (max_bandwidth_ && bandwidth_ > max_bandwidth_)
216 bandwidth = max_bandwidth_;
217
218 bandwidth = static_cast<uint32_t>(bandwidth_ *
219 (adp->type_ == adaptive::AdaptiveTree::VIDEO ? 0.9 : 0.1));
220
221 for (std::vector<adaptive::AdaptiveTree::Representation*>::const_iterator
222 br(adp->representations_.begin()),
223 er(adp->representations_.end());
224 br != er; ++br)
225 {
226 (*br)->assured_buffer_duration_ = assured_buffer_duration_;
227 (*br)->max_buffer_duration_ = max_buffer_duration_;
228 unsigned int score;
229 if (!hdcp_override_)
230 {
231 hdcpVersion = decrypter_caps_[(*br)->pssh_set_].hdcpVersion;
232 hdcpLimit = decrypter_caps_[(*br)->pssh_set_].hdcpLimit;
233 }
234
235 if ((*br)->bandwidth_ <= bandwidth && (*br)->hdcpVersion_ <= hdcpVersion &&
236 (!hdcpLimit || static_cast<uint32_t>((*br)->width_) * (*br)->height_ <= hdcpLimit) &&
237 ((score = abs(static_cast<int>((*br)->width_ * (*br)->height_) -
238 static_cast<int>(width_ * height_)) +
239 static_cast<unsigned int>(sqrt(bandwidth - (*br)->bandwidth_))) < bestScore))
240 {
241 bestScore = score;
242 new_rep = (*br);
243 }
244 else if (!adp->min_rep_ || (*br)->bandwidth_ < adp->min_rep_->bandwidth_)
245 adp->min_rep_ = (*br);
246
247 if (((*br)->hdcpVersion_ <= hdcpVersion) && ((!hdcpLimit || static_cast<uint32_t>((*br)->width_) * (*br)->height_ <= hdcpLimit))
248 && ((score = abs(static_cast<int>((*br)->width_ * (*br)->height_) - static_cast<int>(width_ * height_))) <= valScore)) //it is bandwidth independent(if multiple same resolution bandwidth, will select first rep)
249 {
250 valScore = score;
251 if (!adp->best_rep_ || (*br)->bandwidth_ > adp->best_rep_->bandwidth_)
252 adp->best_rep_ = (*br);
253 }
254
255 }
256 if (!new_rep)
257 new_rep = adp->min_rep_;
258 if (!adp->best_rep_)
259 adp->best_rep_ = adp->min_rep_;
260 Log(LOGLEVEL_DEBUG, "ASSUREDBUFFERDURATION selected: %d ", new_rep->assured_buffer_duration_);
261 Log(LOGLEVEL_DEBUG, "MAXBUFFERDURATION selected: %d ", new_rep->max_buffer_duration_);
262
263 return new_rep;
264 };
265
266 double DefaultRepresentationChooser::get_download_speed() const { return download_speed_; };
267 double DefaultRepresentationChooser::get_average_download_speed() const { return average_download_speed_; };
268 void DefaultRepresentationChooser::set_download_speed(double speed)
269 {
270 download_speed_ = speed;
271 if (!average_download_speed_)
272 average_download_speed_ = download_speed_;
273 else
274 average_download_speed_ = average_download_speed_ * 0.8 + download_speed_ * 0.2;
275 };
0 #pragma once
1 #include "AdaptiveStream.h"
2 #include "../SSD_dll.h"
3
4 struct DefaultRepresentationChooser : adaptive::AdaptiveTree::RepresentationChooser
5 {
6 void SetDisplayDimensions(unsigned int w, unsigned int h);
7 void SetMaxUserBandwidth(uint32_t max_user_bandwidth);
8 void Prepare(bool secure_video_session);
9 adaptive::AdaptiveTree::Representation* ChooseNextRepresentation(
10 adaptive::AdaptiveTree::AdaptationSet* adp,
11 adaptive::AdaptiveTree::Representation* rep,
12 size_t *valid_segment_buffers_,
13 size_t *available_segment_buffers_,
14 uint32_t *assured_buffer_length_,
15 uint32_t * max_buffer_length_,
16 uint32_t rep_counter_);
17 adaptive::AdaptiveTree::Representation* ChooseRepresentation(adaptive::AdaptiveTree::AdaptationSet* adp);
18 virtual ~DefaultRepresentationChooser();
19 double get_download_speed() const;
20 double get_average_download_speed() const;
21 void set_download_speed(double speed);
22
23 uint16_t display_width_, display_height_;
24 uint16_t width_, height_;
25 uint32_t bandwidth_;
26
27 uint16_t next_display_width_ = 0, next_display_height_ = 0;
28 bool res_to_be_changed_ = 1;
29
30 adaptive::AdaptiveTree::Representation *best_rep_, *min_rep_;//min_rep_ will be used for window-change detection
31
32 std::chrono::steady_clock::time_point lastDimensionUpdated_ = std::chrono::steady_clock::now();
33
34 bool ignore_display_;
35 bool secure_video_session_;
36 bool hdcp_override_;
37 int max_resolution_, max_secure_resolution_;
38 bool ignore_window_change_;
39
40 uint32_t current_bandwidth_;
41 uint32_t min_bandwidth_, max_bandwidth_;
42 uint32_t assured_buffer_duration_;
43 uint32_t max_buffer_duration_;
44
45 double download_speed_, average_download_speed_;
46 std::vector<SSD::SSD_DECRYPTER::SSD_CAPS> decrypter_caps_;
47 };
3131 #include "parser/TTML.h"
3232 #include "parser/WebVTT.h"
3333
34 #include <chrono>
3435 #include <algorithm>
3536 #include <iostream>
37 #include <math.h>
3638 #include <sstream>
3739 #include <stdio.h>
3840 #include <string.h>
310312 }
311313
312314 bool KodiAdaptiveStream::download(const char* url,
313 const std::map<std::string, std::string>& mediaHeaders)
315 const std::map<std::string, std::string>& mediaHeaders,
316 std::string* lockfreeBuffer)
314317 {
315318 kodi::vfs::CFile file;
316319
328331 file.CURLAddOption(ADDON_CURL_OPTION_HEADER, entry.first.c_str(), entry.second.c_str());
329332 }
330333
331 if (file.CURLOpen(ADDON_READ_CHUNKED | ADDON_READ_NO_CACHE |
332 ADDON_READ_AUDIO_VIDEO))
334 if (file.CURLOpen(ADDON_READ_CHUNKED | ADDON_READ_NO_CACHE | ADDON_READ_AUDIO_VIDEO))
333335 {
334336 int returnCode = -1;
335337 std::string proto = file.GetPropertyValue(ADDON_FILE_PROPERTY_RESPONSE_PROTOCOL, "");
348350 // read the file
349351 char* buf = (char*)malloc(32 * 1024);
350352 size_t nbReadOverall = 0;
351 while ((nbRead = file.Read(buf, 32 * 1024)) > 0 && ~nbRead && write_data(buf, nbRead))
353 bool write_ok = true;
354 while ((nbRead = file.Read(buf, 32 * 1024)) > 0 && ~nbRead &&
355 (write_ok = write_data(buf, nbRead, lockfreeBuffer)))
352356 nbReadOverall += nbRead;
353357 free(buf);
354358
355 if (!nbReadOverall)
356 {
357 kodi::Log(ADDON_LOG_ERROR, "Download doesn't provide any data: %s", url);
358 return false;
359 }
360
361 double current_download_speed_ = file.GetFileDownloadSpeed();
362 //Calculate the new downloadspeed to 1MB
363 static const size_t ref_packet = 1024 * 1024;
364 if (nbReadOverall >= ref_packet)
365 set_download_speed(current_download_speed_);
359 if (write_ok)
360 {
361 if (!nbReadOverall)
362 {
363 kodi::Log(ADDON_LOG_ERROR, "Download doesn't provide any data: %s", url);
364 return false;
365 }
366
367 double current_download_speed_ = file.GetFileDownloadSpeed();
368 //Calculate the new downloadspeed to 1MB
369 static const size_t ref_packet = 1024 * 1024;
370 if (nbReadOverall >= ref_packet)
371 chooser_->set_download_speed(current_download_speed_);
372 else
373 {
374 double ratio = (double)nbReadOverall / ref_packet;
375 chooser_->set_download_speed((chooser_->get_download_speed() * (1.0 - ratio)) +
376 current_download_speed_ * ratio);
377 }
378 kodi::Log(ADDON_LOG_DEBUG,
379 "Download %s finished, avg speed: %0.2lfbyte/s, current speed: %0.2lfbyte/s", url,
380 chooser_->get_download_speed(), current_download_speed_);
381 //pass download speed to
382 }
366383 else
367 {
368 double ratio = (double)nbReadOverall / ref_packet;
369 set_download_speed((get_download_speed() * (1.0 - ratio)) +
370 current_download_speed_ * ratio);
371 }
372 kodi::Log(ADDON_LOG_DEBUG,
373 "Download finished: %s , avg speed: %0.2lfbyte/s, current speed: %0.2lfbyte/s", url,
374 get_download_speed(), current_download_speed_);
384 kodi::Log(ADDON_LOG_DEBUG, "Download %s cancelled", url);
375385 }
376386 file.Close();
377387 return nbRead == 0;
379389 return false;
380390 }
381391
382 bool KodiAdaptiveStream::parseIndexRange()
392 bool KodiAdaptiveStream::parseIndexRange(adaptive::AdaptiveTree::Representation* rep,
393 const std::string& buffer)
383394 {
384395 kodi::Log(ADDON_LOG_DEBUG, "Build segments from SIDX atom...");
385 AP4_DASHStream byteStream(this);
386
387 adaptive::AdaptiveTree::Representation* rep(
388 const_cast<adaptive::AdaptiveTree::Representation*>(getRepresentation()));
396 AP4_MemoryByteStream byteStream((const AP4_Byte*)(buffer.data()), buffer.size());
397
389398 adaptive::AdaptiveTree::AdaptationSet* adp(
390399 const_cast<adaptive::AdaptiveTree::AdaptationSet*>(getAdaptationSet()));
391400
425434 {
426435 if (!rep->indexRangeMin_)
427436 {
428 AP4_File f(byteStream, AP4_DefaultAtomFactory::Instance, true);
437 AP4_File f(byteStream, AP4_DefaultAtomFactory::Instance_, true);
429438 AP4_Movie* movie = f.GetMovie();
430439 if (movie == NULL)
431440 {
432441 kodi::Log(ADDON_LOG_ERROR, "No MOOV in stream!");
433442 return false;
434443 }
435 if (1 /*!(rep->flags_ & adaptive::AdaptiveTree::Representation::INITIALIZATION)*/)
436 {
437 rep->flags_ |= adaptive::AdaptiveTree::Representation::INITIALIZATION;
438 rep->initialization_.range_begin_ = 0;
439 AP4_Position pos;
440 byteStream.Tell(pos);
441 rep->initialization_.range_end_ = pos - 1;
442 }
444 rep->flags_ |= adaptive::AdaptiveTree::Representation::INITIALIZATION;
445 rep->initialization_.range_begin_ = 0;
446 AP4_Position pos;
447 byteStream.Tell(pos);
448 rep->initialization_.range_end_ = pos - 1;
443449 }
444450
445451 adaptive::AdaptiveTree::Segment seg;
449455 do
450456 {
451457 AP4_Atom* atom(NULL);
452 if (AP4_FAILED(AP4_DefaultAtomFactory::Instance.CreateAtomFromStream(byteStream, atom)))
458 if (AP4_FAILED(AP4_DefaultAtomFactory::Instance_.CreateAtomFromStream(byteStream, atom)))
453459 {
454460 kodi::Log(ADDON_LOG_ERROR, "Unable to create SIDX from IndexRange bytes");
455461 return false;
745751 AP4_AvcPictureParameterSet pps;
746752 for (unsigned int i(0); i < ppsList.ItemCount(); ++i)
747753 {
748 if (AP4_SUCCEEDED(AP4_AvcFrameParser::ParsePPS(ppsList[i].GetData(),
749 ppsList[i].GetDataSize(), pps)) &&
754 AP4_AvcFrameParser fp;
755 if (AP4_SUCCEEDED(fp.ParsePPS(ppsList[i].GetData(),
756 ppsList[i].GetDataSize(), pps)) &&
750757 pps.pic_parameter_set_id == pictureId)
751758 {
752759 AP4_Array<AP4_DataBuffer>& spsList = avc->GetSequenceParameters();
753760 AP4_AvcSequenceParameterSet sps;
754761 for (unsigned int i(0); i < spsList.ItemCount(); ++i)
755762 {
756 if (AP4_SUCCEEDED(AP4_AvcFrameParser::ParseSPS(spsList[i].GetData(),
757 spsList[i].GetDataSize(), sps)) &&
763 if (AP4_SUCCEEDED(fp.ParseSPS(spsList[i].GetData(),
764 spsList[i].GetDataSize(), sps)) &&
758765 sps.seq_parameter_set_id == pps.seq_parameter_set_id)
759766 {
760767 unsigned int width = info.GetWidth();
896903 {
897904 if (AP4_Atom* atom = sample_description->GetDetails().GetChild(AP4_ATOM_TYPE_VPCC, 0))
898905 {
899 AP4_VpcCAtom* vpcc(AP4_DYNAMIC_CAST(AP4_VpcCAtom, atom));
906 AP4_VpccAtom* vpcc(AP4_DYNAMIC_CAST(AP4_VpccAtom, atom));
900907 if (vpcc)
901908 extra_data.SetData(vpcc->GetData().GetData(), vpcc->GetData().GetDataSize());
902909 }
11581165 m_protectedDesc &&
11591166 (m_decrypterCaps.flags & SSD::SSD_DECRYPTER::SSD_CAPS::SSD_SECURE_PATH) != 0;
11601167 bool decrypterPresent(m_decrypter != nullptr);
1161
11621168 if (AP4_FAILED(result = ReadNextSample(m_track->GetId(), m_sample,
11631169 (m_decrypter || useDecryptingDecoder) ? m_encrypted
11641170 : m_sampleData)))
12671273 {
12681274 switch (static_cast<AP4_MpegSampleDescription*>(desc)->GetObjectTypeId())
12691275 {
1270 case AP4_OTI_MPEG4_AUDIO:
1271 case AP4_OTI_MPEG2_AAC_AUDIO_MAIN:
1272 case AP4_OTI_MPEG2_AAC_AUDIO_LC:
1273 case AP4_OTI_MPEG2_AAC_AUDIO_SSRP:
1274 info.SetCodecName("aac");
1275 break;
1276 case AP4_OTI_DTS_AUDIO:
1277 case AP4_OTI_DTS_HIRES_AUDIO:
1278 case AP4_OTI_DTS_MASTER_AUDIO:
1279 case AP4_OTI_DTS_EXPRESS_AUDIO:
1280 info.SetCodecName("dca");
1281 break;
1282 case AP4_OTI_AC3_AUDIO:
1283 info.SetCodecName("ac3");
1284 break;
1285 case AP4_OTI_EAC3_AUDIO:
1286 info.SetCodecName("eac3");
1287 break;
1276 case AP4_OTI_MPEG4_AUDIO:
1277 case AP4_OTI_MPEG2_AAC_AUDIO_MAIN:
1278 case AP4_OTI_MPEG2_AAC_AUDIO_LC:
1279 case AP4_OTI_MPEG2_AAC_AUDIO_SSRP:
1280 info.SetCodecName("aac");
1281 break;
1282 case AP4_OTI_DTS_AUDIO:
1283 case AP4_OTI_DTS_HIRES_AUDIO:
1284 case AP4_OTI_DTS_MASTER_AUDIO:
1285 case AP4_OTI_DTS_EXPRESS_AUDIO:
1286 info.SetCodecName("dca");
1287 break;
1288 case AP4_OTI_AC3_AUDIO:
1289 info.SetCodecName("ac3");
1290 break;
1291 case AP4_OTI_EAC3_AUDIO:
1292 info.SetCodecName("eac3");
1293 break;
12881294 }
12891295 }
12901296
14121418 if (!m_protectedDesc || !traf)
14131419 return AP4_ERROR_INVALID_FORMAT;
14141420
1421 bool reset_iv(false);
14151422 if (AP4_FAILED(result = AP4_CencSampleInfoTable::Create(m_protectedDesc, traf, algorithm_id,
1416 *m_FragmentStream, moof_offset,
1423 reset_iv, *m_FragmentStream, moof_offset,
14171424 sample_table)))
14181425 // we assume unencrypted fragment here
14191426 goto SUCCESS;
14201427
14211428 if (AP4_FAILED(result =
1422 AP4_CencSampleDecrypter::Create(sample_table, algorithm_id, 0, 0, 0,
1429 AP4_CencSampleDecrypter::Create(sample_table, algorithm_id, 0, 0, 0, reset_iv,
14231430 m_singleSampleDecryptor, m_decrypter)))
14241431 return result;
14251432 }
14711478 case AP4_SAMPLE_FORMAT_WVTT:
14721479 m_codecHandler = new WebVTTCodecHandler(desc);
14731480 break;
1474 case AP4_SAMPLE_FORMAT_VP09:
1481 case AP4_SAMPLE_FORMAT_VP9:
14751482 m_codecHandler = new VP9CodecHandler(desc);
14761483 break;
14771484 default:
19591966 if (enabled)
19601967 {
19611968 stream_.stop();
1969 reset();
1970 enabled = encrypted = false;
1971 }
1972 }
1973
1974 void Session::STREAM::reset()
1975 {
1976 if (enabled)
1977 {
19621978 SAFE_DELETE(reader_);
19631979 SAFE_DELETE(input_file_);
19641980 SAFE_DELETE(input_);
1965 enabled = encrypted = false;
19661981 mainId_ = 0;
19671982 }
19681983 }
19771992 const std::map<std::string, std::string>& manifestHeaders,
19781993 const std::map<std::string, std::string>& mediaHeaders,
19791994 const std::string& profile_path,
1980 uint16_t display_width,
1981 uint16_t display_height,
19821995 const std::string& ov_audio,
19831996 bool play_timeshift_buffer,
19841997 bool force_secure_decoder,
19942007 ov_audio_(ov_audio),
19952008 decrypterModule_(0),
19962009 decrypter_(0),
1997 secure_video_session_(false),
19982010 adaptiveTree_(0),
1999 width_(display_width),
2000 height_(display_height),
20012011 timing_stream_(nullptr),
20022012 changed_(false),
20032013 manual_streams_(0),
20062016 chapter_seek_time_(0.0),
20072017 play_timeshift_buffer_(play_timeshift_buffer),
20082018 force_secure_decoder_(force_secure_decoder),
2009 drmPreInitData_(drmPreInitData)
2019 drmPreInitData_(drmPreInitData),
2020 first_period_initialized_(false)
20102021 {
20112022 switch (manifest_type_)
20122023 {
20192030 case MANIFEST_TYPE_HLS:
20202031 adaptiveTree_ = new adaptive::HLSTree(new AESDecrypter(license_key_));
20212032 break;
2022 default:;
2033 default:
2034 return;
20232035 };
2036
2037 representationChooser_ = new DefaultRepresentationChooser();
2038 representationChooser_->assured_buffer_duration_ = kodi::GetSettingInt("ASSUREDBUFFERDURATION");
2039 representationChooser_->max_buffer_duration_ = kodi::GetSettingInt("MAXBUFFERDURATION");
2040 adaptiveTree_->representation_chooser_ = representationChooser_;
20242041
20252042 std::string fn(profile_path_ + "bandwidth.bin");
20262043 FILE* f = fopen(fn.c_str(), "rb");
20302047 size_t sz(fread(&val, sizeof(double), 1, f));
20312048 if (sz)
20322049 {
2033 adaptiveTree_->bandwidth_ = static_cast<uint32_t>(val * 8);
2034 adaptiveTree_->set_download_speed(val);
2050 representationChooser_->bandwidth_ = static_cast<uint32_t>(val * 8);
2051 representationChooser_->set_download_speed(val);
20352052 }
20362053 fclose(f);
20372054 }
20382055 else
2039 adaptiveTree_->bandwidth_ = 4000000;
2040 kodi::Log(ADDON_LOG_DEBUG, "Initial bandwidth: %u ", adaptiveTree_->bandwidth_);
2041
2042 max_resolution_ = kodi::GetSettingInt("MAXRESOLUTION");
2043 kodi::Log(ADDON_LOG_DEBUG, "MAXRESOLUTION selected: %d ", max_resolution_);
2044
2045 max_secure_resolution_ = kodi::GetSettingInt("MAXRESOLUTIONSECURE");
2046 kodi::Log(ADDON_LOG_DEBUG, "MAXRESOLUTIONSECURE selected: %d ", max_secure_resolution_);
2056 representationChooser_->bandwidth_ = 4000000;
2057 kodi::Log(ADDON_LOG_DEBUG, "Initial bandwidth: %u ", representationChooser_->bandwidth_);
2058
2059 representationChooser_->max_resolution_ = kodi::GetSettingInt("MAXRESOLUTION");
2060 kodi::Log(ADDON_LOG_DEBUG, "MAXRESOLUTION selected: %d ",
2061 representationChooser_->max_resolution_);
2062
2063 representationChooser_->max_secure_resolution_ = kodi::GetSettingInt("MAXRESOLUTIONSECURE");
2064 kodi::Log(ADDON_LOG_DEBUG, "MAXRESOLUTIONSECURE selected: %d ",
2065 representationChooser_->max_secure_resolution_);
20472066
20482067 manual_streams_ = kodi::GetSettingInt("STREAMSELECTION");
20492068 kodi::Log(ADDON_LOG_DEBUG, "STREAMSELECTION selected: %d ", manual_streams_);
20682087 media_type_mask_ = static_cast<uint8_t>(~0);
20692088 }
20702089
2071 ignore_display_ = kodi::GetSettingBoolean("IGNOREDISPLAY");
2090 buf = kodi::GetSettingInt("MINBANDWIDTH");
2091 representationChooser_->min_bandwidth_ = buf;
2092 buf = kodi::GetSettingInt("MAXBANDWIDTH");
2093 representationChooser_->max_bandwidth_ = buf;
2094
2095 representationChooser_->ignore_display_ = kodi::GetSettingBoolean("IGNOREDISPLAY");
2096 representationChooser_->hdcp_override_ = kodi::GetSettingBoolean("HDCPOVERRIDE");
2097 representationChooser_->ignore_window_change_= kodi::GetSettingBoolean("IGNOREWINDOWCHANGE");
20722098
20732099 if (!strCert.empty())
20742100 {
20932119 FILE* f = fopen(fn.c_str(), "wb");
20942120 if (f)
20952121 {
2096 double val(adaptiveTree_->get_average_download_speed());
2122 double val(representationChooser_->get_average_download_speed());
20972123 fwrite((const char*)&val, sizeof(double), 1, f);
20982124 fclose(f);
20992125 }
21002126 delete adaptiveTree_;
21012127 adaptiveTree_ = nullptr;
2128
2129 delete representationChooser_;
2130 representationChooser_ = nullptr;
21022131 }
21032132
21042133 void Session::GetSupportedDecrypterURN(std::string& key_system)
22162245 if (!adaptiveTree_)
22172246 return false;
22182247
2248 representationChooser_->SetMaxUserBandwidth(max_user_bandwidth);
2249
22192250 // Get URN's wich are supported by this addon
22202251 if (!license_type_.empty())
22212252 {
22302261 {
22312262 std::string challengeB64;
22322263 std::string sessionId;
2233 // Pre-initialize the DRM allow to generate the challenge and session ID data
2264 // Pre-initialize the DRM allow to generate the challenge and session ID data
22342265 // used to make licensed manifest requests (via proxy callback)
22352266 if (PreInitializeDRM(challengeB64, sessionId))
22362267 {
22562287 "Successfully parsed manifest file. #Periods: %ld, #Streams in first period: %ld, Type: "
22572288 "%s, Download speed: %0.4f Bytes/s",
22582289 adaptiveTree_->periods_.size(), adaptiveTree_->current_period_->adaptationSets_.size(),
2259 adaptiveTree_->has_timeshift_buffer_ ? "live" : "VOD", adaptiveTree_->download_speed_);
2290 adaptiveTree_->has_timeshift_buffer_ ? "live" : "VOD",
2291 representationChooser_->download_speed_);
22602292
22612293 drmConfig_ = config;
2262 maxUserBandwidth_ = max_user_bandwidth;
2294
2295 // Always need at least 16s delay from live
2296 if (adaptiveTree_->live_delay_ < 16)
2297 adaptiveTree_->live_delay_ = 16;
22632298
22642299 return InitializePeriod();
22652300 }
23512386
23522387 bool Session::InitializeDRM()
23532388 {
2389 bool secure_video_session = false;
23542390 cdm_sessions_.resize(adaptiveTree_->current_period_->psshSets_.size());
23552391 memset(&cdm_sessions_.front(), 0, sizeof(CDMSESSION));
2392
2393 representationChooser_->decrypter_caps_.resize(cdm_sessions_.size());
2394 for (const Session::CDMSESSION& cdmsession : cdm_sessions_)
2395 representationChooser_->decrypter_caps_.push_back(cdmsession.decrypter_caps_);
2396
23562397 // Try to initialize an SingleSampleDecryptor
23572398 if (adaptiveTree_->current_period_->encryptionState_)
23582399 {
24062447
24072448 if (license_data_.empty())
24082449 {
2409 Session::STREAM stream(
2410 *adaptiveTree_,
2411 adaptiveTree_->current_period_->psshSets_[ses].adaptation_set_->type_);
2412 stream.stream_.prepare_stream(
2413 adaptiveTree_->current_period_->psshSets_[ses].adaptation_set_, 0, 0, 0, 0, 0, 0, 0,
2414 media_headers_);
2450 Session::STREAM stream(*adaptiveTree_,
2451 adaptiveTree_->current_period_->psshSets_[ses].adaptation_set_,
2452 media_headers_, representationChooser_, play_timeshift_buffer_, 0, false);
24152453
24162454 stream.enabled = true;
2417 stream.stream_.start_stream(~0, width_, height_, play_timeshift_buffer_);
2418 stream.stream_.select_stream(true, false, stream.info_.GetPhysicalIndex() >> 16);
2455 stream.stream_.start_stream();
24192456
24202457 stream.input_ = new AP4_DASHStream(&stream.stream_);
2421 stream.input_file_ = new AP4_File(*stream.input_, AP4_DefaultAtomFactory::Instance, true);
2458 stream.input_file_ = new AP4_File(*stream.input_, AP4_DefaultAtomFactory::Instance_, true);
24222459 AP4_Movie* movie = stream.input_file_->GetMovie();
24232460 if (movie == NULL)
24242461 {
24262463 stream.disable();
24272464 return false;
24282465 }
2429 AP4_Array<AP4_PsshAtom*>& pssh = movie->GetPsshAtoms();
2466 AP4_Array<AP4_PsshAtom>& pssh = movie->GetPsshAtoms();
24302467
24312468 for (unsigned int i = 0; !init_data.GetDataSize() && i < pssh.ItemCount(); i++)
24322469 {
2433 if (memcmp(pssh[i]->GetSystemId(), key_system, 16) == 0)
2470 if (memcmp(pssh[i].GetSystemId(), key_system, 16) == 0)
24342471 {
2435 init_data.AppendData(pssh[i]->GetData().GetData(), pssh[i]->GetData().GetDataSize());
2472 init_data.AppendData(pssh[i].GetData().GetData(), pssh[i].GetData().GetDataSize());
24362473 if (adaptiveTree_->current_period_->psshSets_[ses].defaultKID_.empty())
24372474 {
2438 if (pssh[i]->GetKid(0))
2475 if (pssh[i].GetKid(0))
24392476 adaptiveTree_->current_period_->psshSets_[ses].defaultKID_ =
2440 std::string((const char*)pssh[i]->GetKid(0), 16);
2477 std::string((const char*)pssh[i].GetKid(0), 16);
24412478 else if (AP4_Track* track = movie->GetTrack(TIDC[stream.stream_.get_type()]))
24422479 {
24432480 AP4_ProtectedSampleDescription* m_protectedDesc =
25782615 else if (session.decrypter_caps_.flags & SSD::SSD_DECRYPTER::SSD_CAPS::SSD_SECURE_PATH)
25792616 {
25802617 session.cdm_session_str_ = session.single_sample_decryptor_->GetSessionId();
2581 secure_video_session_ = true;
2618 secure_video_session = true;
25822619
25832620 if (allow_no_secure_decoder_
25842621 && !force_secure_decoder_ && !adaptiveTree_->current_period_->need_secure_decoder_)
25942631 }
25952632 }
25962633 }
2634 representationChooser_->Prepare(secure_video_session);
2635
25972636 return true;
25982637 }
25992638
26172656 return false;
26182657 }
26192658
2620 uint32_t min_bandwidth(0), max_bandwidth(0);
2621 {
2622 int buf;
2623 buf = kodi::GetSettingInt("MINBANDWIDTH");
2624 min_bandwidth = buf;
2625 buf = kodi::GetSettingInt("MAXBANDWIDTH");
2626 max_bandwidth = buf;
2627 }
2628
2629 if (max_bandwidth == 0 || (maxUserBandwidth_ && max_bandwidth > maxUserBandwidth_))
2630 max_bandwidth = maxUserBandwidth_;
2631
26322659 // create SESSION::STREAM objects. One for each AdaptationSet
26332660 unsigned int i(0);
26342661 adaptive::AdaptiveTree::AdaptationSet* adp;
26472674 return false;
26482675 }
26492676
2650 bool hdcpOverride = kodi::GetSettingBoolean("HDCPOVERRIDE");
2651
26522677 while ((adp = adaptiveTree_->GetAdaptationSet(i++)))
26532678 {
26542679 if (adp->representations_.empty())
26582683 ? manual_streams_ != 0
26592684 : manual_streams_ == 1;
26602685
2661 const SSD::SSD_DECRYPTER::SSD_CAPS& caps(
2662 GetDecrypterCaps(adp->representations_[0]->get_psshset()));
2663
2664 uint32_t hdcpLimit(caps.hdcpLimit);
2665 uint16_t hdcpVersion(caps.hdcpVersion);
2666
2667 if (hdcpOverride)
2668 {
2669 hdcpLimit = 0;
2670 hdcpVersion = 99;
2671 }
2672
26732686 // Select good video stream
2674 adaptive::AdaptiveStream defaultVideoStream(*adaptiveTree_,
2675 adaptive::AdaptiveTree::StreamType::VIDEO);
2676 if (adp->type_ == adaptive::AdaptiveTree::StreamType::VIDEO && manual_streams_ == 2)
2677 defaultVideoStream.prepare_stream(adp, GetVideoWidth(), GetVideoHeight(), hdcpLimit,
2678 hdcpVersion, min_bandwidth, max_bandwidth, 0,
2679 media_headers_);
2680
2687 adaptive::AdaptiveTree::Representation* defaultRepresentation =
2688 adaptiveTree_->ChooseRepresentation(adp);
26812689 size_t repId = manual_streams ? adp->representations_.size() : 0;
26822690
26832691 do
26842692 {
2685 streams_.push_back(new STREAM(*adaptiveTree_, adp->type_));
2693 streams_.push_back(new STREAM(*adaptiveTree_, adp, media_headers_, representationChooser_,
2694 play_timeshift_buffer_, repId, first_period_initialized_));
26862695 STREAM& stream(*streams_.back());
26872696
2688 stream.stream_.prepare_stream(adp, GetVideoWidth(), GetVideoHeight(), hdcpLimit, hdcpVersion,
2689 min_bandwidth, max_bandwidth, repId, media_headers_);
26902697 uint32_t flags = INPUTSTREAM_FLAG_NONE;
26912698 size_t copySize = adp->name_.size() > 255 ? 255 : adp->name_.size();
26922699 stream.info_.SetName(adp->name_);
26952702 {
26962703 case adaptive::AdaptiveTree::VIDEO:
26972704 stream.info_.SetStreamType(INPUTSTREAM_TYPE_VIDEO);
2698 if (manual_streams &&
2699 stream.stream_.getRepresentation() == defaultVideoStream.getRepresentation())
2705 if (manual_streams && stream.stream_.getRepresentation() == defaultRepresentation)
27002706 flags |= INPUTSTREAM_FLAG_DEFAULT;
27012707 break;
27022708 case adaptive::AdaptiveTree::AUDIO:
27272733 stream.info_.SetFeatures(0);
27282734 stream.stream_.set_observer(dynamic_cast<adaptive::AdaptiveStreamObserver*>(this));
27292735
2730 UpdateStream(stream, caps);
2736 UpdateStream(stream);
27312737
27322738 } while (repId-- != (manual_streams ? 1 : 0));
27332739 }
2740 first_period_initialized_ = true;
27342741 return true;
27352742 }
27362743
2737 void Session::UpdateStream(STREAM& stream, const SSD::SSD_DECRYPTER::SSD_CAPS& caps)
2744 void Session::UpdateStream(STREAM& stream)
27382745 {
27392746 const adaptive::AdaptiveTree::Representation* rep(stream.stream_.getRepresentation());
2747 const SSD::SSD_DECRYPTER::SSD_CAPS& caps = GetDecrypterCaps(rep->pssh_set_);
27402748
27412749 stream.info_.SetWidth(rep->width_);
27422750 stream.info_.SetHeight(rep->height_);
27462754 stream.info_.SetAspect((float)stream.info_.GetWidth() / stream.info_.GetHeight());
27472755 stream.encrypted = rep->get_psshset() > 0;
27482756
2749 if (!stream.info_.GetExtraDataSize() && rep->codec_private_data_.size())
2757 stream.info_.SetExtraData(nullptr, 0);
2758 if (rep->codec_private_data_.size())
27502759 {
27512760 std::string annexb;
27522761 const std::string* res(&annexb);
28932902 {
28942903 AP4_ContainerAtom schi(AP4_ATOM_TYPE_SCHI);
28952904 schi.AddChild(
2896 new AP4_TencAtom(AP4_CENC_ALGORITHM_ID_CTR, 8,
2905 new AP4_TencAtom(AP4_CENC_CIPHER_AES_128_CTR, 8,
28972906 GetDefaultKeyId(stream->stream_.getRepresentation()->get_psshset())));
28982907 sample_descryption = new AP4_ProtectedSampleDescription(
28992908 0, sample_descryption, 0, AP4_PROTECTION_SCHEME_TYPE_PIFF, 0, "", &schi);
29702979 changed_ = true;
29712980 }
29722981
2982 void Session::SetVideoResolution(unsigned int w, unsigned int h)
2983 {
2984 representationChooser_->SetDisplayDimensions(w, h);
2985 };
2986
29732987 SampleReader* Session::GetNextSample()
29742988 {
29752989 STREAM *res(0), *waiting(0);
30383052 // don't try to seek past the end of the stream, leave a sensible amount so we can buffer properly
30393053 if (adaptiveTree_->has_timeshift_buffer_)
30403054 {
3055 double maxSeek(0);
30413056 uint64_t curTime, maxTime(0);
30423057 for (std::vector<STREAM*>::const_iterator b(streams_.begin()), e(streams_.end()); b != e; ++b)
30433058 if ((*b)->enabled && (curTime = (*b)->stream_.getMaxTimeMs()) && curTime > maxTime)
30443059 maxTime = curTime;
3045 if (seekTime > (static_cast<double>(maxTime) / 1000) - 12)
3046 {
3047 seekTime = (static_cast<double>(maxTime) / 1000) - 12;
3048 preceeding = true;
3049 }
3060
3061 maxSeek = (static_cast<double>(maxTime) / 1000) - adaptiveTree_->live_delay_;
3062 if (maxSeek < 0)
3063 maxSeek = 0;
3064
3065 if (seekTime > maxSeek)
3066 seekTime = maxSeek;
30503067 }
30513068
30523069 // correct for starting segment pts value of chapter and chapter offset within program
31243141
31253142 void Session::OnStreamChange(adaptive::AdaptiveStream* stream)
31263143 {
3144 for (STREAM* s : streams_)
3145 if (s->enabled && &s->stream_ == stream)
3146 {
3147 UpdateStream(*s);
3148 changed_ = true;
3149 }
31273150 }
31283151
31293152 void Session::CheckFragmentDuration(STREAM& stream)
31443167 return reinterpret_cast<const AP4_UI08*>(
31453168 adaptiveTree_->current_period_->psshSets_[index].defaultKID_.data());
31463169 return default_key;
3147 }
3148
3149 std::uint16_t Session::GetVideoWidth() const
3150 {
3151 std::uint16_t ret(ignore_display_ ? 8192 : width_);
3152 switch (secure_video_session_ ? max_secure_resolution_ : max_resolution_)
3153 {
3154 case 1:
3155 if (ret > 640)
3156 ret = 640;
3157 break;
3158 case 2:
3159 if (ret > 960)
3160 ret = 960;
3161 break;
3162 case 3:
3163 if (ret > 1280)
3164 ret = 1280;
3165 break;
3166 case 4:
3167 if (ret > 1920)
3168 ret = 1920;
3169 break;
3170 default:;
3171 }
3172 return ret;
3173 }
3174
3175 std::uint16_t Session::GetVideoHeight() const
3176 {
3177 std::uint16_t ret(ignore_display_ ? 8192 : height_);
3178 switch (secure_video_session_ ? max_secure_resolution_ : max_resolution_)
3179 {
3180 case 1:
3181 if (ret > 480)
3182 ret = 480;
3183 break;
3184 case 2:
3185 if (ret > 640)
3186 ret = 640;
3187 break;
3188 case 3:
3189 if (ret > 720)
3190 ret = 720;
3191 break;
3192 case 4:
3193 if (ret > 1080)
3194 ret = 1080;
3195 break;
3196 default:;
3197 }
3198 return ret;
31993170 }
32003171
32013172 AP4_CencSingleSampleDecrypter* Session::GetSingleSampleDecrypter(std::string sessionId)
33983369 bool m_checkChapterSeek = false;
33993370 bool m_playTimeshiftBuffer = false;
34003371 int m_failedSeekTime = ~0;
3372
3373 void UnlinkIncludedStreams(Session::STREAM* stream);
34013374 };
34023375
34033376 CInputStreamAdaptive::CInputStreamAdaptive(KODI_HANDLE instance, const std::string& kodiVersion)
35433516 kodihost->SetProfilePath(props.GetProfileFolder());
35443517
35453518 m_session = std::shared_ptr<Session>(new Session(
3546 manifest, url.c_str(), mfup, lt, lk, ld, lsc, manh, medh, props.GetProfileFolder(), m_width,
3547 m_height, ov_audio, m_playTimeshiftBuffer, force_secure_decoder, drmPreInitData));
3519 manifest, url.c_str(), mfup, lt, lk, ld, lsc, manh, medh, props.GetProfileFolder(),
3520 ov_audio, m_playTimeshiftBuffer, force_secure_decoder, drmPreInitData));
35483521 m_session->SetVideoResolution(m_width, m_height);
35493522
35503523 if (!m_session->Initialize(config, max_user_bandwidth))
35683541
35693542 if (m_session)
35703543 {
3544 adaptive::AdaptiveTree::Period* period;
35713545 int period_id = m_session->GetPeriodId();
35723546 iids.m_streamCount = 0;
3547 unsigned int id;
35733548
35743549 for (unsigned int i(1);
35753550 i <= INPUTSTREAM_MAX_STREAM_COUNT && i <= m_session->GetStreamCount(); ++i)
35873562 if (rep->flags_ & adaptive::AdaptiveTree::Representation::INCLUDEDSTREAM)
35883563 continue;
35893564 }
3590 ids.emplace_back(m_session->IsLive()
3591 ? i + (m_session->GetStream(i)->stream_.getPeriod()->sequence_ + 1) *
3592 1000
3593 : i + period_id * 1000);
3565 if (m_session->IsLive())
3566 {
3567 period = m_session->GetStream(i)->stream_.getPeriod();
3568 if (period->sequence_ == m_session->GetInitialSequence())
3569 {
3570 id = i + 1000;
3571 }
3572 else
3573 {
3574 id = i + (period->sequence_ + 1) * 1000;
3575 }
3576 }
3577 else
3578 {
3579 id = i + period_id * 1000;
3580 }
3581 ids.emplace_back(id);
35943582 }
35953583 }
35963584 }
36493637 return false;
36503638 }
36513639
3640 void CInputStreamAdaptive::UnlinkIncludedStreams(Session::STREAM* stream)
3641 {
3642 if (stream->mainId_)
3643 {
3644 Session::STREAM* mainStream(m_session->GetStream(stream->mainId_));
3645 if (mainStream->reader_)
3646 mainStream->reader_->RemoveStreamType(stream->info_.GetStreamType());
3647 }
3648 const adaptive::AdaptiveTree::Representation* rep(stream->stream_.getRepresentation());
3649 if (rep->flags_ & adaptive::AdaptiveTree::Representation::INCLUDEDSTREAM)
3650 m_IncludedStreams[stream->info_.GetStreamType()] = 0;
3651 }
3652
36523653 void CInputStreamAdaptive::EnableStream(int streamid, bool enable)
36533654 {
36543655 kodi::Log(ADDON_LOG_DEBUG, "EnableStream(%d: %s)", streamid, enable ? "true" : "false");
36603661
36613662 if (!enable && stream && stream->enabled)
36623663 {
3663 if (stream->mainId_)
3664 {
3665 Session::STREAM* mainStream(m_session->GetStream(stream->mainId_));
3666 if (mainStream->reader_)
3667 mainStream->reader_->RemoveStreamType(stream->info_.GetStreamType());
3668 }
3669 const adaptive::AdaptiveTree::Representation* rep(stream->stream_.getRepresentation());
3670 if (rep->flags_ & adaptive::AdaptiveTree::Representation::INCLUDEDSTREAM)
3671 m_IncludedStreams[stream->info_.GetStreamType()] = 0;
3664 UnlinkIncludedStreams(stream);
36723665 m_session->EnableStream(stream, false);
36733666 }
36743667 }
36833676
36843677 Session::STREAM* stream(m_session->GetStream(streamid - m_session->GetPeriodId() * 1000));
36853678
3686 if (!stream || stream->enabled)
3679 if (!stream)
36873680 return false;
3681
3682 if (stream->enabled)
3683 {
3684 if (stream->stream_.StreamChanged())
3685 {
3686 UnlinkIncludedStreams(stream);
3687 stream->reset();
3688 stream->stream_.Reset();
3689 }
3690 else
3691 return false;
3692 }
36883693
36893694 bool needRefetch = false; //Make sure that Kodi fetches changes
36903695 stream->enabled = true;
36913696
3692 stream->stream_.start_stream(~0, m_session->GetVideoWidth(), m_session->GetVideoHeight(),
3693 m_playTimeshiftBuffer);
36943697 const adaptive::AdaptiveTree::Representation* rep(stream->stream_.getRepresentation());
36953698
36963699 // If we select a dummy (=inside video) stream, open the video part
37133716 return false;
37143717 }
37153718
3716 kodi::Log(ADDON_LOG_DEBUG, "Selecting stream with conditions: w: %u, h: %u, bw: %u",
3717 stream->stream_.getWidth(), stream->stream_.getHeight(),
3718 stream->stream_.getBandwidth());
3719
3720 if (!stream->stream_.select_stream(true, false, stream->info_.GetPhysicalIndex() >> 16))
3721 {
3722 kodi::Log(ADDON_LOG_ERROR, "Unable to select stream!");
3723 stream->disable();
3724 return false;
3725 }
3726
3727 if (rep != stream->stream_.getRepresentation())
3728 {
3729 m_session->UpdateStream(
3730 *stream, m_session->GetDecrypterCaps(stream->stream_.getRepresentation()->pssh_set_));
3731 m_session->CheckChange(true);
3732 }
3733
37343719 if (rep->flags_ & adaptive::AdaptiveTree::Representation::SUBTITLESTREAM)
37353720 {
37363721 stream->reader_ =
37413726 AP4_Movie* movie(m_session->PrepareStream(stream, needRefetch));
37423727
37433728 // We load fragments on PrepareTime for HLS manifests and have to reevaluate the start-segment
3744 if (m_session->GetManifestType() == MANIFEST_TYPE_HLS)
3745 stream->stream_.restart_stream();
3729 //if (m_session->GetManifestType() == MANIFEST_TYPE_HLS)
3730 // stream->stream_.restart_stream();
3731 stream->stream_.start_stream();
37463732
37473733 if (rep->containerType_ == adaptive::AdaptiveTree::CONTAINERTYPE_TEXT)
37483734 {
37613747 stream->disable();
37623748 return false;
37633749 }
3750 m_session->OnSegmentChanged(&stream->stream_);
37643751 }
37653752 else if (rep->containerType_ == adaptive::AdaptiveTree::CONTAINERTYPE_ADTS)
37663753 {
37813768 {
37823769 stream->input_ = new AP4_DASHStream(&stream->stream_);
37833770 stream->input_file_ =
3784 new AP4_File(*stream->input_, AP4_DefaultAtomFactory::Instance, true, movie);
3771 new AP4_File(*stream->input_, AP4_DefaultAtomFactory::Instance_, true, movie);
37853772 movie = stream->input_file_->GetMovie();
37863773
37873774 if (movie == NULL)
37883775 {
37893776 kodi::Log(ADDON_LOG_ERROR, "No MOOV in stream!");
3790 stream->disable();
3777 m_session->EnableStream(stream, false);
37913778 return false;
37923779 }
37933780
37993786 if (!track)
38003787 {
38013788 kodi::Log(ADDON_LOG_ERROR, "No suitable track found in stream");
3802 stream->disable();
3789 m_session->EnableStream(stream, false);
38033790 return false;
38043791 }
38053792 }
38113798 }
38123799 else
38133800 {
3814 stream->disable();
3801 m_session->EnableStream(stream, false);
38153802 return false;
38163803 }
38173804
38483835
38493836 if (~m_failedSeekTime)
38503837 {
3851 kodi::Log(ADDON_LOG_DEBUG, "Seeking do last failed seek position (%d)", m_failedSeekTime);
3838 kodi::Log(ADDON_LOG_DEBUG, "Seeking to last failed seek position (%d)", m_failedSeekTime);
38523839 m_session->SeekTime(static_cast<double>(m_failedSeekTime) * 0.001f, 0, false);
38533840 m_failedSeekTime = ~0;
38543841 }
38693856 const AP4_UI08* pData(sr->GetSampleData());
38703857 DEMUX_PACKET* p;
38713858
3872 if (iSize && pData && sr->IsEncrypted())
3859 if (sr->IsEncrypted() && iSize > 0 && pData)
38733860 {
38743861 unsigned int numSubSamples(*((unsigned int*)pData));
38753862 pData += sizeof(numSubSamples);
38883875 else
38893876 p = AllocateDemuxPacket(iSize);
38903877
3891 if (iSize)
3878 if (iSize > 0 && pData)
38923879 {
38933880 p->dts = static_cast<double>(sr->DTS() + m_session->GetChapterStartTime());
38943881 p->pts = static_cast<double>(sr->PTS() + m_session->GetChapterStartTime());
39273914 }
39283915
39293916 //callback - will be called from kodi
3930 void CInputStreamAdaptive::SetVideoResolution(int width, int height)
3917 void CInputStreamAdaptive::SetVideoResolution (int width, int height)
39313918 {
39323919 kodi::Log(ADDON_LOG_INFO, "SetVideoResolution (%d x %d)", width, height);
39333920 if (m_session)
39493936 bool ret = m_session->SeekTime(static_cast<double>(ms) * 0.001f, 0, false);
39503937 m_failedSeekTime = ret ? ~0 : ms;
39513938
3952 return m_session->SeekTime(static_cast<double>(ms) * 0.001f, 0, false);
3939 return ret;
39533940 }
39543941
39553942 int CInputStreamAdaptive::GetTotalTime()
2323
2424 #include "common/AdaptiveTree.h"
2525 #include "common/AdaptiveStream.h"
26 #include "common/RepresentationChooser.h"
2627 #include <float.h>
2728
2829 #include "Ap4.h"
6162 class ATTRIBUTE_HIDDEN KodiAdaptiveStream : public adaptive::AdaptiveStream
6263 {
6364 public:
64 KodiAdaptiveStream(adaptive::AdaptiveTree &tree, adaptive::AdaptiveTree::StreamType type)
65 :adaptive::AdaptiveStream(tree, type){};
65 KodiAdaptiveStream(adaptive::AdaptiveTree& tree,
66 adaptive::AdaptiveTree::AdaptationSet* adp,
67 const std::map<std::string, std::string>& media_headers,
68 DefaultRepresentationChooser* chooser,
69 bool play_timeshift_buffer,
70 size_t repId,
71 bool choose_rep)
72 : adaptive::AdaptiveStream(tree, adp, media_headers, play_timeshift_buffer, repId, choose_rep),
73 chooser_(chooser){};
74
6675 protected:
67 virtual bool download(const char* url, const std::map<std::string, std::string> &mediaHeaders) override;
68 virtual bool parseIndexRange() override;
76 bool download(const char* url,
77 const std::map<std::string, std::string>& mediaHeaders,
78 std::string* lockfreeBuffer) override;
79 bool parseIndexRange(adaptive::AdaptiveTree::Representation* rep,
80 const std::string& buffer) override;
81
82 private:
83 DefaultRepresentationChooser* chooser_ = nullptr;
6984 };
7085
7186 enum MANIFEST_TYPE
89104 const std::map<std::string, std::string>& manifestHeaders,
90105 const std::map<std::string, std::string>& mediaHeaders,
91106 const std::string& profile_path,
92 uint16_t display_width,
93 uint16_t display_height,
94107 const std::string& ov_audio,
95108 bool play_timeshift_buffer,
96109 bool force_secure_decoder,
104117
105118 struct STREAM
106119 {
107 STREAM(adaptive::AdaptiveTree &t, adaptive::AdaptiveTree::StreamType s) :enabled(false), encrypted(false), mainId_(0), current_segment_(0), stream_(t, s), input_(0), input_file_(0), reader_(0), segmentChanged(false), valid(true)
120 STREAM(adaptive::AdaptiveTree& t,
121 adaptive::AdaptiveTree::AdaptationSet* adp,
122 const std::map<std::string, std::string>& media_headers,
123 DefaultRepresentationChooser* chooser,
124 bool play_timeshift_buffer,
125 size_t repId,
126 bool choose_rep)
127 : enabled(false),
128 encrypted(false),
129 mainId_(0),
130 current_segment_(0),
131 stream_(t, adp, media_headers, chooser, play_timeshift_buffer, repId, choose_rep),
132 input_(0),
133 input_file_(0),
134 reader_(0),
135 segmentChanged(false),
136 valid(true)
108137 {
109138 };
110139 ~STREAM()
112141 disable();
113142 };
114143 void disable();
144 void reset();
115145
116146 bool enabled, encrypted;
117147 uint16_t mainId_;
125155 bool valid;
126156 };
127157
128 void UpdateStream(STREAM &stream, const SSD::SSD_DECRYPTER::SSD_CAPS &caps);
158 void UpdateStream(STREAM &stream);
129159 AP4_Movie* PrepareStream(STREAM* stream, bool& needRefetch);
130160
131161 STREAM* GetStream(unsigned int sid)const { return sid - 1 < streams_.size() ? streams_[sid - 1] : 0; };
133163 unsigned int GetStreamCount() const { return streams_.size(); };
134164 const char *GetCDMSession(int nSet) { return cdm_sessions_[nSet].cdm_session_str_; };;
135165 uint8_t GetMediaTypeMask() const { return media_type_mask_; };
136 std::uint16_t GetVideoWidth()const;
137 std::uint16_t GetVideoHeight()const;
138166 AP4_CencSingleSampleDecrypter * GetSingleSampleDecryptor(unsigned int nIndex)const{ return cdm_sessions_[nIndex].single_sample_decryptor_; };
139167 SSD::SSD_DECRYPTER *GetDecrypter() { return decrypter_; };
140168 AP4_CencSingleSampleDecrypter *GetSingleSampleDecrypter(std::string sessionId);
146174 void StartReader(
147175 STREAM* stream, uint64_t seekTimeCorrected, int64_t ptsDiff, bool preceeding, bool timing);
148176 bool CheckChange(bool bSet = false){ bool ret = changed_; changed_ = bSet; return ret; };
149 void SetVideoResolution(unsigned int w, unsigned int h) { width_ = w; height_ = h;};
177 void SetVideoResolution(unsigned int w, unsigned int h);
150178 bool SeekTime(double seekTime, unsigned int streamId = 0, bool preceeding=true);
151179 bool IsLive() const { return adaptiveTree_->has_timeshift_buffer_; };
152180 MANIFEST_TYPE GetManifestType() const { return manifest_type_; };
153181 const AP4_UI08 *GetDefaultKeyId(const uint16_t index) const;
154182 uint32_t GetIncludedStreamMask() const;
155183 STREAM_CRYPTO_KEY_SYSTEM GetCryptoKeySystem() const;
184 uint32_t GetInitialSequence() const { return adaptiveTree_->initial_sequence_; }
156185
157186 int GetChapter() const;
158187 int GetChapterCount() const;
194223 bool shared_single_sample_decryptor_ = false;
195224 };
196225 std::vector<CDMSESSION> cdm_sessions_;
197 bool secure_video_session_;
198
199 adaptive::AdaptiveTree *adaptiveTree_;
226
227 adaptive::AdaptiveTree* adaptiveTree_;
228 DefaultRepresentationChooser* representationChooser_;
200229
201230 std::vector<STREAM*> streams_;
202231 STREAM* timing_stream_;
203232
204 uint16_t width_, height_;
205 int max_resolution_, max_secure_resolution_;
206233 uint32_t fixed_bandwidth_;
207 uint32_t maxUserBandwidth_;
208234 bool changed_;
209235 int manual_streams_;
210236 uint64_t elapsed_time_, chapter_start_time_; // In STREAM_TIME_BASE
211237 double chapter_seek_time_; // In seconds
212238 uint8_t media_type_mask_;
213239 uint8_t drmConfig_;
214 bool ignore_display_;
215240 bool play_timeshift_buffer_;
216241 bool force_secure_decoder_;
217242 bool allow_no_secure_decoder_;
218 };
243 bool first_period_initialized_;
244 };
471471 else if (strcmp((const char*)*attr, "indexRangeExact") == 0 &&
472472 strcmp((const char*)*(attr + 1), "true") == 0)
473473 dash->current_representation_->flags_ |= DASHTree::Representation::INDEXRANGEEXACT;
474 dash->current_representation_->flags_ |= DASHTree::Representation::SEGMENTBASE;
475474 attr += 2;
476475 }
476 dash->current_representation_->flags_ |= DASHTree::Representation::SEGMENTBASE;
477477 if (dash->current_representation_->indexRangeMax_)
478478 dash->currentNode_ |= MPDNODE_SEGMENTLIST;
479479 }
596596 break;
597597 }
598598 attr += 2;
599 }
600 }
601 else if (strcmp(el, "SupplementalProperty") == 0)
602 {
603 const char *schemeIdUri(0), *value(0);
604
605 for (; *attr;)
606 {
607 if (strcmp((const char*)*attr, "schemeIdUri") == 0)
608 schemeIdUri = (const char*)*(attr + 1);
609 else if (strcmp((const char*)*attr, "value") == 0)
610 value = (const char*)*(attr + 1);
611 attr += 2;
612 }
613
614 if (schemeIdUri && value)
615 {
616 if (strcmp(schemeIdUri, "urn:mpeg:dash:adaptation-set-switching:2016") == 0)
617 dash->current_adaptationset_->switching_ids_ = split(value, ',');
599618 }
600619 }
601620 else if (dash->currentNode_ & MPDNODE_BASEURL)
10481067 }
10491068 else if (strcmp((const char*)*attr, "availabilityStartTime") == 0)
10501069 dash->available_time_ = getTime((const char*)*(attr + 1));
1070 else if (strcmp((const char*)*attr, "suggestedPresentationDelay") == 0)
1071 AddDuration((const char*)*(attr + 1), dash->live_delay_, 1);
10511072 else if (strcmp((const char*)*attr, "minimumUpdatePeriod") == 0)
10521073 {
10531074 uint64_t dur(0);
13001321 dash->current_representation_->id,
13011322 dash->current_representation_->bandwidth_);
13021323 }
1324
1325 if ((dash->current_representation_->flags_ & DASHTree::Representation::SEGMENTBASE) &&
1326 dash->current_representation_->indexRangeMin_ == 0 && dash->current_representation_->indexRangeMax_ > 0
1327 && !(dash->current_representation_->flags_ & DASHTree::Representation::INITIALIZATION))
1328 {
1329 // AdaptiveStream::ParseIndexRange will fix the initialization max to its real value.
1330 dash->current_representation_->flags_ |= DASHTree::Representation::INITIALIZATION;
1331 dash->current_representation_->initialization_.range_begin_ = 0;
1332 dash->current_representation_->initialization_.range_end_ =
1333 dash->current_representation_->indexRangeMax_;
1334 }
1335
13031336
13041337 if ((dash->current_representation_->flags_ &
13051338 AdaptiveTree::Representation::INITIALIZATION) == 0 &&
17711804 break;
17721805 else if (s.range_begin_ > search_pts)
17731806 misaligned = search_pts - (&s - 1)->range_begin_;
1774 else
1807 else
17751808 ++(*brd)->startNumber_;
17761809 }
17771810 }
761761 period = current_period_;
762762 adp = period->adaptationSets_[adp_pos];
763763 rep = adp->representations_[rep_pos];
764 rep->flags_ |= Representation::INITIALIZED;
764765 return retVal;
765766 }
766767 return PREPARE_RESULT_FAILURE;
6262 Representation* rep,
6363 StreamType type) override;
6464 virtual bool processManifest(std::stringstream& stream);
65
65 virtual std::chrono::time_point<std::chrono::system_clock> GetRepLastUpdated(const Representation* rep)
66 {
67 return rep->repLastUpdated_;
68 }
69
6670 protected:
6771 virtual void RefreshLiveSegments() override;
6872
1717
1818 #include "WebVTT.h"
1919 #include "../helpers.h"
20 #include "../log.h"
2021 #include <cstring>
22
23 constexpr const char* signatureCharsBOM = "\xEF\xBB\xBF\x57\x45\x42\x56\x54\x54";
24 constexpr const char* signatureChars = "\x57\x45\x42\x56\x54\x54";
25 constexpr char signatureLastChars[] = {'\x0A', '\x0D', '\x20', '\x09'};
26
27 static bool ValidateSignature(const char* data, const char* signature)
28 {
29 if (std::strlen(data) > std::strlen(signature))
30 {
31 if (std::strncmp(data, signature, std::strlen(signature)) == 0)
32 {
33 // Check if last char is valid
34 if (std::strchr(signatureLastChars, data[std::strlen(signature)]) != NULL)
35 return true;
36 }
37 }
38 return false;
39 }
2140
2241 bool WebVTT::Parse(uint64_t pts, uint32_t duration, const void *buffer, size_t buffer_size, uint64_t timescale, uint64_t ptsOffset)
2342 {
135154 }
136155 else
137156 {
138 //TODO: BOM
139 while (cbuf < next && *cbuf != 'W')
140 ++cbuf;
141 if (strncmp(cbuf, "WEBVTT", 6) == 0)
157 // Check WEBVTT signature
158 if (ValidateSignature(cbuf, signatureCharsBOM) || ValidateSignature(cbuf, signatureChars))
142159 webvtt_visited = true;
160 else
161 kodi::Log(ADDON_LOG_ERROR, "WebVTT signature not valid");
143162 }
144163
145164 cbuf = next;
1111 ../parser/PRProtectionParser.cpp
1212 ../common/AdaptiveStream.cpp
1313 ../common/AdaptiveTree.cpp
14 ../common/RepresentationChooser.cpp
1415 ../helpers.cpp
1516 ../oscompat.cpp
1617 )
3939 protected:
4040 void SetUp() override
4141 {
42 testHelper::lastDownloadUrl.clear();
4342 DASHTreeTest::SetUp();
44 videoStream = new TestAdaptiveStream(*tree, adaptive::AdaptiveTree::StreamType::VIDEO);
45 audioStream = new TestAdaptiveStream(*tree, adaptive::AdaptiveTree::StreamType::AUDIO);
43 m_chooser = new DefaultRepresentationChooser();
44 m_chooser->hdcp_override_ = true;
45 m_chooser->assured_buffer_duration_ = 5;
46 m_chooser->max_buffer_duration_ = 5;
47 tree->representation_chooser_ = m_chooser;
48
4649 }
4750
4851 void TearDown() override
4952 {
50 delete videoStream;
51 delete audioStream;
52 videoStream = nullptr;
53 audioStream = nullptr;
53 delete testStream;
54 delete m_chooser;
5455 DASHTreeTest::TearDown();
56 }
57
58 void SetTestStream(TestAdaptiveStream* newStream)
59 {
60 delete testStream;
61 testHelper::downloadList.clear();
62 testStream = newStream;
63 }
64
65 TestAdaptiveStream* NewStream(adaptive::AdaptiveTree::AdaptationSet* adp, bool playTsb=true)
66 {
67 tree->ChooseRepresentation(adp);
68 return new TestAdaptiveStream(*tree, adp, mediaHeaders, m_chooser, playTsb, 0, false);
5569 }
5670
5771 void ReadSegments(TestAdaptiveStream* stream,
5872 uint32_t bytesToRead,
59 uint32_t reads,
60 bool clearUrls = true)
73 uint32_t reads)
6174 {
6275 // Rudimentary simulation of running a stream and consuming segment data.
6376 // Normally AdaptiveStream::read is called from a sample reader for the exact
6477 // amount of bytes needed to supply the next sample until the segment is
6578 // exhausted. Here our segments are a fixed size (16 bytes) and for testing we can
6679 // optimally call to read 1 segment per AdaptiveStream::read
67
68 if (clearUrls)
69 downloadedUrls.clear();
70
80 bool ret;
7181 for (unsigned int i = 0; i < reads; i++)
72 if (stream->read(buf, bytesToRead))
73 downloadedUrls.push_back(testHelper::lastDownloadUrl);
74 else
82 {
83 ret = stream->read(&buf, bytesToRead);
84 // prevent race condition leading to deadlock
85 std::this_thread::sleep_for(std::chrono::milliseconds(10));
86 if (!ret)
7587 break;
88 }
89
7690 // Decrement last updated time so live manifest will always refresh on each segment
7791 // in order to test manifest update changes
7892 tree->SetLastUpdated(std::chrono::system_clock::now() - std::chrono::seconds(2));
7993 stream->SetLastUpdated(std::chrono::system_clock::now() - std::chrono::seconds(2));
8094 }
81
82 TestAdaptiveStream* videoStream;
83 TestAdaptiveStream* audioStream;
95 DefaultRepresentationChooser* m_chooser;
96 TestAdaptiveStream* testStream = nullptr;
97 TestAdaptiveStream* newStream = nullptr;
8498 std::vector<std::string> downloadedUrls;
8599 std::map<std::string, std::string> mediaHeaders;
86100 unsigned char buf[16];
121135 OpenTestFile("mpd/segtpl_baseurl_noslashs.mpd", "https://foo.bar/initialpath/test.mpd", "");
122136
123137 adaptive::AdaptiveTree::SegmentTemplate segtpl =
124 tree->periods_[0]->adaptationSets_[0]->representations_[0]->segtpl_;
138 tree->periods_[0]->adaptationSets_[1]->representations_[0]->segtpl_;
125139
126140 EXPECT_EQ(segtpl.initialization, "https://foo.bar/guid.ism/dash/media-video=66000.dash");
127141 EXPECT_EQ(segtpl.media, "https://foo.bar/guid.ism/dash/media-video=66000-$Number$.m4s");
133147 OpenTestFile("mpd/segtpl_slash_baseurl_noslash.mpd", "https://foo.bar/initialpath/test.mpd", "");
134148
135149 adaptive::AdaptiveTree::SegmentTemplate segtpl =
136 tree->periods_[0]->adaptationSets_[0]->representations_[0]->segtpl_;
150 tree->periods_[0]->adaptationSets_[1]->representations_[0]->segtpl_;
137151
138152 EXPECT_EQ(segtpl.initialization, "https://foo.bar/media-video=66000.dash");
139153 EXPECT_EQ(segtpl.media, "https://foo.bar/media-video=66000-$Number$.m4s");
145159 OpenTestFile("mpd/segtpl_noslash_baseurl_slash.mpd", "https://foo.bar/initialpath/test.mpd", "");
146160
147161 adaptive::AdaptiveTree::SegmentTemplate segtpl =
148 tree->periods_[0]->adaptationSets_[0]->representations_[0]->segtpl_;
162 tree->periods_[0]->adaptationSets_[1]->representations_[0]->segtpl_;
149163
150164 EXPECT_EQ(segtpl.initialization, "https://foo.bar/guid.ism/dash/media-video=66000.dash");
151165 EXPECT_EQ(segtpl.media, "https://foo.bar/guid.ism/dash/media-video=66000-$Number$.m4s");
157171 OpenTestFile("mpd/segtpl_slash_baseurl_slash.mpd", "https://foo.bar/initialpath/test.mpd", "");
158172
159173 adaptive::AdaptiveTree::SegmentTemplate segtpl =
160 tree->periods_[0]->adaptationSets_[0]->representations_[0]->segtpl_;
174 tree->periods_[0]->adaptationSets_[1]->representations_[0]->segtpl_;
161175
162176 EXPECT_EQ(segtpl.initialization, "https://foo.bar/media-video=66000.dash");
163177 EXPECT_EQ(segtpl.media, "https://foo.bar/media-video=66000-$Number$.m4s");
167181 {
168182 // Byteranged indexing
169183 OpenTestFile("mpd/segmentbase.mpd", "https://foo.bar/test.mpd", "");
170 EXPECT_EQ(tree->periods_[0]->adaptationSets_[0]->representations_[0]->url_,
184 EXPECT_EQ(tree->periods_[0]->adaptationSets_[1]->representations_[0]->url_,
171185 "https://foo.bar/video/23.98p/r0/vid10.mp4");
172186 }
173187
253267 TEST_F(DASHTreeAdaptiveStreamTest, replacePlaceHolders)
254268 {
255269 OpenTestFile("mpd/placeholders.mpd", "https://foo.bar/placeholders.mpd", "");
256
257 videoStream->prepare_stream(tree->current_period_->adaptationSets_[0], 0, 0, 0, 0, 0, 0, 0,
258 mediaHeaders);
259 videoStream->start_stream(~0, 0, 0, true);
260 ReadSegments(videoStream, 16, 5);
261 EXPECT_EQ(downloadedUrls[0], "https://foo.bar/videosd-400x224/segment_487050.m4s");
262 EXPECT_EQ(downloadedUrls.back(), "https://foo.bar/videosd-400x224/segment_487054.m4s");
263
264 videoStream->prepare_stream(tree->current_period_->adaptationSets_[1], 0, 0, 0, 0, 0, 0, 0,
265 mediaHeaders);
266 videoStream->start_stream(~0, 0, 0, true);
267 ReadSegments(videoStream, 16, 5);
268 EXPECT_EQ(downloadedUrls[0], "https://foo.bar/videosd-400x224/segment_00487050.m4s");
269 EXPECT_EQ(downloadedUrls.back(), "https://foo.bar/videosd-400x224/segment_00487054.m4s");
270
271 videoStream->prepare_stream(tree->current_period_->adaptationSets_[2], 0, 0, 0, 0, 0, 0, 0,
272 mediaHeaders);
273 videoStream->start_stream(~0, 0, 0, true);
274 ReadSegments(videoStream, 16, 5);
275 EXPECT_EQ(downloadedUrls[0], "https://foo.bar/videosd-400x224/segment_263007000000.m4s");
276 EXPECT_EQ(downloadedUrls.back(), "https://foo.bar/videosd-400x224/segment_263009160000.m4s");
277
278 videoStream->prepare_stream(tree->current_period_->adaptationSets_[3], 0, 0, 0, 0, 0, 0, 0,
279 mediaHeaders);
280 videoStream->start_stream(~0, 0, 0, true);
281 ReadSegments(videoStream, 16, 5);
282 EXPECT_EQ(downloadedUrls[0], "https://foo.bar/videosd-400x224/segment_00263007000000");
283 EXPECT_EQ(downloadedUrls.back(), "https://foo.bar/videosd-400x224/segment_00263009160000");
284
285 videoStream->prepare_stream(tree->current_period_->adaptationSets_[4], 0, 0, 0, 0, 0, 0, 0,
286 mediaHeaders);
287 videoStream->start_stream(~0, 0, 0, true);
288 ReadSegments(videoStream, 16, 5);
289 EXPECT_EQ(downloadedUrls[0], "https://foo.bar/videosd-400x224/segment_487050.m4s?t=263007000000");
290 EXPECT_EQ(downloadedUrls.back(), "https://foo.bar/videosd-400x224/segment_487054.m4s?t=263009160000");
291
292 videoStream->prepare_stream(tree->current_period_->adaptationSets_[5], 0, 0, 0, 0, 0, 0, 0,
293 mediaHeaders);
294 videoStream->start_stream(~0, 0, 0, true);
295 ReadSegments(videoStream, 16, 5);
296 EXPECT_EQ(downloadedUrls[0], "https://foo.bar/videosd-400x224/segment_00487050.m4s?t=00263007000000");
297 EXPECT_EQ(downloadedUrls.back(), "https://foo.bar/videosd-400x224/segment_00487054.m4s?t=00263009160000");
298
299 videoStream->prepare_stream(tree->current_period_->adaptationSets_[6], 0, 0, 0, 0, 0, 0, 0,
300 mediaHeaders);
301 videoStream->start_stream(~0, 0, 0, true);
302 ReadSegments(videoStream, 16, 5);
303 EXPECT_EQ(downloadedUrls[0], "https://foo.bar/videosd-400x224/segment.m4s");
304 EXPECT_EQ(downloadedUrls.back(), "https://foo.bar/videosd-400x224/segment.m4s");
270 tree->has_timeshift_buffer_ = false;
271 SetTestStream(NewStream(tree->periods_[0]->adaptationSets_[0]));
272
273 testStream->start_stream();
274 ReadSegments(testStream, 16, 5);
275 EXPECT_EQ(testHelper::downloadList[0], "https://foo.bar/videosd-400x224/init.mp4");
276 EXPECT_EQ(testHelper::downloadList[4], "https://foo.bar/videosd-400x224/segment_487053.m4s");
277
278 SetTestStream(NewStream(tree->periods_[0]->adaptationSets_[1]));
279 testStream->start_stream();
280 ReadSegments(testStream, 16, 5);
281 EXPECT_EQ(testHelper::downloadList[1], "https://foo.bar/videosd-400x224/segment_00487050.m4s");
282 EXPECT_EQ(testHelper::downloadList[4], "https://foo.bar/videosd-400x224/segment_00487053.m4s");
283
284
285 SetTestStream(NewStream(tree->periods_[0]->adaptationSets_[2]));
286 testStream->start_stream();
287 ReadSegments(testStream, 16, 5);
288 EXPECT_EQ(testHelper::downloadList[1], "https://foo.bar/videosd-400x224/segment_263007000000.m4s");
289 EXPECT_EQ(testHelper::downloadList[4], "https://foo.bar/videosd-400x224/segment_263008620000.m4s");
290
291 SetTestStream(NewStream(tree->periods_[0]->adaptationSets_[3]));
292 testStream->start_stream();
293 ReadSegments(testStream, 16, 5);
294 EXPECT_EQ(testHelper::downloadList[1], "https://foo.bar/videosd-400x224/segment_00263007000000");
295 EXPECT_EQ(testHelper::downloadList[4], "https://foo.bar/videosd-400x224/segment_00263008620000");
296
297 SetTestStream(NewStream(tree->periods_[0]->adaptationSets_[4]));
298 testStream->start_stream();
299 ReadSegments(testStream, 16, 5);
300 EXPECT_EQ(testHelper::downloadList[1], "https://foo.bar/videosd-400x224/segment_487050.m4s?t=263007000000");
301 EXPECT_EQ(testHelper::downloadList[4], "https://foo.bar/videosd-400x224/segment_487053.m4s?t=263008620000");
302
303 SetTestStream(NewStream(tree->periods_[0]->adaptationSets_[5]));
304 testStream->start_stream();
305 ReadSegments(testStream, 16, 5);
306 EXPECT_EQ(testHelper::downloadList[1], "https://foo.bar/videosd-400x224/segment_00487050.m4s?t=00263007000000");
307 EXPECT_EQ(testHelper::downloadList[4], "https://foo.bar/videosd-400x224/segment_00487053.m4s?t=00263008620000");
308
309 SetTestStream(NewStream(tree->periods_[0]->adaptationSets_[6]));
310 testStream->start_stream();
311 ReadSegments(testStream, 16, 5);
312 EXPECT_EQ(testHelper::downloadList[0], "https://foo.bar/videosd-400x224/init.mp4");
313 EXPECT_EQ(testHelper::downloadList[4], "https://foo.bar/videosd-400x224/segment.m4s");
305314 }
306315
307316 TEST_F(DASHTreeTest, updateParameterLiveSegmentTimeline)
404413 EXPECT_EQ(tree->periods_[0]->adaptationSets_[11]->type_, DASHTestTree::SUBTITLE);
405414 EXPECT_EQ(tree->periods_[0]->adaptationSets_[11]->mimeType_, "application/mp4");
406415 EXPECT_EQ(tree->periods_[0]->adaptationSets_[11]->representations_[0]->codecs_, "stpp");
407 videoStream->prepare_stream(tree->periods_[0]->adaptationSets_[11], 0, 0, 0, 0, 0, 0, 0,
408 mediaHeaders);
409 videoStream->start_stream(~0, 0, 0, true);
410 ReadSegments(videoStream, 16, 5);
411 EXPECT_EQ(downloadedUrls[0], "https://foo.bar/11/0001.m4s");
412 EXPECT_EQ(downloadedUrls.back(), "https://foo.bar/11/0005.m4s");
416
417 SetTestStream(NewStream(tree->periods_[0]->adaptationSets_[11]));
418 testStream->start_stream();
419 ReadSegments(testStream, 16, 5);
420 EXPECT_EQ(testHelper::downloadList[0], "https://foo.bar/11/init.mp4");
421 EXPECT_EQ(testHelper::downloadList[4], "https://foo.bar/11/0004.m4s");
413422
414423 EXPECT_EQ(tree->periods_[0]->adaptationSets_[12]->type_, DASHTestTree::SUBTITLE);
415424 EXPECT_EQ(tree->periods_[0]->adaptationSets_[12]->mimeType_, "application/mp4");
416425 EXPECT_EQ(tree->periods_[0]->adaptationSets_[12]->representations_[0]->codecs_, "stpp.ttml.im1t");
417 videoStream->prepare_stream(tree->periods_[0]->adaptationSets_[12], 0, 0, 0, 0, 0, 0, 0,
418 mediaHeaders);
419 videoStream->start_stream(~0, 0, 0, true);
420 ReadSegments(videoStream, 16, 5);
421 EXPECT_EQ(downloadedUrls[0], "https://foo.bar/tears-of-steel-multiple-subtitles-12-0.dash");
422 EXPECT_EQ(downloadedUrls.back(), "https://foo.bar/tears-of-steel-multiple-subtitles-12-16000.dash");
426
427 SetTestStream(NewStream(tree->periods_[0]->adaptationSets_[12]));
428 testStream->start_stream();
429 ReadSegments(testStream, 16, 5);
430 EXPECT_EQ(testHelper::downloadList[0], "https://foo.bar/tears-of-steel-multiple-subtitles-12.dash");
431 EXPECT_EQ(testHelper::downloadList[4], "https://foo.bar/tears-of-steel-multiple-subtitles-12-12000.dash");
423432 }
424433
425434 TEST_F(DASHTreeTest, CalculateMultipleSegTpl)
481490 TEST_F(DASHTreeAdaptiveStreamTest, MisalignedSegmentTimeline)
482491 {
483492 OpenTestFile("mpd/bad_segtimeline_1.mpd", "https://foo.bar/placeholders.mpd", "");
484 audioStream->prepare_stream(tree->current_period_->adaptationSets_[1], 0, 0, 0, 0, 0, 0, 0,
485 mediaHeaders);
486 audioStream->start_stream(~0, 0, 0, false);
487
488 ReadSegments(audioStream, 16, 1);
493 SetTestStream(NewStream(tree->current_period_->adaptationSets_[1]));
494 testStream->start_stream();
495
496 ReadSegments(testStream, 16, 1);
489497
490498 SetFileName(testHelper::testFile, "mpd/bad_segtimeline_2.mpd");
491 ReadSegments(audioStream, 16, 1);
499 ReadSegments(testStream, 16, 1);
492500 EXPECT_EQ(tree->current_period_->adaptationSets_[1]->representations_[0]->startNumber_, 3);
493501
494502 SetFileName(testHelper::testFile, "mpd/bad_segtimeline_3.mpd");
495 ReadSegments(audioStream, 16, 1);
503 ReadSegments(testStream, 16, 1);
496504 EXPECT_EQ(tree->current_period_->adaptationSets_[1]->representations_[0]->startNumber_, 4);
497505
498506 SetFileName(testHelper::testFile, "mpd/bad_segtimeline_4.mpd");
499 ReadSegments(audioStream, 16, 1);
507 ReadSegments(testStream, 16, 1);
500508 EXPECT_EQ(tree->current_period_->adaptationSets_[1]->representations_[0]->startNumber_, 5);
501509 }
510
511 TEST_F(DASHTreeTest, AdaptionSetSwitching)
512 {
513 OpenTestFile("mpd/adaptation_set_switching.mpd", "", "");
514
515 EXPECT_EQ(tree->periods_[0]->adaptationSets_.size(), 5);
516 EXPECT_EQ(tree->periods_[0]->adaptationSets_[0]->representations_[0]->id, "3");
517 EXPECT_EQ(tree->periods_[0]->adaptationSets_[0]->representations_[1]->id, "1");
518 EXPECT_EQ(tree->periods_[0]->adaptationSets_[0]->representations_[2]->id, "2");
519
520 EXPECT_EQ(tree->periods_[0]->adaptationSets_[1]->representations_[0]->id, "4");
521 EXPECT_EQ(tree->periods_[0]->adaptationSets_[1]->representations_[1]->id, "5");
522
523 EXPECT_EQ(tree->periods_[0]->adaptationSets_[2]->representations_[0]->id, "6");
524
525 EXPECT_EQ(tree->periods_[0]->adaptationSets_[3]->representations_[0]->id, "7");
526
527 EXPECT_EQ(tree->periods_[0]->adaptationSets_[4]->representations_[0]->id, "8");
528 }
529
530 TEST_F(DASHTreeTest, SuggestedPresentationDelay)
531 {
532 OpenTestFile("mpd/segtpl_spd.mpd", "https://foo.bar/segtpl_spd.mpd", "");
533 EXPECT_EQ(tree->live_delay_, 32);
534 }
11
22 std::string testHelper::testFile;
33 std::string testHelper::effectiveUrl;
4 std::string testHelper::lastDownloadUrl;
4 std::vector<std::string> testHelper::downloadList;
55
66 void Log(const LogLevel loglevel, const char* format, ...){}
77
5353 return nbRead == 0;
5454 }
5555
56 bool TestAdaptiveStream::download_segment()
57 {
58 if (download_url_.empty())
59 return false;
60 testHelper::downloadList.push_back(download_url_);
61
62 return download(download_url_.c_str(), download_headers_, nullptr);
63 }
64
5665 bool TestAdaptiveStream::download(const char* url,
57 const std::map<std::string, std::string>& mediaHeaders)
66 const std::map<std::string, std::string>& mediaHeaders,
67 std::string* lockfreeBuffer)
5868 {
59 testHelper::lastDownloadUrl = url;
6069 size_t nbRead = ~0UL;
6170 std::stringstream ss("Sixteen bytes!!!");
6271
6372 char buf[16];
6473 size_t nbReadOverall = 0;
65 while ((nbRead = ss.readsome(buf, 16)) > 0 && ~nbRead && write_data(buf, nbRead))
74 ss.clear();
75 ss.seekg(0);
76 while (true)
77 {
78 ss.read(buf, 16);
79 nbRead = ss.gcount();
80 if (!nbRead || !~nbRead || !write_data(buf, nbRead, lockfreeBuffer))
81 break;
6682 nbReadOverall += nbRead;
83 }
6784
6885 if (!nbReadOverall)
6986 {
22 #include "../common/AdaptiveStream.h"
33 #include "../parser/DASHTree.h"
44 #include "../parser/HLSTree.h"
5 #include "../common/RepresentationChooser.h"
56
67 std::string GetEnv(const std::string& var);
78 void SetFileName(std::string& file, const std::string name);
89 void Log(const LogLevel loglevel, const char* format, ...);
10
11 struct DefaultRepresentationChooser;
912
1013 class testHelper
1114 {
1215 public:
1316 static std::string testFile;
1417 static std::string effectiveUrl;
15 static std::string lastDownloadUrl;
18 static std::vector<std::string> downloadList;
1619 };
1720
1821 class TestAdaptiveStream : public adaptive::AdaptiveStream
1922 {
2023 public:
21 TestAdaptiveStream(adaptive::AdaptiveTree& tree, adaptive::AdaptiveTree::StreamType type)
22 : adaptive::AdaptiveStream(tree, type){};
24 TestAdaptiveStream(adaptive::AdaptiveTree& tree,
25 adaptive::AdaptiveTree::AdaptationSet* adp,
26 const std::map<std::string, std::string>& media_headers,
27 DefaultRepresentationChooser* chooser,
28 bool play_timeshift_buffer,
29 size_t repId,
30 bool choose_rep)
31 : adaptive::AdaptiveStream(tree, adp, media_headers, play_timeshift_buffer, repId, choose_rep),
32 chooser_(chooser) {};
2333 std::chrono::system_clock::time_point mock_time_stream = std::chrono::system_clock::now();
2434 void SetLastUpdated(std::chrono::system_clock::time_point tm) override { lastUpdated_ = tm; };
35 virtual bool download_segment() override;
2536
2637 protected:
2738 virtual bool download(const char* url,
28 const std::map<std::string, std::string>& mediaHeaders) override;
39 const std::map<std::string, std::string>& mediaHeaders,
40 std::string* lockfreeBuffer) override;
41
42 private:
43 DefaultRepresentationChooser* chooser_ = nullptr;
2944 };
3045
3146 class AESDecrypter : public IAESDecrypter
0 <?xml version="1.0" encoding="utf-8"?>
1 <MPD _xmlns:ns2="http://www.w3.org/1999/xlink" mediaPresentationDuration="PT1H45M47.904S" minBufferTime="PT10S" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" type="static" xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:_xmlns="xmlns">
2 <Period duration="PT1H45M47.904S">
3 <!-- 3 below should merge -->
4 <AdaptationSet id="0" group="0" contentType="video">
5 <SegmentTemplate duration="2" initialization="$RepresentationID$/init.mp4" media="$RepresentationID$/$Number$.m4s" startNumber="0" />
6 <Representation id="1" bandwidth="300000" codecs="avc1.64001e" frameRate="60/2" height="720" sar="1:1" width="1080" />
7 <SupplementalProperty schemeIdUri="urn:mpeg:dash:adaptation-set-switching:2016" value="1,2"/>
8 </AdaptationSet>
9 <AdaptationSet id="1" group="0" contentType="video">
10 <SegmentTemplate duration="2" initialization="$RepresentationID$/init.mp4" media="$RepresentationID$/$Number$.m4s" startNumber="0" />
11 <Representation id="2" bandwidth="1000000" codecs="avc1.64001e" frameRate="60/2" height="1080" sar="1:1" width="1920" />
12 <SupplementalProperty schemeIdUri="urn:mpeg:dash:adaptation-set-switching:2016" value="0,2"/>
13 </AdaptationSet>
14 <AdaptationSet id="2" group="0" contentType="video">
15 <SegmentTemplate duration="2" initialization="$RepresentationID$/init.mp4" media="$RepresentationID$/$Number$.m4s" startNumber="0" />
16 <Representation id="3" bandwidth="1000" codecs="avc1.64001e" frameRate="60/2" height="480" sar="1:1" width="720" />
17 <SupplementalProperty schemeIdUri="urn:mpeg:dash:adaptation-set-switching:2016" value="0,1"/>
18 </AdaptationSet>
19
20 <!-- 2 below should merge -->
21 <AdaptationSet id="0" group="1" contentType="video">
22 <SegmentTemplate duration="2" initialization="$RepresentationID$/init.mp4" media="$RepresentationID$/$Number$.m4s" startNumber="0" />
23 <Representation id="4" bandwidth="300000" codecs="avc1.64001e" frameRate="60/2" height="720" sar="1:1" width="1080" />
24 <SupplementalProperty schemeIdUri="urn:mpeg:dash:adaptation-set-switching:2016" value="1"/>
25 </AdaptationSet>
26 <AdaptationSet id="1" group="1" contentType="video">
27 <SegmentTemplate duration="2" initialization="$RepresentationID$/init.mp4" media="$RepresentationID$/$Number$.m4s" startNumber="0" />
28 <Representation id="5" bandwidth="1000000" codecs="avc1.64001e" frameRate="60/2" height="1080" sar="1:1" width="1920" />
29 <SupplementalProperty schemeIdUri="urn:mpeg:dash:adaptation-set-switching:2016" value="0"/>
30 </AdaptationSet>
31
32 <!-- Wont merge as id 99 doesnt exist -->
33 <AdaptationSet id="2" group="1" contentType="video">
34 <SegmentTemplate duration="2" initialization="$RepresentationID$/init.mp4" media="$RepresentationID$/$Number$.m4s" startNumber="0" />
35 <Representation id="6" bandwidth="1000" codecs="avc1.64001e" frameRate="60/2" height="480" sar="1:1" width="720" />
36 <SupplementalProperty schemeIdUri="urn:mpeg:dash:adaptation-set-switching:2016" value="99"/>
37 </AdaptationSet>
38
39 <!-- Wont merge as id 1 doesnt list my id -->
40 <AdaptationSet id="2" group="1" contentType="video">
41 <SegmentTemplate duration="2" initialization="$RepresentationID$/init.mp4" media="$RepresentationID$/$Number$.m4s" startNumber="0" />
42 <Representation id="7" bandwidth="1000" codecs="avc1.64001e" frameRate="60/2" height="480" sar="1:1" width="720" />
43 <SupplementalProperty schemeIdUri="urn:mpeg:dash:adaptation-set-switching:2016" value="1"/>
44 </AdaptationSet>
45
46 <!-- Wont merge as no adaptation-set-switching -->
47 <AdaptationSet id="3" group="1" contentType="video">
48 <SegmentTemplate duration="2" initialization="$RepresentationID$/init.mp4" media="$RepresentationID$/$Number$.m4s" startNumber="0" />
49 <Representation id="8" bandwidth="1000" codecs="avc1.64001e" frameRate="60/2" height="480" sar="1:1" width="720" />
50 </AdaptationSet>
51 </Period>
52 </MPD>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <MPD xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:mpeg:dash:schema:mpd:2011" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" type="dynamic" minimumUpdatePeriod="PT4.000S" suggestedPresentationDelay="PT32S" minBufferTime="PT5.000S" maxSegmentDuration="PT4.500S" availabilityStartTime="2021-03-25T23:44:03Z" timeShiftBufferDepth="PT1800.000S" publishTime="2021-03-31T20:52:37Z" profiles="urn:mpeg:dash:profile:isoff-live:2011">
2 <Period id="404187865" start="PT35652S">
3 <AdaptationSet mimeType="video/mp4" segmentAlignment="true" startWithSAP="1" maxWidth="1920" maxHeight="1080" maxFrameRate="25" par="25:14">
4 <SegmentTemplate timescale="90000" initialization="$RepresentationID$/segment-Header-init.m4s" media="$RepresentationID$/segment-$Number$.m4s" duration="360000" startNumber="404187866" presentationTimeOffset="7539818380345"/>
5 <Representation id="video1" width="400" height="224" frameRate="25" sar="1:1" scanType="progressive" bandwidth="450000" codecs="avc1.4D4015"/>
6 <Representation id="video2" width="640" height="360" frameRate="25" sar="1:1" scanType="progressive" bandwidth="600000" codecs="avc1.4D401E"/>
7 <Representation id="video3" width="960" height="540" frameRate="25" sar="1:1" scanType="progressive" bandwidth="1200000" codecs="avc1.4D401F"/>
8 <Representation id="video4" width="960" height="540" frameRate="25" sar="1:1" scanType="progressive" bandwidth="1800000" codecs="avc1.4D401F"/>
9 <Representation id="video5" width="1280" height="720" frameRate="25" sar="1:1" scanType="progressive" bandwidth="2600000" codecs="avc1.4D401F"/>
10 <Representation id="video6" width="1920" height="1080" frameRate="25" sar="1:1" scanType="progressive" bandwidth="3400000" codecs="avc1.4D4028"/>
11 </AdaptationSet>
12 <AdaptationSet mimeType="audio/mp4" lang="ar" segmentAlignment="true" startWithSAP="1">
13 <Role schemeIdUri="urn:mpeg:dash:role:2011" value="main"/>
14 <SegmentTemplate timescale="90000" initialization="$RepresentationID$/segment-Header-init.m4s" media="$RepresentationID$/segment-$Number$.m4s" duration="360000" startNumber="404187866" presentationTimeOffset="7539818380345"/>
15 <Representation id="audio1" audioSamplingRate="24000" bandwidth="96000" codecs="mp4a.40.2">
16 <AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
17 </Representation>
18 </AdaptationSet>
19 </Period>
20 <UTCTiming schemeIdUri="urn:mpeg:dash:utc:direct:2014" value="2021-03-31T20:53:07Z"/>
21 </MPD>
3131 if(CORE_SYSTEM_NAME STREQUAL android)
3232 subdirs ( jni )
3333 add_library ( ssd_wv SHARED
34 wvdecrypter_android_jni.cpp
34 wvdecrypter_android.cpp
3535 jsmn.c
3636 ../src/helpers.cpp
3737 ../src/md5.cpp
3232 #error "WIDEVINECDMFILENAME must be set"
3333 #endif
3434
35 #define LOCLICENSE 1
35 //#define LOCLICENSE
3636
3737 using namespace SSD;
3838
363363 if (serverCert.GetDataSize())
364364 wv_adapter->SetServerCertificate(0, serverCert.GetData(), serverCert.GetDataSize());
365365
366 // For backward compatibility: If no | is found in URL, make the amazon convention out of it
366 // For backward compatibility: If no | is found in URL, use the most common working config
367367 if (license_url_.find('|') == std::string::npos)
368 license_url_ += "|Content-Type=application%2Fx-www-form-urlencoded|widevine2Challenge=B{SSM}&includeHdcpTestKeyInLicense=true|JBlicense;hdcpEnforcementResolutionPixels";
368 license_url_ += "|Content-Type=application%2Foctet-stream|R{SSM}|";
369369
370370 //wv_adapter->GetStatusForPolicy();
371371 //wv_adapter->QueryOutputProtectionStatus();