Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
SDK
/
exoplayer
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
539a1ac2
authored
Dec 09, 2019
by
olly
Committed by
Oliver Woodman
Dec 10, 2019
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Partial nullness annotations for AtomParsers
PiperOrigin-RevId: 284558886
parent
4b281cec
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
94 additions
and
55 deletions
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java
View file @
539a1ac2
...
...
@@ -40,6 +40,7 @@ import java.util.ArrayList;
import
java.util.Arrays
;
import
java.util.Collections
;
import
java.util.List
;
import
org.checkerframework.checker.nullness.compatqual.NullableType
;
/** Utility methods for parsing MP4 format atom payloads according to ISO 14496-12. */
@SuppressWarnings
({
"ConstantField"
})
...
...
@@ -85,15 +86,21 @@ import java.util.List;
*
* @param trak Atom to decode.
* @param mvhd Movie header atom, used to get the timescale.
* @param duration The duration in units of the timescale declared in the mvhd atom, or
*
{@link
C#TIME_UNSET} if the duration should be parsed from the tkhd atom.
* @param drmInitData {@link DrmInitData} to be included in the format.
* @param duration The duration in units of the timescale declared in the mvhd atom, or
{@link
* C#TIME_UNSET} if the duration should be parsed from the tkhd atom.
* @param drmInitData {@link DrmInitData} to be included in the format
, or {@code null}
.
* @param ignoreEditLists Whether to ignore any edit lists in the trak box.
* @param isQuickTime True for QuickTime media. False otherwise.
* @return A {@link Track} instance, or {@code null} if the track's type isn't supported.
*/
public
static
Track
parseTrak
(
Atom
.
ContainerAtom
trak
,
Atom
.
LeafAtom
mvhd
,
long
duration
,
DrmInitData
drmInitData
,
boolean
ignoreEditLists
,
boolean
isQuickTime
)
@Nullable
public
static
Track
parseTrak
(
Atom
.
ContainerAtom
trak
,
Atom
.
LeafAtom
mvhd
,
long
duration
,
@Nullable
DrmInitData
drmInitData
,
boolean
ignoreEditLists
,
boolean
isQuickTime
)
throws
ParserException
{
Atom
.
ContainerAtom
mdia
=
trak
.
getContainerAtomOfType
(
Atom
.
TYPE_mdia
);
int
trackType
=
getTrackTypeForHdlr
(
parseHdlr
(
mdia
.
getLeafAtomOfType
(
Atom
.
TYPE_hdlr
).
data
));
...
...
@@ -121,9 +128,12 @@ import java.util.List;
long
[]
editListDurations
=
null
;
long
[]
editListMediaTimes
=
null
;
if
(!
ignoreEditLists
)
{
@Nullable
Pair
<
long
[],
long
[]>
edtsData
=
parseEdts
(
trak
.
getContainerAtomOfType
(
Atom
.
TYPE_edts
));
editListDurations
=
edtsData
.
first
;
editListMediaTimes
=
edtsData
.
second
;
if
(
edtsData
!=
null
)
{
editListDurations
=
edtsData
.
first
;
editListMediaTimes
=
edtsData
.
second
;
}
}
return
stsdData
.
format
==
null
?
null
:
new
Track
(
tkhdData
.
id
,
trackType
,
mdhdData
.
first
,
movieTimescale
,
durationUs
,
...
...
@@ -736,19 +746,25 @@ import java.util.List;
* @param trackId The track's identifier in its container.
* @param rotationDegrees The rotation of the track in degrees.
* @param language The language of the track.
* @param drmInitData {@link DrmInitData} to be included in the format.
* @param drmInitData {@link DrmInitData} to be included in the format
, or {@code null}
.
* @param isQuickTime True for QuickTime media. False otherwise.
* @return An object containing the parsed data.
*/
private
static
StsdData
parseStsd
(
ParsableByteArray
stsd
,
int
trackId
,
int
rotationDegrees
,
String
language
,
DrmInitData
drmInitData
,
boolean
isQuickTime
)
throws
ParserException
{
private
static
StsdData
parseStsd
(
ParsableByteArray
stsd
,
int
trackId
,
int
rotationDegrees
,
String
language
,
@Nullable
DrmInitData
drmInitData
,
boolean
isQuickTime
)
throws
ParserException
{
stsd
.
setPosition
(
Atom
.
FULL_HEADER_SIZE
);
int
numberOfEntries
=
stsd
.
readInt
();
StsdData
out
=
new
StsdData
(
numberOfEntries
);
for
(
int
i
=
0
;
i
<
numberOfEntries
;
i
++)
{
int
childStartPosition
=
stsd
.
getPosition
();
int
childAtomSize
=
stsd
.
readInt
();
Assertions
.
check
Argument
(
childAtomSize
>
0
,
"childAtomSize should be positive"
);
Assertions
.
check
State
(
childAtomSize
>
0
,
"childAtomSize should be positive"
);
int
childAtomType
=
stsd
.
readInt
();
if
(
childAtomType
==
Atom
.
TYPE_avc1
||
childAtomType
==
Atom
.
TYPE_avc3
...
...
@@ -846,9 +862,17 @@ import java.util.List;
initializationData
);
}
private
static
void
parseVideoSampleEntry
(
ParsableByteArray
parent
,
int
atomType
,
int
position
,
int
size
,
int
trackId
,
int
rotationDegrees
,
DrmInitData
drmInitData
,
StsdData
out
,
int
entryIndex
)
throws
ParserException
{
private
static
void
parseVideoSampleEntry
(
ParsableByteArray
parent
,
int
atomType
,
int
position
,
int
size
,
int
trackId
,
int
rotationDegrees
,
@Nullable
DrmInitData
drmInitData
,
StsdData
out
,
int
entryIndex
)
throws
ParserException
{
parent
.
setPosition
(
position
+
Atom
.
HEADER_SIZE
+
StsdData
.
STSD_HEADER_SIZE
);
parent
.
skipBytes
(
16
);
...
...
@@ -860,8 +884,9 @@ import java.util.List;
int
childPosition
=
parent
.
getPosition
();
if
(
atomType
==
Atom
.
TYPE_encv
)
{
Pair
<
Integer
,
TrackEncryptionBox
>
sampleEntryEncryptionData
=
parseSampleEntryEncryptionData
(
parent
,
position
,
size
);
@Nullable
Pair
<
Integer
,
TrackEncryptionBox
>
sampleEntryEncryptionData
=
parseSampleEntryEncryptionData
(
parent
,
position
,
size
);
if
(
sampleEntryEncryptionData
!=
null
)
{
atomType
=
sampleEntryEncryptionData
.
first
;
drmInitData
=
drmInitData
==
null
?
null
...
...
@@ -875,10 +900,10 @@ import java.util.List;
// drmInitData = null;
// }
List
<
byte
[]>
initializationData
=
null
;
String
mimeType
=
null
;
String
codecs
=
null
;
byte
[]
projectionData
=
null
;
@Nullable
List
<
byte
[]>
initializationData
=
null
;
@Nullable
String
mimeType
=
null
;
@Nullable
String
codecs
=
null
;
@Nullable
byte
[]
projectionData
=
null
;
@C
.
StereoMode
int
stereoMode
=
Format
.
NO_VALUE
;
while
(
childPosition
-
position
<
size
)
{
...
...
@@ -889,7 +914,7 @@ import java.util.List;
// Handle optional terminating four zero bytes in MOV files.
break
;
}
Assertions
.
check
Argument
(
childAtomSize
>
0
,
"childAtomSize should be positive"
);
Assertions
.
check
State
(
childAtomSize
>
0
,
"childAtomSize should be positive"
);
int
childAtomType
=
parent
.
readInt
();
if
(
childAtomType
==
Atom
.
TYPE_avcC
)
{
Assertions
.
checkState
(
mimeType
==
null
);
...
...
@@ -925,10 +950,13 @@ import java.util.List;
mimeType
=
MimeTypes
.
VIDEO_H263
;
}
else
if
(
childAtomType
==
Atom
.
TYPE_esds
)
{
Assertions
.
checkState
(
mimeType
==
null
);
Pair
<
String
,
byte
[]>
mimeTypeAndInitializationData
=
Pair
<
@NullableType
String
,
byte
@NullableType
[]>
mimeTypeAndInitializationDataBytes
=
parseEsdsFromParent
(
parent
,
childStartPosition
);
mimeType
=
mimeTypeAndInitializationData
.
first
;
initializationData
=
Collections
.
singletonList
(
mimeTypeAndInitializationData
.
second
);
mimeType
=
mimeTypeAndInitializationDataBytes
.
first
;
@Nullable
byte
[]
initializationDataBytes
=
mimeTypeAndInitializationDataBytes
.
second
;
if
(
initializationDataBytes
!=
null
)
{
initializationData
=
Collections
.
singletonList
(
initializationDataBytes
);
}
}
else
if
(
childAtomType
==
Atom
.
TYPE_pasp
)
{
pixelWidthHeightRatio
=
parsePaspFromParent
(
parent
,
childStartPosition
);
pixelWidthHeightRatioFromPasp
=
true
;
...
...
@@ -988,13 +1016,14 @@ import java.util.List;
* Parses the edts atom (defined in 14496-12 subsection 8.6.5).
*
* @param edtsAtom edts (edit box) atom to decode.
* @return Pair of edit list durations and edit list media times, or
a pair of nulls if they are
*
not
present.
* @return Pair of edit list durations and edit list media times, or
{@code null} if they are not
* present.
*/
@Nullable
private
static
Pair
<
long
[],
long
[]>
parseEdts
(
Atom
.
ContainerAtom
edtsAtom
)
{
Atom
.
LeafAtom
elst
;
if
(
edtsAtom
==
null
||
(
elst
=
edtsAtom
.
getLeafAtomOfType
(
Atom
.
TYPE_elst
))
==
null
)
{
return
Pair
.
create
(
null
,
null
)
;
return
null
;
}
ParsableByteArray
elstData
=
elst
.
data
;
elstData
.
setPosition
(
Atom
.
HEADER_SIZE
);
...
...
@@ -1024,9 +1053,18 @@ import java.util.List;
return
(
float
)
hSpacing
/
vSpacing
;
}
private
static
void
parseAudioSampleEntry
(
ParsableByteArray
parent
,
int
atomType
,
int
position
,
int
size
,
int
trackId
,
String
language
,
boolean
isQuickTime
,
DrmInitData
drmInitData
,
StsdData
out
,
int
entryIndex
)
throws
ParserException
{
private
static
void
parseAudioSampleEntry
(
ParsableByteArray
parent
,
int
atomType
,
int
position
,
int
size
,
int
trackId
,
String
language
,
boolean
isQuickTime
,
@Nullable
DrmInitData
drmInitData
,
StsdData
out
,
int
entryIndex
)
throws
ParserException
{
parent
.
setPosition
(
position
+
Atom
.
HEADER_SIZE
+
StsdData
.
STSD_HEADER_SIZE
);
int
quickTimeSoundDescriptionVersion
=
0
;
...
...
@@ -1064,8 +1102,9 @@ import java.util.List;
int
childPosition
=
parent
.
getPosition
();
if
(
atomType
==
Atom
.
TYPE_enca
)
{
Pair
<
Integer
,
TrackEncryptionBox
>
sampleEntryEncryptionData
=
parseSampleEntryEncryptionData
(
parent
,
position
,
size
);
@Nullable
Pair
<
Integer
,
TrackEncryptionBox
>
sampleEntryEncryptionData
=
parseSampleEntryEncryptionData
(
parent
,
position
,
size
);
if
(
sampleEntryEncryptionData
!=
null
)
{
atomType
=
sampleEntryEncryptionData
.
first
;
drmInitData
=
drmInitData
==
null
?
null
...
...
@@ -1080,7 +1119,7 @@ import java.util.List;
// }
// If the atom type determines a MIME type, set it immediately.
String
mimeType
=
null
;
@Nullable
String
mimeType
=
null
;
if
(
atomType
==
Atom
.
TYPE_ac_3
)
{
mimeType
=
MimeTypes
.
AUDIO_AC3
;
}
else
if
(
atomType
==
Atom
.
TYPE_ec_3
)
{
...
...
@@ -1113,21 +1152,21 @@ import java.util.List;
mimeType
=
MimeTypes
.
AUDIO_FLAC
;
}
byte
[]
initializationData
=
null
;
@Nullable
byte
[]
initializationData
=
null
;
while
(
childPosition
-
position
<
size
)
{
parent
.
setPosition
(
childPosition
);
int
childAtomSize
=
parent
.
readInt
();
Assertions
.
check
Argument
(
childAtomSize
>
0
,
"childAtomSize should be positive"
);
Assertions
.
check
State
(
childAtomSize
>
0
,
"childAtomSize should be positive"
);
int
childAtomType
=
parent
.
readInt
();
if
(
childAtomType
==
Atom
.
TYPE_esds
||
(
isQuickTime
&&
childAtomType
==
Atom
.
TYPE_wave
))
{
int
esdsAtomPosition
=
childAtomType
==
Atom
.
TYPE_esds
?
childPosition
:
findEsdsPosition
(
parent
,
childPosition
,
childAtomSize
);
if
(
esdsAtomPosition
!=
C
.
POSITION_UNSET
)
{
Pair
<
String
,
byte
[]>
mimeTypeAndInitializationData
=
Pair
<
@NullableType
String
,
byte
@NullableType
[]>
mimeTypeAndInitializationData
=
parseEsdsFromParent
(
parent
,
esdsAtomPosition
);
mimeType
=
mimeTypeAndInitializationData
.
first
;
initializationData
=
mimeTypeAndInitializationData
.
second
;
if
(
MimeTypes
.
AUDIO_AAC
.
equals
(
mimeType
))
{
if
(
MimeTypes
.
AUDIO_AAC
.
equals
(
mimeType
)
&&
initializationData
!=
null
)
{
// Update sampleRate and channelCount from the AudioSpecificConfig initialization data,
// which is more reliable. See [Internal: b/10903778].
Pair
<
Integer
,
Integer
>
audioSpecificConfig
=
...
...
@@ -1204,7 +1243,7 @@ import java.util.List;
while
(
childAtomPosition
-
position
<
size
)
{
parent
.
setPosition
(
childAtomPosition
);
int
childAtomSize
=
parent
.
readInt
();
Assertions
.
check
Argument
(
childAtomSize
>
0
,
"childAtomSize should be positive"
);
Assertions
.
check
State
(
childAtomSize
>
0
,
"childAtomSize should be positive"
);
int
childType
=
parent
.
readInt
();
if
(
childType
==
Atom
.
TYPE_esds
)
{
return
childAtomPosition
;
...
...
@@ -1214,10 +1253,9 @@ import java.util.List;
return
C
.
POSITION_UNSET
;
}
/**
* Returns codec-specific initialization data contained in an esds box.
*/
private
static
Pair
<
String
,
byte
[]>
parseEsdsFromParent
(
ParsableByteArray
parent
,
int
position
)
{
/** Returns codec-specific initialization data contained in an esds box. */
private
static
Pair
<
@NullableType
String
,
byte
@NullableType
[]>
parseEsdsFromParent
(
ParsableByteArray
parent
,
int
position
)
{
parent
.
setPosition
(
position
+
Atom
.
HEADER_SIZE
+
4
);
// Start of the ES_Descriptor (defined in 14496-1)
parent
.
skipBytes
(
1
);
// ES_Descriptor tag
...
...
@@ -1263,13 +1301,14 @@ import java.util.List;
* unencrypted atom type and a {@link TrackEncryptionBox}. Null is returned if no common
* encryption sinf atom was present.
*/
@Nullable
private
static
Pair
<
Integer
,
TrackEncryptionBox
>
parseSampleEntryEncryptionData
(
ParsableByteArray
parent
,
int
position
,
int
size
)
{
int
childPosition
=
parent
.
getPosition
();
while
(
childPosition
-
position
<
size
)
{
parent
.
setPosition
(
childPosition
);
int
childAtomSize
=
parent
.
readInt
();
Assertions
.
check
Argument
(
childAtomSize
>
0
,
"childAtomSize should be positive"
);
Assertions
.
check
State
(
childAtomSize
>
0
,
"childAtomSize should be positive"
);
int
childAtomType
=
parent
.
readInt
();
if
(
childAtomType
==
Atom
.
TYPE_sinf
)
{
Pair
<
Integer
,
TrackEncryptionBox
>
result
=
parseCommonEncryptionSinfFromParent
(
parent
,
...
...
@@ -1283,6 +1322,7 @@ import java.util.List;
return
null
;
}
@Nullable
/* package */
static
Pair
<
Integer
,
TrackEncryptionBox
>
parseCommonEncryptionSinfFromParent
(
ParsableByteArray
parent
,
int
position
,
int
size
)
{
int
childPosition
=
position
+
Atom
.
HEADER_SIZE
;
...
...
@@ -1309,20 +1349,21 @@ import java.util.List;
if
(
C
.
CENC_TYPE_cenc
.
equals
(
schemeType
)
||
C
.
CENC_TYPE_cbc1
.
equals
(
schemeType
)
||
C
.
CENC_TYPE_cens
.
equals
(
schemeType
)
||
C
.
CENC_TYPE_cbcs
.
equals
(
schemeType
))
{
Assertions
.
check
Argument
(
dataFormat
!=
null
,
"frma atom is mandatory"
);
Assertions
.
check
Argument
(
schemeInformationBoxPosition
!=
C
.
POSITION_UNSET
,
"schi atom is mandatory"
);
Assertions
.
check
StateNotNull
(
dataFormat
,
"frma atom is mandatory"
);
Assertions
.
check
State
(
schemeInformationBoxPosition
!=
C
.
POSITION_UNSET
,
"schi atom is mandatory"
);
TrackEncryptionBox
encryptionBox
=
parseSchiFromParent
(
parent
,
schemeInformationBoxPosition
,
schemeInformationBoxSize
,
schemeType
);
Assertions
.
check
Argument
(
encryptionBox
!=
null
,
"tenc atom is mandatory"
);
Assertions
.
check
StateNotNull
(
encryptionBox
,
"tenc atom is mandatory"
);
return
Pair
.
create
(
dataFormat
,
encryptionBox
);
}
else
{
return
null
;
}
}
private
static
TrackEncryptionBox
parseSchiFromParent
(
ParsableByteArray
parent
,
int
position
,
int
size
,
String
schemeType
)
{
@Nullable
private
static
TrackEncryptionBox
parseSchiFromParent
(
ParsableByteArray
parent
,
int
position
,
int
size
,
String
schemeType
)
{
int
childPosition
=
position
+
Atom
.
HEADER_SIZE
;
while
(
childPosition
-
position
<
size
)
{
parent
.
setPosition
(
childPosition
);
...
...
@@ -1359,9 +1400,8 @@ import java.util.List;
return
null
;
}
/**
* Parses the proj box from sv3d box, as specified by https://github.com/google/spatial-media.
*/
/** Parses the proj box from sv3d box, as specified by https://github.com/google/spatial-media. */
@Nullable
private
static
byte
[]
parseProjFromParent
(
ParsableByteArray
parent
,
int
position
,
int
size
)
{
int
childPosition
=
position
+
Atom
.
HEADER_SIZE
;
while
(
childPosition
-
position
<
size
)
{
...
...
@@ -1477,10 +1517,9 @@ import java.util.List;
public
final
TrackEncryptionBox
[]
trackEncryptionBoxes
;
public
Format
format
;
@Nullable
public
Format
format
;
public
int
nalUnitLengthFieldLength
;
@Track
.
Transformation
public
int
requiredSampleTransformation
;
@Track
.
Transformation
public
int
requiredSampleTransformation
;
public
StsdData
(
int
numberOfEntries
)
{
trackEncryptionBoxes
=
new
TrackEncryptionBox
[
numberOfEntries
];
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment