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
430d06d4
authored
Feb 20, 2015
by
ojw28
Browse files
Options
_('Browse Files')
Download
Plain Diff
Merge pull request #313 from google/dev
dev -> dev-webm-vp9-opus
parents
654d37fe
6d14fc33
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
391 additions
and
62 deletions
demo/src/main/java/com/google/android/exoplayer/demo/player/DashRendererBuilder.java
library/src/main/java/com/google/android/exoplayer/dash/DashChunkSource.java
library/src/main/java/com/google/android/exoplayer/dash/mpd/UtcTimingElement.java
library/src/main/java/com/google/android/exoplayer/dash/mpd/UtcTimingElementResolver.java
library/src/main/java/com/google/android/exoplayer/hls/parser/SeiReader.java
library/src/main/java/com/google/android/exoplayer/text/eia608/Eia608Parser.java
library/src/main/java/com/google/android/exoplayer/util/ManifestFetcher.java
library/src/main/java/com/google/android/exoplayer/util/NetworkLoadable.java
demo/src/main/java/com/google/android/exoplayer/demo/player/DashRendererBuilder.java
View file @
430d06d4
...
@@ -37,6 +37,9 @@ import com.google.android.exoplayer.dash.mpd.MediaPresentationDescription;
...
@@ -37,6 +37,9 @@ import com.google.android.exoplayer.dash.mpd.MediaPresentationDescription;
import
com.google.android.exoplayer.dash.mpd.MediaPresentationDescriptionParser
;
import
com.google.android.exoplayer.dash.mpd.MediaPresentationDescriptionParser
;
import
com.google.android.exoplayer.dash.mpd.Period
;
import
com.google.android.exoplayer.dash.mpd.Period
;
import
com.google.android.exoplayer.dash.mpd.Representation
;
import
com.google.android.exoplayer.dash.mpd.Representation
;
import
com.google.android.exoplayer.dash.mpd.UtcTimingElement
;
import
com.google.android.exoplayer.dash.mpd.UtcTimingElementResolver
;
import
com.google.android.exoplayer.dash.mpd.UtcTimingElementResolver.UtcTimingCallback
;
import
com.google.android.exoplayer.demo.DemoUtil
;
import
com.google.android.exoplayer.demo.DemoUtil
;
import
com.google.android.exoplayer.demo.player.DemoPlayer.RendererBuilder
;
import
com.google.android.exoplayer.demo.player.DemoPlayer.RendererBuilder
;
import
com.google.android.exoplayer.demo.player.DemoPlayer.RendererBuilderCallback
;
import
com.google.android.exoplayer.demo.player.DemoPlayer.RendererBuilderCallback
;
...
@@ -59,6 +62,7 @@ import android.annotation.TargetApi;
...
@@ -59,6 +62,7 @@ import android.annotation.TargetApi;
import
android.media.MediaCodec
;
import
android.media.MediaCodec
;
import
android.media.UnsupportedSchemeException
;
import
android.media.UnsupportedSchemeException
;
import
android.os.Handler
;
import
android.os.Handler
;
import
android.util.Log
;
import
android.util.Pair
;
import
android.util.Pair
;
import
android.widget.TextView
;
import
android.widget.TextView
;
...
@@ -70,7 +74,9 @@ import java.util.List;
...
@@ -70,7 +74,9 @@ import java.util.List;
* A {@link RendererBuilder} for DASH.
* A {@link RendererBuilder} for DASH.
*/
*/
public
class
DashRendererBuilder
implements
RendererBuilder
,
public
class
DashRendererBuilder
implements
RendererBuilder
,
ManifestCallback
<
MediaPresentationDescription
>
{
ManifestCallback
<
MediaPresentationDescription
>,
UtcTimingCallback
{
private
static
final
String
TAG
=
"DashRendererBuilder"
;
private
static
final
int
BUFFER_SEGMENT_SIZE
=
64
*
1024
;
private
static
final
int
BUFFER_SEGMENT_SIZE
=
64
*
1024
;
private
static
final
int
VIDEO_BUFFER_SEGMENTS
=
200
;
private
static
final
int
VIDEO_BUFFER_SEGMENTS
=
200
;
...
@@ -96,6 +102,9 @@ public class DashRendererBuilder implements RendererBuilder,
...
@@ -96,6 +102,9 @@ public class DashRendererBuilder implements RendererBuilder,
private
RendererBuilderCallback
callback
;
private
RendererBuilderCallback
callback
;
private
ManifestFetcher
<
MediaPresentationDescription
>
manifestFetcher
;
private
ManifestFetcher
<
MediaPresentationDescription
>
manifestFetcher
;
private
MediaPresentationDescription
manifest
;
private
long
elapsedRealtimeOffset
;
public
DashRendererBuilder
(
String
userAgent
,
String
url
,
String
contentId
,
public
DashRendererBuilder
(
String
userAgent
,
String
url
,
String
contentId
,
MediaDrmCallback
drmCallback
,
TextView
debugTextView
,
AudioCapabilities
audioCapabilities
)
{
MediaDrmCallback
drmCallback
,
TextView
debugTextView
,
AudioCapabilities
audioCapabilities
)
{
this
.
userAgent
=
userAgent
;
this
.
userAgent
=
userAgent
;
...
@@ -117,12 +126,35 @@ public class DashRendererBuilder implements RendererBuilder,
...
@@ -117,12 +126,35 @@ public class DashRendererBuilder implements RendererBuilder,
}
}
@Override
@Override
public
void
onManifest
(
String
contentId
,
MediaPresentationDescription
manifest
)
{
this
.
manifest
=
manifest
;
if
(
manifest
.
dynamic
&&
manifest
.
utcTiming
!=
null
)
{
UtcTimingElementResolver
.
resolveTimingElement
(
userAgent
,
manifest
.
utcTiming
,
manifestFetcher
.
getManifestLoadTimestamp
(),
this
);
}
else
{
buildRenderers
();
}
}
@Override
public
void
onManifestError
(
String
contentId
,
IOException
e
)
{
public
void
onManifestError
(
String
contentId
,
IOException
e
)
{
callback
.
onRenderersError
(
e
);
callback
.
onRenderersError
(
e
);
}
}
@Override
@Override
public
void
onManifest
(
String
contentId
,
MediaPresentationDescription
manifest
)
{
public
void
onTimestampResolved
(
UtcTimingElement
utcTiming
,
long
elapsedRealtimeOffset
)
{
this
.
elapsedRealtimeOffset
=
elapsedRealtimeOffset
;
buildRenderers
();
}
@Override
public
void
onTimestampError
(
UtcTimingElement
utcTiming
,
IOException
e
)
{
Log
.
e
(
TAG
,
"Failed to resolve UtcTiming element ["
+
utcTiming
+
"]"
,
e
);
// Be optimistic and continue in the hope that the device clock is correct.
buildRenderers
();
}
private
void
buildRenderers
()
{
Period
period
=
manifest
.
periods
.
get
(
0
);
Period
period
=
manifest
.
periods
.
get
(
0
);
Handler
mainHandler
=
player
.
getMainHandler
();
Handler
mainHandler
=
player
.
getMainHandler
();
LoadControl
loadControl
=
new
DefaultLoadControl
(
new
BufferPool
(
BUFFER_SEGMENT_SIZE
));
LoadControl
loadControl
=
new
DefaultLoadControl
(
new
BufferPool
(
BUFFER_SEGMENT_SIZE
));
...
@@ -207,7 +239,7 @@ public class DashRendererBuilder implements RendererBuilder,
...
@@ -207,7 +239,7 @@ public class DashRendererBuilder implements RendererBuilder,
DataSource
videoDataSource
=
new
UriDataSource
(
userAgent
,
bandwidthMeter
);
DataSource
videoDataSource
=
new
UriDataSource
(
userAgent
,
bandwidthMeter
);
ChunkSource
videoChunkSource
=
new
DashChunkSource
(
manifestFetcher
,
videoAdaptationSetIndex
,
ChunkSource
videoChunkSource
=
new
DashChunkSource
(
manifestFetcher
,
videoAdaptationSetIndex
,
videoRepresentationIndices
,
videoDataSource
,
new
AdaptiveEvaluator
(
bandwidthMeter
),
videoRepresentationIndices
,
videoDataSource
,
new
AdaptiveEvaluator
(
bandwidthMeter
),
LIVE_EDGE_LATENCY_MS
);
LIVE_EDGE_LATENCY_MS
,
elapsedRealtimeOffset
);
ChunkSampleSource
videoSampleSource
=
new
ChunkSampleSource
(
videoChunkSource
,
loadControl
,
ChunkSampleSource
videoSampleSource
=
new
ChunkSampleSource
(
videoChunkSource
,
loadControl
,
VIDEO_BUFFER_SEGMENTS
*
BUFFER_SEGMENT_SIZE
,
true
,
mainHandler
,
player
,
VIDEO_BUFFER_SEGMENTS
*
BUFFER_SEGMENT_SIZE
,
true
,
mainHandler
,
player
,
DemoPlayer
.
TYPE_VIDEO
);
DemoPlayer
.
TYPE_VIDEO
);
...
@@ -230,7 +262,8 @@ public class DashRendererBuilder implements RendererBuilder,
...
@@ -230,7 +262,8 @@ public class DashRendererBuilder implements RendererBuilder,
audioTrackNameList
.
add
(
format
.
id
+
" ("
+
format
.
numChannels
+
"ch, "
+
audioTrackNameList
.
add
(
format
.
id
+
" ("
+
format
.
numChannels
+
"ch, "
+
format
.
audioSamplingRate
+
"Hz)"
);
format
.
audioSamplingRate
+
"Hz)"
);
audioChunkSourceList
.
add
(
new
DashChunkSource
(
manifestFetcher
,
audioAdaptationSetIndex
,
audioChunkSourceList
.
add
(
new
DashChunkSource
(
manifestFetcher
,
audioAdaptationSetIndex
,
new
int
[]
{
i
},
audioDataSource
,
audioEvaluator
,
LIVE_EDGE_LATENCY_MS
));
new
int
[]
{
i
},
audioDataSource
,
audioEvaluator
,
LIVE_EDGE_LATENCY_MS
,
elapsedRealtimeOffset
));
haveAc3Tracks
|=
AC_3_CODEC
.
equals
(
format
.
codecs
)
||
E_AC_3_CODEC
.
equals
(
format
.
codecs
);
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.
// Filter out non-AC-3 tracks if there is an AC-3 track, to avoid having to switch renderers.
...
@@ -285,7 +318,7 @@ public class DashRendererBuilder implements RendererBuilder,
...
@@ -285,7 +318,7 @@ public class DashRendererBuilder implements RendererBuilder,
Representation
representation
=
representations
.
get
(
j
);
Representation
representation
=
representations
.
get
(
j
);
textTrackNameList
.
add
(
representation
.
format
.
id
);
textTrackNameList
.
add
(
representation
.
format
.
id
);
textChunkSourceList
.
add
(
new
DashChunkSource
(
manifestFetcher
,
i
,
new
int
[]
{
j
},
textChunkSourceList
.
add
(
new
DashChunkSource
(
manifestFetcher
,
i
,
new
int
[]
{
j
},
textDataSource
,
textEvaluator
,
LIVE_EDGE_LATENCY_MS
));
textDataSource
,
textEvaluator
,
LIVE_EDGE_LATENCY_MS
,
elapsedRealtimeOffset
));
}
}
}
}
}
}
...
...
library/src/main/java/com/google/android/exoplayer/dash/DashChunkSource.java
View file @
430d06d4
...
@@ -86,6 +86,7 @@ public class DashChunkSource implements ChunkSource {
...
@@ -86,6 +86,7 @@ public class DashChunkSource implements ChunkSource {
private
final
Evaluation
evaluation
;
private
final
Evaluation
evaluation
;
private
final
StringBuilder
headerBuilder
;
private
final
StringBuilder
headerBuilder
;
private
final
long
liveEdgeLatencyUs
;
private
final
long
liveEdgeLatencyUs
;
private
final
long
elapsedRealtimeOffsetUs
;
private
final
int
maxWidth
;
private
final
int
maxWidth
;
private
final
int
maxHeight
;
private
final
int
maxHeight
;
...
@@ -140,7 +141,8 @@ public class DashChunkSource implements ChunkSource {
...
@@ -140,7 +141,8 @@ public class DashChunkSource implements ChunkSource {
*/
*/
public
DashChunkSource
(
MediaPresentationDescription
manifest
,
int
adaptationSetIndex
,
public
DashChunkSource
(
MediaPresentationDescription
manifest
,
int
adaptationSetIndex
,
int
[]
representationIndices
,
DataSource
dataSource
,
FormatEvaluator
formatEvaluator
)
{
int
[]
representationIndices
,
DataSource
dataSource
,
FormatEvaluator
formatEvaluator
)
{
this
(
null
,
manifest
,
adaptationSetIndex
,
representationIndices
,
dataSource
,
formatEvaluator
,
0
);
this
(
null
,
manifest
,
adaptationSetIndex
,
representationIndices
,
dataSource
,
formatEvaluator
,
0
,
0
);
}
}
/**
/**
...
@@ -162,18 +164,21 @@ public class DashChunkSource implements ChunkSource {
...
@@ -162,18 +164,21 @@ public class DashChunkSource implements ChunkSource {
* manifest). Choosing a small value will minimize latency introduced by the player, however
* manifest). Choosing a small value will minimize latency introduced by the player, however
* note that the value sets an upper bound on the length of media that the player can buffer.
* note that the value sets an upper bound on the length of media that the player can buffer.
* Hence a small value may increase the probability of rebuffering and playback failures.
* Hence a small value may increase the probability of rebuffering and playback failures.
* @param elapsedRealtimeOffsetMs If known, an estimate of the instantaneous difference between
* server-side unix time and {@link SystemClock#elapsedRealtime()} in milliseconds, specified
* as the server's unix time minus the local elapsed time. It unknown, set to 0.
*/
*/
public
DashChunkSource
(
ManifestFetcher
<
MediaPresentationDescription
>
manifestFetcher
,
public
DashChunkSource
(
ManifestFetcher
<
MediaPresentationDescription
>
manifestFetcher
,
int
adaptationSetIndex
,
int
[]
representationIndices
,
DataSource
dataSource
,
int
adaptationSetIndex
,
int
[]
representationIndices
,
DataSource
dataSource
,
FormatEvaluator
formatEvaluator
,
long
liveEdgeLatencyMs
)
{
FormatEvaluator
formatEvaluator
,
long
liveEdgeLatencyMs
,
long
elapsedRealtimeOffsetMs
)
{
this
(
manifestFetcher
,
manifestFetcher
.
getManifest
(),
adaptationSetIndex
,
representationIndices
,
this
(
manifestFetcher
,
manifestFetcher
.
getManifest
(),
adaptationSetIndex
,
representationIndices
,
dataSource
,
formatEvaluator
,
liveEdgeLatencyMs
*
1000
);
dataSource
,
formatEvaluator
,
liveEdgeLatencyMs
*
1000
,
elapsedRealtimeOffsetMs
*
1000
);
}
}
private
DashChunkSource
(
ManifestFetcher
<
MediaPresentationDescription
>
manifestFetcher
,
private
DashChunkSource
(
ManifestFetcher
<
MediaPresentationDescription
>
manifestFetcher
,
MediaPresentationDescription
initialManifest
,
int
adaptationSetIndex
,
MediaPresentationDescription
initialManifest
,
int
adaptationSetIndex
,
int
[]
representationIndices
,
DataSource
dataSource
,
FormatEvaluator
formatEvaluator
,
int
[]
representationIndices
,
DataSource
dataSource
,
FormatEvaluator
formatEvaluator
,
long
liveEdgeLatencyUs
)
{
long
liveEdgeLatencyUs
,
long
elapsedRealtimeOffsetUs
)
{
this
.
manifestFetcher
=
manifestFetcher
;
this
.
manifestFetcher
=
manifestFetcher
;
this
.
currentManifest
=
initialManifest
;
this
.
currentManifest
=
initialManifest
;
this
.
adaptationSetIndex
=
adaptationSetIndex
;
this
.
adaptationSetIndex
=
adaptationSetIndex
;
...
@@ -181,6 +186,7 @@ public class DashChunkSource implements ChunkSource {
...
@@ -181,6 +186,7 @@ public class DashChunkSource implements ChunkSource {
this
.
dataSource
=
dataSource
;
this
.
dataSource
=
dataSource
;
this
.
evaluator
=
formatEvaluator
;
this
.
evaluator
=
formatEvaluator
;
this
.
liveEdgeLatencyUs
=
liveEdgeLatencyUs
;
this
.
liveEdgeLatencyUs
=
liveEdgeLatencyUs
;
this
.
elapsedRealtimeOffsetUs
=
elapsedRealtimeOffsetUs
;
this
.
evaluation
=
new
Evaluation
();
this
.
evaluation
=
new
Evaluation
();
this
.
headerBuilder
=
new
StringBuilder
();
this
.
headerBuilder
=
new
StringBuilder
();
...
@@ -326,8 +332,12 @@ public class DashChunkSource implements ChunkSource {
...
@@ -326,8 +332,12 @@ public class DashChunkSource implements ChunkSource {
return
;
return
;
}
}
// TODO: Use UtcTimingElement where possible.
long
nowUs
;
long
nowUs
=
System
.
currentTimeMillis
()
*
1000
;
if
(
elapsedRealtimeOffsetUs
!=
0
)
{
nowUs
=
(
SystemClock
.
elapsedRealtime
()
*
1000
)
+
elapsedRealtimeOffsetUs
;
}
else
{
nowUs
=
System
.
currentTimeMillis
()
*
1000
;
}
int
firstAvailableSegmentNum
=
segmentIndex
.
getFirstSegmentNum
();
int
firstAvailableSegmentNum
=
segmentIndex
.
getFirstSegmentNum
();
int
lastAvailableSegmentNum
=
segmentIndex
.
getLastSegmentNum
();
int
lastAvailableSegmentNum
=
segmentIndex
.
getLastSegmentNum
();
...
...
library/src/main/java/com/google/android/exoplayer/dash/mpd/UtcTimingElement.java
View file @
430d06d4
...
@@ -28,4 +28,9 @@ public class UtcTimingElement {
...
@@ -28,4 +28,9 @@ public class UtcTimingElement {
this
.
value
=
value
;
this
.
value
=
value
;
}
}
@Override
public
String
toString
()
{
return
schemeIdUri
+
", "
+
value
;
}
}
}
library/src/main/java/com/google/android/exoplayer/dash/mpd/UtcTimingElementResolver.java
0 → 100644
View file @
430d06d4
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com
.
google
.
android
.
exoplayer
.
dash
.
mpd
;
import
com.google.android.exoplayer.ParserException
;
import
com.google.android.exoplayer.upstream.Loader
;
import
com.google.android.exoplayer.upstream.Loader.Loadable
;
import
com.google.android.exoplayer.util.Assertions
;
import
com.google.android.exoplayer.util.NetworkLoadable
;
import
com.google.android.exoplayer.util.Util
;
import
android.os.SystemClock
;
import
java.io.BufferedReader
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.InputStreamReader
;
import
java.text.ParseException
;
import
java.text.SimpleDateFormat
;
import
java.util.Locale
;
import
java.util.concurrent.CancellationException
;
/**
* Resolves a {@link UtcTimingElement}.
*/
public
class
UtcTimingElementResolver
implements
Loader
.
Callback
{
/**
* Callback for timing element resolution.
*/
public
interface
UtcTimingCallback
{
/**
* Invoked when the element has been resolved.
*
* @param utcTiming The element that was resolved.
* @param elapsedRealtimeOffset The offset between the resolved UTC time and
* {@link SystemClock#elapsedRealtime()} in milliseconds, specified as the UTC time minus
* the local elapsed time.
*/
void
onTimestampResolved
(
UtcTimingElement
utcTiming
,
long
elapsedRealtimeOffset
);
/**
* Invoked when the element was not successfully resolved.
*
* @param utcTiming The element that was not resolved.
* @param e The cause of the failure.
*/
void
onTimestampError
(
UtcTimingElement
utcTiming
,
IOException
e
);
}
private
static
final
int
TYPE_XS
=
0
;
private
static
final
int
TYPE_ISO
=
1
;
private
final
String
userAgent
;
private
final
UtcTimingElement
timingElement
;
private
final
long
timingElementElapsedRealtime
;
private
final
UtcTimingCallback
callback
;
private
Loader
singleUseLoader
;
private
HttpTimestampLoadable
singleUseLoadable
;
/**
* Resolves a {@link UtcTimingElement}.
*
* @param userAgent A user agent to use should network requests be necessary.
* @param timingElement The element to resolve.
* @param timingElementElapsedRealtime The {@link SystemClock#elapsedRealtime()} timestamp at
* which the element was obtained. Used if the element contains a timestamp directly.
* @param callback The callback to invoke on resolution or failure.
*/
public
static
void
resolveTimingElement
(
String
userAgent
,
UtcTimingElement
timingElement
,
long
timingElementElapsedRealtime
,
UtcTimingCallback
callback
)
{
UtcTimingElementResolver
resolver
=
new
UtcTimingElementResolver
(
userAgent
,
timingElement
,
timingElementElapsedRealtime
,
callback
);
resolver
.
resolve
();
}
private
UtcTimingElementResolver
(
String
userAgent
,
UtcTimingElement
timingElement
,
long
timingElementElapsedRealtime
,
UtcTimingCallback
callback
)
{
this
.
userAgent
=
userAgent
;
this
.
timingElement
=
Assertions
.
checkNotNull
(
timingElement
);
this
.
timingElementElapsedRealtime
=
timingElementElapsedRealtime
;
this
.
callback
=
Assertions
.
checkNotNull
(
callback
);
}
private
void
resolve
()
{
String
scheme
=
timingElement
.
schemeIdUri
;
if
(
Util
.
areEqual
(
scheme
,
"urn:mpeg:dash:utc:direct:2012"
))
{
resolveDirect
();
}
else
if
(
Util
.
areEqual
(
scheme
,
"urn:mpeg:dash:utc:http-iso:2014"
))
{
resolveHttp
(
TYPE_ISO
);
}
else
if
(
Util
.
areEqual
(
scheme
,
"urn:mpeg:dash:utc:http-xsdate:2012"
)
||
Util
.
areEqual
(
scheme
,
"urn:mpeg:dash:utc:http-xsdate:2014"
))
{
resolveHttp
(
TYPE_XS
);
}
else
{
// Unsupported scheme.
callback
.
onTimestampError
(
timingElement
,
new
IOException
(
"Unsupported utc timing scheme"
));
}
}
private
void
resolveDirect
()
{
try
{
long
utcTimestamp
=
Util
.
parseXsDateTime
(
timingElement
.
value
);
long
elapsedRealtimeOffset
=
utcTimestamp
-
timingElementElapsedRealtime
;
callback
.
onTimestampResolved
(
timingElement
,
elapsedRealtimeOffset
);
}
catch
(
ParseException
e
)
{
callback
.
onTimestampError
(
timingElement
,
new
ParserException
(
e
));
}
}
private
void
resolveHttp
(
int
type
)
{
singleUseLoader
=
new
Loader
(
"utctiming"
);
singleUseLoadable
=
new
HttpTimestampLoadable
(
timingElement
.
value
,
userAgent
,
type
);
singleUseLoader
.
startLoading
(
singleUseLoadable
,
this
);
}
@Override
public
void
onLoadCanceled
(
Loadable
loadable
)
{
onLoadError
(
loadable
,
new
IOException
(
"Load cancelled"
,
new
CancellationException
()));
}
@Override
public
void
onLoadCompleted
(
Loadable
loadable
)
{
releaseLoader
();
long
elapsedRealtimeOffset
=
singleUseLoadable
.
getResult
()
-
SystemClock
.
elapsedRealtime
();
callback
.
onTimestampResolved
(
timingElement
,
elapsedRealtimeOffset
);
}
@Override
public
void
onLoadError
(
Loadable
loadable
,
IOException
exception
)
{
releaseLoader
();
callback
.
onTimestampError
(
timingElement
,
exception
);
}
private
void
releaseLoader
()
{
singleUseLoader
.
release
();
}
private
static
class
HttpTimestampLoadable
extends
NetworkLoadable
<
Long
>
{
private
final
int
type
;
public
HttpTimestampLoadable
(
String
url
,
String
userAgent
,
int
type
)
{
super
(
url
,
userAgent
);
this
.
type
=
type
;
}
@Override
protected
Long
parse
(
String
connectionUrl
,
InputStream
inputStream
,
String
inputEncoding
)
throws
ParserException
,
IOException
{
BufferedReader
reader
=
new
BufferedReader
(
new
InputStreamReader
(
inputStream
));
String
firstLine
=
reader
.
readLine
();
try
{
switch
(
type
)
{
case
TYPE_XS:
return
Util
.
parseXsDateTime
(
firstLine
);
case
TYPE_ISO:
// TODO: It may be necessary to handle timestamp offsets from UTC.
SimpleDateFormat
format
=
new
SimpleDateFormat
(
"yyyy-MM-dd'T'HH:mm:ss'Z'"
,
Locale
.
US
);
return
format
.
parse
(
firstLine
).
getTime
();
default
:
// Never happens.
throw
new
RuntimeException
();
}
}
catch
(
ParseException
e
)
{
throw
new
ParserException
(
e
);
}
}
}
}
library/src/main/java/com/google/android/exoplayer/hls/parser/SeiReader.java
View file @
430d06d4
...
@@ -56,7 +56,7 @@ import com.google.android.exoplayer.util.ParsableByteArray;
...
@@ -56,7 +56,7 @@ import com.google.android.exoplayer.util.ParsableByteArray;
payloadSize
+=
b
;
payloadSize
+=
b
;
}
while
(
b
==
0xFF
);
}
while
(
b
==
0xFF
);
// Process the payload. We only support EIA-608 payloads currently.
// Process the payload. We only support EIA-608 payloads currently.
if
(
Eia608Parser
.
i
nspectSeiMessage
(
payloadType
,
payloadSize
,
seiBuffer
))
{
if
(
Eia608Parser
.
i
sSeiMessageEia608
(
payloadType
,
payloadSize
,
seiBuffer
))
{
startSample
(
pesTimeUs
);
startSample
(
pesTimeUs
);
appendData
(
seiBuffer
,
payloadSize
);
appendData
(
seiBuffer
,
payloadSize
);
commitSample
(
true
);
commitSample
(
true
);
...
...
library/src/main/java/com/google/android/exoplayer/text/eia608/Eia608Parser.java
View file @
430d06d4
...
@@ -189,7 +189,7 @@ public class Eia608Parser {
...
@@ -189,7 +189,7 @@ public class Eia608Parser {
* @param payload A {@link ParsableByteArray} containing the payload.
* @param payload A {@link ParsableByteArray} containing the payload.
* @return True if the sei message contains EIA-608. False otherwise.
* @return True if the sei message contains EIA-608. False otherwise.
*/
*/
public
static
boolean
i
nspectSeiMessage
(
int
payloadType
,
int
payloadLength
,
public
static
boolean
i
sSeiMessageEia608
(
int
payloadType
,
int
payloadLength
,
ParsableByteArray
payload
)
{
ParsableByteArray
payload
)
{
if
(
payloadType
!=
PAYLOAD_TYPE_CC
||
payloadLength
<
8
)
{
if
(
payloadType
!=
PAYLOAD_TYPE_CC
||
payloadLength
<
8
)
{
return
false
;
return
false
;
...
...
library/src/main/java/com/google/android/exoplayer/util/ManifestFetcher.java
View file @
430d06d4
...
@@ -15,6 +15,7 @@
...
@@ -15,6 +15,7 @@
*/
*/
package
com
.
google
.
android
.
exoplayer
.
util
;
package
com
.
google
.
android
.
exoplayer
.
util
;
import
com.google.android.exoplayer.ParserException
;
import
com.google.android.exoplayer.upstream.Loader
;
import
com.google.android.exoplayer.upstream.Loader
;
import
com.google.android.exoplayer.upstream.Loader.Loadable
;
import
com.google.android.exoplayer.upstream.Loader.Loadable
;
...
@@ -25,8 +26,6 @@ import android.util.Pair;
...
@@ -25,8 +26,6 @@ import android.util.Pair;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.InputStream
;
import
java.net.URL
;
import
java.net.URLConnection
;
import
java.util.concurrent.CancellationException
;
import
java.util.concurrent.CancellationException
;
/**
/**
...
@@ -84,7 +83,7 @@ public class ManifestFetcher<T> implements Loader.Callback {
...
@@ -84,7 +83,7 @@ public class ManifestFetcher<T> implements Loader.Callback {
private
int
enabledCount
;
private
int
enabledCount
;
private
Loader
loader
;
private
Loader
loader
;
private
ManifestLoadable
currentLoadable
;
private
ManifestLoadable
<
T
>
currentLoadable
;
private
int
loadExceptionCount
;
private
int
loadExceptionCount
;
private
long
loadExceptionTimestamp
;
private
long
loadExceptionTimestamp
;
...
@@ -204,7 +203,7 @@ public class ManifestFetcher<T> implements Loader.Callback {
...
@@ -204,7 +203,7 @@ public class ManifestFetcher<T> implements Loader.Callback {
loader
=
new
Loader
(
"manifestLoader"
);
loader
=
new
Loader
(
"manifestLoader"
);
}
}
if
(!
loader
.
isLoading
())
{
if
(!
loader
.
isLoading
())
{
currentLoadable
=
new
ManifestLoadable
(
);
currentLoadable
=
new
ManifestLoadable
<
T
>(
manifestUrl
,
userAgent
,
contentId
,
parser
);
loader
.
startLoading
(
currentLoadable
,
this
);
loader
.
startLoading
(
currentLoadable
,
this
);
notifyManifestRefreshStarted
();
notifyManifestRefreshStarted
();
}
}
...
@@ -217,7 +216,7 @@ public class ManifestFetcher<T> implements Loader.Callback {
...
@@ -217,7 +216,7 @@ public class ManifestFetcher<T> implements Loader.Callback {
return
;
return
;
}
}
manifest
=
currentLoadable
.
result
;
manifest
=
currentLoadable
.
getResult
()
;
manifestLoadTimestamp
=
SystemClock
.
elapsedRealtime
();
manifestLoadTimestamp
=
SystemClock
.
elapsedRealtime
();
loadExceptionCount
=
0
;
loadExceptionCount
=
0
;
loadException
=
null
;
loadException
=
null
;
...
@@ -244,6 +243,11 @@ public class ManifestFetcher<T> implements Loader.Callback {
...
@@ -244,6 +243,11 @@ public class ManifestFetcher<T> implements Loader.Callback {
notifyManifestError
(
loadException
);
notifyManifestError
(
loadException
);
}
}
/* package */
void
onSingleFetchCompleted
(
T
result
)
{
manifest
=
result
;
manifestLoadTimestamp
=
SystemClock
.
elapsedRealtime
();
}
private
long
getRetryDelayMillis
(
long
errorCount
)
{
private
long
getRetryDelayMillis
(
long
errorCount
)
{
return
Math
.
min
((
errorCount
-
1
)
*
1000
,
5000
);
return
Math
.
min
((
errorCount
-
1
)
*
1000
,
5000
);
}
}
...
@@ -286,13 +290,13 @@ public class ManifestFetcher<T> implements Loader.Callback {
...
@@ -286,13 +290,13 @@ public class ManifestFetcher<T> implements Loader.Callback {
private
final
Looper
callbackLooper
;
private
final
Looper
callbackLooper
;
private
final
ManifestCallback
<
T
>
wrappedCallback
;
private
final
ManifestCallback
<
T
>
wrappedCallback
;
private
final
Loader
singleUseLoader
;
private
final
Loader
singleUseLoader
;
private
final
ManifestLoadable
singleUseLoadable
;
private
final
ManifestLoadable
<
T
>
singleUseLoadable
;
public
SingleFetchHelper
(
Looper
callbackLooper
,
ManifestCallback
<
T
>
wrappedCallback
)
{
public
SingleFetchHelper
(
Looper
callbackLooper
,
ManifestCallback
<
T
>
wrappedCallback
)
{
this
.
callbackLooper
=
callbackLooper
;
this
.
callbackLooper
=
callbackLooper
;
this
.
wrappedCallback
=
wrappedCallback
;
this
.
wrappedCallback
=
wrappedCallback
;
singleUseLoader
=
new
Loader
(
"manifestLoader:single"
);
singleUseLoader
=
new
Loader
(
"manifestLoader:single"
);
singleUseLoadable
=
new
ManifestLoadable
(
);
singleUseLoadable
=
new
ManifestLoadable
<
T
>(
manifestUrl
,
userAgent
,
contentId
,
parser
);
}
}
public
void
startLoading
()
{
public
void
startLoading
()
{
...
@@ -302,9 +306,9 @@ public class ManifestFetcher<T> implements Loader.Callback {
...
@@ -302,9 +306,9 @@ public class ManifestFetcher<T> implements Loader.Callback {
@Override
@Override
public
void
onLoadCompleted
(
Loadable
loadable
)
{
public
void
onLoadCompleted
(
Loadable
loadable
)
{
try
{
try
{
manifest
=
singleUseLoadable
.
result
;
T
result
=
singleUseLoadable
.
getResult
()
;
manifestLoadTimestamp
=
SystemClock
.
elapsedRealtime
(
);
onSingleFetchCompleted
(
result
);
wrappedCallback
.
onManifest
(
contentId
,
singleUseLoadable
.
result
);
wrappedCallback
.
onManifest
(
contentId
,
result
);
}
finally
{
}
finally
{
releaseLoader
();
releaseLoader
();
}
}
...
@@ -336,50 +340,22 @@ public class ManifestFetcher<T> implements Loader.Callback {
...
@@ -336,50 +340,22 @@ public class ManifestFetcher<T> implements Loader.Callback {
}
}
private
class
ManifestLoadable
implements
Loadable
{
private
static
class
ManifestLoadable
<
T
>
extends
NetworkLoadable
<
T
>
{
private
static
final
int
TIMEOUT_MILLIS
=
10000
;
/* package */
volatile
T
result
;
private
final
String
contentId
;
private
volatile
boolean
isCanceled
;
private
final
ManifestParser
<
T
>
parser
;
@Override
public
void
cancelLoad
()
{
// We don't actually cancel anything, but we need to record the cancellation so that
// isLoadCanceled can return the correct value.
isCanceled
=
true
;
}
@Override
public
ManifestLoadable
(
String
url
,
String
userAgent
,
String
contentId
,
public
boolean
isLoadCanceled
()
{
ManifestParser
<
T
>
parser
)
{
return
isCanceled
;
super
(
url
,
userAgent
);
this
.
contentId
=
contentId
;
this
.
parser
=
parser
;
}
}
@Override
@Override
public
void
load
()
throws
IOException
,
InterruptedException
{
protected
T
parse
(
String
connectionUrl
,
InputStream
inputStream
,
String
inputEncoding
)
String
inputEncoding
;
throws
ParserException
,
IOException
{
InputStream
inputStream
=
null
;
return
parser
.
parse
(
inputStream
,
inputEncoding
,
contentId
,
Util
.
parseBaseUri
(
connectionUrl
));
try
{
URLConnection
connection
=
configureConnection
(
new
URL
(
manifestUrl
));
inputStream
=
connection
.
getInputStream
();
inputEncoding
=
connection
.
getContentEncoding
();
result
=
parser
.
parse
(
inputStream
,
inputEncoding
,
contentId
,
Util
.
parseBaseUri
(
connection
.
getURL
().
toString
()));
}
finally
{
if
(
inputStream
!=
null
)
{
inputStream
.
close
();
}
}
}
private
URLConnection
configureConnection
(
URL
url
)
throws
IOException
{
URLConnection
connection
=
url
.
openConnection
();
connection
.
setConnectTimeout
(
TIMEOUT_MILLIS
);
connection
.
setReadTimeout
(
TIMEOUT_MILLIS
);
connection
.
setDoOutput
(
false
);
connection
.
setRequestProperty
(
"User-Agent"
,
userAgent
);
connection
.
connect
();
return
connection
;
}
}
}
}
...
...
library/src/main/java/com/google/android/exoplayer/util/NetworkLoadable.java
0 → 100644
View file @
430d06d4
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com
.
google
.
android
.
exoplayer
.
util
;
import
com.google.android.exoplayer.ParserException
;
import
com.google.android.exoplayer.upstream.Loader.Loadable
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.net.URL
;
import
java.net.URLConnection
;
/**
* A {@link Loadable} for loading an object over the network.
*
* @param <T> The type of the object being loaded.
*/
public
abstract
class
NetworkLoadable
<
T
>
implements
Loadable
{
public
static
final
int
DEFAULT_TIMEOUT_MILLIS
=
10000
;
private
final
String
url
;
private
final
String
userAgent
;
private
final
int
timeoutMillis
;
private
volatile
T
result
;
private
volatile
boolean
isCanceled
;
/**
* @param url The url from which the object should be loaded.
* @param userAgent The user agent to use when requesting the object.
*/
public
NetworkLoadable
(
String
url
,
String
userAgent
)
{
this
(
url
,
userAgent
,
DEFAULT_TIMEOUT_MILLIS
);
}
/**
* @param url The url from which the object should be loaded.
* @param userAgent The user agent to use when requesting the object.
* @param timeoutMillis The desired http timeout in milliseconds.
*/
public
NetworkLoadable
(
String
url
,
String
userAgent
,
int
timeoutMillis
)
{
this
.
url
=
url
;
this
.
userAgent
=
userAgent
;
this
.
timeoutMillis
=
timeoutMillis
;
}
/**
* Returns the loaded object, or null if an object has not been loaded.
*/
public
final
T
getResult
()
{
return
result
;
}
@Override
public
final
void
cancelLoad
()
{
// We don't actually cancel anything, but we need to record the cancellation so that
// isLoadCanceled can return the correct value.
isCanceled
=
true
;
}
@Override
public
final
boolean
isLoadCanceled
()
{
return
isCanceled
;
}
@Override
public
final
void
load
()
throws
IOException
,
InterruptedException
{
String
inputEncoding
;
InputStream
inputStream
=
null
;
try
{
URLConnection
connection
=
configureConnection
(
new
URL
(
url
));
inputStream
=
connection
.
getInputStream
();
inputEncoding
=
connection
.
getContentEncoding
();
result
=
parse
(
connection
.
getURL
().
toString
(),
inputStream
,
inputEncoding
);
}
finally
{
if
(
inputStream
!=
null
)
{
inputStream
.
close
();
}
}
}
/**
* Parses the raw data into an object.
*
* @param connectionUrl The url, after any redirection has taken place.
* @param inputStream An {@link InputStream} from which the raw data can be read.
* @param inputEncoding The encoding of the raw data, if available.
* @return The parsed object.
* @throws ParserException If an error occurs parsing the data.
* @throws IOException If an error occurs reading data from the stream.
*/
protected
abstract
T
parse
(
String
connectionUrl
,
InputStream
inputStream
,
String
inputEncoding
)
throws
ParserException
,
IOException
;
private
URLConnection
configureConnection
(
URL
url
)
throws
IOException
{
URLConnection
connection
=
url
.
openConnection
();
connection
.
setConnectTimeout
(
timeoutMillis
);
connection
.
setReadTimeout
(
timeoutMillis
);
connection
.
setDoOutput
(
false
);
connection
.
setRequestProperty
(
"User-Agent"
,
userAgent
);
connection
.
connect
();
return
connection
;
}
}
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