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
0005f41f
authored
Nov 13, 2014
by
ojw28
Browse files
Options
_('Browse Files')
Download
Plain Diff
Merge pull request #138 from google/dev
dev -> dev-hls
parents
7b5c4d70
cb068459
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
241 additions
and
62 deletions
demo/src/main/java/com/google/android/exoplayer/demo/full/player/DashVodRendererBuilder.java
demo/src/main/java/com/google/android/exoplayer/demo/full/player/DefaultRendererBuilder.java
demo/src/main/java/com/google/android/exoplayer/demo/full/player/SmoothStreamingRendererBuilder.java
library/src/main/java/com/google/android/exoplayer/MediaCodecAudioTrackRenderer.java
library/src/main/java/com/google/android/exoplayer/MediaCodecTrackRenderer.java
library/src/main/java/com/google/android/exoplayer/MediaCodecUtil.java
library/src/main/java/com/google/android/exoplayer/MediaCodecVideoTrackRenderer.java
library/src/main/java/com/google/android/exoplayer/MediaFormat.java
library/src/main/java/com/google/android/exoplayer/parser/mp4/Atom.java
library/src/main/java/com/google/android/exoplayer/parser/mp4/FragmentedMp4Extractor.java
library/src/main/java/com/google/android/exoplayer/text/CaptionStyleCompat.java
library/src/main/java/com/google/android/exoplayer/util/ManifestFetcher.java
demo/src/main/java/com/google/android/exoplayer/demo/full/player/DashVodRendererBuilder.java
View file @
0005f41f
...
...
@@ -175,13 +175,13 @@ public class DashVodRendererBuilder implements RendererBuilder,
VIDEO_BUFFER_SEGMENTS
*
BUFFER_SEGMENT_SIZE
,
true
,
mainHandler
,
player
,
DemoPlayer
.
TYPE_VIDEO
);
MediaCodecVideoTrackRenderer
videoRenderer
=
new
MediaCodecVideoTrackRenderer
(
videoSampleSource
,
drmSessionManager
,
true
,
MediaCodec
.
VIDEO_SCALING_MODE_SCALE_TO_FIT
,
5000
,
drmSessionManager
,
true
,
MediaCodec
.
VIDEO_SCALING_MODE_SCALE_TO_FIT
,
5000
,
null
,
mainHandler
,
player
,
50
);
// Build the audio renderer.
final
String
[]
audioTrackNames
;
final
MultiTrackChunkSource
audioChunkSource
;
final
MediaCodecAudio
TrackRenderer
audioRenderer
;
final
TrackRenderer
audioRenderer
;
if
(
audioRepresentationsList
.
isEmpty
())
{
audioTrackNames
=
null
;
audioChunkSource
=
null
;
...
...
demo/src/main/java/com/google/android/exoplayer/demo/full/player/DefaultRendererBuilder.java
View file @
0005f41f
...
...
@@ -48,8 +48,8 @@ public class DefaultRendererBuilder implements RendererBuilder {
// Build the video and audio renderers.
FrameworkSampleSource
sampleSource
=
new
FrameworkSampleSource
(
context
,
uri
,
null
,
2
);
MediaCodecVideoTrackRenderer
videoRenderer
=
new
MediaCodecVideoTrackRenderer
(
sampleSource
,
null
,
true
,
MediaCodec
.
VIDEO_SCALING_MODE_SCALE_TO_FIT
,
5000
,
player
.
getMainHandler
(),
player
,
50
);
null
,
true
,
MediaCodec
.
VIDEO_SCALING_MODE_SCALE_TO_FIT
,
5000
,
null
,
player
.
getMainHandler
(),
player
,
50
);
MediaCodecAudioTrackRenderer
audioRenderer
=
new
MediaCodecAudioTrackRenderer
(
sampleSource
,
null
,
true
,
player
.
getMainHandler
(),
player
);
...
...
demo/src/main/java/com/google/android/exoplayer/demo/full/player/SmoothStreamingRendererBuilder.java
View file @
0005f41f
...
...
@@ -163,7 +163,7 @@ public class SmoothStreamingRendererBuilder implements RendererBuilder,
VIDEO_BUFFER_SEGMENTS
*
BUFFER_SEGMENT_SIZE
,
true
,
mainHandler
,
player
,
DemoPlayer
.
TYPE_VIDEO
);
MediaCodecVideoTrackRenderer
videoRenderer
=
new
MediaCodecVideoTrackRenderer
(
videoSampleSource
,
drmSessionManager
,
true
,
MediaCodec
.
VIDEO_SCALING_MODE_SCALE_TO_FIT
,
5000
,
drmSessionManager
,
true
,
MediaCodec
.
VIDEO_SCALING_MODE_SCALE_TO_FIT
,
5000
,
null
,
mainHandler
,
player
,
50
);
// Build the audio renderer.
...
...
library/src/main/java/com/google/android/exoplayer/MediaCodecAudioTrackRenderer.java
View file @
0005f41f
...
...
@@ -68,8 +68,8 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer {
public
AudioTrackInitializationException
(
int
audioTrackState
,
int
sampleRate
,
int
channelConfig
,
int
bufferSize
)
{
super
(
"AudioTrack init failed: "
+
audioTrackState
+
", Config("
+
sampleRate
+
", "
+
channelConfig
+
", "
+
bufferSize
+
")"
);
super
(
"AudioTrack init failed: "
+
audioTrackState
+
", Config("
+
sampleRate
+
", "
+
channelConfig
+
", "
+
bufferSize
+
")"
);
this
.
audioTrackState
=
audioTrackState
;
}
...
...
@@ -538,8 +538,8 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer {
// Compute the audio track latency, excluding the latency due to the buffer (leaving
// latency due to the mixer and audio hardware driver).
audioTrackLatencyUs
=
(
Integer
)
audioTrackGetLatencyMethod
.
invoke
(
audioTrack
,
(
Object
[])
null
)
*
1000L
-
framesToDurationUs
(
bufferSize
/
frameSize
);
(
Integer
)
audioTrackGetLatencyMethod
.
invoke
(
audioTrack
,
(
Object
[])
null
)
*
1000L
-
framesToDurationUs
(
bufferSize
/
frameSize
);
// Sanity check that the latency is non-negative.
audioTrackLatencyUs
=
Math
.
max
(
audioTrackLatencyUs
,
0
);
// Sanity check that the latency isn't too large.
...
...
@@ -612,19 +612,19 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer {
if
(
temporaryBufferSize
==
0
)
{
// This is the first time we've seen this {@code buffer}.
// Note: presentationTimeUs corresponds to the end of the sample, not the start.
long
bufferStartTime
=
bufferInfo
.
presentationTimeUs
-
framesToDurationUs
(
bufferInfo
.
size
/
frameSize
);
long
bufferStartTime
=
bufferInfo
.
presentationTimeUs
-
framesToDurationUs
(
bufferInfo
.
size
/
frameSize
);
if
(
audioTrackStartMediaTimeState
==
START_NOT_SET
)
{
audioTrackStartMediaTimeUs
=
Math
.
max
(
0
,
bufferStartTime
);
audioTrackStartMediaTimeState
=
START_IN_SYNC
;
}
else
{
// Sanity check that bufferStartTime is consistent with the expected value.
long
expectedBufferStartTime
=
audioTrackStartMediaTimeUs
+
framesToDurationUs
(
submittedBytes
/
frameSize
);
long
expectedBufferStartTime
=
audioTrackStartMediaTimeUs
+
framesToDurationUs
(
submittedBytes
/
frameSize
);
if
(
audioTrackStartMediaTimeState
==
START_IN_SYNC
&&
Math
.
abs
(
expectedBufferStartTime
-
bufferStartTime
)
>
200000
)
{
Log
.
e
(
TAG
,
"Discontinuity detected [expected "
+
expectedBufferStartTime
+
", got "
+
bufferStartTime
+
"]"
);
Log
.
e
(
TAG
,
"Discontinuity detected [expected "
+
expectedBufferStartTime
+
", got "
+
bufferStartTime
+
"]"
);
audioTrackStartMediaTimeState
=
START_NEED_SYNC
;
}
if
(
audioTrackStartMediaTimeState
==
START_NEED_SYNC
)
{
...
...
@@ -679,7 +679,7 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer {
}
@TargetApi
(
21
)
private
int
writeNonBlockingV21
(
AudioTrack
audioTrack
,
ByteBuffer
buffer
,
int
size
)
{
private
static
int
writeNonBlockingV21
(
AudioTrack
audioTrack
,
ByteBuffer
buffer
,
int
size
)
{
return
audioTrack
.
write
(
buffer
,
size
,
AudioTrack
.
WRITE_NON_BLOCKING
);
}
...
...
@@ -703,8 +703,8 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer {
}
private
int
getPendingFrameCount
()
{
return
audioTrack
==
null
?
0
:
(
int
)
(
submittedBytes
/
frameSize
-
getPlaybackHeadPosition
());
return
audioTrack
==
null
?
0
:
(
int
)
(
submittedBytes
/
frameSize
-
getPlaybackHeadPosition
());
}
@Override
...
...
library/src/main/java/com/google/android/exoplayer/MediaCodecTrackRenderer.java
View file @
0005f41f
...
...
@@ -21,6 +21,7 @@ import com.google.android.exoplayer.util.Util;
import
android.annotation.TargetApi
;
import
android.media.MediaCodec
;
import
android.media.MediaCodec.CodecException
;
import
android.media.MediaCodec.CryptoException
;
import
android.media.MediaCrypto
;
import
android.media.MediaExtractor
;
...
...
@@ -70,10 +71,24 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
*/
public
final
String
decoderName
;
/**
* An optional developer-readable diagnostic information string. May be null.
*/
public
final
String
diagnosticInfo
;
public
DecoderInitializationException
(
String
decoderName
,
MediaFormat
mediaFormat
,
Exception
cause
)
{
Throwable
cause
)
{
super
(
"Decoder init failed: "
+
decoderName
+
", "
+
mediaFormat
,
cause
);
this
.
decoderName
=
decoderName
;
this
.
diagnosticInfo
=
Util
.
SDK_INT
>=
21
?
getDiagnosticInfoV21
(
cause
)
:
null
;
}
@TargetApi
(
21
)
private
static
String
getDiagnosticInfoV21
(
Throwable
cause
)
{
if
(
cause
instanceof
CodecException
)
{
return
((
CodecException
)
cause
).
getDiagnosticInfo
();
}
return
null
;
}
}
...
...
@@ -235,6 +250,7 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
codec
.
configure
(
x
,
null
,
crypto
,
0
);
}
@SuppressWarnings
(
"deprecation"
)
protected
final
void
maybeInitCodec
()
throws
ExoPlaybackException
{
if
(!
shouldInitCodec
())
{
return
;
...
...
@@ -694,6 +710,7 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
* @return True if it may be possible to drain more output data. False otherwise.
* @throws ExoPlaybackException If an error occurs draining the output buffer.
*/
@SuppressWarnings
(
"deprecation"
)
private
boolean
drainOutputBuffer
(
long
positionUs
,
long
elapsedRealtimeUs
)
throws
ExoPlaybackException
{
if
(
outputStreamEnded
)
{
...
...
library/src/main/java/com/google/android/exoplayer/MediaCodecUtil.java
View file @
0005f41f
...
...
@@ -64,7 +64,10 @@ public class MediaCodecUtil {
/**
* Returns the best decoder and its capabilities for the given mimeType. If there's no decoder
* returns null.
*
* TODO: We need to use the new object based MediaCodecList API.
*/
@SuppressWarnings
(
"deprecation"
)
private
static
synchronized
Pair
<
MediaCodecInfo
,
CodecCapabilities
>
getMediaCodecInfo
(
String
mimeType
)
{
Pair
<
MediaCodecInfo
,
CodecCapabilities
>
result
=
codecs
.
get
(
mimeType
);
...
...
library/src/main/java/com/google/android/exoplayer/MediaCodecVideoTrackRenderer.java
View file @
0005f41f
...
...
@@ -75,6 +75,34 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
}
/**
* An interface for fine-grained adjustment of frame release times.
*/
public
interface
FrameReleaseTimeHelper
{
/**
* Enables the helper.
*/
void
enable
();
/**
* Disables the helper.
*/
void
disable
();
/**
* Called to make a fine-grained adjustment to a frame release time.
*
* @param framePresentationTimeUs The frame's media presentation time, in microseconds.
* @param unadjustedReleaseTimeNs The frame's unadjusted release time, in nanoseconds and in
* the same time base as {@link System#nanoTime()}.
* @return An adjusted release time for the frame, in nanoseconds and in the same time base as
* {@link System#nanoTime()}.
*/
public
long
adjustReleaseTime
(
long
framePresentationTimeUs
,
long
unadjustedReleaseTimeNs
);
}
// TODO: Use MediaFormat constants if these get exposed through the API. See [redacted].
private
static
final
String
KEY_CROP_LEFT
=
"crop-left"
;
private
static
final
String
KEY_CROP_RIGHT
=
"crop-right"
;
...
...
@@ -88,6 +116,7 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
*/
public
static
final
int
MSG_SET_SURFACE
=
1
;
private
final
FrameReleaseTimeHelper
frameReleaseTimeHelper
;
private
final
EventListener
eventListener
;
private
final
long
allowedJoiningTimeUs
;
private
final
int
videoScalingMode
;
...
...
@@ -162,7 +191,7 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
public
MediaCodecVideoTrackRenderer
(
SampleSource
source
,
DrmSessionManager
drmSessionManager
,
boolean
playClearSamplesWithoutKeys
,
int
videoScalingMode
,
long
allowedJoiningTimeMs
)
{
this
(
source
,
drmSessionManager
,
playClearSamplesWithoutKeys
,
videoScalingMode
,
allowedJoiningTimeMs
,
null
,
null
,
-
1
);
allowedJoiningTimeMs
,
null
,
null
,
null
,
-
1
);
}
/**
...
...
@@ -180,8 +209,8 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
public
MediaCodecVideoTrackRenderer
(
SampleSource
source
,
int
videoScalingMode
,
long
allowedJoiningTimeMs
,
Handler
eventHandler
,
EventListener
eventListener
,
int
maxDroppedFrameCountToNotify
)
{
this
(
source
,
null
,
true
,
videoScalingMode
,
allowedJoiningTimeMs
,
eventHandler
,
eventListen
er
,
maxDroppedFrameCountToNotify
);
this
(
source
,
null
,
true
,
videoScalingMode
,
allowedJoiningTimeMs
,
null
,
eventHandl
er
,
eventListener
,
maxDroppedFrameCountToNotify
);
}
/**
...
...
@@ -197,6 +226,8 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
* {@link MediaCodec#setVideoScalingMode(int)}.
* @param allowedJoiningTimeMs The maximum duration in milliseconds for which this video renderer
* can attempt to seamlessly join an ongoing playback.
* @param frameReleaseTimeHelper An optional helper to make fine-grained adjustments to frame
* release times. May be null.
* @param eventHandler A handler to use when delivering events to {@code eventListener}. May be
* null if delivery of events is not required.
* @param eventListener A listener of events. May be null if delivery of events is not required.
...
...
@@ -205,10 +236,12 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
*/
public
MediaCodecVideoTrackRenderer
(
SampleSource
source
,
DrmSessionManager
drmSessionManager
,
boolean
playClearSamplesWithoutKeys
,
int
videoScalingMode
,
long
allowedJoiningTimeMs
,
Handler
eventHandler
,
EventListener
eventListener
,
int
maxDroppedFrameCountToNotify
)
{
FrameReleaseTimeHelper
frameReleaseTimeHelper
,
Handler
eventHandler
,
EventListener
eventListener
,
int
maxDroppedFrameCountToNotify
)
{
super
(
source
,
drmSessionManager
,
playClearSamplesWithoutKeys
,
eventHandler
,
eventListener
);
this
.
videoScalingMode
=
videoScalingMode
;
this
.
allowedJoiningTimeUs
=
allowedJoiningTimeMs
*
1000
;
this
.
frameReleaseTimeHelper
=
frameReleaseTimeHelper
;
this
.
eventListener
=
eventListener
;
this
.
maxDroppedFrameCountToNotify
=
maxDroppedFrameCountToNotify
;
joiningDeadlineUs
=
-
1
;
...
...
@@ -232,6 +265,9 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
if
(
joining
&&
allowedJoiningTimeUs
>
0
)
{
joiningDeadlineUs
=
SystemClock
.
elapsedRealtime
()
*
1000L
+
allowedJoiningTimeUs
;
}
if
(
frameReleaseTimeHelper
!=
null
)
{
frameReleaseTimeHelper
.
enable
();
}
}
@Override
...
...
@@ -283,6 +319,9 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
lastReportedWidth
=
-
1
;
lastReportedHeight
=
-
1
;
lastReportedPixelWidthHeightRatio
=
-
1
;
if
(
frameReleaseTimeHelper
!=
null
)
{
frameReleaseTimeHelper
.
disable
();
}
super
.
onDisabled
();
}
...
...
@@ -362,8 +401,24 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
return
true
;
}
long
elapsedSinceStartOfLoop
=
SystemClock
.
elapsedRealtime
()
*
1000
-
elapsedRealtimeUs
;
long
earlyUs
=
bufferInfo
.
presentationTimeUs
-
positionUs
-
elapsedSinceStartOfLoop
;
// Compute how many microseconds it is until the buffer's presentation time.
long
elapsedSinceStartOfLoopUs
=
(
SystemClock
.
elapsedRealtime
()
*
1000
)
-
elapsedRealtimeUs
;
long
earlyUs
=
bufferInfo
.
presentationTimeUs
-
positionUs
-
elapsedSinceStartOfLoopUs
;
// Compute the buffer's desired release time in nanoseconds.
long
systemTimeNs
=
System
.
nanoTime
();
long
unadjustedFrameReleaseTimeNs
=
systemTimeNs
+
(
earlyUs
*
1000
);
// Apply a timestamp adjustment, if there is one.
long
adjustedReleaseTimeNs
;
if
(
frameReleaseTimeHelper
!=
null
)
{
adjustedReleaseTimeNs
=
frameReleaseTimeHelper
.
adjustReleaseTime
(
bufferInfo
.
presentationTimeUs
,
unadjustedFrameReleaseTimeNs
);
earlyUs
=
(
adjustedReleaseTimeNs
-
systemTimeNs
)
/
1000
;
}
else
{
adjustedReleaseTimeNs
=
unadjustedFrameReleaseTimeNs
;
}
if
(
earlyUs
<
-
30000
)
{
// We're more than 30ms late rendering the frame.
dropOutputBuffer
(
codec
,
bufferIndex
);
...
...
@@ -383,7 +438,7 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
if
(
Util
.
SDK_INT
>=
21
)
{
// Let the underlying framework time the release.
if
(
earlyUs
<
50000
)
{
renderOutputBufferTimedV21
(
codec
,
bufferIndex
,
System
.
nanoTime
()
+
(
earlyUs
*
1000L
)
);
renderOutputBufferTimedV21
(
codec
,
bufferIndex
,
adjustedReleaseTimeNs
);
return
true
;
}
}
else
{
...
...
@@ -436,10 +491,10 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
}
@TargetApi
(
21
)
private
void
renderOutputBufferTimedV21
(
MediaCodec
codec
,
int
bufferIndex
,
long
nanoTime
)
{
private
void
renderOutputBufferTimedV21
(
MediaCodec
codec
,
int
bufferIndex
,
long
releaseTimeNs
)
{
maybeNotifyVideoSizeChanged
();
TraceUtil
.
beginSection
(
"releaseOutputBufferTimed"
);
codec
.
releaseOutputBuffer
(
bufferIndex
,
nanoTime
);
codec
.
releaseOutputBuffer
(
bufferIndex
,
releaseTimeNs
);
TraceUtil
.
endSection
();
codecCounters
.
renderedOutputBufferCount
++;
maybeNotifyDrawnToSurface
();
...
...
library/src/main/java/com/google/android/exoplayer/MediaFormat.java
View file @
0005f41f
...
...
@@ -47,6 +47,8 @@ public class MediaFormat {
public
final
int
channelCount
;
public
final
int
sampleRate
;
public
final
int
bitrate
;
private
int
maxWidth
;
private
int
maxHeight
;
...
...
@@ -70,13 +72,19 @@ public class MediaFormat {
public
static
MediaFormat
createVideoFormat
(
String
mimeType
,
int
maxInputSize
,
int
width
,
int
height
,
float
pixelWidthHeightRatio
,
List
<
byte
[]>
initializationData
)
{
return
new
MediaFormat
(
mimeType
,
maxInputSize
,
width
,
height
,
pixelWidthHeightRatio
,
NO_VALUE
,
NO_VALUE
,
initializationData
);
NO_VALUE
,
NO_VALUE
,
initializationData
);
}
public
static
MediaFormat
createAudioFormat
(
String
mimeType
,
int
maxInputSize
,
int
channelCount
,
int
sampleRate
,
List
<
byte
[]>
initializationData
)
{
return
new
MediaFormat
(
mimeType
,
maxInputSize
,
NO_VALUE
,
NO_VALUE
,
NO_VALUE
,
channelCount
,
sampleRate
,
initializationData
);
sampleRate
,
NO_VALUE
,
initializationData
);
}
public
static
MediaFormat
createAudioFormat
(
String
mimeType
,
int
maxInputSize
,
int
channelCount
,
int
sampleRate
,
int
bitrate
,
List
<
byte
[]>
initializationData
)
{
return
new
MediaFormat
(
mimeType
,
maxInputSize
,
NO_VALUE
,
NO_VALUE
,
NO_VALUE
,
channelCount
,
sampleRate
,
bitrate
,
initializationData
);
}
public
static
MediaFormat
createId3Format
()
{
...
...
@@ -93,6 +101,7 @@ public class MediaFormat {
height
=
getOptionalIntegerV16
(
format
,
android
.
media
.
MediaFormat
.
KEY_HEIGHT
);
channelCount
=
getOptionalIntegerV16
(
format
,
android
.
media
.
MediaFormat
.
KEY_CHANNEL_COUNT
);
sampleRate
=
getOptionalIntegerV16
(
format
,
android
.
media
.
MediaFormat
.
KEY_SAMPLE_RATE
);
bitrate
=
getOptionalIntegerV16
(
format
,
android
.
media
.
MediaFormat
.
KEY_BIT_RATE
);
pixelWidthHeightRatio
=
getOptionalFloatV16
(
format
,
KEY_PIXEL_WIDTH_HEIGHT_RATIO
);
initializationData
=
new
ArrayList
<
byte
[]>();
for
(
int
i
=
0
;
format
.
containsKey
(
"csd-"
+
i
);
i
++)
{
...
...
@@ -107,7 +116,7 @@ public class MediaFormat {
}
private
MediaFormat
(
String
mimeType
,
int
maxInputSize
,
int
width
,
int
height
,
float
pixelWidthHeightRatio
,
int
channelCount
,
int
sampleRate
,
float
pixelWidthHeightRatio
,
int
channelCount
,
int
sampleRate
,
int
bitrate
,
List
<
byte
[]>
initializationData
)
{
this
.
mimeType
=
mimeType
;
this
.
maxInputSize
=
maxInputSize
;
...
...
@@ -116,6 +125,7 @@ public class MediaFormat {
this
.
pixelWidthHeightRatio
=
pixelWidthHeightRatio
;
this
.
channelCount
=
channelCount
;
this
.
sampleRate
=
sampleRate
;
this
.
bitrate
=
bitrate
;
this
.
initializationData
=
initializationData
==
null
?
Collections
.<
byte
[]>
emptyList
()
:
initializationData
;
maxWidth
=
NO_VALUE
;
...
...
@@ -151,6 +161,7 @@ public class MediaFormat {
result
=
31
*
result
+
maxHeight
;
result
=
31
*
result
+
channelCount
;
result
=
31
*
result
+
sampleRate
;
result
=
31
*
result
+
bitrate
;
for
(
int
i
=
0
;
i
<
initializationData
.
size
();
i
++)
{
result
=
31
*
result
+
Arrays
.
hashCode
(
initializationData
.
get
(
i
));
}
...
...
@@ -186,6 +197,7 @@ public class MediaFormat {
||
(!
ignoreMaxDimensions
&&
(
maxWidth
!=
other
.
maxWidth
||
maxHeight
!=
other
.
maxHeight
))
||
channelCount
!=
other
.
channelCount
||
sampleRate
!=
other
.
sampleRate
||
!
Util
.
areEqual
(
mimeType
,
other
.
mimeType
)
||
bitrate
!=
other
.
bitrate
||
initializationData
.
size
()
!=
other
.
initializationData
.
size
())
{
return
false
;
}
...
...
@@ -200,8 +212,8 @@ public class MediaFormat {
@Override
public
String
toString
()
{
return
"MediaFormat("
+
mimeType
+
", "
+
maxInputSize
+
", "
+
width
+
", "
+
height
+
", "
+
pixelWidthHeightRatio
+
", "
+
channelCount
+
", "
+
sampleRate
+
", "
+
maxWidth
+
", "
+
maxHeight
+
")"
;
+
pixelWidthHeightRatio
+
", "
+
channelCount
+
", "
+
sampleRate
+
", "
+
bitrate
+
", "
+
max
Width
+
", "
+
max
Height
+
")"
;
}
/**
...
...
@@ -217,6 +229,7 @@ public class MediaFormat {
maybeSetIntegerV16
(
format
,
android
.
media
.
MediaFormat
.
KEY_HEIGHT
,
height
);
maybeSetIntegerV16
(
format
,
android
.
media
.
MediaFormat
.
KEY_CHANNEL_COUNT
,
channelCount
);
maybeSetIntegerV16
(
format
,
android
.
media
.
MediaFormat
.
KEY_SAMPLE_RATE
,
sampleRate
);
maybeSetIntegerV16
(
format
,
android
.
media
.
MediaFormat
.
KEY_BIT_RATE
,
bitrate
);
maybeSetFloatV16
(
format
,
KEY_PIXEL_WIDTH_HEIGHT_RATIO
,
pixelWidthHeightRatio
);
for
(
int
i
=
0
;
i
<
initializationData
.
size
();
i
++)
{
format
.
setByteBuffer
(
"csd-"
+
i
,
ByteBuffer
.
wrap
(
initializationData
.
get
(
i
)));
...
...
library/src/main/java/com/google/android/exoplayer/parser/mp4/Atom.java
View file @
0005f41f
...
...
@@ -24,6 +24,10 @@ import java.util.ArrayList;
public
static
final
int
TYPE_esds
=
0x65736473
;
public
static
final
int
TYPE_mdat
=
0x6D646174
;
public
static
final
int
TYPE_mp4a
=
0x6D703461
;
public
static
final
int
TYPE_ac_3
=
0x61632D33
;
// ac-3
public
static
final
int
TYPE_dac3
=
0x64616333
;
public
static
final
int
TYPE_ec_3
=
0x65632D33
;
// ec-3
public
static
final
int
TYPE_dec3
=
0x64656333
;
public
static
final
int
TYPE_tfdt
=
0x74666474
;
public
static
final
int
TYPE_tfhd
=
0x74666864
;
public
static
final
int
TYPE_trex
=
0x74726578
;
...
...
library/src/main/java/com/google/android/exoplayer/parser/mp4/FragmentedMp4Extractor.java
View file @
0005f41f
...
...
@@ -65,6 +65,11 @@ public final class FragmentedMp4Extractor implements Extractor {
private
static
final
byte
[]
NAL_START_CODE
=
new
byte
[]
{
0
,
0
,
0
,
1
};
private
static
final
byte
[]
PIFF_SAMPLE_ENCRYPTION_BOX_EXTENDED_TYPE
=
new
byte
[]
{-
94
,
57
,
79
,
82
,
90
,
-
101
,
79
,
20
,
-
94
,
68
,
108
,
66
,
124
,
100
,
-
115
,
-
12
};
/** Channel counts for AC-3 audio, indexed by acmod. (See ETSI TS 102 366.) */
private
static
final
int
[]
AC3_CHANNEL_COUNTS
=
new
int
[]
{
2
,
1
,
2
,
3
,
3
,
4
,
4
,
5
};
/** Nominal bit-rates for AC-3 audio in kbps, indexed by bit_rate_code. (See ETSI TS 102 366.) */
private
static
final
int
[]
AC3_BIT_RATES
=
new
int
[]
{
32
,
40
,
48
,
56
,
64
,
80
,
96
,
112
,
128
,
160
,
192
,
224
,
256
,
320
,
384
,
448
,
512
,
576
,
640
};
// Parser states
private
static
final
int
STATE_READING_ATOM_HEADER
=
0
;
...
...
@@ -512,11 +517,12 @@ public final class FragmentedMp4Extractor implements Extractor {
parseAvcFromParent
(
stsd
,
childStartPosition
,
childAtomSize
);
mediaFormat
=
avc
.
first
;
trackEncryptionBoxes
[
i
]
=
avc
.
second
;
}
else
if
(
childAtomType
==
Atom
.
TYPE_mp4a
||
childAtomType
==
Atom
.
TYPE_enca
)
{
Pair
<
MediaFormat
,
TrackEncryptionBox
>
mp4a
=
parseMp4aFromParent
(
stsd
,
childStartPosition
,
childAtomSize
);
mediaFormat
=
mp4a
.
first
;
trackEncryptionBoxes
[
i
]
=
mp4a
.
second
;
}
else
if
(
childAtomType
==
Atom
.
TYPE_mp4a
||
childAtomType
==
Atom
.
TYPE_enca
||
childAtomType
==
Atom
.
TYPE_ac_3
)
{
Pair
<
MediaFormat
,
TrackEncryptionBox
>
audioSampleEntry
=
parseAudioSampleEntry
(
stsd
,
childAtomType
,
childStartPosition
,
childAtomSize
);
mediaFormat
=
audioSampleEntry
.
first
;
trackEncryptionBoxes
[
i
]
=
audioSampleEntry
.
second
;
}
stsd
.
setPosition
(
childStartPosition
+
childAtomSize
);
}
...
...
@@ -556,15 +562,15 @@ public final class FragmentedMp4Extractor implements Extractor {
return
Pair
.
create
(
format
,
trackEncryptionBox
);
}
private
static
Pair
<
MediaFormat
,
TrackEncryptionBox
>
parse
Mp4aFromParent
(
ParsableByteArray
parent
,
int
position
,
int
size
)
{
private
static
Pair
<
MediaFormat
,
TrackEncryptionBox
>
parse
AudioSampleEntry
(
ParsableByteArray
parent
,
int
atomType
,
int
position
,
int
size
)
{
parent
.
setPosition
(
position
+
ATOM_HEADER_SIZE
);
// Start of the mp4a atom (defined in 14496-14)
parent
.
skip
(
16
);
int
channelCount
=
parent
.
readUnsignedShort
();
int
sampleSize
=
parent
.
readUnsignedShort
();
parent
.
skip
(
4
);
int
sampleRate
=
parent
.
readUnsignedFixedPoint1616
();
int
bitrate
=
MediaFormat
.
NO_VALUE
;
byte
[]
initializationData
=
null
;
TrackEncryptionBox
trackEncryptionBox
=
null
;
...
...
@@ -574,25 +580,97 @@ public final class FragmentedMp4Extractor implements Extractor {
int
childStartPosition
=
parent
.
getPosition
();
int
childAtomSize
=
parent
.
readInt
();
int
childAtomType
=
parent
.
readInt
();
if
(
childAtomType
==
Atom
.
TYPE_esds
)
{
initializationData
=
parseEsdsFromParent
(
parent
,
childStartPosition
);
// TODO: Do we really need to do this? See [redacted]
// Update sampleRate and channelCount from the AudioSpecificConfig initialization data.
Pair
<
Integer
,
Integer
>
audioSpecificConfig
=
CodecSpecificDataUtil
.
parseAudioSpecificConfig
(
initializationData
);
sampleRate
=
audioSpecificConfig
.
first
;
channelCount
=
audioSpecificConfig
.
second
;
}
else
if
(
childAtomType
==
Atom
.
TYPE_sinf
)
{
trackEncryptionBox
=
parseSinfFromParent
(
parent
,
childStartPosition
,
childAtomSize
);
if
(
atomType
==
Atom
.
TYPE_mp4a
||
atomType
==
Atom
.
TYPE_enca
)
{
if
(
childAtomType
==
Atom
.
TYPE_esds
)
{
initializationData
=
parseEsdsFromParent
(
parent
,
childStartPosition
);
// TODO: Do we really need to do this? See [redacted]
// Update sampleRate and channelCount from the AudioSpecificConfig initialization data.
Pair
<
Integer
,
Integer
>
audioSpecificConfig
=
CodecSpecificDataUtil
.
parseAudioSpecificConfig
(
initializationData
);
sampleRate
=
audioSpecificConfig
.
first
;
channelCount
=
audioSpecificConfig
.
second
;
}
else
if
(
childAtomType
==
Atom
.
TYPE_sinf
)
{
trackEncryptionBox
=
parseSinfFromParent
(
parent
,
childStartPosition
,
childAtomSize
);
}
}
else
if
(
atomType
==
Atom
.
TYPE_ac_3
&&
childAtomType
==
Atom
.
TYPE_dac3
)
{
// TODO: Choose the right AC-3 track based on the contents of dac3/dec3.
Ac3Format
ac3Format
=
parseAc3SpecificBoxFromParent
(
parent
,
childStartPosition
);
if
(
ac3Format
!=
null
)
{
sampleRate
=
ac3Format
.
sampleRate
;
channelCount
=
ac3Format
.
channelCount
;
bitrate
=
ac3Format
.
bitrate
;
}
// TODO: Add support for encrypted AC-3.
trackEncryptionBox
=
null
;
}
else
if
(
atomType
==
Atom
.
TYPE_ec_3
&&
childAtomType
==
Atom
.
TYPE_dec3
)
{
sampleRate
=
parseEc3SpecificBoxFromParent
(
parent
,
childStartPosition
);
trackEncryptionBox
=
null
;
}
childPosition
+=
childAtomSize
;
}
MediaFormat
format
=
MediaFormat
.
createAudioFormat
(
"audio/mp4a-latm"
,
sampleSize
,
channelCount
,
sampleRate
,
Collections
.
singletonList
(
initializationData
));
String
mimeType
;
if
(
atomType
==
Atom
.
TYPE_ac_3
)
{
mimeType
=
MimeTypes
.
AUDIO_AC3
;
}
else
if
(
atomType
==
Atom
.
TYPE_ec_3
)
{
mimeType
=
MimeTypes
.
AUDIO_EC3
;
}
else
{
mimeType
=
MimeTypes
.
AUDIO_AAC
;
}
MediaFormat
format
=
MediaFormat
.
createAudioFormat
(
mimeType
,
sampleSize
,
channelCount
,
sampleRate
,
bitrate
,
initializationData
==
null
?
null
:
Collections
.
singletonList
(
initializationData
));
return
Pair
.
create
(
format
,
trackEncryptionBox
);
}
private
static
Ac3Format
parseAc3SpecificBoxFromParent
(
ParsableByteArray
parent
,
int
position
)
{
// Start of the dac3 atom (defined in ETSI TS 102 366)
parent
.
setPosition
(
position
+
ATOM_HEADER_SIZE
);
// fscod (sample rate code)
int
fscod
=
(
parent
.
readUnsignedByte
()
&
0xC0
)
>>
6
;
int
sampleRate
;
switch
(
fscod
)
{
case
0
:
sampleRate
=
48000
;
break
;
case
1
:
sampleRate
=
44100
;
break
;
case
2
:
sampleRate
=
32000
;
break
;
default
:
// TODO: The decoder should not use this stream.
return
null
;
}
int
nextByte
=
parent
.
readUnsignedByte
();
// Map acmod (audio coding mode) onto a channel count.
int
channelCount
=
AC3_CHANNEL_COUNTS
[(
nextByte
&
0x38
)
>>
3
];
// lfeon (low frequency effects on)
if
((
nextByte
&
0x04
)
!=
0
)
{
channelCount
++;
}
// Map bit_rate_code onto a bit-rate in kbit/s.
int
bitrate
=
AC3_BIT_RATES
[((
nextByte
&
0x03
)
<<
3
)
+
(
parent
.
readUnsignedByte
()
>>
5
)];
return
new
Ac3Format
(
channelCount
,
sampleRate
,
bitrate
);
}
private
static
int
parseEc3SpecificBoxFromParent
(
ParsableByteArray
parent
,
int
position
)
{
// Start of the dec3 atom (defined in ETSI TS 102 366)
parent
.
setPosition
(
position
+
ATOM_HEADER_SIZE
);
// TODO: Implement parsing for enhanced AC-3 with multiple sub-streams.
return
0
;
}
private
static
List
<
byte
[]>
parseAvcCFromParent
(
ParsableByteArray
parent
,
int
position
)
{
parent
.
setPosition
(
position
+
ATOM_HEADER_SIZE
+
4
);
// Start of the AVCDecoderConfigurationRecord (defined in 14496-15)
...
...
@@ -1182,4 +1260,19 @@ public final class FragmentedMp4Extractor implements Extractor {
return
result
;
}
/** Represents the format for AC-3 audio. */
private
static
final
class
Ac3Format
{
public
final
int
channelCount
;
public
final
int
sampleRate
;
public
final
int
bitrate
;
public
Ac3Format
(
int
channelCount
,
int
sampleRate
,
int
bitrate
)
{
this
.
channelCount
=
channelCount
;
this
.
sampleRate
=
sampleRate
;
this
.
bitrate
=
bitrate
;
}
}
}
library/src/main/java/com/google/android/exoplayer/text/CaptionStyleCompat.java
View file @
0005f41f
...
...
@@ -113,7 +113,7 @@ public final class CaptionStyleCompat {
if
(
Util
.
SDK_INT
>=
21
)
{
return
createFromCaptionStyleV21
(
captionStyle
);
}
else
{
// Note - Any caller must be on at least API level 19 o
f
greater (because CaptionStyle did
// Note - Any caller must be on at least API level 19 o
r
greater (because CaptionStyle did
// not exist in earlier API levels).
return
createFromCaptionStyleV19
(
captionStyle
);
}
...
...
library/src/main/java/com/google/android/exoplayer/util/ManifestFetcher.java
View file @
0005f41f
...
...
@@ -171,7 +171,7 @@ public class ManifestFetcher<T> implements Loader.Callback {
loader
=
new
Loader
(
"manifestLoader"
);
}
if
(!
loader
.
isLoading
())
{
currentLoadable
=
new
ManifestLoadable
(
userAgent
);
currentLoadable
=
new
ManifestLoadable
();
loader
.
startLoading
(
currentLoadable
,
this
);
}
}
...
...
@@ -221,7 +221,7 @@ public class ManifestFetcher<T> implements Loader.Callback {
this
.
callbackLooper
=
callbackLooper
;
this
.
wrappedCallback
=
wrappedCallback
;
singleUseLoader
=
new
Loader
(
"manifestLoader:single"
);
singleUseLoadable
=
new
ManifestLoadable
(
userAgent
);
singleUseLoadable
=
new
ManifestLoadable
();
}
public
void
startLoading
()
{
...
...
@@ -269,15 +269,9 @@ public class ManifestFetcher<T> implements Loader.Callback {
private
static
final
int
TIMEOUT_MILLIS
=
10000
;
private
final
String
userAgent
;
/* package */
volatile
T
result
;
private
volatile
boolean
isCanceled
;
public
ManifestLoadable
(
String
userAgent
)
{
this
.
userAgent
=
userAgent
;
}
@Override
public
void
cancelLoad
()
{
// We don't actually cancel anything, but we need to record the cancellation so that
...
...
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