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
511dd943
authored
Dec 03, 2014
by
Oliver Woodman
Browse files
Options
_('Browse Files')
Download
Plain Diff
Merge branch 'dev' into dev-hls
parents
c2d55aca
4efc0abd
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
25 changed files
with
326 additions
and
103 deletions
demo/src/main/java/com/google/android/exoplayer/demo/DemoUtil.java
demo/src/main/java/com/google/android/exoplayer/demo/Samples.java
demo/src/main/java/com/google/android/exoplayer/demo/full/FullPlayerActivity.java
demo/src/main/java/com/google/android/exoplayer/demo/full/player/DashVodRendererBuilder.java → 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
demo/src/main/java/com/google/android/exoplayer/demo/simple/DashVodRendererBuilder.java → demo/src/main/java/com/google/android/exoplayer/demo/simple/DashRendererBuilder.java
demo/src/main/java/com/google/android/exoplayer/demo/simple/SimplePlayerActivity.java
demo/src/main/java/com/google/android/exoplayer/demo/simple/SmoothStreamingRendererBuilder.java
library/src/main/java/com/google/android/exoplayer/C.java
library/src/main/java/com/google/android/exoplayer/FrameworkSampleSource.java
library/src/main/java/com/google/android/exoplayer/TrackInfo.java
library/src/main/java/com/google/android/exoplayer/TrackRenderer.java
library/src/main/java/com/google/android/exoplayer/audio/AudioCapabilitiesReceiver.java
library/src/main/java/com/google/android/exoplayer/audio/AudioTrack.java
library/src/main/java/com/google/android/exoplayer/chunk/MultiTrackChunkSource.java
library/src/main/java/com/google/android/exoplayer/chunk/SingleSampleChunkSource.java
library/src/main/java/com/google/android/exoplayer/dash/DashChunkSource.java
library/src/main/java/com/google/android/exoplayer/dash/mpd/Period.java
library/src/main/java/com/google/android/exoplayer/dash/mpd/SegmentBase.java
library/src/main/java/com/google/android/exoplayer/parser/mp4/FragmentedMp4Extractor.java
library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingManifest.java
library/src/main/java/com/google/android/exoplayer/text/ttml/TtmlParser.java
library/src/main/java/com/google/android/exoplayer/util/ManifestFetcher.java
library/src/main/java/com/google/android/exoplayer/util/PlayerControl.java
library/src/main/java/com/google/android/exoplayer/util/Util.java
demo/src/main/java/com/google/android/exoplayer/demo/DemoUtil.java
View file @
511dd943
...
...
@@ -47,7 +47,7 @@ public class DemoUtil {
public
static
final
String
CONTENT_TYPE_EXTRA
=
"content_type"
;
public
static
final
String
CONTENT_ID_EXTRA
=
"content_id"
;
public
static
final
int
TYPE_DASH
_VOD
=
0
;
public
static
final
int
TYPE_DASH
=
0
;
public
static
final
int
TYPE_SS
=
1
;
public
static
final
int
TYPE_OTHER
=
2
;
public
static
final
int
TYPE_DASH_LIVE
=
3
;
...
...
demo/src/main/java/com/google/android/exoplayer/demo/Samples.java
View file @
511dd943
...
...
@@ -46,13 +46,13 @@ package com.google.android.exoplayer.demo;
"http://www.youtube.com/api/manifest/dash/id/bf5bb2419360daf1/source/youtube?"
+
"as=fmp4_audio_clear,fmp4_sd_hd_clear&sparams=ip,ipbits,expire,as&ip=0.0.0.0&"
+
"ipbits=0&expire=19000000000&signature=255F6B3C07C753C88708C07EA31B7A1A10703C8D."
+
"2D6A28B21F921D0B245CDCF36F7EB54A2B5ABFC2&key=ik0"
,
DemoUtil
.
TYPE_DASH
_VOD
,
false
,
+
"2D6A28B21F921D0B245CDCF36F7EB54A2B5ABFC2&key=ik0"
,
DemoUtil
.
TYPE_DASH
,
false
,
false
),
new
Sample
(
"Google Play (DASH)"
,
"3aa39fa2cc27967f"
,
"http://www.youtube.com/api/manifest/dash/id/3aa39fa2cc27967f/source/youtube?"
+
"as=fmp4_audio_clear,fmp4_sd_hd_clear&sparams=ip,ipbits,expire,as&ip=0.0.0.0&ipbits=0&"
+
"expire=19000000000&signature=7181C59D0252B285D593E1B61D985D5B7C98DE2A."
+
"5B445837F55A40E0F28AACAA047982E372D177E2&key=ik0"
,
DemoUtil
.
TYPE_DASH
_VOD
,
false
,
+
"5B445837F55A40E0F28AACAA047982E372D177E2&key=ik0"
,
DemoUtil
.
TYPE_DASH
,
false
,
false
),
new
Sample
(
"Super speed (SmoothStreaming)"
,
"uid:ss:superspeed"
,
"http://playready.directtaps.net/smoothstreaming/SSWSS720H264/SuperSpeedway_720.ism"
,
...
...
@@ -69,13 +69,13 @@ package com.google.android.exoplayer.demo;
"http://www.youtube.com/api/manifest/dash/id/bf5bb2419360daf1/source/youtube?"
+
"as=fmp4_audio_clear,fmp4_sd_hd_clear&sparams=ip,ipbits,expire,as&ip=0.0.0.0&"
+
"ipbits=0&expire=19000000000&signature=255F6B3C07C753C88708C07EA31B7A1A10703C8D."
+
"2D6A28B21F921D0B245CDCF36F7EB54A2B5ABFC2&key=ik0"
,
DemoUtil
.
TYPE_DASH
_VOD
,
false
,
+
"2D6A28B21F921D0B245CDCF36F7EB54A2B5ABFC2&key=ik0"
,
DemoUtil
.
TYPE_DASH
,
false
,
true
),
new
Sample
(
"Google Play"
,
"3aa39fa2cc27967f"
,
"http://www.youtube.com/api/manifest/dash/id/3aa39fa2cc27967f/source/youtube?"
+
"as=fmp4_audio_clear,fmp4_sd_hd_clear&sparams=ip,ipbits,expire,as&ip=0.0.0.0&ipbits=0&"
+
"expire=19000000000&signature=7181C59D0252B285D593E1B61D985D5B7C98DE2A."
+
"5B445837F55A40E0F28AACAA047982E372D177E2&key=ik0"
,
DemoUtil
.
TYPE_DASH
_VOD
,
false
,
+
"5B445837F55A40E0F28AACAA047982E372D177E2&key=ik0"
,
DemoUtil
.
TYPE_DASH
,
false
,
true
),
};
...
...
@@ -84,12 +84,12 @@ package com.google.android.exoplayer.demo;
"http://www.youtube.com/api/manifest/dash/id/bf5bb2419360daf1/source/youtube?"
+
"as=fmp4_audio_clear,webm2_sd_hd_clear&sparams=ip,ipbits,expire,as&ip=0.0.0.0&ipbits=0&"
+
"expire=19000000000&signature=A3EC7EE53ABE601B357F7CAB8B54AD0702CA85A7."
+
"446E9C38E47E3EDAF39E0163C390FF83A7944918&key=ik0"
,
DemoUtil
.
TYPE_DASH
_VOD
,
false
,
true
),
+
"446E9C38E47E3EDAF39E0163C390FF83A7944918&key=ik0"
,
DemoUtil
.
TYPE_DASH
,
false
,
true
),
new
Sample
(
"Google Play"
,
"3aa39fa2cc27967f"
,
"http://www.youtube.com/api/manifest/dash/id/3aa39fa2cc27967f/source/youtube?"
+
"as=fmp4_audio_clear,webm2_sd_hd_clear&sparams=ip,ipbits,expire,as&ip=0.0.0.0&ipbits=0&"
+
"expire=19000000000&signature=B752B262C6D7262EC4E4EB67901E5D8F7058A81D."
+
"C0358CE1E335417D9A8D88FF192F0D5D8F6DA1B6&key=ik0"
,
DemoUtil
.
TYPE_DASH
_VOD
,
false
,
true
),
+
"C0358CE1E335417D9A8D88FF192F0D5D8F6DA1B6&key=ik0"
,
DemoUtil
.
TYPE_DASH
,
false
,
true
),
};
public
static
final
Sample
[]
SMOOTHSTREAMING
=
new
Sample
[]
{
...
...
@@ -106,32 +106,32 @@ package com.google.android.exoplayer.demo;
"http://www.youtube.com/api/manifest/dash/id/d286538032258a1c/source/youtube?"
+
"as=fmp4_audio_cenc,fmp4_sd_hd_cenc&sparams=ip,ipbits,expire,as&ip=0.0.0.0&ipbits=0"
+
"&expire=19000000000&signature=41EA40A027A125A16292E0A5E3277A3B5FA9B938."
+
"0BB075C396FFDDC97E526E8F77DC26FF9667D0D6&key=ik0"
,
DemoUtil
.
TYPE_DASH
_VOD
,
true
,
true
),
+
"0BB075C396FFDDC97E526E8F77DC26FF9667D0D6&key=ik0"
,
DemoUtil
.
TYPE_DASH
,
true
,
true
),
new
Sample
(
"WV: HDCP not required"
,
"48fcc369939ac96c"
,
"http://www.youtube.com/api/manifest/dash/id/48fcc369939ac96c/source/youtube?"
+
"as=fmp4_audio_cenc,fmp4_sd_hd_cenc&sparams=ip,ipbits,expire,as&ip=0.0.0.0&ipbits=0"
+
"&expire=19000000000&signature=315911BDCEED0FB0C763455BDCC97449DAAFA9E8."
+
"5B41E2EB411F797097A359D6671D2CDE26272373&key=ik0"
,
DemoUtil
.
TYPE_DASH
_VOD
,
true
,
true
),
+
"5B41E2EB411F797097A359D6671D2CDE26272373&key=ik0"
,
DemoUtil
.
TYPE_DASH
,
true
,
true
),
new
Sample
(
"WV: HDCP required"
,
"e06c39f1151da3df"
,
"http://www.youtube.com/api/manifest/dash/id/e06c39f1151da3df/source/youtube?"
+
"as=fmp4_audio_cenc,fmp4_sd_hd_cenc&sparams=ip,ipbits,expire,as&ip=0.0.0.0&ipbits=0"
+
"&expire=19000000000&signature=A47A1E13E7243BD567601A75F79B34644D0DC592."
+
"B09589A34FA23527EFC1552907754BB8033870BD&key=ik0"
,
DemoUtil
.
TYPE_DASH
_VOD
,
true
,
true
),
+
"B09589A34FA23527EFC1552907754BB8033870BD&key=ik0"
,
DemoUtil
.
TYPE_DASH
,
true
,
true
),
new
Sample
(
"WV: Secure video path required"
,
"0894c7c8719b28a0"
,
"http://www.youtube.com/api/manifest/dash/id/0894c7c8719b28a0/source/youtube?"
+
"as=fmp4_audio_cenc,fmp4_sd_hd_cenc&sparams=ip,ipbits,expire,as&ip=0.0.0.0&ipbits=0"
+
"&expire=19000000000&signature=2847EE498970F6B45176766CD2802FEB4D4CB7B2."
+
"A1CA51EC40A1C1039BA800C41500DD448C03EEDA&key=ik0"
,
DemoUtil
.
TYPE_DASH
_VOD
,
true
,
true
),
+
"A1CA51EC40A1C1039BA800C41500DD448C03EEDA&key=ik0"
,
DemoUtil
.
TYPE_DASH
,
true
,
true
),
new
Sample
(
"WV: HDCP + secure video path required"
,
"efd045b1eb61888a"
,
"http://www.youtube.com/api/manifest/dash/id/efd045b1eb61888a/source/youtube?"
+
"as=fmp4_audio_cenc,fmp4_sd_hd_cenc&sparams=ip,ipbits,expire,as&ip=0.0.0.0&ipbits=0"
+
"&expire=19000000000&signature=61611F115EEEC7BADE5536827343FFFE2D83D14F."
+
"2FDF4BFA502FB5865C5C86401314BDDEA4799BD0&key=ik0"
,
DemoUtil
.
TYPE_DASH
_VOD
,
true
,
true
),
+
"2FDF4BFA502FB5865C5C86401314BDDEA4799BD0&key=ik0"
,
DemoUtil
.
TYPE_DASH
,
true
,
true
),
new
Sample
(
"WV: 30s license duration"
,
"f9a34cab7b05881a"
,
"http://www.youtube.com/api/manifest/dash/id/f9a34cab7b05881a/source/youtube?"
+
"as=fmp4_audio_cenc,fmp4_sd_hd_cenc&sparams=ip,ipbits,expire,as&ip=0.0.0.0&ipbits=0"
+
"&expire=19000000000&signature=88DC53943385CED8CF9F37ADD9E9843E3BF621E6."
+
"22727BB612D24AA4FACE4EF62726F9461A9BF57A&key=ik0"
,
DemoUtil
.
TYPE_DASH
_VOD
,
true
,
true
),
+
"22727BB612D24AA4FACE4EF62726F9461A9BF57A&key=ik0"
,
DemoUtil
.
TYPE_DASH
,
true
,
true
),
};
public
static
final
Sample
[]
HLS
=
new
Sample
[]
{
...
...
demo/src/main/java/com/google/android/exoplayer/demo/full/FullPlayerActivity.java
View file @
511dd943
...
...
@@ -19,7 +19,7 @@ import com.google.android.exoplayer.ExoPlayer;
import
com.google.android.exoplayer.VideoSurfaceView
;
import
com.google.android.exoplayer.demo.DemoUtil
;
import
com.google.android.exoplayer.demo.R
;
import
com.google.android.exoplayer.demo.full.player.Dash
Vod
RendererBuilder
;
import
com.google.android.exoplayer.demo.full.player.DashRendererBuilder
;
import
com.google.android.exoplayer.demo.full.player.DefaultRendererBuilder
;
import
com.google.android.exoplayer.demo.full.player.DemoPlayer
;
import
com.google.android.exoplayer.demo.full.player.DemoPlayer.RendererBuilder
;
...
...
@@ -179,8 +179,8 @@ public class FullPlayerActivity extends Activity implements SurfaceHolder.Callba
case
DemoUtil
.
TYPE_SS
:
return
new
SmoothStreamingRendererBuilder
(
userAgent
,
contentUri
.
toString
(),
contentId
,
new
SmoothStreamingTestMediaDrmCallback
(),
debugTextView
);
case
DemoUtil
.
TYPE_DASH
_VOD
:
return
new
Dash
Vod
RendererBuilder
(
userAgent
,
contentUri
.
toString
(),
contentId
,
case
DemoUtil
.
TYPE_DASH
:
return
new
DashRendererBuilder
(
userAgent
,
contentUri
.
toString
(),
contentId
,
new
WidevineTestMediaDrmCallback
(
contentId
),
debugTextView
);
case
DemoUtil
.
TYPE_HLS
:
return
new
HlsRendererBuilder
(
userAgent
,
contentUri
.
toString
(),
contentId
);
...
...
demo/src/main/java/com/google/android/exoplayer/demo/full/player/Dash
Vod
RendererBuilder.java
→
demo/src/main/java/com/google/android/exoplayer/demo/full/player/DashRendererBuilder.java
View file @
511dd943
This diff is collapsed.
Click to expand it.
demo/src/main/java/com/google/android/exoplayer/demo/full/player/SmoothStreamingRendererBuilder.java
View file @
511dd943
...
...
@@ -64,7 +64,7 @@ public class SmoothStreamingRendererBuilder implements RendererBuilder,
private
static
final
int
BUFFER_SEGMENT_SIZE
=
64
*
1024
;
private
static
final
int
VIDEO_BUFFER_SEGMENTS
=
200
;
private
static
final
int
AUDIO_BUFFER_SEGMENTS
=
60
;
private
static
final
int
T
TML
_BUFFER_SEGMENTS
=
2
;
private
static
final
int
T
EXT
_BUFFER_SEGMENTS
=
2
;
private
static
final
int
LIVE_EDGE_LATENCY_MS
=
30000
;
private
final
String
userAgent
;
...
...
@@ -149,10 +149,7 @@ public class SmoothStreamingRendererBuilder implements RendererBuilder,
}
}
}
int
[]
videoTrackIndices
=
new
int
[
videoTrackIndexList
.
size
()];
for
(
int
i
=
0
;
i
<
videoTrackIndexList
.
size
();
i
++)
{
videoTrackIndices
[
i
]
=
videoTrackIndexList
.
get
(
i
);
}
int
[]
videoTrackIndices
=
Util
.
toArray
(
videoTrackIndexList
);
// Build the video renderer.
DataSource
videoDataSource
=
new
UriDataSource
(
userAgent
,
bandwidthMeter
);
...
...
@@ -221,7 +218,7 @@ public class SmoothStreamingRendererBuilder implements RendererBuilder,
}
textChunkSource
=
new
MultiTrackChunkSource
(
textChunkSources
);
ChunkSampleSource
ttmlSampleSource
=
new
ChunkSampleSource
(
textChunkSource
,
loadControl
,
T
TML
_BUFFER_SEGMENTS
*
BUFFER_SEGMENT_SIZE
,
true
,
mainHandler
,
player
,
T
EXT
_BUFFER_SEGMENTS
*
BUFFER_SEGMENT_SIZE
,
true
,
mainHandler
,
player
,
DemoPlayer
.
TYPE_TEXT
);
textRenderer
=
new
TextTrackRenderer
(
ttmlSampleSource
,
new
TtmlParser
(),
player
,
mainHandler
.
getLooper
());
...
...
demo/src/main/java/com/google/android/exoplayer/demo/simple/Dash
Vod
RendererBuilder.java
→
demo/src/main/java/com/google/android/exoplayer/demo/simple/DashRendererBuilder.java
View file @
511dd943
...
...
@@ -40,22 +40,26 @@ import com.google.android.exoplayer.upstream.DefaultBandwidthMeter;
import
com.google.android.exoplayer.upstream.UriDataSource
;
import
com.google.android.exoplayer.util.ManifestFetcher
;
import
com.google.android.exoplayer.util.ManifestFetcher.ManifestCallback
;
import
com.google.android.exoplayer.util.MimeTypes
;
import
com.google.android.exoplayer.util.Util
;
import
android.media.MediaCodec
;
import
android.os.Handler
;
import
java.io.IOException
;
import
java.util.ArrayList
;
import
java.util.List
;
/**
* A {@link RendererBuilder} for DASH
VOD
.
* A {@link RendererBuilder} for DASH.
*/
/* package */
class
Dash
Vod
RendererBuilder
implements
RendererBuilder
,
/* package */
class
DashRendererBuilder
implements
RendererBuilder
,
ManifestCallback
<
MediaPresentationDescription
>
{
private
static
final
int
BUFFER_SEGMENT_SIZE
=
64
*
1024
;
private
static
final
int
VIDEO_BUFFER_SEGMENTS
=
200
;
private
static
final
int
AUDIO_BUFFER_SEGMENTS
=
60
;
private
static
final
int
LIVE_EDGE_LATENCY_MS
=
30000
;
private
final
SimplePlayerActivity
playerActivity
;
private
final
String
userAgent
;
...
...
@@ -63,8 +67,9 @@ import java.util.ArrayList;
private
final
String
contentId
;
private
RendererBuilderCallback
callback
;
private
ManifestFetcher
<
MediaPresentationDescription
>
manifestFetcher
;
public
Dash
Vod
RendererBuilder
(
SimplePlayerActivity
playerActivity
,
String
userAgent
,
String
url
,
public
DashRendererBuilder
(
SimplePlayerActivity
playerActivity
,
String
userAgent
,
String
url
,
String
contentId
)
{
this
.
playerActivity
=
playerActivity
;
this
.
userAgent
=
userAgent
;
...
...
@@ -76,8 +81,8 @@ import java.util.ArrayList;
public
void
buildRenderers
(
RendererBuilderCallback
callback
)
{
this
.
callback
=
callback
;
MediaPresentationDescriptionParser
parser
=
new
MediaPresentationDescriptionParser
();
ManifestFetcher
<
MediaPresentationDescription
>
manifestFetcher
=
new
ManifestFetcher
<
MediaPresentationDescription
>(
parser
,
contentId
,
url
,
userAgent
);
manifestFetcher
=
new
ManifestFetcher
<
MediaPresentationDescription
>(
parser
,
contentId
,
url
,
userAgent
);
manifestFetcher
.
singleLoad
(
playerActivity
.
getMainLooper
(),
this
);
}
...
...
@@ -88,48 +93,50 @@ import java.util.ArrayList;
@Override
public
void
onManifest
(
String
contentId
,
MediaPresentationDescription
manifest
)
{
Period
period
=
manifest
.
periods
.
get
(
0
);
Handler
mainHandler
=
playerActivity
.
getMainHandler
();
LoadControl
loadControl
=
new
DefaultLoadControl
(
new
BufferPool
(
BUFFER_SEGMENT_SIZE
));
DefaultBandwidthMeter
bandwidthMeter
=
new
DefaultBandwidthMeter
();
//
Obtain Representations
for playback.
//
Determine which video representations we should use
for playback.
int
maxDecodableFrameSize
=
MediaCodecUtil
.
maxH264DecodableFrameSize
();
Representation
audioRepresentation
=
null
;
ArrayList
<
Representation
>
videoRepresentationsList
=
new
ArrayList
<
Representation
>();
Period
period
=
manifest
.
periods
.
get
(
0
);
for
(
int
i
=
0
;
i
<
period
.
adaptationSets
.
size
();
i
++)
{
AdaptationSet
adaptationSet
=
period
.
adaptationSets
.
get
(
i
);
int
adaptationSetType
=
adaptationSet
.
type
;
for
(
int
j
=
0
;
j
<
adaptationSet
.
representations
.
size
();
j
++)
{
Representation
representation
=
adaptationSet
.
representations
.
get
(
j
);
if
(
audioRepresentation
==
null
&&
adaptationSetType
==
AdaptationSet
.
TYPE_AUDIO
)
{
audioRepresentation
=
representation
;
}
else
if
(
adaptationSetType
==
AdaptationSet
.
TYPE_VIDEO
)
{
Format
format
=
representation
.
format
;
if
(
format
.
width
*
format
.
height
<=
maxDecodableFrameSize
)
{
videoRepresentationsList
.
add
(
representation
);
}
else
{
// The device isn't capable of playing this stream.
}
}
int
videoAdaptationSetIndex
=
period
.
getAdaptationSetIndex
(
AdaptationSet
.
TYPE_VIDEO
);
List
<
Representation
>
videoRepresentations
=
period
.
adaptationSets
.
get
(
videoAdaptationSetIndex
).
representations
;
ArrayList
<
Integer
>
videoRepresentationIndexList
=
new
ArrayList
<
Integer
>();
for
(
int
i
=
0
;
i
<
videoRepresentations
.
size
();
i
++)
{
Format
format
=
videoRepresentations
.
get
(
i
).
format
;
if
(
format
.
width
*
format
.
height
>
maxDecodableFrameSize
)
{
// Filtering stream that device cannot play
}
else
if
(!
format
.
mimeType
.
equals
(
MimeTypes
.
VIDEO_MP4
)
&&
!
format
.
mimeType
.
equals
(
MimeTypes
.
VIDEO_WEBM
))
{
// Filtering unsupported mime type
}
else
{
videoRepresentationIndexList
.
add
(
i
);
}
}
Representation
[]
videoRepresentations
=
new
Representation
[
videoRepresentationsList
.
size
()];
videoRepresentationsList
.
toArray
(
videoRepresentations
);
// Build the video renderer.
DataSource
videoDataSource
=
new
UriDataSource
(
userAgent
,
bandwidthMeter
);
ChunkSource
videoChunkSource
=
new
DashChunkSource
(
videoDataSource
,
new
AdaptiveEvaluator
(
bandwidthMeter
),
videoRepresentations
);
ChunkSampleSource
videoSampleSource
=
new
ChunkSampleSource
(
videoChunkSource
,
loadControl
,
VIDEO_BUFFER_SEGMENTS
*
BUFFER_SEGMENT_SIZE
,
true
);
MediaCodecVideoTrackRenderer
videoRenderer
=
new
MediaCodecVideoTrackRenderer
(
videoSampleSource
,
MediaCodec
.
VIDEO_SCALING_MODE_SCALE_TO_FIT
,
0
,
mainHandler
,
playerActivity
,
50
);
final
MediaCodecVideoTrackRenderer
videoRenderer
;
if
(
videoRepresentationIndexList
.
isEmpty
())
{
videoRenderer
=
null
;
}
else
{
int
[]
videoRepresentationIndices
=
Util
.
toArray
(
videoRepresentationIndexList
);
DataSource
videoDataSource
=
new
UriDataSource
(
userAgent
,
bandwidthMeter
);
ChunkSource
videoChunkSource
=
new
DashChunkSource
(
manifestFetcher
,
videoAdaptationSetIndex
,
videoRepresentationIndices
,
videoDataSource
,
new
AdaptiveEvaluator
(
bandwidthMeter
),
LIVE_EDGE_LATENCY_MS
);
ChunkSampleSource
videoSampleSource
=
new
ChunkSampleSource
(
videoChunkSource
,
loadControl
,
VIDEO_BUFFER_SEGMENTS
*
BUFFER_SEGMENT_SIZE
,
true
);
videoRenderer
=
new
MediaCodecVideoTrackRenderer
(
videoSampleSource
,
MediaCodec
.
VIDEO_SCALING_MODE_SCALE_TO_FIT
,
0
,
mainHandler
,
playerActivity
,
50
);
}
// Build the audio renderer.
int
audioAdaptationSetIndex
=
period
.
getAdaptationSetIndex
(
AdaptationSet
.
TYPE_AUDIO
);
DataSource
audioDataSource
=
new
UriDataSource
(
userAgent
,
bandwidthMeter
);
ChunkSource
audioChunkSource
=
new
DashChunkSource
(
audioDataSource
,
new
FormatEvaluator
.
FixedEvaluator
(),
audioRepresentation
);
ChunkSource
audioChunkSource
=
new
DashChunkSource
(
manifestFetcher
,
audioAdaptationSetIndex
,
new
int
[]
{
0
},
audioDataSource
,
new
FormatEvaluator
.
FixedEvaluator
(),
LIVE_EDGE_LATENCY_MS
);
SampleSource
audioSampleSource
=
new
ChunkSampleSource
(
audioChunkSource
,
loadControl
,
AUDIO_BUFFER_SEGMENTS
*
BUFFER_SEGMENT_SIZE
,
true
);
MediaCodecAudioTrackRenderer
audioRenderer
=
new
MediaCodecAudioTrackRenderer
(
...
...
demo/src/main/java/com/google/android/exoplayer/demo/simple/SimplePlayerActivity.java
View file @
511dd943
...
...
@@ -164,8 +164,8 @@ public class SimplePlayerActivity extends Activity implements SurfaceHolder.Call
case
DemoUtil
.
TYPE_SS
:
return
new
SmoothStreamingRendererBuilder
(
this
,
userAgent
,
contentUri
.
toString
(),
contentId
);
case
DemoUtil
.
TYPE_DASH
_VOD
:
return
new
Dash
Vod
RendererBuilder
(
this
,
userAgent
,
contentUri
.
toString
(),
contentId
);
case
DemoUtil
.
TYPE_DASH
:
return
new
DashRendererBuilder
(
this
,
userAgent
,
contentUri
.
toString
(),
contentId
);
case
DemoUtil
.
TYPE_HLS
:
return
new
HlsRendererBuilder
(
this
,
userAgent
,
contentUri
.
toString
(),
contentId
);
default
:
...
...
demo/src/main/java/com/google/android/exoplayer/demo/simple/SmoothStreamingRendererBuilder.java
View file @
511dd943
...
...
@@ -38,6 +38,7 @@ import com.google.android.exoplayer.upstream.DefaultBandwidthMeter;
import
com.google.android.exoplayer.upstream.UriDataSource
;
import
com.google.android.exoplayer.util.ManifestFetcher
;
import
com.google.android.exoplayer.util.ManifestFetcher.ManifestCallback
;
import
com.google.android.exoplayer.util.Util
;
import
android.media.MediaCodec
;
import
android.os.Handler
;
...
...
@@ -115,10 +116,7 @@ import java.util.ArrayList;
}
}
}
int
[]
videoTrackIndices
=
new
int
[
videoTrackIndexList
.
size
()];
for
(
int
i
=
0
;
i
<
videoTrackIndexList
.
size
();
i
++)
{
videoTrackIndices
[
i
]
=
videoTrackIndexList
.
get
(
i
);
}
int
[]
videoTrackIndices
=
Util
.
toArray
(
videoTrackIndexList
);
// Build the video renderer.
DataSource
videoDataSource
=
new
UriDataSource
(
userAgent
,
bandwidthMeter
);
...
...
library/src/main/java/com/google/android/exoplayer/C.java
View file @
511dd943
...
...
@@ -21,6 +21,16 @@ package com.google.android.exoplayer;
public
final
class
C
{
/**
* Represents an unknown microsecond time or duration.
*/
public
static
final
long
UNKNOWN_TIME_US
=
-
1L
;
/**
* The number of microseconds in one second.
*/
public
static
final
long
MICROS_PER_SECOND
=
1000000L
;
/**
* Represents an unbounded length of data.
*/
public
static
final
int
LENGTH_UNBOUNDED
=
-
1
;
...
...
library/src/main/java/com/google/android/exoplayer/FrameworkSampleSource.java
View file @
511dd943
...
...
@@ -71,10 +71,10 @@ public final class FrameworkSampleSource implements SampleSource {
trackInfos
=
new
TrackInfo
[
trackStates
.
length
];
for
(
int
i
=
0
;
i
<
trackStates
.
length
;
i
++)
{
android
.
media
.
MediaFormat
format
=
extractor
.
getTrackFormat
(
i
);
long
duration
=
format
.
containsKey
(
android
.
media
.
MediaFormat
.
KEY_DURATION
)
?
format
.
getLong
(
android
.
media
.
MediaFormat
.
KEY_DURATION
)
:
TrackRenderer
.
UNKNOWN_TIME_US
;
long
duration
Us
=
format
.
containsKey
(
android
.
media
.
MediaFormat
.
KEY_DURATION
)
?
format
.
getLong
(
android
.
media
.
MediaFormat
.
KEY_DURATION
)
:
C
.
UNKNOWN_TIME_US
;
String
mime
=
format
.
getString
(
android
.
media
.
MediaFormat
.
KEY_MIME
);
trackInfos
[
i
]
=
new
TrackInfo
(
mime
,
duration
);
trackInfos
[
i
]
=
new
TrackInfo
(
mime
,
duration
Us
);
}
prepared
=
true
;
}
...
...
library/src/main/java/com/google/android/exoplayer/TrackInfo.java
View file @
511dd943
...
...
@@ -20,9 +20,21 @@ package com.google.android.exoplayer;
*/
public
final
class
TrackInfo
{
/**
* The mime type.
*/
public
final
String
mimeType
;
/**
* The duration in microseconds, or {@link C#UNKNOWN_TIME_US} if the duration is unknown.
*/
public
final
long
durationUs
;
/**
* @param mimeType The mime type.
* @param durationUs The duration in microseconds, or {@link C#UNKNOWN_TIME_US} if the duration
* is unknown.
*/
public
TrackInfo
(
String
mimeType
,
long
durationUs
)
{
this
.
mimeType
=
mimeType
;
this
.
durationUs
=
durationUs
;
...
...
library/src/main/java/com/google/android/exoplayer/TrackRenderer.java
View file @
511dd943
...
...
@@ -67,9 +67,9 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
protected
static
final
int
STATE_STARTED
=
3
;
/**
* Represents an unknown time or duration.
* Represents an unknown time or duration.
Equal to {@link C#UNKNOWN_TIME_US}.
*/
public
static
final
long
UNKNOWN_TIME_US
=
-
1
;
public
static
final
long
UNKNOWN_TIME_US
=
C
.
UNKNOWN_TIME_US
;
// -1
/**
* Represents a time or duration that should match the duration of the longest track whose
* duration is known.
...
...
library/src/main/java/com/google/android/exoplayer/audio/AudioCapabilitiesReceiver.java
View file @
511dd943
...
...
@@ -40,7 +40,7 @@ public final class AudioCapabilitiesReceiver {
}
/** Default to stereo PCM on SDK <
=
21 and when HDMI is unplugged. */
/** Default to stereo PCM on SDK < 21 and when HDMI is unplugged. */
private
static
final
AudioCapabilities
DEFAULT_AUDIO_CAPABILITIES
=
new
AudioCapabilities
(
new
int
[]
{
AudioFormat
.
ENCODING_PCM_16BIT
},
2
);
...
...
library/src/main/java/com/google/android/exoplayer/audio/AudioTrack.java
View file @
511dd943
...
...
@@ -15,9 +15,11 @@
*/
package
com
.
google
.
android
.
exoplayer
.
audio
;
import
com.google.android.exoplayer.C
;
import
com.google.android.exoplayer.util.Assertions
;
import
com.google.android.exoplayer.util.Util
;
import
android.annotation.SuppressLint
;
import
android.annotation.TargetApi
;
import
android.media.AudioFormat
;
import
android.media.AudioManager
;
...
...
@@ -80,22 +82,23 @@ public final class AudioTrack {
private
static
final
String
TAG
=
"AudioTrack"
;
private
static
final
long
MICROS_PER_SECOND
=
1000000L
;
/**
* AudioTrack timestamps are deemed spurious if they are offset from the system clock by more
* than this amount.
*
* <p>This is a fail safe that should not be required on correctly functioning devices.
*/
private
static
final
long
MAX_AUDIO_TIMESTAMP_OFFSET_US
=
10
*
MICROS_PER_SECOND
;
private
static
final
long
MAX_AUDIO_TIMESTAMP_OFFSET_US
=
10
*
C
.
MICROS_PER_SECOND
;
/**
* AudioTrack latencies are deemed impossibly large if they are greater than this amount.
*
* <p>This is a fail safe that should not be required on correctly functioning devices.
*/
private
static
final
long
MAX_LATENCY_US
=
10
*
MICROS_PER_SECOND
;
private
static
final
long
MAX_LATENCY_US
=
10
*
C
.
MICROS_PER_SECOND
;
/** Value for ac3Bitrate before the bitrate has been calculated. */
private
static
final
int
UNKNOWN_AC3_BITRATE
=
0
;
private
static
final
int
START_NOT_SET
=
0
;
private
static
final
int
START_IN_SYNC
=
1
;
...
...
@@ -139,6 +142,11 @@ public final class AudioTrack {
private
int
temporaryBufferOffset
;
private
int
temporaryBufferSize
;
private
boolean
isAc3
;
/** Bitrate measured in kilobits per second, if {@link #isAc3} is true. */
private
int
ac3Bitrate
;
/** Constructs an audio track using the default minimum buffer size multiplier. */
public
AudioTrack
()
{
this
(
DEFAULT_MIN_BUFFER_MULTIPLICATION_FACTOR
);
...
...
@@ -277,6 +285,7 @@ public final class AudioTrack {
* @param bufferSize The total size of the playback buffer in bytes. Specify 0 to use a buffer
* size based on the minimum for format.
*/
@SuppressLint
(
"InlinedApi"
)
public
void
reconfigure
(
MediaFormat
format
,
int
encoding
,
int
bufferSize
)
{
int
channelCount
=
format
.
getInteger
(
MediaFormat
.
KEY_CHANNEL_COUNT
);
int
channelConfig
;
...
...
@@ -300,8 +309,9 @@ public final class AudioTrack {
int
sampleRate
=
format
.
getInteger
(
MediaFormat
.
KEY_SAMPLE_RATE
);
// TODO: Does channelConfig determine channelCount?
boolean
isAc3
=
encoding
==
AudioFormat
.
ENCODING_AC3
||
encoding
==
AudioFormat
.
ENCODING_E_AC3
;
if
(
audioTrack
!=
null
&&
this
.
sampleRate
==
sampleRate
&&
this
.
channelConfig
==
channelConfig
)
{
&&
this
.
channelConfig
==
channelConfig
&&
!
this
.
isAc3
&&
!
isAc3
)
{
// We already have an existing audio track with the correct sample rate and channel config.
return
;
}
...
...
@@ -315,7 +325,8 @@ public final class AudioTrack {
bufferSize
==
0
?
(
int
)
(
minBufferMultiplicationFactor
*
minBufferSize
)
:
bufferSize
;
this
.
sampleRate
=
sampleRate
;
this
.
channelConfig
=
channelConfig
;
this
.
isAc3
=
isAc3
;
ac3Bitrate
=
UNKNOWN_AC3_BITRATE
;
// Calculated on receiving the first buffer if isAc3 is true.
frameSize
=
2
*
channelCount
;
// 2 bytes per 16 bit sample * number of channels.
}
...
...
@@ -353,6 +364,14 @@ public final class AudioTrack {
int
result
=
0
;
if
(
temporaryBufferSize
==
0
&&
size
!=
0
)
{
if
(
isAc3
&&
ac3Bitrate
==
UNKNOWN_AC3_BITRATE
)
{
// Each AC-3 buffer contains 1536 frames of audio, so the AudioTrack playback position
// advances by 1536 per buffer (32 ms at 48 kHz). Calculate the bitrate in kbit/s.
int
unscaledAc3Bitrate
=
size
*
8
*
sampleRate
;
int
divisor
=
1000
*
1536
;
ac3Bitrate
=
(
unscaledAc3Bitrate
+
divisor
/
2
)
/
divisor
;
}
// 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
=
presentationTimeUs
-
framesToDurationUs
(
bytesToFrames
(
size
));
...
...
@@ -616,19 +635,24 @@ public final class AudioTrack {
}
private
long
framesToBytes
(
long
frameCount
)
{
// This method is unused on SDK >= 21.
return
frameCount
*
frameSize
;
}
private
long
bytesToFrames
(
long
byteCount
)
{
return
byteCount
/
frameSize
;
if
(
isAc3
)
{
return
byteCount
*
8
*
sampleRate
/
(
1000
*
ac3Bitrate
);
}
else
{
return
byteCount
/
frameSize
;
}
}
private
long
framesToDurationUs
(
long
frameCount
)
{
return
(
frameCount
*
MICROS_PER_SECOND
)
/
sampleRate
;
return
(
frameCount
*
C
.
MICROS_PER_SECOND
)
/
sampleRate
;
}
private
long
durationUsToFrames
(
long
durationUs
)
{
return
(
durationUs
*
sampleRate
)
/
MICROS_PER_SECOND
;
return
(
durationUs
*
sampleRate
)
/
C
.
MICROS_PER_SECOND
;
}
private
void
resetSyncParams
()
{
...
...
library/src/main/java/com/google/android/exoplayer/chunk/MultiTrackChunkSource.java
View file @
511dd943
...
...
@@ -46,6 +46,10 @@ public class MultiTrackChunkSource implements ChunkSource, ExoPlayerComponent {
this
.
selectedSource
=
sources
[
0
];
}
public
MultiTrackChunkSource
(
List
<
ChunkSource
>
sources
)
{
this
(
toChunkSourceArray
(
sources
));
}
/**
* Gets the number of tracks that this source can switch between. May be called safely from any
* thread.
...
...
@@ -107,4 +111,10 @@ public class MultiTrackChunkSource implements ChunkSource, ExoPlayerComponent {
selectedSource
.
onChunkLoadError
(
chunk
,
e
);
}
private
static
ChunkSource
[]
toChunkSourceArray
(
List
<
ChunkSource
>
sources
)
{
ChunkSource
[]
chunkSourceArray
=
new
ChunkSource
[
sources
.
size
()];
sources
.
toArray
(
chunkSourceArray
);
return
chunkSourceArray
;
}
}
library/src/main/java/com/google/android/exoplayer/chunk/SingleSampleChunkSource.java
View file @
511dd943
...
...
@@ -15,6 +15,7 @@
*/
package
com
.
google
.
android
.
exoplayer
.
chunk
;
import
com.google.android.exoplayer.C
;
import
com.google.android.exoplayer.MediaFormat
;
import
com.google.android.exoplayer.TrackInfo
;
import
com.google.android.exoplayer.upstream.DataSource
;
...
...
@@ -42,7 +43,8 @@ public class SingleSampleChunkSource implements ChunkSource {
* @param dataSource A {@link DataSource} suitable for loading the sample data.
* @param dataSpec Defines the location of the sample.
* @param format The format of the sample.
* @param durationUs The duration of the sample in microseconds.
* @param durationUs The duration of the sample in microseconds, or {@link C#UNKNOWN_TIME_US} if
* the duration is unknown.
* @param mediaFormat The sample media format. May be null.
*/
public
SingleSampleChunkSource
(
DataSource
dataSource
,
DataSpec
dataSpec
,
Format
format
,
...
...
library/src/main/java/com/google/android/exoplayer/dash/DashChunkSource.java
View file @
511dd943
This diff is collapsed.
Click to expand it.
library/src/main/java/com/google/android/exoplayer/dash/mpd/Period.java
View file @
511dd943
...
...
@@ -56,4 +56,21 @@ public class Period {
this
.
adaptationSets
=
Collections
.
unmodifiableList
(
adaptationSets
);
}
/**
* Returns the index of the first adaptation set of a given type, or -1 if no adaptation set of
* the specified type exists.
*
* @param type An adaptation set type.
* @return The index of the first adaptation set of the specified type, or -1.
*/
public
int
getAdaptationSetIndex
(
int
type
)
{
int
adaptationCount
=
adaptationSets
.
size
();
for
(
int
i
=
0
;
i
<
adaptationCount
;
i
++)
{
if
(
adaptationSets
.
get
(
i
).
type
==
type
)
{
return
i
;
}
}
return
-
1
;
}
}
library/src/main/java/com/google/android/exoplayer/dash/mpd/SegmentBase.java
View file @
511dd943
...
...
@@ -15,6 +15,7 @@
*/
package
com
.
google
.
android
.
exoplayer
.
dash
.
mpd
;
import
com.google.android.exoplayer.C
;
import
com.google.android.exoplayer.util.Util
;
import
android.net.Uri
;
...
...
@@ -141,11 +142,12 @@ public abstract class SegmentBase {
public
final
long
getSegmentDurationUs
(
int
sequenceNumber
)
{
if
(
segmentTimeline
!=
null
)
{
return
(
segmentTimeline
.
get
(
sequenceNumber
-
startNumber
).
duration
*
1000000
)
/
timescale
;
long
duration
=
segmentTimeline
.
get
(
sequenceNumber
-
startNumber
).
duration
;
return
(
duration
*
C
.
MICROS_PER_SECOND
)
/
timescale
;
}
else
{
return
sequenceNumber
==
getLastSegmentNum
()
?
(
periodDurationMs
*
1000
)
-
getSegmentTimeUs
(
sequenceNumber
)
:
((
duration
*
1000000L
)
/
timescale
);
?
(
(
periodDurationMs
*
1000
)
-
getSegmentTimeUs
(
sequenceNumber
)
)
:
((
duration
*
C
.
MICROS_PER_SECOND
)
/
timescale
);
}
}
...
...
@@ -157,7 +159,7 @@ public abstract class SegmentBase {
}
else
{
unscaledSegmentTime
=
(
sequenceNumber
-
startNumber
)
*
duration
;
}
return
Util
.
scaleLargeTimestamp
(
unscaledSegmentTime
,
1000000
,
timescale
);
return
Util
.
scaleLargeTimestamp
(
unscaledSegmentTime
,
C
.
MICROS_PER_SECOND
,
timescale
);
}
public
abstract
RangedUri
getSegmentUrl
(
Representation
representation
,
int
index
);
...
...
library/src/main/java/com/google/android/exoplayer/parser/mp4/FragmentedMp4Extractor.java
View file @
511dd943
...
...
@@ -15,6 +15,7 @@
*/
package
com
.
google
.
android
.
exoplayer
.
parser
.
mp4
;
import
com.google.android.exoplayer.C
;
import
com.google.android.exoplayer.MediaFormat
;
import
com.google.android.exoplayer.ParserException
;
import
com.google.android.exoplayer.SampleHolder
;
...
...
@@ -26,6 +27,7 @@ import com.google.android.exoplayer.upstream.NonBlockingInputStream;
import
com.google.android.exoplayer.util.Assertions
;
import
com.google.android.exoplayer.util.CodecSpecificDataUtil
;
import
com.google.android.exoplayer.util.MimeTypes
;
import
com.google.android.exoplayer.util.Util
;
import
android.annotation.SuppressLint
;
import
android.media.MediaCodec
;
...
...
@@ -1053,6 +1055,7 @@ public final class FragmentedMp4Extractor implements Extractor {
long
offset
=
firstOffset
;
long
time
=
earliestPresentationTime
;
long
timeUs
=
Util
.
scaleLargeTimestamp
(
time
,
C
.
MICROS_PER_SECOND
,
timescale
);
for
(
int
i
=
0
;
i
<
referenceCount
;
i
++)
{
int
firstInt
=
atom
.
readInt
();
...
...
@@ -1067,10 +1070,10 @@ public final class FragmentedMp4Extractor implements Extractor {
// Calculate time and duration values such that any rounding errors are consistent. i.e. That
// timesUs[i] + durationsUs[i] == timesUs[i + 1].
timesUs
[
i
]
=
(
time
*
1000000L
)
/
timescale
;
long
nextTimeUs
=
((
time
+
referenceDuration
)
*
1000000L
)
/
timescale
;
durationsUs
[
i
]
=
nextTimeUs
-
timesUs
[
i
];
timesUs
[
i
]
=
timeUs
;
time
+=
referenceDuration
;
timeUs
=
Util
.
scaleLargeTimestamp
(
time
,
C
.
MICROS_PER_SECOND
,
timescale
);
durationsUs
[
i
]
=
timeUs
-
timesUs
[
i
];
atom
.
skip
(
4
);
offset
+=
sizes
[
i
];
...
...
library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingManifest.java
View file @
511dd943
...
...
@@ -15,6 +15,7 @@
*/
package
com
.
google
.
android
.
exoplayer
.
smoothstreaming
;
import
com.google.android.exoplayer.C
;
import
com.google.android.exoplayer.util.Assertions
;
import
com.google.android.exoplayer.util.Util
;
...
...
@@ -31,30 +32,77 @@ import java.util.UUID;
*/
public
class
SmoothStreamingManifest
{
private
static
final
long
MICROS_PER_SECOND
=
1000000L
;
/**
* The client manifest major version.
*/
public
final
int
majorVersion
;
/**
* The client manifest minor version.
*/
public
final
int
minorVersion
;
public
final
long
timescale
;
/**
* The number of fragments in a lookahead, or -1 if the lookahead is unspecified.
*/
public
final
int
lookAheadCount
;
/**
* True if the manifest describes a live presentation still in progress. False otherwise.
*/
public
final
boolean
isLive
;
/**
* Content protection information, or null if the content is not protected.
*/
public
final
ProtectionElement
protectionElement
;
/**
* The contained stream elements.
*/
public
final
StreamElement
[]
streamElements
;
/**
* The overall presentation duration of the media in microseconds, or {@link C#UNKNOWN_TIME_US}
* if the duration is unknown.
*/
public
final
long
durationUs
;
/**
* The length of the trailing window for a live broadcast in microseconds, or
* {@link C#UNKNOWN_TIME_US} if the stream is not live or if the window length is unspecified.
*/
public
final
long
dvrWindowLengthUs
;
/**
* @param majorVersion The client manifest major version.
* @param minorVersion The client manifest minor version.
* @param timescale The timescale of the media as the number of units that pass in one second.
* @param duration The overall presentation duration in units of the timescale attribute, or 0
* if the duration is unknown.
* @param dvrWindowLength The length of the trailing window in units of the timescale attribute,
* or 0 if this attribute is unspecified or not applicable.
* @param lookAheadCount The number of fragments in a lookahead, or -1 if this attribute is
* unspecified or not applicable.
* @param isLive True if the manifest describes a live presentation still in progress. False
* otherwise.
* @param protectionElement Content protection information, or null if the content is not
* protected.
* @param streamElements The contained stream elements.
*/
public
SmoothStreamingManifest
(
int
majorVersion
,
int
minorVersion
,
long
timescale
,
long
duration
,
long
dvrWindowLength
,
int
lookAheadCount
,
boolean
isLive
,
ProtectionElement
protectionElement
,
StreamElement
[]
streamElements
)
{
this
.
majorVersion
=
majorVersion
;
this
.
minorVersion
=
minorVersion
;
this
.
timescale
=
timescale
;
this
.
lookAheadCount
=
lookAheadCount
;
this
.
isLive
=
isLive
;
this
.
protectionElement
=
protectionElement
;
this
.
streamElements
=
streamElements
;
dvrWindowLengthUs
=
Util
.
scaleLargeTimestamp
(
dvrWindowLength
,
MICROS_PER_SECOND
,
timescale
);
durationUs
=
Util
.
scaleLargeTimestamp
(
duration
,
MICROS_PER_SECOND
,
timescale
);
dvrWindowLengthUs
=
dvrWindowLength
==
0
?
C
.
UNKNOWN_TIME_US
:
Util
.
scaleLargeTimestamp
(
dvrWindowLength
,
C
.
MICROS_PER_SECOND
,
timescale
);
durationUs
=
duration
==
0
?
C
.
UNKNOWN_TIME_US
:
Util
.
scaleLargeTimestamp
(
duration
,
C
.
MICROS_PER_SECOND
,
timescale
);
}
/**
...
...
@@ -176,9 +224,9 @@ public class SmoothStreamingManifest {
this
.
chunkCount
=
chunkStartTimes
.
size
();
this
.
chunkStartTimes
=
chunkStartTimes
;
lastChunkDurationUs
=
Util
.
scaleLargeTimestamp
(
lastChunkDuration
,
MICROS_PER_SECOND
,
timescale
);
Util
.
scaleLargeTimestamp
(
lastChunkDuration
,
C
.
MICROS_PER_SECOND
,
timescale
);
chunkStartTimesUs
=
Util
.
scaleLargeTimestamps
(
chunkStartTimes
,
MICROS_PER_SECOND
,
timescale
);
Util
.
scaleLargeTimestamps
(
chunkStartTimes
,
C
.
MICROS_PER_SECOND
,
timescale
);
}
/**
...
...
library/src/main/java/com/google/android/exoplayer/text/ttml/TtmlParser.java
View file @
511dd943
...
...
@@ -15,6 +15,7 @@
*/
package
com
.
google
.
android
.
exoplayer
.
text
.
ttml
;
import
com.google.android.exoplayer.C
;
import
com.google.android.exoplayer.ParserException
;
import
com.google.android.exoplayer.text.Subtitle
;
import
com.google.android.exoplayer.text.SubtitleParser
;
...
...
@@ -254,7 +255,7 @@ public class TtmlParser implements SubtitleParser {
String
subframes
=
matcher
.
group
(
6
);
durationSeconds
+=
(
subframes
!=
null
)
?
((
double
)
Long
.
parseLong
(
subframes
))
/
subframeRate
/
frameRate
:
0
;
return
(
long
)
(
durationSeconds
*
1000000
);
return
(
long
)
(
durationSeconds
*
C
.
MICROS_PER_SECOND
);
}
matcher
=
OFFSET_TIME
.
matcher
(
time
);
if
(
matcher
.
matches
())
{
...
...
@@ -274,7 +275,7 @@ public class TtmlParser implements SubtitleParser {
}
else
if
(
unit
.
equals
(
"t"
))
{
offsetSeconds
/=
tickRate
;
}
return
(
long
)
(
offsetSeconds
*
1000000
);
return
(
long
)
(
offsetSeconds
*
C
.
MICROS_PER_SECOND
);
}
throw
new
ParserException
(
"Malformed time expression: "
+
time
);
}
...
...
library/src/main/java/com/google/android/exoplayer/util/ManifestFetcher.java
View file @
511dd943
...
...
@@ -18,6 +18,7 @@ package com.google.android.exoplayer.util;
import
com.google.android.exoplayer.upstream.Loader
;
import
com.google.android.exoplayer.upstream.Loader.Loadable
;
import
android.os.Handler
;
import
android.os.Looper
;
import
android.os.SystemClock
;
import
android.util.Pair
;
...
...
@@ -29,13 +30,26 @@ import java.net.URLConnection;
import
java.util.concurrent.CancellationException
;
/**
* Performs both single and repeated loads of media man
f
ifests.
* Performs both single and repeated loads of media manifests.
*
* @param <T> The type of manifest.
*/
public
class
ManifestFetcher
<
T
>
implements
Loader
.
Callback
{
/**
* Interface definition for a callback to be notified of {@link ManifestFetcher} events.
*/
public
interface
EventListener
{
public
void
onManifestRefreshStarted
();
public
void
onManifestRefreshed
();
public
void
onManifestError
(
IOException
e
);
}
/**
* Callback for the result of a single load.
*
* @param <T> The type of manifest.
...
...
@@ -61,9 +75,12 @@ public class ManifestFetcher<T> implements Loader.Callback {
}
/* package */
final
ManifestParser
<
T
>
parser
;
/* package */
final
String
manifestUrl
;
/* package */
final
String
contentId
;
/* package */
final
String
userAgent
;
private
final
Handler
eventHandler
;
private
final
EventListener
eventListener
;
/* package */
volatile
String
manifestUrl
;
private
int
enabledCount
;
private
Loader
loader
;
...
...
@@ -76,6 +93,11 @@ public class ManifestFetcher<T> implements Loader.Callback {
private
volatile
T
manifest
;
private
volatile
long
manifestLoadTimestamp
;
public
ManifestFetcher
(
ManifestParser
<
T
>
parser
,
String
contentId
,
String
manifestUrl
,
String
userAgent
)
{
this
(
parser
,
contentId
,
manifestUrl
,
userAgent
,
null
,
null
);
}
/**
* @param parser A parser to parse the loaded manifest data.
* @param contentId The content id of the content being loaded. May be null.
...
...
@@ -83,11 +105,22 @@ public class ManifestFetcher<T> implements Loader.Callback {
* @param userAgent The User-Agent string that should be used.
*/
public
ManifestFetcher
(
ManifestParser
<
T
>
parser
,
String
contentId
,
String
manifestUrl
,
String
userAgent
)
{
String
userAgent
,
Handler
eventHandler
,
EventListener
eventListener
)
{
this
.
parser
=
parser
;
this
.
contentId
=
contentId
;
this
.
manifestUrl
=
manifestUrl
;
this
.
userAgent
=
userAgent
;
this
.
eventHandler
=
eventHandler
;
this
.
eventListener
=
eventListener
;
}
/**
* Updates the manifest location.
*
* @param manifestUrl The manifest location.
*/
public
void
updateManifestUrl
(
String
manifestUrl
)
{
this
.
manifestUrl
=
manifestUrl
;
}
/**
...
...
@@ -173,6 +206,7 @@ public class ManifestFetcher<T> implements Loader.Callback {
if
(!
loader
.
isLoading
())
{
currentLoadable
=
new
ManifestLoadable
();
loader
.
startLoading
(
currentLoadable
,
this
);
notifyManifestRefreshStarted
();
}
}
...
...
@@ -187,6 +221,8 @@ public class ManifestFetcher<T> implements Loader.Callback {
manifestLoadTimestamp
=
SystemClock
.
elapsedRealtime
();
loadExceptionCount
=
0
;
loadException
=
null
;
notifyManifestRefreshed
();
}
@Override
...
...
@@ -204,12 +240,47 @@ public class ManifestFetcher<T> implements Loader.Callback {
loadExceptionCount
++;
loadExceptionTimestamp
=
SystemClock
.
elapsedRealtime
();
loadException
=
new
IOException
(
exception
);
notifyManifestError
(
loadException
);
}
private
long
getRetryDelayMillis
(
long
errorCount
)
{
return
Math
.
min
((
errorCount
-
1
)
*
1000
,
5000
);
}
private
void
notifyManifestRefreshStarted
()
{
if
(
eventHandler
!=
null
&&
eventListener
!=
null
)
{
eventHandler
.
post
(
new
Runnable
()
{
@Override
public
void
run
()
{
eventListener
.
onManifestRefreshStarted
();
}
});
}
}
private
void
notifyManifestRefreshed
()
{
if
(
eventHandler
!=
null
&&
eventListener
!=
null
)
{
eventHandler
.
post
(
new
Runnable
()
{
@Override
public
void
run
()
{
eventListener
.
onManifestRefreshed
();
}
});
}
}
private
void
notifyManifestError
(
final
IOException
e
)
{
if
(
eventHandler
!=
null
&&
eventListener
!=
null
)
{
eventHandler
.
post
(
new
Runnable
()
{
@Override
public
void
run
()
{
eventListener
.
onManifestError
(
e
);
}
});
}
}
private
class
SingleFetchHelper
implements
Loader
.
Callback
{
private
final
Looper
callbackLooper
;
...
...
library/src/main/java/com/google/android/exoplayer/util/PlayerControl.java
View file @
511dd943
...
...
@@ -70,12 +70,14 @@ public class PlayerControl implements MediaPlayerControl {
@Override
public
int
getCurrentPosition
()
{
return
(
int
)
exoPlayer
.
getCurrentPosition
();
return
exoPlayer
.
getDuration
()
==
ExoPlayer
.
UNKNOWN_TIME
?
0
:
(
int
)
exoPlayer
.
getCurrentPosition
();
}
@Override
public
int
getDuration
()
{
return
(
int
)
exoPlayer
.
getDuration
();
return
exoPlayer
.
getDuration
()
==
ExoPlayer
.
UNKNOWN_TIME
?
0
:
(
int
)
exoPlayer
.
getDuration
();
}
@Override
...
...
@@ -95,8 +97,9 @@ public class PlayerControl implements MediaPlayerControl {
@Override
public
void
seekTo
(
int
timeMillis
)
{
// MediaController arrow keys generate unbounded values.
exoPlayer
.
seekTo
(
Math
.
min
(
Math
.
max
(
0
,
timeMillis
),
getDuration
()));
long
seekPosition
=
exoPlayer
.
getDuration
()
==
ExoPlayer
.
UNKNOWN_TIME
?
0
:
Math
.
min
(
Math
.
max
(
0
,
timeMillis
),
getDuration
());
exoPlayer
.
seekTo
(
seekPosition
);
}
}
library/src/main/java/com/google/android/exoplayer/util/Util.java
View file @
511dd943
...
...
@@ -399,4 +399,22 @@ public final class Util {
return
scaledTimestamps
;
}
/**
* Converts a list of integers to a primitive array.
*
* @param list A list of integers.
* @return The list in array form, or null if the input list was null.
*/
public
static
int
[]
toArray
(
List
<
Integer
>
list
)
{
if
(
list
==
null
)
{
return
null
;
}
int
length
=
list
.
size
();
int
[]
intArray
=
new
int
[
length
];
for
(
int
i
=
0
;
i
<
length
;
i
++)
{
intArray
[
i
]
=
list
.
get
(
i
);
}
return
intArray
;
}
}
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