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
821d4fb1
authored
Dec 18, 2019
by
olly
Committed by
Oliver Woodman
Dec 18, 2019
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Add NonNull at package level for extractor.mp4
PiperOrigin-RevId: 286191078
parent
7a03e8ed
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
150 additions
and
100 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/FragmentedMp4Extractor.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/MdtaMetadataEntry.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/MetadataUtil.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/Mp4Extractor.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/PsshAtomUtil.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/TrackFragment.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/package-info.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java
View file @
821d4fb1
...
@@ -125,14 +125,16 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
...
@@ -125,14 +125,16 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
Pair
<
Long
,
String
>
mdhdData
=
parseMdhd
(
mdia
.
getLeafAtomOfType
(
Atom
.
TYPE_mdhd
).
data
);
Pair
<
Long
,
String
>
mdhdData
=
parseMdhd
(
mdia
.
getLeafAtomOfType
(
Atom
.
TYPE_mdhd
).
data
);
StsdData
stsdData
=
parseStsd
(
stbl
.
getLeafAtomOfType
(
Atom
.
TYPE_stsd
).
data
,
tkhdData
.
id
,
StsdData
stsdData
=
parseStsd
(
stbl
.
getLeafAtomOfType
(
Atom
.
TYPE_stsd
).
data
,
tkhdData
.
id
,
tkhdData
.
rotationDegrees
,
mdhdData
.
second
,
drmInitData
,
isQuickTime
);
tkhdData
.
rotationDegrees
,
mdhdData
.
second
,
drmInitData
,
isQuickTime
);
long
[]
editListDurations
=
null
;
@Nullable
long
[]
editListDurations
=
null
;
long
[]
editListMediaTimes
=
null
;
@Nullable
long
[]
editListMediaTimes
=
null
;
if
(!
ignoreEditLists
)
{
if
(!
ignoreEditLists
)
{
@Nullable
@Nullable
Atom
.
ContainerAtom
edtsAtom
=
trak
.
getContainerAtomOfType
(
Atom
.
TYPE_edts
);
Pair
<
long
[],
long
[]>
edtsData
=
parseEdts
(
trak
.
getContainerAtomOfType
(
Atom
.
TYPE_edts
));
if
(
edtsAtom
!=
null
)
{
if
(
edtsData
!=
null
)
{
@Nullable
Pair
<
long
[],
long
[]>
edtsData
=
parseEdts
(
edtsAtom
);
editListDurations
=
edtsData
.
first
;
if
(
edtsData
!=
null
)
{
editListMediaTimes
=
edtsData
.
second
;
editListDurations
=
edtsData
.
first
;
editListMediaTimes
=
edtsData
.
second
;
}
}
}
}
}
return
stsdData
.
format
==
null
?
null
return
stsdData
.
format
==
null
?
null
...
@@ -154,11 +156,11 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
...
@@ -154,11 +156,11 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
Track
track
,
Atom
.
ContainerAtom
stblAtom
,
GaplessInfoHolder
gaplessInfoHolder
)
Track
track
,
Atom
.
ContainerAtom
stblAtom
,
GaplessInfoHolder
gaplessInfoHolder
)
throws
ParserException
{
throws
ParserException
{
SampleSizeBox
sampleSizeBox
;
SampleSizeBox
sampleSizeBox
;
Atom
.
LeafAtom
stszAtom
=
stblAtom
.
getLeafAtomOfType
(
Atom
.
TYPE_stsz
);
@Nullable
Atom
.
LeafAtom
stszAtom
=
stblAtom
.
getLeafAtomOfType
(
Atom
.
TYPE_stsz
);
if
(
stszAtom
!=
null
)
{
if
(
stszAtom
!=
null
)
{
sampleSizeBox
=
new
StszSampleSizeBox
(
stszAtom
);
sampleSizeBox
=
new
StszSampleSizeBox
(
stszAtom
);
}
else
{
}
else
{
Atom
.
LeafAtom
stz2Atom
=
stblAtom
.
getLeafAtomOfType
(
Atom
.
TYPE_stz2
);
@Nullable
Atom
.
LeafAtom
stz2Atom
=
stblAtom
.
getLeafAtomOfType
(
Atom
.
TYPE_stz2
);
if
(
stz2Atom
==
null
)
{
if
(
stz2Atom
==
null
)
{
throw
new
ParserException
(
"Track has no sample table size information"
);
throw
new
ParserException
(
"Track has no sample table size information"
);
}
}
...
@@ -179,7 +181,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
...
@@ -179,7 +181,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
// Entries are byte offsets of chunks.
// Entries are byte offsets of chunks.
boolean
chunkOffsetsAreLongs
=
false
;
boolean
chunkOffsetsAreLongs
=
false
;
Atom
.
LeafAtom
chunkOffsetsAtom
=
stblAtom
.
getLeafAtomOfType
(
Atom
.
TYPE_stco
);
@Nullable
Atom
.
LeafAtom
chunkOffsetsAtom
=
stblAtom
.
getLeafAtomOfType
(
Atom
.
TYPE_stco
);
if
(
chunkOffsetsAtom
==
null
)
{
if
(
chunkOffsetsAtom
==
null
)
{
chunkOffsetsAreLongs
=
true
;
chunkOffsetsAreLongs
=
true
;
chunkOffsetsAtom
=
stblAtom
.
getLeafAtomOfType
(
Atom
.
TYPE_co64
);
chunkOffsetsAtom
=
stblAtom
.
getLeafAtomOfType
(
Atom
.
TYPE_co64
);
...
@@ -190,11 +192,11 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
...
@@ -190,11 +192,11 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
// Entries are (number of samples, timestamp delta between those samples).
// Entries are (number of samples, timestamp delta between those samples).
ParsableByteArray
stts
=
stblAtom
.
getLeafAtomOfType
(
Atom
.
TYPE_stts
).
data
;
ParsableByteArray
stts
=
stblAtom
.
getLeafAtomOfType
(
Atom
.
TYPE_stts
).
data
;
// Entries are the indices of samples that are synchronization samples.
// Entries are the indices of samples that are synchronization samples.
Atom
.
LeafAtom
stssAtom
=
stblAtom
.
getLeafAtomOfType
(
Atom
.
TYPE_stss
);
@Nullable
Atom
.
LeafAtom
stssAtom
=
stblAtom
.
getLeafAtomOfType
(
Atom
.
TYPE_stss
);
ParsableByteArray
stss
=
stssAtom
!=
null
?
stssAtom
.
data
:
null
;
@Nullable
ParsableByteArray
stss
=
stssAtom
!=
null
?
stssAtom
.
data
:
null
;
// Entries are (number of samples, timestamp offset).
// Entries are (number of samples, timestamp offset).
Atom
.
LeafAtom
cttsAtom
=
stblAtom
.
getLeafAtomOfType
(
Atom
.
TYPE_ctts
);
@Nullable
Atom
.
LeafAtom
cttsAtom
=
stblAtom
.
getLeafAtomOfType
(
Atom
.
TYPE_ctts
);
ParsableByteArray
ctts
=
cttsAtom
!=
null
?
cttsAtom
.
data
:
null
;
@Nullable
ParsableByteArray
ctts
=
cttsAtom
!=
null
?
cttsAtom
.
data
:
null
;
// Prepare to read chunk information.
// Prepare to read chunk information.
ChunkIterator
chunkIterator
=
new
ChunkIterator
(
stsc
,
chunkOffsets
,
chunkOffsetsAreLongs
);
ChunkIterator
chunkIterator
=
new
ChunkIterator
(
stsc
,
chunkOffsets
,
chunkOffsetsAreLongs
);
...
@@ -542,9 +544,9 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
...
@@ -542,9 +544,9 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
*/
*/
@Nullable
@Nullable
public
static
Metadata
parseMdtaFromMeta
(
Atom
.
ContainerAtom
meta
)
{
public
static
Metadata
parseMdtaFromMeta
(
Atom
.
ContainerAtom
meta
)
{
Atom
.
LeafAtom
hdlrAtom
=
meta
.
getLeafAtomOfType
(
Atom
.
TYPE_hdlr
);
@Nullable
Atom
.
LeafAtom
hdlrAtom
=
meta
.
getLeafAtomOfType
(
Atom
.
TYPE_hdlr
);
Atom
.
LeafAtom
keysAtom
=
meta
.
getLeafAtomOfType
(
Atom
.
TYPE_keys
);
@Nullable
Atom
.
LeafAtom
keysAtom
=
meta
.
getLeafAtomOfType
(
Atom
.
TYPE_keys
);
Atom
.
LeafAtom
ilstAtom
=
meta
.
getLeafAtomOfType
(
Atom
.
TYPE_ilst
);
@Nullable
Atom
.
LeafAtom
ilstAtom
=
meta
.
getLeafAtomOfType
(
Atom
.
TYPE_ilst
);
if
(
hdlrAtom
==
null
if
(
hdlrAtom
==
null
||
keysAtom
==
null
||
keysAtom
==
null
||
ilstAtom
==
null
||
ilstAtom
==
null
...
@@ -575,6 +577,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
...
@@ -575,6 +577,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
int
keyIndex
=
ilst
.
readInt
()
-
1
;
int
keyIndex
=
ilst
.
readInt
()
-
1
;
if
(
keyIndex
>=
0
&&
keyIndex
<
keyNames
.
length
)
{
if
(
keyIndex
>=
0
&&
keyIndex
<
keyNames
.
length
)
{
String
key
=
keyNames
[
keyIndex
];
String
key
=
keyNames
[
keyIndex
];
@Nullable
Metadata
.
Entry
entry
=
Metadata
.
Entry
entry
=
MetadataUtil
.
parseMdtaMetadataEntryFromIlst
(
ilst
,
atomPosition
+
atomSize
,
key
);
MetadataUtil
.
parseMdtaMetadataEntryFromIlst
(
ilst
,
atomPosition
+
atomSize
,
key
);
if
(
entry
!=
null
)
{
if
(
entry
!=
null
)
{
...
@@ -609,7 +612,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
...
@@ -609,7 +612,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
ilst
.
skipBytes
(
Atom
.
HEADER_SIZE
);
ilst
.
skipBytes
(
Atom
.
HEADER_SIZE
);
ArrayList
<
Metadata
.
Entry
>
entries
=
new
ArrayList
<>();
ArrayList
<
Metadata
.
Entry
>
entries
=
new
ArrayList
<>();
while
(
ilst
.
getPosition
()
<
limit
)
{
while
(
ilst
.
getPosition
()
<
limit
)
{
Metadata
.
Entry
entry
=
MetadataUtil
.
parseIlstElement
(
ilst
);
@Nullable
Metadata
.
Entry
entry
=
MetadataUtil
.
parseIlstElement
(
ilst
);
if
(
entry
!=
null
)
{
if
(
entry
!=
null
)
{
entries
.
add
(
entry
);
entries
.
add
(
entry
);
}
}
...
@@ -817,12 +820,18 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
...
@@ -817,12 +820,18 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
return
out
;
return
out
;
}
}
private
static
void
parseTextSampleEntry
(
ParsableByteArray
parent
,
int
atomType
,
int
position
,
private
static
void
parseTextSampleEntry
(
int
atomSize
,
int
trackId
,
String
language
,
StsdData
out
)
throws
ParserException
{
ParsableByteArray
parent
,
int
atomType
,
int
position
,
int
atomSize
,
int
trackId
,
String
language
,
StsdData
out
)
{
parent
.
setPosition
(
position
+
Atom
.
HEADER_SIZE
+
StsdData
.
STSD_HEADER_SIZE
);
parent
.
setPosition
(
position
+
Atom
.
HEADER_SIZE
+
StsdData
.
STSD_HEADER_SIZE
);
// Default values.
// Default values.
List
<
byte
[]>
initializationData
=
null
;
@Nullable
List
<
byte
[]>
initializationData
=
null
;
long
subsampleOffsetUs
=
Format
.
OFFSET_SAMPLE_RELATIVE
;
long
subsampleOffsetUs
=
Format
.
OFFSET_SAMPLE_RELATIVE
;
String
mimeType
;
String
mimeType
;
...
@@ -934,7 +943,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
...
@@ -934,7 +943,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
initializationData
=
hevcConfig
.
initializationData
;
initializationData
=
hevcConfig
.
initializationData
;
out
.
nalUnitLengthFieldLength
=
hevcConfig
.
nalUnitLengthFieldLength
;
out
.
nalUnitLengthFieldLength
=
hevcConfig
.
nalUnitLengthFieldLength
;
}
else
if
(
childAtomType
==
Atom
.
TYPE_dvcC
||
childAtomType
==
Atom
.
TYPE_dvvC
)
{
}
else
if
(
childAtomType
==
Atom
.
TYPE_dvcC
||
childAtomType
==
Atom
.
TYPE_dvvC
)
{
DolbyVisionConfig
dolbyVisionConfig
=
DolbyVisionConfig
.
parse
(
parent
);
@Nullable
DolbyVisionConfig
dolbyVisionConfig
=
DolbyVisionConfig
.
parse
(
parent
);
if
(
dolbyVisionConfig
!=
null
)
{
if
(
dolbyVisionConfig
!=
null
)
{
codecs
=
dolbyVisionConfig
.
codecs
;
codecs
=
dolbyVisionConfig
.
codecs
;
mimeType
=
MimeTypes
.
VIDEO_DOLBY_VISION
;
mimeType
=
MimeTypes
.
VIDEO_DOLBY_VISION
;
...
@@ -1021,11 +1030,11 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
...
@@ -1021,11 +1030,11 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
*/
*/
@Nullable
@Nullable
private
static
Pair
<
long
[],
long
[]>
parseEdts
(
Atom
.
ContainerAtom
edtsAtom
)
{
private
static
Pair
<
long
[],
long
[]>
parseEdts
(
Atom
.
ContainerAtom
edtsAtom
)
{
Atom
.
LeafAtom
elst
;
@Nullable
Atom
.
LeafAtom
elstAtom
=
edtsAtom
.
getLeafAtomOfType
(
Atom
.
TYPE_elst
)
;
if
(
e
dtsAtom
==
null
||
(
elst
=
edtsAtom
.
getLeafAtomOfType
(
Atom
.
TYPE_elst
))
==
null
)
{
if
(
e
lstAtom
==
null
)
{
return
null
;
return
null
;
}
}
ParsableByteArray
elstData
=
elst
.
data
;
ParsableByteArray
elstData
=
elst
Atom
.
data
;
elstData
.
setPosition
(
Atom
.
HEADER_SIZE
);
elstData
.
setPosition
(
Atom
.
HEADER_SIZE
);
int
fullAtom
=
elstData
.
readInt
();
int
fullAtom
=
elstData
.
readInt
();
int
version
=
Atom
.
parseFullAtomVersion
(
fullAtom
);
int
version
=
Atom
.
parseFullAtomVersion
(
fullAtom
);
...
@@ -1328,8 +1337,8 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
...
@@ -1328,8 +1337,8 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
int
childPosition
=
position
+
Atom
.
HEADER_SIZE
;
int
childPosition
=
position
+
Atom
.
HEADER_SIZE
;
int
schemeInformationBoxPosition
=
C
.
POSITION_UNSET
;
int
schemeInformationBoxPosition
=
C
.
POSITION_UNSET
;
int
schemeInformationBoxSize
=
0
;
int
schemeInformationBoxSize
=
0
;
String
schemeType
=
null
;
@Nullable
String
schemeType
=
null
;
Integer
dataFormat
=
null
;
@Nullable
Integer
dataFormat
=
null
;
while
(
childPosition
-
position
<
size
)
{
while
(
childPosition
-
position
<
size
)
{
parent
.
setPosition
(
childPosition
);
parent
.
setPosition
(
childPosition
);
int
childAtomSize
=
parent
.
readInt
();
int
childAtomSize
=
parent
.
readInt
();
...
@@ -1352,9 +1361,11 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
...
@@ -1352,9 +1361,11 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
Assertions
.
checkStateNotNull
(
dataFormat
,
"frma atom is mandatory"
);
Assertions
.
checkStateNotNull
(
dataFormat
,
"frma atom is mandatory"
);
Assertions
.
checkState
(
Assertions
.
checkState
(
schemeInformationBoxPosition
!=
C
.
POSITION_UNSET
,
"schi atom is mandatory"
);
schemeInformationBoxPosition
!=
C
.
POSITION_UNSET
,
"schi atom is mandatory"
);
TrackEncryptionBox
encryptionBox
=
parseSchiFromParent
(
parent
,
schemeInformationBoxPosition
,
TrackEncryptionBox
encryptionBox
=
schemeInformationBoxSize
,
schemeType
);
Assertions
.
checkStateNotNull
(
Assertions
.
checkStateNotNull
(
encryptionBox
,
"tenc atom is mandatory"
);
parseSchiFromParent
(
parent
,
schemeInformationBoxPosition
,
schemeInformationBoxSize
,
schemeType
),
"tenc atom is mandatory"
);
return
Pair
.
create
(
dataFormat
,
encryptionBox
);
return
Pair
.
create
(
dataFormat
,
encryptionBox
);
}
else
{
}
else
{
return
null
;
return
null
;
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java
View file @
821d4fb1
...
@@ -55,6 +55,7 @@ import java.util.Arrays;
...
@@ -55,6 +55,7 @@ import java.util.Arrays;
import
java.util.Collections
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.List
;
import
java.util.UUID
;
import
java.util.UUID
;
import
org.checkerframework.checker.nullness.qual.MonotonicNonNull
;
/** Extracts data from the FMP4 container format. */
/** Extracts data from the FMP4 container format. */
@SuppressWarnings
(
"ConstantField"
)
@SuppressWarnings
(
"ConstantField"
)
...
@@ -155,14 +156,14 @@ public class FragmentedMp4Extractor implements Extractor {
...
@@ -155,14 +156,14 @@ public class FragmentedMp4Extractor implements Extractor {
private
int
atomType
;
private
int
atomType
;
private
long
atomSize
;
private
long
atomSize
;
private
int
atomHeaderBytesRead
;
private
int
atomHeaderBytesRead
;
private
ParsableByteArray
atomData
;
@Nullable
private
ParsableByteArray
atomData
;
private
long
endOfMdatPosition
;
private
long
endOfMdatPosition
;
private
int
pendingMetadataSampleBytes
;
private
int
pendingMetadataSampleBytes
;
private
long
pendingSeekTimeUs
;
private
long
pendingSeekTimeUs
;
private
long
durationUs
;
private
long
durationUs
;
private
long
segmentIndexEarliestPresentationTimeUs
;
private
long
segmentIndexEarliestPresentationTimeUs
;
private
TrackBundle
currentTrackBundle
;
@Nullable
private
TrackBundle
currentTrackBundle
;
private
int
sampleSize
;
private
int
sampleSize
;
private
int
sampleBytesWritten
;
private
int
sampleBytesWritten
;
private
int
sampleCurrentNalBytesRemaining
;
private
int
sampleCurrentNalBytesRemaining
;
...
@@ -170,7 +171,7 @@ public class FragmentedMp4Extractor implements Extractor {
...
@@ -170,7 +171,7 @@ public class FragmentedMp4Extractor implements Extractor {
private
boolean
isAc4HeaderRequired
;
private
boolean
isAc4HeaderRequired
;
// Extractor output.
// Extractor output.
private
ExtractorOutput
extractorOutput
;
@MonotonicNonNull
private
ExtractorOutput
extractorOutput
;
private
TrackOutput
[]
emsgTrackOutputs
;
private
TrackOutput
[]
emsgTrackOutputs
;
private
TrackOutput
[]
cea608TrackOutputs
;
private
TrackOutput
[]
cea608TrackOutputs
;
...
@@ -495,6 +496,7 @@ public class FragmentedMp4Extractor implements Extractor {
...
@@ -495,6 +496,7 @@ public class FragmentedMp4Extractor implements Extractor {
for
(
int
i
=
0
;
i
<
moovContainerChildrenSize
;
i
++)
{
for
(
int
i
=
0
;
i
<
moovContainerChildrenSize
;
i
++)
{
Atom
.
ContainerAtom
atom
=
moov
.
containerChildren
.
get
(
i
);
Atom
.
ContainerAtom
atom
=
moov
.
containerChildren
.
get
(
i
);
if
(
atom
.
type
==
Atom
.
TYPE_trak
)
{
if
(
atom
.
type
==
Atom
.
TYPE_trak
)
{
@Nullable
Track
track
=
Track
track
=
modifyTrack
(
modifyTrack
(
AtomParsers
.
parseTrak
(
AtomParsers
.
parseTrak
(
...
@@ -712,7 +714,7 @@ public class FragmentedMp4Extractor implements Extractor {
...
@@ -712,7 +714,7 @@ public class FragmentedMp4Extractor implements Extractor {
private
static
void
parseTraf
(
ContainerAtom
traf
,
SparseArray
<
TrackBundle
>
trackBundleArray
,
private
static
void
parseTraf
(
ContainerAtom
traf
,
SparseArray
<
TrackBundle
>
trackBundleArray
,
@Flags
int
flags
,
byte
[]
extendedTypeScratch
)
throws
ParserException
{
@Flags
int
flags
,
byte
[]
extendedTypeScratch
)
throws
ParserException
{
LeafAtom
tfhd
=
traf
.
getLeafAtomOfType
(
Atom
.
TYPE_tfhd
);
LeafAtom
tfhd
=
traf
.
getLeafAtomOfType
(
Atom
.
TYPE_tfhd
);
TrackBundle
trackBundle
=
parseTfhd
(
tfhd
.
data
,
trackBundleArray
);
@Nullable
TrackBundle
trackBundle
=
parseTfhd
(
tfhd
.
data
,
trackBundleArray
);
if
(
trackBundle
==
null
)
{
if
(
trackBundle
==
null
)
{
return
;
return
;
}
}
...
@@ -721,33 +723,34 @@ public class FragmentedMp4Extractor implements Extractor {
...
@@ -721,33 +723,34 @@ public class FragmentedMp4Extractor implements Extractor {
long
decodeTime
=
fragment
.
nextFragmentDecodeTime
;
long
decodeTime
=
fragment
.
nextFragmentDecodeTime
;
trackBundle
.
reset
();
trackBundle
.
reset
();
LeafAtom
tfdtAtom
=
traf
.
getLeafAtomOfType
(
Atom
.
TYPE_tfdt
);
@Nullable
LeafAtom
tfdtAtom
=
traf
.
getLeafAtomOfType
(
Atom
.
TYPE_tfdt
);
if
(
tfdtAtom
!=
null
&&
(
flags
&
FLAG_WORKAROUND_IGNORE_TFDT_BOX
)
==
0
)
{
if
(
tfdtAtom
!=
null
&&
(
flags
&
FLAG_WORKAROUND_IGNORE_TFDT_BOX
)
==
0
)
{
decodeTime
=
parseTfdt
(
traf
.
getLeafAtomOfType
(
Atom
.
TYPE_tfdt
).
data
);
decodeTime
=
parseTfdt
(
traf
.
getLeafAtomOfType
(
Atom
.
TYPE_tfdt
).
data
);
}
}
parseTruns
(
traf
,
trackBundle
,
decodeTime
,
flags
);
parseTruns
(
traf
,
trackBundle
,
decodeTime
,
flags
);
TrackEncryptionBox
encryptionBox
=
trackBundle
.
track
@Nullable
.
getSampleDescriptionEncryptionBox
(
fragment
.
header
.
sampleDescriptionIndex
);
TrackEncryptionBox
encryptionBox
=
trackBundle
.
track
.
getSampleDescriptionEncryptionBox
(
fragment
.
header
.
sampleDescriptionIndex
);
LeafAtom
saiz
=
traf
.
getLeafAtomOfType
(
Atom
.
TYPE_saiz
);
@Nullable
LeafAtom
saiz
=
traf
.
getLeafAtomOfType
(
Atom
.
TYPE_saiz
);
if
(
saiz
!=
null
)
{
if
(
saiz
!=
null
)
{
parseSaiz
(
encryptionBox
,
saiz
.
data
,
fragment
);
parseSaiz
(
encryptionBox
,
saiz
.
data
,
fragment
);
}
}
LeafAtom
saio
=
traf
.
getLeafAtomOfType
(
Atom
.
TYPE_saio
);
@Nullable
LeafAtom
saio
=
traf
.
getLeafAtomOfType
(
Atom
.
TYPE_saio
);
if
(
saio
!=
null
)
{
if
(
saio
!=
null
)
{
parseSaio
(
saio
.
data
,
fragment
);
parseSaio
(
saio
.
data
,
fragment
);
}
}
LeafAtom
senc
=
traf
.
getLeafAtomOfType
(
Atom
.
TYPE_senc
);
@Nullable
LeafAtom
senc
=
traf
.
getLeafAtomOfType
(
Atom
.
TYPE_senc
);
if
(
senc
!=
null
)
{
if
(
senc
!=
null
)
{
parseSenc
(
senc
.
data
,
fragment
);
parseSenc
(
senc
.
data
,
fragment
);
}
}
LeafAtom
sbgp
=
traf
.
getLeafAtomOfType
(
Atom
.
TYPE_sbgp
);
@Nullable
LeafAtom
sbgp
=
traf
.
getLeafAtomOfType
(
Atom
.
TYPE_sbgp
);
LeafAtom
sgpd
=
traf
.
getLeafAtomOfType
(
Atom
.
TYPE_sgpd
);
@Nullable
LeafAtom
sgpd
=
traf
.
getLeafAtomOfType
(
Atom
.
TYPE_sgpd
);
if
(
sbgp
!=
null
&&
sgpd
!=
null
)
{
if
(
sbgp
!=
null
&&
sgpd
!=
null
)
{
parseSgpd
(
sbgp
.
data
,
sgpd
.
data
,
encryptionBox
!=
null
?
encryptionBox
.
schemeType
:
null
,
parseSgpd
(
sbgp
.
data
,
sgpd
.
data
,
encryptionBox
!=
null
?
encryptionBox
.
schemeType
:
null
,
fragment
);
fragment
);
...
@@ -863,13 +866,14 @@ public class FragmentedMp4Extractor implements Extractor {
...
@@ -863,13 +866,14 @@ public class FragmentedMp4Extractor implements Extractor {
* @return The {@link TrackBundle} to which the {@link TrackFragment} belongs, or null if the tfhd
* @return The {@link TrackBundle} to which the {@link TrackFragment} belongs, or null if the tfhd
* does not refer to any {@link TrackBundle}.
* does not refer to any {@link TrackBundle}.
*/
*/
@Nullable
private
static
TrackBundle
parseTfhd
(
private
static
TrackBundle
parseTfhd
(
ParsableByteArray
tfhd
,
SparseArray
<
TrackBundle
>
trackBundles
)
{
ParsableByteArray
tfhd
,
SparseArray
<
TrackBundle
>
trackBundles
)
{
tfhd
.
setPosition
(
Atom
.
HEADER_SIZE
);
tfhd
.
setPosition
(
Atom
.
HEADER_SIZE
);
int
fullAtom
=
tfhd
.
readInt
();
int
fullAtom
=
tfhd
.
readInt
();
int
atomFlags
=
Atom
.
parseFullAtomFlags
(
fullAtom
);
int
atomFlags
=
Atom
.
parseFullAtomFlags
(
fullAtom
);
int
trackId
=
tfhd
.
readInt
();
int
trackId
=
tfhd
.
readInt
();
TrackBundle
trackBundle
=
getTrackBundle
(
trackBundles
,
trackId
);
@Nullable
TrackBundle
trackBundle
=
getTrackBundle
(
trackBundles
,
trackId
);
if
(
trackBundle
==
null
)
{
if
(
trackBundle
==
null
)
{
return
null
;
return
null
;
}
}
...
@@ -1053,8 +1057,12 @@ public class FragmentedMp4Extractor implements Extractor {
...
@@ -1053,8 +1057,12 @@ public class FragmentedMp4Extractor implements Extractor {
out
.
fillEncryptionData
(
senc
);
out
.
fillEncryptionData
(
senc
);
}
}
private
static
void
parseSgpd
(
ParsableByteArray
sbgp
,
ParsableByteArray
sgpd
,
String
schemeType
,
private
static
void
parseSgpd
(
TrackFragment
out
)
throws
ParserException
{
ParsableByteArray
sbgp
,
ParsableByteArray
sgpd
,
@Nullable
String
schemeType
,
TrackFragment
out
)
throws
ParserException
{
sbgp
.
setPosition
(
Atom
.
HEADER_SIZE
);
sbgp
.
setPosition
(
Atom
.
HEADER_SIZE
);
int
sbgpFullAtom
=
sbgp
.
readInt
();
int
sbgpFullAtom
=
sbgp
.
readInt
();
if
(
sbgp
.
readInt
()
!=
SAMPLE_GROUP_TYPE_seig
)
{
if
(
sbgp
.
readInt
()
!=
SAMPLE_GROUP_TYPE_seig
)
{
...
@@ -1216,7 +1224,7 @@ public class FragmentedMp4Extractor implements Extractor {
...
@@ -1216,7 +1224,7 @@ public class FragmentedMp4Extractor implements Extractor {
private
boolean
readSample
(
ExtractorInput
input
)
throws
IOException
,
InterruptedException
{
private
boolean
readSample
(
ExtractorInput
input
)
throws
IOException
,
InterruptedException
{
if
(
parserState
==
STATE_READING_SAMPLE_START
)
{
if
(
parserState
==
STATE_READING_SAMPLE_START
)
{
if
(
currentTrackBundle
==
null
)
{
if
(
currentTrackBundle
==
null
)
{
TrackBundle
currentTrackBundle
=
getNextFragmentRun
(
trackBundles
);
@Nullable
TrackBundle
currentTrackBundle
=
getNextFragmentRun
(
trackBundles
);
if
(
currentTrackBundle
==
null
)
{
if
(
currentTrackBundle
==
null
)
{
// We've run out of samples in the current mdat. Discard any trailing data and prepare to
// We've run out of samples in the current mdat. Discard any trailing data and prepare to
// read the header of the next atom.
// read the header of the next atom.
...
@@ -1388,6 +1396,7 @@ public class FragmentedMp4Extractor implements Extractor {
...
@@ -1388,6 +1396,7 @@ public class FragmentedMp4Extractor implements Extractor {
* Returns the {@link TrackBundle} whose fragment run has the earliest file position out of those
* Returns the {@link TrackBundle} whose fragment run has the earliest file position out of those
* yet to be consumed, or null if all have been consumed.
* yet to be consumed, or null if all have been consumed.
*/
*/
@Nullable
private
static
TrackBundle
getNextFragmentRun
(
SparseArray
<
TrackBundle
>
trackBundles
)
{
private
static
TrackBundle
getNextFragmentRun
(
SparseArray
<
TrackBundle
>
trackBundles
)
{
TrackBundle
nextTrackBundle
=
null
;
TrackBundle
nextTrackBundle
=
null
;
long
nextTrackRunOffset
=
Long
.
MAX_VALUE
;
long
nextTrackRunOffset
=
Long
.
MAX_VALUE
;
...
@@ -1410,7 +1419,7 @@ public class FragmentedMp4Extractor implements Extractor {
...
@@ -1410,7 +1419,7 @@ public class FragmentedMp4Extractor implements Extractor {
/** Returns DrmInitData from leaf atoms. */
/** Returns DrmInitData from leaf atoms. */
private
static
DrmInitData
getDrmInitDataFromAtoms
(
List
<
Atom
.
LeafAtom
>
leafChildren
)
{
private
static
DrmInitData
getDrmInitDataFromAtoms
(
List
<
Atom
.
LeafAtom
>
leafChildren
)
{
ArrayList
<
SchemeData
>
schemeDatas
=
null
;
@Nullable
ArrayList
<
SchemeData
>
schemeDatas
=
null
;
int
leafChildrenSize
=
leafChildren
.
size
();
int
leafChildrenSize
=
leafChildren
.
size
();
for
(
int
i
=
0
;
i
<
leafChildrenSize
;
i
++)
{
for
(
int
i
=
0
;
i
<
leafChildrenSize
;
i
++)
{
LeafAtom
child
=
leafChildren
.
get
(
i
);
LeafAtom
child
=
leafChildren
.
get
(
i
);
...
@@ -1419,7 +1428,7 @@ public class FragmentedMp4Extractor implements Extractor {
...
@@ -1419,7 +1428,7 @@ public class FragmentedMp4Extractor implements Extractor {
schemeDatas
=
new
ArrayList
<>();
schemeDatas
=
new
ArrayList
<>();
}
}
byte
[]
psshData
=
child
.
data
.
data
;
byte
[]
psshData
=
child
.
data
.
data
;
UUID
uuid
=
PsshAtomUtil
.
parseUuid
(
psshData
);
@Nullable
UUID
uuid
=
PsshAtomUtil
.
parseUuid
(
psshData
);
if
(
uuid
==
null
)
{
if
(
uuid
==
null
)
{
Log
.
w
(
TAG
,
"Skipped pssh atom (failed to extract uuid)"
);
Log
.
w
(
TAG
,
"Skipped pssh atom (failed to extract uuid)"
);
}
else
{
}
else
{
...
@@ -1496,9 +1505,10 @@ public class FragmentedMp4Extractor implements Extractor {
...
@@ -1496,9 +1505,10 @@ public class FragmentedMp4Extractor implements Extractor {
}
}
public
void
updateDrmInitData
(
DrmInitData
drmInitData
)
{
public
void
updateDrmInitData
(
DrmInitData
drmInitData
)
{
@Nullable
TrackEncryptionBox
encryptionBox
=
TrackEncryptionBox
encryptionBox
=
track
.
getSampleDescriptionEncryptionBox
(
fragment
.
header
.
sampleDescriptionIndex
);
track
.
getSampleDescriptionEncryptionBox
(
fragment
.
header
.
sampleDescriptionIndex
);
String
schemeType
=
encryptionBox
!=
null
?
encryptionBox
.
schemeType
:
null
;
@Nullable
String
schemeType
=
encryptionBox
!=
null
?
encryptionBox
.
schemeType
:
null
;
output
.
format
(
track
.
format
.
copyWithDrmInitData
(
drmInitData
.
copyWithSchemeType
(
schemeType
)));
output
.
format
(
track
.
format
.
copyWithDrmInitData
(
drmInitData
.
copyWithSchemeType
(
schemeType
)));
}
}
...
@@ -1595,7 +1605,7 @@ public class FragmentedMp4Extractor implements Extractor {
...
@@ -1595,7 +1605,7 @@ public class FragmentedMp4Extractor implements Extractor {
/** Skips the encryption data for the current sample. */
/** Skips the encryption data for the current sample. */
private
void
skipSampleEncryptionData
()
{
private
void
skipSampleEncryptionData
()
{
TrackEncryptionBox
encryptionBox
=
getEncryptionBoxIfEncrypted
();
@Nullable
TrackEncryptionBox
encryptionBox
=
getEncryptionBoxIfEncrypted
();
if
(
encryptionBox
==
null
)
{
if
(
encryptionBox
==
null
)
{
return
;
return
;
}
}
...
@@ -1609,8 +1619,10 @@ public class FragmentedMp4Extractor implements Extractor {
...
@@ -1609,8 +1619,10 @@ public class FragmentedMp4Extractor implements Extractor {
}
}
}
}
@Nullable
private
TrackEncryptionBox
getEncryptionBoxIfEncrypted
()
{
private
TrackEncryptionBox
getEncryptionBoxIfEncrypted
()
{
int
sampleDescriptionIndex
=
fragment
.
header
.
sampleDescriptionIndex
;
int
sampleDescriptionIndex
=
fragment
.
header
.
sampleDescriptionIndex
;
@Nullable
TrackEncryptionBox
encryptionBox
=
TrackEncryptionBox
encryptionBox
=
fragment
.
trackEncryptionBox
!=
null
fragment
.
trackEncryptionBox
!=
null
?
fragment
.
trackEncryptionBox
?
fragment
.
trackEncryptionBox
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/MdtaMetadataEntry.java
View file @
821d4fb1
...
@@ -47,8 +47,7 @@ public final class MdtaMetadataEntry implements Metadata.Entry {
...
@@ -47,8 +47,7 @@ public final class MdtaMetadataEntry implements Metadata.Entry {
private
MdtaMetadataEntry
(
Parcel
in
)
{
private
MdtaMetadataEntry
(
Parcel
in
)
{
key
=
Util
.
castNonNull
(
in
.
readString
());
key
=
Util
.
castNonNull
(
in
.
readString
());
value
=
new
byte
[
in
.
readInt
()];
value
=
Util
.
castNonNull
(
in
.
createByteArray
());
in
.
readByteArray
(
value
);
localeIndicator
=
in
.
readInt
();
localeIndicator
=
in
.
readInt
();
typeIndicator
=
in
.
readInt
();
typeIndicator
=
in
.
readInt
();
}
}
...
@@ -88,7 +87,6 @@ public final class MdtaMetadataEntry implements Metadata.Entry {
...
@@ -88,7 +87,6 @@ public final class MdtaMetadataEntry implements Metadata.Entry {
@Override
@Override
public
void
writeToParcel
(
Parcel
dest
,
int
flags
)
{
public
void
writeToParcel
(
Parcel
dest
,
int
flags
)
{
dest
.
writeString
(
key
);
dest
.
writeString
(
key
);
dest
.
writeInt
(
value
.
length
);
dest
.
writeByteArray
(
value
);
dest
.
writeByteArray
(
value
);
dest
.
writeInt
(
localeIndicator
);
dest
.
writeInt
(
localeIndicator
);
dest
.
writeInt
(
typeIndicator
);
dest
.
writeInt
(
typeIndicator
);
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/MetadataUtil.java
View file @
821d4fb1
...
@@ -325,8 +325,11 @@ import com.google.android.exoplayer2.util.ParsableByteArray;
...
@@ -325,8 +325,11 @@ import com.google.android.exoplayer2.util.ParsableByteArray;
@Nullable
@Nullable
private
static
TextInformationFrame
parseStandardGenreAttribute
(
ParsableByteArray
data
)
{
private
static
TextInformationFrame
parseStandardGenreAttribute
(
ParsableByteArray
data
)
{
int
genreCode
=
parseUint8AttributeValue
(
data
);
int
genreCode
=
parseUint8AttributeValue
(
data
);
String
genreString
=
(
0
<
genreCode
&&
genreCode
<=
STANDARD_GENRES
.
length
)
@Nullable
?
STANDARD_GENRES
[
genreCode
-
1
]
:
null
;
String
genreString
=
(
0
<
genreCode
&&
genreCode
<=
STANDARD_GENRES
.
length
)
?
STANDARD_GENRES
[
genreCode
-
1
]
:
null
;
if
(
genreString
!=
null
)
{
if
(
genreString
!=
null
)
{
return
new
TextInformationFrame
(
"TCON"
,
/* description= */
null
,
genreString
);
return
new
TextInformationFrame
(
"TCON"
,
/* description= */
null
,
genreString
);
}
}
...
@@ -341,7 +344,7 @@ import com.google.android.exoplayer2.util.ParsableByteArray;
...
@@ -341,7 +344,7 @@ import com.google.android.exoplayer2.util.ParsableByteArray;
if
(
atomType
==
Atom
.
TYPE_data
)
{
if
(
atomType
==
Atom
.
TYPE_data
)
{
int
fullVersionInt
=
data
.
readInt
();
int
fullVersionInt
=
data
.
readInt
();
int
flags
=
Atom
.
parseFullAtomFlags
(
fullVersionInt
);
int
flags
=
Atom
.
parseFullAtomFlags
(
fullVersionInt
);
String
mimeType
=
flags
==
13
?
"image/jpeg"
:
flags
==
14
?
"image/png"
:
null
;
@Nullable
String
mimeType
=
flags
==
13
?
"image/jpeg"
:
flags
==
14
?
"image/png"
:
null
;
if
(
mimeType
==
null
)
{
if
(
mimeType
==
null
)
{
Log
.
w
(
TAG
,
"Unrecognized cover art flags: "
+
flags
);
Log
.
w
(
TAG
,
"Unrecognized cover art flags: "
+
flags
);
return
null
;
return
null
;
...
@@ -361,8 +364,8 @@ import com.google.android.exoplayer2.util.ParsableByteArray;
...
@@ -361,8 +364,8 @@ import com.google.android.exoplayer2.util.ParsableByteArray;
@Nullable
@Nullable
private
static
Id3Frame
parseInternalAttribute
(
ParsableByteArray
data
,
int
endPosition
)
{
private
static
Id3Frame
parseInternalAttribute
(
ParsableByteArray
data
,
int
endPosition
)
{
String
domain
=
null
;
@Nullable
String
domain
=
null
;
String
name
=
null
;
@Nullable
String
name
=
null
;
int
dataAtomPosition
=
-
1
;
int
dataAtomPosition
=
-
1
;
int
dataAtomSize
=
-
1
;
int
dataAtomSize
=
-
1
;
while
(
data
.
getPosition
()
<
endPosition
)
{
while
(
data
.
getPosition
()
<
endPosition
)
{
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/Mp4Extractor.java
View file @
821d4fb1
...
@@ -16,6 +16,7 @@
...
@@ -16,6 +16,7 @@
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
mp4
;
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
mp4
;
import
androidx.annotation.IntDef
;
import
androidx.annotation.IntDef
;
import
androidx.annotation.Nullable
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.ParserException
;
import
com.google.android.exoplayer2.ParserException
;
...
@@ -42,6 +43,7 @@ import java.lang.annotation.RetentionPolicy;
...
@@ -42,6 +43,7 @@ import java.lang.annotation.RetentionPolicy;
import
java.util.ArrayDeque
;
import
java.util.ArrayDeque
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.List
;
import
org.checkerframework.checker.nullness.qual.MonotonicNonNull
;
/**
/**
* Extracts data from the MP4 container format.
* Extracts data from the MP4 container format.
...
@@ -105,7 +107,7 @@ public final class Mp4Extractor implements Extractor, SeekMap {
...
@@ -105,7 +107,7 @@ public final class Mp4Extractor implements Extractor, SeekMap {
private
int
atomType
;
private
int
atomType
;
private
long
atomSize
;
private
long
atomSize
;
private
int
atomHeaderBytesRead
;
private
int
atomHeaderBytesRead
;
private
ParsableByteArray
atomData
;
@Nullable
private
ParsableByteArray
atomData
;
private
int
sampleTrackIndex
;
private
int
sampleTrackIndex
;
private
int
sampleBytesWritten
;
private
int
sampleBytesWritten
;
...
@@ -113,7 +115,7 @@ public final class Mp4Extractor implements Extractor, SeekMap {
...
@@ -113,7 +115,7 @@ public final class Mp4Extractor implements Extractor, SeekMap {
private
boolean
isAc4HeaderRequired
;
private
boolean
isAc4HeaderRequired
;
// Extractor outputs.
// Extractor outputs.
private
ExtractorOutput
extractorOutput
;
@MonotonicNonNull
private
ExtractorOutput
extractorOutput
;
private
Mp4Track
[]
tracks
;
private
Mp4Track
[]
tracks
;
private
long
[][]
accumulatedSampleSizes
;
private
long
[][]
accumulatedSampleSizes
;
private
int
firstVideoTrackIndex
;
private
int
firstVideoTrackIndex
;
...
@@ -290,8 +292,11 @@ public final class Mp4Extractor implements Extractor, SeekMap {
...
@@ -290,8 +292,11 @@ public final class Mp4Extractor implements Extractor, SeekMap {
// The atom extends to the end of the file. Note that if the atom is within a container we can
// The atom extends to the end of the file. Note that if the atom is within a container we can
// work out its size even if the input length is unknown.
// work out its size even if the input length is unknown.
long
endPosition
=
input
.
getLength
();
long
endPosition
=
input
.
getLength
();
if
(
endPosition
==
C
.
LENGTH_UNSET
&&
!
containerAtoms
.
isEmpty
())
{
if
(
endPosition
==
C
.
LENGTH_UNSET
)
{
endPosition
=
containerAtoms
.
peek
().
endPosition
;
@Nullable
ContainerAtom
containerAtom
=
containerAtoms
.
peek
();
if
(
containerAtom
!=
null
)
{
endPosition
=
containerAtom
.
endPosition
;
}
}
}
if
(
endPosition
!=
C
.
LENGTH_UNSET
)
{
if
(
endPosition
!=
C
.
LENGTH_UNSET
)
{
atomSize
=
endPosition
-
input
.
getPosition
()
+
atomHeaderBytesRead
;
atomSize
=
endPosition
-
input
.
getPosition
()
+
atomHeaderBytesRead
;
...
@@ -386,17 +391,17 @@ public final class Mp4Extractor implements Extractor, SeekMap {
...
@@ -386,17 +391,17 @@ public final class Mp4Extractor implements Extractor, SeekMap {
List
<
Mp4Track
>
tracks
=
new
ArrayList
<>();
List
<
Mp4Track
>
tracks
=
new
ArrayList
<>();
// Process metadata.
// Process metadata.
Metadata
udtaMetadata
=
null
;
@Nullable
Metadata
udtaMetadata
=
null
;
GaplessInfoHolder
gaplessInfoHolder
=
new
GaplessInfoHolder
();
GaplessInfoHolder
gaplessInfoHolder
=
new
GaplessInfoHolder
();
Atom
.
LeafAtom
udta
=
moov
.
getLeafAtomOfType
(
Atom
.
TYPE_udta
);
@Nullable
Atom
.
LeafAtom
udta
=
moov
.
getLeafAtomOfType
(
Atom
.
TYPE_udta
);
if
(
udta
!=
null
)
{
if
(
udta
!=
null
)
{
udtaMetadata
=
AtomParsers
.
parseUdta
(
udta
,
isQuickTime
);
udtaMetadata
=
AtomParsers
.
parseUdta
(
udta
,
isQuickTime
);
if
(
udtaMetadata
!=
null
)
{
if
(
udtaMetadata
!=
null
)
{
gaplessInfoHolder
.
setFromMetadata
(
udtaMetadata
);
gaplessInfoHolder
.
setFromMetadata
(
udtaMetadata
);
}
}
}
}
Metadata
mdtaMetadata
=
null
;
@Nullable
Metadata
mdtaMetadata
=
null
;
Atom
.
ContainerAtom
meta
=
moov
.
getContainerAtomOfType
(
Atom
.
TYPE_meta
);
@Nullable
Atom
.
ContainerAtom
meta
=
moov
.
getContainerAtomOfType
(
Atom
.
TYPE_meta
);
if
(
meta
!=
null
)
{
if
(
meta
!=
null
)
{
mdtaMetadata
=
AtomParsers
.
parseMdtaFromMeta
(
meta
);
mdtaMetadata
=
AtomParsers
.
parseMdtaFromMeta
(
meta
);
}
}
...
@@ -453,6 +458,7 @@ public final class Mp4Extractor implements Extractor, SeekMap {
...
@@ -453,6 +458,7 @@ public final class Mp4Extractor implements Extractor, SeekMap {
if
(
atom
.
type
!=
Atom
.
TYPE_trak
)
{
if
(
atom
.
type
!=
Atom
.
TYPE_trak
)
{
continue
;
continue
;
}
}
@Nullable
Track
track
=
Track
track
=
AtomParsers
.
parseTrak
(
AtomParsers
.
parseTrak
(
atom
,
atom
,
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/PsshAtomUtil.java
View file @
821d4fb1
...
@@ -49,8 +49,6 @@ public final class PsshAtomUtil {
...
@@ -49,8 +49,6 @@ public final class PsshAtomUtil {
* @param data The scheme specific data.
* @param data The scheme specific data.
* @return The PSSH atom.
* @return The PSSH atom.
*/
*/
// dereference of possibly-null reference keyId
@SuppressWarnings
({
"ParameterNotNullable"
,
"nullness:dereference.of.nullable"
})
public
static
byte
[]
buildPsshAtom
(
public
static
byte
[]
buildPsshAtom
(
UUID
systemId
,
@Nullable
UUID
[]
keyIds
,
@Nullable
byte
[]
data
)
{
UUID
systemId
,
@Nullable
UUID
[]
keyIds
,
@Nullable
byte
[]
data
)
{
int
dataLength
=
data
!=
null
?
data
.
length
:
0
;
int
dataLength
=
data
!=
null
?
data
.
length
:
0
;
...
@@ -97,8 +95,9 @@ public final class PsshAtomUtil {
...
@@ -97,8 +95,9 @@ public final class PsshAtomUtil {
* @return The parsed UUID. Null if the input is not a valid PSSH atom, or if the PSSH atom has an
* @return The parsed UUID. Null if the input is not a valid PSSH atom, or if the PSSH atom has an
* unsupported version.
* unsupported version.
*/
*/
public
static
@Nullable
UUID
parseUuid
(
byte
[]
atom
)
{
@Nullable
PsshAtom
parsedAtom
=
parsePsshAtom
(
atom
);
public
static
UUID
parseUuid
(
byte
[]
atom
)
{
@Nullable
PsshAtom
parsedAtom
=
parsePsshAtom
(
atom
);
if
(
parsedAtom
==
null
)
{
if
(
parsedAtom
==
null
)
{
return
null
;
return
null
;
}
}
...
@@ -115,7 +114,7 @@ public final class PsshAtomUtil {
...
@@ -115,7 +114,7 @@ public final class PsshAtomUtil {
* an unsupported version.
* an unsupported version.
*/
*/
public
static
int
parseVersion
(
byte
[]
atom
)
{
public
static
int
parseVersion
(
byte
[]
atom
)
{
PsshAtom
parsedAtom
=
parsePsshAtom
(
atom
);
@Nullable
PsshAtom
parsedAtom
=
parsePsshAtom
(
atom
);
if
(
parsedAtom
==
null
)
{
if
(
parsedAtom
==
null
)
{
return
-
1
;
return
-
1
;
}
}
...
@@ -133,8 +132,9 @@ public final class PsshAtomUtil {
...
@@ -133,8 +132,9 @@ public final class PsshAtomUtil {
* @return The parsed scheme specific data. Null if the input is not a valid PSSH atom, or if the
* @return The parsed scheme specific data. Null if the input is not a valid PSSH atom, or if the
* PSSH atom has an unsupported version, or if the PSSH atom does not match the passed UUID.
* PSSH atom has an unsupported version, or if the PSSH atom does not match the passed UUID.
*/
*/
public
static
@Nullable
byte
[]
parseSchemeSpecificData
(
byte
[]
atom
,
UUID
uuid
)
{
@Nullable
PsshAtom
parsedAtom
=
parsePsshAtom
(
atom
);
public
static
byte
[]
parseSchemeSpecificData
(
byte
[]
atom
,
UUID
uuid
)
{
@Nullable
PsshAtom
parsedAtom
=
parsePsshAtom
(
atom
);
if
(
parsedAtom
==
null
)
{
if
(
parsedAtom
==
null
)
{
return
null
;
return
null
;
}
}
...
@@ -153,7 +153,8 @@ public final class PsshAtomUtil {
...
@@ -153,7 +153,8 @@ public final class PsshAtomUtil {
* has an unsupported version.
* has an unsupported version.
*/
*/
// TODO: Support parsing of the key ids for version 1 PSSH atoms.
// TODO: Support parsing of the key ids for version 1 PSSH atoms.
private
static
@Nullable
PsshAtom
parsePsshAtom
(
byte
[]
atom
)
{
@Nullable
private
static
PsshAtom
parsePsshAtom
(
byte
[]
atom
)
{
ParsableByteArray
atomData
=
new
ParsableByteArray
(
atom
);
ParsableByteArray
atomData
=
new
ParsableByteArray
(
atom
);
if
(
atomData
.
limit
()
<
Atom
.
FULL_HEADER_SIZE
+
16
/* UUID */
+
4
/* DataSize */
)
{
if
(
atomData
.
limit
()
<
Atom
.
FULL_HEADER_SIZE
+
16
/* UUID */
+
4
/* DataSize */
)
{
// Data too short.
// Data too short.
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/TrackFragment.java
View file @
821d4fb1
...
@@ -15,19 +15,19 @@
...
@@ -15,19 +15,19 @@
*/
*/
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
mp4
;
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
mp4
;
import
androidx.annotation.Nullable
;
import
com.google.android.exoplayer2.extractor.ExtractorInput
;
import
com.google.android.exoplayer2.extractor.ExtractorInput
;
import
com.google.android.exoplayer2.util.ParsableByteArray
;
import
com.google.android.exoplayer2.util.ParsableByteArray
;
import
java.io.IOException
;
import
java.io.IOException
;
import
org.checkerframework.checker.nullness.qual.MonotonicNonNull
;
/**
/**
* A holder for information corresponding to a single fragment of an mp4 file.
* A holder for information corresponding to a single fragment of an mp4 file.
*/
*/
/* package */
final
class
TrackFragment
{
/* package */
final
class
TrackFragment
{
/**
/** The default values for samples from the track fragment header. */
* The default values for samples from the track fragment header.
@MonotonicNonNull
public
DefaultSampleValues
header
;
*/
public
DefaultSampleValues
header
;
/**
/**
* The position (byte offset) of the start of fragment.
* The position (byte offset) of the start of fragment.
*/
*/
...
@@ -81,20 +81,13 @@ import java.io.IOException;
...
@@ -81,20 +81,13 @@ import java.io.IOException;
* Undefined otherwise.
* Undefined otherwise.
*/
*/
public
boolean
[]
sampleHasSubsampleEncryptionTable
;
public
boolean
[]
sampleHasSubsampleEncryptionTable
;
/**
/** Fragment specific track encryption. May be null. */
* Fragment specific track encryption. May be null.
@Nullable
public
TrackEncryptionBox
trackEncryptionBox
;
*/
public
TrackEncryptionBox
trackEncryptionBox
;
/**
* If {@link #definesEncryptionData} is true, indicates the length of the sample encryption data.
* Undefined otherwise.
*/
public
int
sampleEncryptionDataLength
;
/**
/**
* If {@link #definesEncryptionData} is true, contains binary sample encryption data. Undefined
* If {@link #definesEncryptionData} is true, contains binary sample encryption data. Undefined
* otherwise.
* otherwise.
*/
*/
public
ParsableByteArray
sampleEncryptionData
;
public
final
ParsableByteArray
sampleEncryptionData
;
/**
/**
* Whether {@link #sampleEncryptionData} needs populating with the actual encryption data.
* Whether {@link #sampleEncryptionData} needs populating with the actual encryption data.
*/
*/
...
@@ -104,6 +97,17 @@ import java.io.IOException;
...
@@ -104,6 +97,17 @@ import java.io.IOException;
*/
*/
public
long
nextFragmentDecodeTime
;
public
long
nextFragmentDecodeTime
;
public
TrackFragment
()
{
trunDataPosition
=
new
long
[
0
];
trunLength
=
new
int
[
0
];
sampleSizeTable
=
new
int
[
0
];
sampleCompositionTimeOffsetTable
=
new
int
[
0
];
sampleDecodingTimeTable
=
new
long
[
0
];
sampleIsSyncFrameTable
=
new
boolean
[
0
];
sampleHasSubsampleEncryptionTable
=
new
boolean
[
0
];
sampleEncryptionData
=
new
ParsableByteArray
();
}
/**
/**
* Resets the fragment.
* Resets the fragment.
* <p>
* <p>
...
@@ -130,11 +134,11 @@ import java.io.IOException;
...
@@ -130,11 +134,11 @@ import java.io.IOException;
public
void
initTables
(
int
trunCount
,
int
sampleCount
)
{
public
void
initTables
(
int
trunCount
,
int
sampleCount
)
{
this
.
trunCount
=
trunCount
;
this
.
trunCount
=
trunCount
;
this
.
sampleCount
=
sampleCount
;
this
.
sampleCount
=
sampleCount
;
if
(
trunLength
==
null
||
trunLength
.
length
<
trunCount
)
{
if
(
trunLength
.
length
<
trunCount
)
{
trunDataPosition
=
new
long
[
trunCount
];
trunDataPosition
=
new
long
[
trunCount
];
trunLength
=
new
int
[
trunCount
];
trunLength
=
new
int
[
trunCount
];
}
}
if
(
sampleSizeTable
==
null
||
sampleSizeTable
.
length
<
sampleCount
)
{
if
(
sampleSizeTable
.
length
<
sampleCount
)
{
// Size the tables 25% larger than needed, so as to make future resize operations less
// Size the tables 25% larger than needed, so as to make future resize operations less
// likely. The choice of 25% is relatively arbitrary.
// likely. The choice of 25% is relatively arbitrary.
int
tableSize
=
(
sampleCount
*
125
)
/
100
;
int
tableSize
=
(
sampleCount
*
125
)
/
100
;
...
@@ -148,18 +152,14 @@ import java.io.IOException;
...
@@ -148,18 +152,14 @@ import java.io.IOException;
/**
/**
* Configures the fragment to be one that defines encryption data of the specified length.
* Configures the fragment to be one that defines encryption data of the specified length.
* <p>
*
* {@link #definesEncryptionData} is set to true, {@link #sampleEncryptionDataLength} is set to
* <p>{@link #definesEncryptionData} is set to true, and the {@link ParsableByteArray#limit()
* the specified length, and {@link #sampleEncryptionData} is resized if necessary such that it
* limit} of {@link #sampleEncryptionData} is set to the specified length.
* is at least this length.
*
*
* @param length The length in bytes of the encryption data.
* @param length The length in bytes of the encryption data.
*/
*/
public
void
initEncryptionData
(
int
length
)
{
public
void
initEncryptionData
(
int
length
)
{
if
(
sampleEncryptionData
==
null
||
sampleEncryptionData
.
limit
()
<
length
)
{
sampleEncryptionData
.
reset
(
length
);
sampleEncryptionData
=
new
ParsableByteArray
(
length
);
}
sampleEncryptionDataLength
=
length
;
definesEncryptionData
=
true
;
definesEncryptionData
=
true
;
sampleEncryptionDataNeedsFill
=
true
;
sampleEncryptionDataNeedsFill
=
true
;
}
}
...
@@ -170,7 +170,7 @@ import java.io.IOException;
...
@@ -170,7 +170,7 @@ import java.io.IOException;
* @param input An {@link ExtractorInput} from which to read the encryption data.
* @param input An {@link ExtractorInput} from which to read the encryption data.
*/
*/
public
void
fillEncryptionData
(
ExtractorInput
input
)
throws
IOException
,
InterruptedException
{
public
void
fillEncryptionData
(
ExtractorInput
input
)
throws
IOException
,
InterruptedException
{
input
.
readFully
(
sampleEncryptionData
.
data
,
0
,
sampleEncryptionData
Length
);
input
.
readFully
(
sampleEncryptionData
.
data
,
0
,
sampleEncryptionData
.
limit
()
);
sampleEncryptionData
.
setPosition
(
0
);
sampleEncryptionData
.
setPosition
(
0
);
sampleEncryptionDataNeedsFill
=
false
;
sampleEncryptionDataNeedsFill
=
false
;
}
}
...
@@ -181,7 +181,7 @@ import java.io.IOException;
...
@@ -181,7 +181,7 @@ import java.io.IOException;
* @param source A source from which to read the encryption data.
* @param source A source from which to read the encryption data.
*/
*/
public
void
fillEncryptionData
(
ParsableByteArray
source
)
{
public
void
fillEncryptionData
(
ParsableByteArray
source
)
{
source
.
readBytes
(
sampleEncryptionData
.
data
,
0
,
sampleEncryptionData
Length
);
source
.
readBytes
(
sampleEncryptionData
.
data
,
0
,
sampleEncryptionData
.
limit
()
);
sampleEncryptionData
.
setPosition
(
0
);
sampleEncryptionData
.
setPosition
(
0
);
sampleEncryptionDataNeedsFill
=
false
;
sampleEncryptionDataNeedsFill
=
false
;
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/package-info.java
0 → 100644
View file @
821d4fb1
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@NonNullApi
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
mp4
;
import
com.google.android.exoplayer2.util.NonNullApi
;
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