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
1face387
authored
Dec 15, 2014
by
ojw28
Browse files
Options
_('Browse Files')
Download
Plain Diff
Merge pull request #204 from google/dev
dev -> dev-hls
parents
b8056923
57068a64
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
87 additions
and
41 deletions
demo/src/main/java/com/google/android/exoplayer/demo/full/player/DashRendererBuilder.java
demo/src/main/java/com/google/android/exoplayer/demo/full/player/SmoothStreamingRendererBuilder.java
library/src/main/java/com/google/android/exoplayer/Ac3PassthroughAudioTrackRenderer.java
library/src/main/java/com/google/android/exoplayer/audio/AudioTrack.java
library/src/main/java/com/google/android/exoplayer/chunk/Format.java
library/src/main/java/com/google/android/exoplayer/dash/DashChunkSource.java
library/src/main/java/com/google/android/exoplayer/dash/mpd/MediaPresentationDescriptionParser.java
demo/src/main/java/com/google/android/exoplayer/demo/full/player/DashRendererBuilder.java
View file @
1face387
...
...
@@ -81,6 +81,9 @@ public class DashRendererBuilder implements RendererBuilder,
private
static
final
int
SECURITY_LEVEL_1
=
1
;
private
static
final
int
SECURITY_LEVEL_3
=
3
;
private
static
final
String
AC_3_CODEC
=
"ac-3"
;
private
static
final
String
E_AC_3_CODEC
=
"ec-3"
;
private
final
String
userAgent
;
private
final
String
url
;
private
final
String
contentId
;
...
...
@@ -160,12 +163,8 @@ public class DashRendererBuilder implements RendererBuilder,
// HD streams require L1 security.
filterHdContent
=
videoAdaptationSet
!=
null
&&
videoAdaptationSet
.
hasContentProtection
()
&&
!
drmSessionManagerData
.
second
;
}
catch
(
UnsupportedSchemeException
e
)
{
callback
.
onRenderersError
(
new
UnsupportedDrmException
(
UnsupportedDrmException
.
REASON_UNSUPPORTED_SCHEME
,
e
));
}
catch
(
Exception
e
)
{
callback
.
onRenderersError
(
new
UnsupportedDrmException
(
UnsupportedDrmException
.
REASON_UNKNOWN
,
e
));
}
catch
(
UnsupportedDrmException
e
)
{
callback
.
onRenderersError
(
e
);
return
;
}
}
...
...
@@ -225,15 +224,13 @@ public class DashRendererBuilder implements RendererBuilder,
format
.
audioSamplingRate
+
"Hz)"
);
audioChunkSourceList
.
add
(
new
DashChunkSource
(
manifestFetcher
,
audioAdaptationSetIndex
,
new
int
[]
{
i
},
audioDataSource
,
audioEvaluator
,
LIVE_EDGE_LATENCY_MS
));
haveAc3Tracks
|=
format
.
mimeType
.
equals
(
MimeTypes
.
AUDIO_AC3
)
||
format
.
mimeType
.
equals
(
MimeTypes
.
AUDIO_EC3
);
haveAc3Tracks
|=
AC_3_CODEC
.
equals
(
format
.
codecs
)
||
E_AC_3_CODEC
.
equals
(
format
.
codecs
);
}
// Filter out non-AC-3 tracks if there is an AC-3 track, to avoid having to switch renderers.
if
(
haveAc3Tracks
)
{
for
(
int
i
=
audioRepresentations
.
size
()
-
1
;
i
>=
0
;
i
--)
{
Format
format
=
audioRepresentations
.
get
(
i
).
format
;
if
(!
format
.
mimeType
.
equals
(
MimeTypes
.
AUDIO_AC3
)
&&
!
format
.
mimeType
.
equals
(
MimeTypes
.
AUDIO_EC3
))
{
if
(!
AC_3_CODEC
.
equals
(
format
.
codecs
)
&&
!
E_AC_3_CODEC
.
equals
(
format
.
codecs
))
{
audioTrackNameList
.
remove
(
i
);
audioChunkSourceList
.
remove
(
i
);
}
...
...
@@ -327,12 +324,18 @@ public class DashRendererBuilder implements RendererBuilder,
private
static
class
V18Compat
{
public
static
Pair
<
DrmSessionManager
,
Boolean
>
getDrmSessionManagerData
(
DemoPlayer
player
,
MediaDrmCallback
drmCallback
)
throws
UnsupportedSchemeException
{
MediaDrmCallback
drmCallback
)
throws
UnsupportedDrmException
{
try
{
StreamingDrmSessionManager
streamingDrmSessionManager
=
new
StreamingDrmSessionManager
(
DemoUtil
.
WIDEVINE_UUID
,
player
.
getPlaybackLooper
(),
drmCallback
,
null
,
player
.
getMainHandler
(),
player
);
return
Pair
.
create
((
DrmSessionManager
)
streamingDrmSessionManager
,
getWidevineSecurityLevel
(
streamingDrmSessionManager
)
==
SECURITY_LEVEL_1
);
}
catch
(
UnsupportedSchemeException
e
)
{
throw
new
UnsupportedDrmException
(
UnsupportedDrmException
.
REASON_UNSUPPORTED_SCHEME
);
}
catch
(
Exception
e
)
{
throw
new
UnsupportedDrmException
(
UnsupportedDrmException
.
REASON_UNKNOWN
,
e
);
}
}
private
static
int
getWidevineSecurityLevel
(
StreamingDrmSessionManager
sessionManager
)
{
...
...
demo/src/main/java/com/google/android/exoplayer/demo/full/player/SmoothStreamingRendererBuilder.java
View file @
1face387
...
...
@@ -118,12 +118,8 @@ public class SmoothStreamingRendererBuilder implements RendererBuilder,
try
{
drmSessionManager
=
V18Compat
.
getDrmSessionManager
(
manifest
.
protectionElement
.
uuid
,
player
,
drmCallback
);
}
catch
(
UnsupportedSchemeException
e
)
{
callback
.
onRenderersError
(
new
UnsupportedDrmException
(
UnsupportedDrmException
.
REASON_UNSUPPORTED_SCHEME
,
e
));
}
catch
(
Exception
e
)
{
callback
.
onRenderersError
(
new
UnsupportedDrmException
(
UnsupportedDrmException
.
REASON_UNKNOWN
,
e
));
}
catch
(
UnsupportedDrmException
e
)
{
callback
.
onRenderersError
(
e
);
return
;
}
}
...
...
@@ -259,9 +255,15 @@ public class SmoothStreamingRendererBuilder implements RendererBuilder,
private
static
class
V18Compat
{
public
static
DrmSessionManager
getDrmSessionManager
(
UUID
uuid
,
DemoPlayer
player
,
MediaDrmCallback
drmCallback
)
throws
UnsupportedSchemeException
{
MediaDrmCallback
drmCallback
)
throws
UnsupportedDrmException
{
try
{
return
new
StreamingDrmSessionManager
(
uuid
,
player
.
getPlaybackLooper
(),
drmCallback
,
null
,
player
.
getMainHandler
(),
player
);
}
catch
(
UnsupportedSchemeException
e
)
{
throw
new
UnsupportedDrmException
(
UnsupportedDrmException
.
REASON_UNSUPPORTED_SCHEME
);
}
catch
(
Exception
e
)
{
throw
new
UnsupportedDrmException
(
UnsupportedDrmException
.
REASON_UNKNOWN
,
e
);
}
}
}
...
...
library/src/main/java/com/google/android/exoplayer/Ac3PassthroughAudioTrackRenderer.java
View file @
1face387
...
...
@@ -136,7 +136,7 @@ public final class Ac3PassthroughAudioTrackRenderer extends TrackRenderer {
}
private
static
boolean
handlesMimeType
(
String
mimeType
)
{
return
MimeTypes
.
AUDIO_
AC3
.
equals
(
mimeType
)
||
MimeTypes
.
AUDIO_EC3
.
equals
(
mimeType
);
return
MimeTypes
.
AUDIO_
MP4
.
equals
(
mimeType
);
}
@Override
...
...
library/src/main/java/com/google/android/exoplayer/audio/AudioTrack.java
View file @
1face387
...
...
@@ -641,7 +641,8 @@ public final class AudioTrack {
private
long
bytesToFrames
(
long
byteCount
)
{
if
(
isAc3
)
{
return
byteCount
*
8
*
sampleRate
/
(
1000
*
ac3Bitrate
);
return
ac3Bitrate
==
UNKNOWN_AC3_BITRATE
?
0L
:
byteCount
*
8
*
sampleRate
/
(
1000
*
ac3Bitrate
);
}
else
{
return
byteCount
/
frameSize
;
}
...
...
library/src/main/java/com/google/android/exoplayer/chunk/Format.java
View file @
1face387
...
...
@@ -47,6 +47,11 @@ public class Format {
public
final
String
mimeType
;
/**
* The codecs used to decode the format, or {@code null} if they are not specified.
*/
public
final
String
codecs
;
/**
* The width of the video in pixels, or -1 for non-video formats.
*/
public
final
int
width
;
...
...
@@ -98,7 +103,7 @@ public class Format {
*/
public
Format
(
String
id
,
String
mimeType
,
int
width
,
int
height
,
int
numChannels
,
int
audioSamplingRate
,
int
bitrate
)
{
this
(
id
,
mimeType
,
width
,
height
,
numChannels
,
audioSamplingRate
,
bitrate
,
null
);
this
(
id
,
mimeType
,
width
,
height
,
numChannels
,
audioSamplingRate
,
bitrate
,
null
,
null
);
}
/**
...
...
@@ -113,6 +118,23 @@ public class Format {
*/
public
Format
(
String
id
,
String
mimeType
,
int
width
,
int
height
,
int
numChannels
,
int
audioSamplingRate
,
int
bitrate
,
String
language
)
{
this
(
id
,
mimeType
,
width
,
height
,
numChannels
,
audioSamplingRate
,
bitrate
,
language
,
null
);
}
/**
* @param id The format identifier.
* @param mimeType The format mime type.
* @param width The width of the video in pixels, or -1 for non-video formats.
* @param height The height of the video in pixels, or -1 for non-video formats.
* @param numChannels The number of audio channels, or -1 for non-audio formats.
* @param audioSamplingRate The audio sampling rate in Hz, or -1 for non-audio formats.
* @param bitrate The average bandwidth of the format in bits per second.
* @param language The language of the format.
* @param codecs The codecs used to decode the format.
*/
public
Format
(
String
id
,
String
mimeType
,
int
width
,
int
height
,
int
numChannels
,
int
audioSamplingRate
,
int
bitrate
,
String
language
,
String
codecs
)
{
this
.
id
=
Assertions
.
checkNotNull
(
id
);
this
.
mimeType
=
mimeType
;
this
.
width
=
width
;
...
...
@@ -121,6 +143,7 @@ public class Format {
this
.
audioSamplingRate
=
audioSamplingRate
;
this
.
bitrate
=
bitrate
;
this
.
language
=
language
;
this
.
codecs
=
codecs
;
this
.
bandwidth
=
bitrate
/
8
;
}
...
...
library/src/main/java/com/google/android/exoplayer/dash/DashChunkSource.java
View file @
1face387
...
...
@@ -326,13 +326,30 @@ public class DashChunkSource implements ChunkSource {
return
;
}
int
lastSegmentNum
=
segmentIndex
.
getLastSegmentNum
();
boolean
indexUnbounded
=
lastSegmentNum
==
DashSegmentIndex
.
INDEX_UNBOUNDED
;
// TODO: Use UtcTimingElement where possible.
long
nowUs
=
System
.
currentTimeMillis
()
*
1000
;
int
firstAvailableSegmentNum
=
segmentIndex
.
getFirstSegmentNum
();
int
lastAvailableSegmentNum
=
segmentIndex
.
getLastSegmentNum
();
boolean
indexUnbounded
=
lastAvailableSegmentNum
==
DashSegmentIndex
.
INDEX_UNBOUNDED
;
if
(
indexUnbounded
)
{
// The index is itself unbounded. We need to use the current time to calculate the range of
// available segments.
long
liveEdgeTimestampUs
=
nowUs
-
currentManifest
.
availabilityStartTime
*
1000
;
if
(
currentManifest
.
timeShiftBufferDepth
!=
-
1
)
{
long
bufferDepthUs
=
currentManifest
.
timeShiftBufferDepth
*
1000
;
firstAvailableSegmentNum
=
Math
.
max
(
firstAvailableSegmentNum
,
segmentIndex
.
getSegmentNum
(
liveEdgeTimestampUs
-
bufferDepthUs
));
}
// getSegmentNum(liveEdgeTimestampUs) will not be completed yet, so subtract one to get the
// index of the last completed segment.
lastAvailableSegmentNum
=
segmentIndex
.
getSegmentNum
(
liveEdgeTimestampUs
)
-
1
;
}
int
segmentNum
;
if
(
queue
.
isEmpty
())
{
if
(
currentManifest
.
dynamic
)
{
seekPositionUs
=
getLiveSeekPosition
(
indexUnbounded
);
seekPositionUs
=
getLiveSeekPosition
(
nowUs
,
indexUnbounded
);
}
segmentNum
=
segmentIndex
.
getSegmentNum
(
seekPositionUs
);
}
else
{
...
...
@@ -340,20 +357,20 @@ public class DashChunkSource implements ChunkSource {
-
representationHolder
.
segmentNumShift
;
}
// TODO: For unbounded manifests, we need to enforce that we don't try and request chunks
// behind or in front of the live window.
if
(
currentManifest
.
dynamic
)
{
if
(
segmentNum
<
segmentIndex
.
getFirstSegmentNum
()
)
{
if
(
segmentNum
<
firstAvailableSegmentNum
)
{
// This is before the first chunk in the current manifest.
fatalError
=
new
BehindLiveWindowException
();
return
;
}
else
if
(!
indexUnbounded
&&
segmentNum
>
lastSegmentNum
)
{
// This is beyond the last chunk in the current manifest.
finishedCurrentManifest
=
true
;
}
else
if
(
segmentNum
>
lastAvailableSegmentNum
)
{
// This chunk is beyond the last chunk in the current manifest. If the index is bounded
// we'll need to refresh it. If it's unbounded we just need to wait for a while before
// attempting to load the chunk.
finishedCurrentManifest
=
!
indexUnbounded
;
return
;
}
else
if
(!
indexUnbounded
&&
segmentNum
==
lastSegmentNum
)
{
// This is the last chunk in
the current manifest. Mark the manifest as being finished,
//
but continue to return the final
chunk.
}
else
if
(!
indexUnbounded
&&
segmentNum
==
last
Available
SegmentNum
)
{
// This is the last chunk in
a dynamic bounded manifest. We'll need to refresh the manifest
//
to obtain the next
chunk.
finishedCurrentManifest
=
true
;
}
}
...
...
@@ -457,15 +474,14 @@ public class DashChunkSource implements ChunkSource {
* For live playbacks, determines the seek position that snaps playback to be
* {@link #liveEdgeLatencyUs} behind the live edge of the current manifest
*
* @param nowUs An estimate of the current server time, in microseconds.
* @param indexUnbounded True if the segment index for this source is unbounded. False otherwise.
* @return The seek position in microseconds.
*/
private
long
getLiveSeekPosition
(
boolean
indexUnbounded
)
{
private
long
getLiveSeekPosition
(
long
nowUs
,
boolean
indexUnbounded
)
{
long
liveEdgeTimestampUs
;
if
(
indexUnbounded
)
{
// TODO: Use UtcTimingElement where possible.
long
nowMs
=
System
.
currentTimeMillis
();
liveEdgeTimestampUs
=
(
nowMs
-
currentManifest
.
availabilityStartTime
)
*
1000
;
liveEdgeTimestampUs
=
nowUs
-
currentManifest
.
availabilityStartTime
*
1000
;
}
else
{
liveEdgeTimestampUs
=
Long
.
MIN_VALUE
;
for
(
RepresentationHolder
representationHolder
:
representationHolders
.
values
())
{
...
...
library/src/main/java/com/google/android/exoplayer/dash/mpd/MediaPresentationDescriptionParser.java
View file @
1face387
...
...
@@ -283,6 +283,7 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
int
width
=
parseInt
(
xpp
,
"width"
);
int
height
=
parseInt
(
xpp
,
"height"
);
mimeType
=
parseString
(
xpp
,
"mimeType"
,
mimeType
);
String
codecs
=
parseString
(
xpp
,
"codecs"
,
null
);
int
numChannels
=
-
1
;
do
{
...
...
@@ -302,15 +303,15 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
}
while
(!
isEndTag
(
xpp
,
"Representation"
));
Format
format
=
buildFormat
(
id
,
mimeType
,
width
,
height
,
numChannels
,
audioSamplingRate
,
bandwidth
,
language
);
bandwidth
,
language
,
codecs
);
return
buildRepresentation
(
periodStartMs
,
periodDurationMs
,
contentId
,
-
1
,
format
,
segmentBase
);
}
protected
Format
buildFormat
(
String
id
,
String
mimeType
,
int
width
,
int
height
,
int
numChannels
,
int
audioSamplingRate
,
int
bandwidth
,
String
language
)
{
return
new
Format
(
id
,
mimeType
,
width
,
height
,
numChannels
,
audioSamplingRate
,
bandwidth
,
language
);
int
audioSamplingRate
,
int
bandwidth
,
String
language
,
String
codecs
)
{
return
new
Format
(
id
,
mimeType
,
width
,
height
,
numChannels
,
audioSamplingRate
,
bandwidth
,
language
,
codecs
);
}
protected
Representation
buildRepresentation
(
long
periodStartMs
,
long
periodDurationMs
,
...
...
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