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
04e60614
authored
Feb 13, 2019
by
aquilescanta
Committed by
Andrew Lewis
Feb 18, 2019
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Reduce the number of parameters required to create an HlsMediaChunk
PiperOrigin-RevId: 233765839
parent
cc153cfc
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
141 additions
and
86 deletions
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java
View file @
04e60614
...
...
@@ -290,8 +290,8 @@ import java.util.List;
}
}
int
chunkIndex
=
(
int
)
(
chunkMediaSequence
-
mediaPlaylist
.
mediaSequence
);
if
(
chunkIndex
>=
mediaPlaylist
.
segments
.
size
())
{
int
segmentIndexInPlaylist
=
(
int
)
(
chunkMediaSequence
-
mediaPlaylist
.
mediaSequence
);
if
(
segmentIndexInPlaylist
>=
mediaPlaylist
.
segments
.
size
())
{
if
(
mediaPlaylist
.
hasEndTag
)
{
out
.
endOfStream
=
true
;
}
else
/* Live */
{
...
...
@@ -306,7 +306,7 @@ import java.util.List;
expectedPlaylistUrl
=
null
;
// Handle encryption.
HlsMediaPlaylist
.
Segment
segment
=
mediaPlaylist
.
segments
.
get
(
chunkIndex
);
HlsMediaPlaylist
.
Segment
segment
=
mediaPlaylist
.
segments
.
get
(
segmentIndexInPlaylist
);
// Check if the segment is completely encrypted using the identity key format.
if
(
segment
.
fullSegmentEncryptionKeyUri
!=
null
)
{
...
...
@@ -324,44 +324,20 @@ import java.util.List;
clearEncryptionData
();
}
DataSpec
initDataSpec
=
null
;
Segment
initSegment
=
segment
.
initializationSegment
;
if
(
initSegment
!=
null
)
{
Uri
initSegmentUri
=
UriUtil
.
resolveToUri
(
mediaPlaylist
.
baseUri
,
initSegment
.
url
);
initDataSpec
=
new
DataSpec
(
initSegmentUri
,
initSegment
.
byterangeOffset
,
initSegment
.
byterangeLength
,
null
);
}
// Compute start time of the next chunk.
long
segmentStartTimeInPeriodUs
=
startOfPlaylistInPeriodUs
+
segment
.
relativeStartTimeUs
;
int
discontinuitySequence
=
mediaPlaylist
.
discontinuitySequence
+
segment
.
relativeDiscontinuitySequence
;
TimestampAdjuster
timestampAdjuster
=
timestampAdjusterProvider
.
getAdjuster
(
discontinuitySequence
);
// Configure the data source and spec for the chunk.
Uri
chunkUri
=
UriUtil
.
resolveToUri
(
mediaPlaylist
.
baseUri
,
segment
.
url
);
DataSpec
dataSpec
=
new
DataSpec
(
chunkUri
,
segment
.
byterangeOffset
,
segment
.
byterangeLength
,
null
);
out
.
chunk
=
new
HlsMediaChunk
(
HlsMediaChunk
.
createInstance
(
extractorFactory
,
mediaDataSource
,
dataSpec
,
initDataSpec
,
startOfPlaylistInPeriodUs
,
mediaPlaylist
,
segmentIndexInPlaylist
,
selectedUrl
,
muxedCaptionFormats
,
trackSelection
.
getSelectionReason
(),
trackSelection
.
getSelectionData
(),
segmentStartTimeInPeriodUs
,
segmentStartTimeInPeriodUs
+
segment
.
durationUs
,
chunkMediaSequence
,
discontinuitySequence
,
segment
.
hasGapTag
,
isTimestampMaster
,
timestampAdjuster
,
timestampAdjuster
Provider
,
previous
,
segment
.
drmInitData
,
encryptionKey
,
encryptionIv
);
}
...
...
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java
View file @
04e60614
...
...
@@ -15,6 +15,7 @@
*/
package
com
.
google
.
android
.
exoplayer2
.
source
.
hls
;
import
android.net.Uri
;
import
android.util.Pair
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.Format
;
...
...
@@ -27,10 +28,12 @@ import com.google.android.exoplayer2.metadata.id3.Id3Decoder;
import
com.google.android.exoplayer2.metadata.id3.PrivFrame
;
import
com.google.android.exoplayer2.source.chunk.MediaChunk
;
import
com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist.HlsUrl
;
import
com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist
;
import
com.google.android.exoplayer2.upstream.DataSource
;
import
com.google.android.exoplayer2.upstream.DataSpec
;
import
com.google.android.exoplayer2.util.ParsableByteArray
;
import
com.google.android.exoplayer2.util.TimestampAdjuster
;
import
com.google.android.exoplayer2.util.UriUtil
;
import
com.google.android.exoplayer2.util.Util
;
import
java.io.EOFException
;
import
java.io.IOException
;
...
...
@@ -42,6 +45,112 @@ import java.util.concurrent.atomic.AtomicInteger;
*/
/* package */
final
class
HlsMediaChunk
extends
MediaChunk
{
/**
* Creates a new instance.
*
* @param extractorFactory A {@link HlsExtractorFactory} from which the HLS media chunk extractor
* is obtained.
* @param dataSource The source from which the data should be loaded.
* @param startOfPlaylistInPeriodUs The position of the playlist in the period in microseconds.
* @param mediaPlaylist The media playlist from which this chunk was obtained.
* @param hlsUrl The url of the playlist from which this chunk was obtained.
* @param muxedCaptionFormats List of muxed caption {@link Format}s. Null if no closed caption
* information is available in the master playlist.
* @param trackSelectionReason See {@link #trackSelectionReason}.
* @param trackSelectionData See {@link #trackSelectionData}.
* @param isMasterTimestampSource True if the chunk can initialize the timestamp adjuster.
* @param timestampAdjusterProvider The provider from which to obtain the {@link
* TimestampAdjuster}.
* @param previousChunk The {@link HlsMediaChunk} that preceded this one. May be null.
* @param fullSegmentEncryptionKey The key to decrypt the full segment, or null if the segment is
* not fully encrypted.
* @param encryptionIv The AES initialization vector, or null if the segment is not fully
* encrypted.
*/
public
static
HlsMediaChunk
createInstance
(
HlsExtractorFactory
extractorFactory
,
DataSource
dataSource
,
long
startOfPlaylistInPeriodUs
,
HlsMediaPlaylist
mediaPlaylist
,
int
segmentIndexInPlaylist
,
HlsUrl
hlsUrl
,
List
<
Format
>
muxedCaptionFormats
,
int
trackSelectionReason
,
Object
trackSelectionData
,
boolean
isMasterTimestampSource
,
TimestampAdjusterProvider
timestampAdjusterProvider
,
HlsMediaChunk
previousChunk
,
byte
[]
fullSegmentEncryptionKey
,
byte
[]
encryptionIv
)
{
HlsMediaPlaylist
.
Segment
segment
=
mediaPlaylist
.
segments
.
get
(
segmentIndexInPlaylist
);
DataSpec
dataSpec
=
new
DataSpec
(
UriUtil
.
resolveToUri
(
mediaPlaylist
.
baseUri
,
segment
.
url
),
segment
.
byterangeOffset
,
segment
.
byterangeLength
,
/* key= */
null
);
DataSpec
initDataSpec
=
null
;
HlsMediaPlaylist
.
Segment
initSegment
=
segment
.
initializationSegment
;
if
(
initSegment
!=
null
)
{
Uri
initSegmentUri
=
UriUtil
.
resolveToUri
(
mediaPlaylist
.
baseUri
,
initSegment
.
url
);
initDataSpec
=
new
DataSpec
(
initSegmentUri
,
initSegment
.
byterangeOffset
,
initSegment
.
byterangeLength
,
/* key= */
null
);
}
long
segmentStartTimeInPeriodUs
=
startOfPlaylistInPeriodUs
+
segment
.
relativeStartTimeUs
;
long
segmentEndTimeInPeriodUs
=
segmentStartTimeInPeriodUs
+
segment
.
durationUs
;
int
discontinuitySequenceNumber
=
mediaPlaylist
.
discontinuitySequence
+
segment
.
relativeDiscontinuitySequence
;
Extractor
previousExtractor
=
null
;
Id3Decoder
id3Decoder
;
ParsableByteArray
scratchId3Data
;
boolean
shouldSpliceIn
;
if
(
previousChunk
!=
null
)
{
id3Decoder
=
previousChunk
.
id3Decoder
;
scratchId3Data
=
previousChunk
.
scratchId3Data
;
shouldSpliceIn
=
previousChunk
.
hlsUrl
!=
hlsUrl
||
!
previousChunk
.
loadCompleted
;
previousExtractor
=
previousChunk
.
discontinuitySequenceNumber
!=
discontinuitySequenceNumber
||
shouldSpliceIn
?
null
:
previousChunk
.
extractor
;
}
else
{
id3Decoder
=
new
Id3Decoder
();
scratchId3Data
=
new
ParsableByteArray
(
Id3Decoder
.
ID3_HEADER_LENGTH
);
shouldSpliceIn
=
false
;
}
return
new
HlsMediaChunk
(
extractorFactory
,
dataSource
,
dataSpec
,
initDataSpec
,
hlsUrl
,
muxedCaptionFormats
,
trackSelectionReason
,
trackSelectionData
,
segmentStartTimeInPeriodUs
,
segmentEndTimeInPeriodUs
,
/* chunkMediaSequence= */
mediaPlaylist
.
mediaSequence
+
segmentIndexInPlaylist
,
discontinuitySequenceNumber
,
segment
.
hasGapTag
,
isMasterTimestampSource
,
/* timestampAdjuster= */
timestampAdjusterProvider
.
getAdjuster
(
discontinuitySequenceNumber
),
segment
.
drmInitData
,
previousExtractor
,
id3Decoder
,
scratchId3Data
,
shouldSpliceIn
,
fullSegmentEncryptionKey
,
encryptionIv
);
}
public
static
final
String
PRIV_TIMESTAMP_FRAME_OWNER
=
"com.apple.streaming.transportStreamTimestamp"
;
...
...
@@ -74,7 +183,7 @@ import java.util.concurrent.atomic.AtomicInteger;
private
final
DrmInitData
drmInitData
;
private
final
Extractor
previousExtractor
;
private
final
Id3Decoder
id3Decoder
;
private
final
ParsableByteArray
i
d3Data
;
private
final
ParsableByteArray
scratchI
d3Data
;
private
Extractor
extractor
;
private
HlsSampleStreamWrapper
output
;
...
...
@@ -84,32 +193,7 @@ import java.util.concurrent.atomic.AtomicInteger;
private
volatile
boolean
loadCanceled
;
private
boolean
loadCompleted
;
/**
* @param extractorFactory A {@link HlsExtractorFactory} from which the HLS media chunk extractor
* is obtained.
* @param dataSource The source from which the data should be loaded.
* @param dataSpec Defines the data to be loaded.
* @param initDataSpec Defines the initialization data to be fed to new extractors. May be null.
* @param hlsUrl The url of the playlist from which this chunk was obtained.
* @param muxedCaptionFormats List of muxed caption {@link Format}s. Null if no closed caption
* information is available in the master playlist.
* @param trackSelectionReason See {@link #trackSelectionReason}.
* @param trackSelectionData See {@link #trackSelectionData}.
* @param startTimeUs The start time of the chunk in microseconds.
* @param endTimeUs The end time of the chunk in microseconds.
* @param chunkMediaSequence The media sequence number of the chunk.
* @param discontinuitySequenceNumber The discontinuity sequence number of the chunk.
* @param hasGapTag Whether the chunk is tagged with EXT-X-GAP.
* @param isMasterTimestampSource True if the chunk can initialize the timestamp adjuster.
* @param timestampAdjuster Adjuster corresponding to the provided discontinuity sequence number.
* @param previousChunk The {@link HlsMediaChunk} that preceded this one. May be null.
* @param drmInitData A {@link DrmInitData} to sideload to the extractor.
* @param fullSegmentEncryptionKey The key to decrypt the full segment, or null if the segment is
* not fully encrypted.
* @param encryptionIv The AES initialization vector, or null if the segment is not fully
* encrypted.
*/
public
HlsMediaChunk
(
private
HlsMediaChunk
(
HlsExtractorFactory
extractorFactory
,
DataSource
dataSource
,
DataSpec
dataSpec
,
...
...
@@ -125,8 +209,11 @@ import java.util.concurrent.atomic.AtomicInteger;
boolean
hasGapTag
,
boolean
isMasterTimestampSource
,
TimestampAdjuster
timestampAdjuster
,
HlsMediaChunk
previousChunk
,
DrmInitData
drmInitData
,
Extractor
previousExtractor
,
Id3Decoder
id3Decoder
,
ParsableByteArray
scratchId3Data
,
boolean
shouldSpliceIn
,
byte
[]
fullSegmentEncryptionKey
,
byte
[]
encryptionIv
)
{
super
(
...
...
@@ -148,19 +235,10 @@ import java.util.concurrent.atomic.AtomicInteger;
this
.
extractorFactory
=
extractorFactory
;
this
.
muxedCaptionFormats
=
muxedCaptionFormats
;
this
.
drmInitData
=
drmInitData
;
Extractor
previousExtractor
=
null
;
if
(
previousChunk
!=
null
)
{
id3Decoder
=
previousChunk
.
id3Decoder
;
id3Data
=
previousChunk
.
id3Data
;
shouldSpliceIn
=
previousChunk
.
hlsUrl
!=
hlsUrl
||
!
previousChunk
.
loadCompleted
;
previousExtractor
=
previousChunk
.
discontinuitySequenceNumber
!=
discontinuitySequenceNumber
||
shouldSpliceIn
?
null
:
previousChunk
.
extractor
;
}
else
{
id3Decoder
=
new
Id3Decoder
();
id3Data
=
new
ParsableByteArray
(
Id3Decoder
.
ID3_HEADER_LENGTH
);
shouldSpliceIn
=
false
;
}
this
.
previousExtractor
=
previousExtractor
;
this
.
id3Decoder
=
id3Decoder
;
this
.
scratchId3Data
=
scratchId3Data
;
this
.
shouldSpliceIn
=
shouldSpliceIn
;
initDataSource
=
dataSource
;
uid
=
uidSource
.
getAndIncrement
();
}
...
...
@@ -314,26 +392,26 @@ import java.util.concurrent.atomic.AtomicInteger;
private
long
peekId3PrivTimestamp
(
ExtractorInput
input
)
throws
IOException
,
InterruptedException
{
input
.
resetPeekPosition
();
try
{
input
.
peekFully
(
i
d3Data
.
data
,
0
,
Id3Decoder
.
ID3_HEADER_LENGTH
);
input
.
peekFully
(
scratchI
d3Data
.
data
,
0
,
Id3Decoder
.
ID3_HEADER_LENGTH
);
}
catch
(
EOFException
e
)
{
// The input isn't long enough for there to be any ID3 data.
return
C
.
TIME_UNSET
;
}
i
d3Data
.
reset
(
Id3Decoder
.
ID3_HEADER_LENGTH
);
int
id
=
i
d3Data
.
readUnsignedInt24
();
scratchI
d3Data
.
reset
(
Id3Decoder
.
ID3_HEADER_LENGTH
);
int
id
=
scratchI
d3Data
.
readUnsignedInt24
();
if
(
id
!=
Id3Decoder
.
ID3_TAG
)
{
return
C
.
TIME_UNSET
;
}
i
d3Data
.
skipBytes
(
3
);
// version(2), flags(1).
int
id3Size
=
i
d3Data
.
readSynchSafeInt
();
scratchI
d3Data
.
skipBytes
(
3
);
// version(2), flags(1).
int
id3Size
=
scratchI
d3Data
.
readSynchSafeInt
();
int
requiredCapacity
=
id3Size
+
Id3Decoder
.
ID3_HEADER_LENGTH
;
if
(
requiredCapacity
>
i
d3Data
.
capacity
())
{
byte
[]
data
=
i
d3Data
.
data
;
i
d3Data
.
reset
(
requiredCapacity
);
System
.
arraycopy
(
data
,
0
,
i
d3Data
.
data
,
0
,
Id3Decoder
.
ID3_HEADER_LENGTH
);
if
(
requiredCapacity
>
scratchI
d3Data
.
capacity
())
{
byte
[]
data
=
scratchI
d3Data
.
data
;
scratchI
d3Data
.
reset
(
requiredCapacity
);
System
.
arraycopy
(
data
,
0
,
scratchI
d3Data
.
data
,
0
,
Id3Decoder
.
ID3_HEADER_LENGTH
);
}
input
.
peekFully
(
i
d3Data
.
data
,
Id3Decoder
.
ID3_HEADER_LENGTH
,
id3Size
);
Metadata
metadata
=
id3Decoder
.
decode
(
i
d3Data
.
data
,
id3Size
);
input
.
peekFully
(
scratchI
d3Data
.
data
,
Id3Decoder
.
ID3_HEADER_LENGTH
,
id3Size
);
Metadata
metadata
=
id3Decoder
.
decode
(
scratchI
d3Data
.
data
,
id3Size
);
if
(
metadata
==
null
)
{
return
C
.
TIME_UNSET
;
}
...
...
@@ -343,11 +421,12 @@ import java.util.concurrent.atomic.AtomicInteger;
if
(
frame
instanceof
PrivFrame
)
{
PrivFrame
privFrame
=
(
PrivFrame
)
frame
;
if
(
PRIV_TIMESTAMP_FRAME_OWNER
.
equals
(
privFrame
.
owner
))
{
System
.
arraycopy
(
privFrame
.
privateData
,
0
,
id3Data
.
data
,
0
,
8
/* timestamp size */
);
id3Data
.
reset
(
8
);
System
.
arraycopy
(
privFrame
.
privateData
,
0
,
scratchId3Data
.
data
,
0
,
8
/* timestamp size */
);
scratchId3Data
.
reset
(
8
);
// The top 31 bits should be zeros, but explicitly zero them to wrap in the case that the
// streaming provider forgot. See: https://github.com/google/ExoPlayer/pull/3495.
return
i
d3Data
.
readLong
()
&
0x1FFFFFFFF
L
;
return
scratchI
d3Data
.
readLong
()
&
0x1FFFFFFFF
L
;
}
}
}
...
...
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