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
709fc773
authored
May 19, 2015
by
Oliver Woodman
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
First steps toward implementing bounded live seek.
parent
763d68f2
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
591 additions
and
58 deletions
RELEASENOTES.md
demo/src/main/java/com/google/android/exoplayer/demo/EventLogger.java
demo/src/main/java/com/google/android/exoplayer/demo/player/DashRendererBuilder.java
demo/src/main/java/com/google/android/exoplayer/demo/player/DebugTrackRenderer.java
demo/src/main/java/com/google/android/exoplayer/demo/player/DemoPlayer.java
demo/src/main/java/com/google/android/exoplayer/demo/player/ExtractorRendererBuilder.java
demo/src/main/java/com/google/android/exoplayer/demo/player/HlsRendererBuilder.java
demo/src/main/java/com/google/android/exoplayer/demo/player/SmoothStreamingRendererBuilder.java
library/src/main/java/com/google/android/exoplayer/TimeRange.java
library/src/main/java/com/google/android/exoplayer/dash/DashChunkSource.java
library/src/main/java/com/google/android/exoplayer/extractor/ts/H264Reader.java
library/src/main/java/com/google/android/exoplayer/extractor/ts/TsExtractor.java
library/src/main/java/com/google/android/exoplayer/upstream/MulticastDataSource.java
library/src/main/java/com/google/android/exoplayer/util/ParsableBitArray.java
library/src/main/java/com/google/android/exoplayer/util/Util.java
library/src/test/java/com/google/android/exoplayer/TimeRangeTest.java
library/src/test/java/com/google/android/exoplayer/dash/DashChunkSourceTest.java
RELEASENOTES.md
View file @
709fc773
# Release notes #
# Release notes #
### r1.3.2 ###
### Current dev branch (from r1.3.2) ###
*
Add option to TsExtractor to allow non-IDR keyframes.
*
Added MulticastDataSource for connecting to multicast streams.
*
(WorkInProgress) - First steps to supporting seeking in DASH DVR window.
### r1.3.2 (from r1.3.1) ###
*
DataSource improvements:
`DefaultUriDataSource`
now handles http://, https://, file://, asset://
*
DataSource improvements:
`DefaultUriDataSource`
now handles http://, https://, file://, asset://
and content:// URIs automatically. It also handles file:///android_asset/
*
URIs, and file paths
and content:// URIs automatically. It also handles file:///android_asset/
*
URIs, and file paths
...
...
demo/src/main/java/com/google/android/exoplayer/demo/EventLogger.java
View file @
709fc773
...
@@ -17,6 +17,7 @@ package com.google.android.exoplayer.demo;
...
@@ -17,6 +17,7 @@ package com.google.android.exoplayer.demo;
import
com.google.android.exoplayer.ExoPlayer
;
import
com.google.android.exoplayer.ExoPlayer
;
import
com.google.android.exoplayer.MediaCodecTrackRenderer.DecoderInitializationException
;
import
com.google.android.exoplayer.MediaCodecTrackRenderer.DecoderInitializationException
;
import
com.google.android.exoplayer.TimeRange
;
import
com.google.android.exoplayer.audio.AudioTrack
;
import
com.google.android.exoplayer.audio.AudioTrack
;
import
com.google.android.exoplayer.chunk.Format
;
import
com.google.android.exoplayer.chunk.Format
;
import
com.google.android.exoplayer.demo.player.DemoPlayer
;
import
com.google.android.exoplayer.demo.player.DemoPlayer
;
...
@@ -46,6 +47,7 @@ public class EventLogger implements DemoPlayer.Listener, DemoPlayer.InfoListener
...
@@ -46,6 +47,7 @@ public class EventLogger implements DemoPlayer.Listener, DemoPlayer.InfoListener
private
long
sessionStartTimeMs
;
private
long
sessionStartTimeMs
;
private
long
[]
loadStartTimeMs
;
private
long
[]
loadStartTimeMs
;
private
long
[]
seekRangeValuesUs
;
public
EventLogger
()
{
public
EventLogger
()
{
loadStartTimeMs
=
new
long
[
DemoPlayer
.
RENDERER_COUNT
];
loadStartTimeMs
=
new
long
[
DemoPlayer
.
RENDERER_COUNT
];
...
@@ -163,7 +165,14 @@ public class EventLogger implements DemoPlayer.Listener, DemoPlayer.InfoListener
...
@@ -163,7 +165,14 @@ public class EventLogger implements DemoPlayer.Listener, DemoPlayer.InfoListener
@Override
@Override
public
void
onDecoderInitialized
(
String
decoderName
,
long
elapsedRealtimeMs
,
public
void
onDecoderInitialized
(
String
decoderName
,
long
elapsedRealtimeMs
,
long
initializationDurationMs
)
{
long
initializationDurationMs
)
{
Log
.
d
(
TAG
,
"decoderInitialized ["
+
getSessionTimeString
()
+
"]"
);
Log
.
d
(
TAG
,
"decoderInitialized ["
+
getSessionTimeString
()
+
", "
+
decoderName
+
"]"
);
}
@Override
public
void
onSeekRangeChanged
(
TimeRange
seekRange
)
{
seekRangeValuesUs
=
seekRange
.
getCurrentBoundsUs
(
seekRangeValuesUs
);
Log
.
d
(
TAG
,
"seekRange [ "
+
seekRange
.
type
+
", "
+
seekRangeValuesUs
[
0
]
+
", "
+
seekRangeValuesUs
[
1
]
+
"]"
);
}
}
private
void
printInternalError
(
String
type
,
Exception
e
)
{
private
void
printInternalError
(
String
type
,
Exception
e
)
{
...
...
demo/src/main/java/com/google/android/exoplayer/demo/player/DashRendererBuilder.java
View file @
709fc773
...
@@ -235,14 +235,15 @@ public class DashRendererBuilder implements RendererBuilder,
...
@@ -235,14 +235,15 @@ public class DashRendererBuilder implements RendererBuilder,
DataSource
videoDataSource
=
new
DefaultUriDataSource
(
context
,
bandwidthMeter
,
userAgent
);
DataSource
videoDataSource
=
new
DefaultUriDataSource
(
context
,
bandwidthMeter
,
userAgent
);
ChunkSource
videoChunkSource
=
new
DashChunkSource
(
manifestFetcher
,
ChunkSource
videoChunkSource
=
new
DashChunkSource
(
manifestFetcher
,
videoAdaptationSetIndex
,
videoRepresentationIndices
,
videoDataSource
,
videoAdaptationSetIndex
,
videoRepresentationIndices
,
videoDataSource
,
new
AdaptiveEvaluator
(
bandwidthMeter
),
LIVE_EDGE_LATENCY_MS
,
elapsedRealtimeOffset
);
new
AdaptiveEvaluator
(
bandwidthMeter
),
LIVE_EDGE_LATENCY_MS
,
elapsedRealtimeOffset
,
mainHandler
,
player
);
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
);
videoRenderer
=
new
MediaCodecVideoTrackRenderer
(
videoSampleSource
,
drmSessionManager
,
true
,
videoRenderer
=
new
MediaCodecVideoTrackRenderer
(
videoSampleSource
,
drmSessionManager
,
true
,
MediaCodec
.
VIDEO_SCALING_MODE_SCALE_TO_FIT
,
5000
,
null
,
mainHandler
,
player
,
50
);
MediaCodec
.
VIDEO_SCALING_MODE_SCALE_TO_FIT
,
5000
,
null
,
mainHandler
,
player
,
50
);
debugRenderer
=
debugTextView
!=
null
debugRenderer
=
debugTextView
!=
null
?
new
DebugTrackRenderer
(
debugTextView
,
player
,
videoRenderer
)
:
null
;
?
new
DebugTrackRenderer
(
debugTextView
,
player
,
videoRenderer
,
bandwidthMeter
)
:
null
;
}
}
// Build the audio chunk sources.
// Build the audio chunk sources.
...
@@ -259,7 +260,7 @@ public class DashRendererBuilder implements RendererBuilder,
...
@@ -259,7 +260,7 @@ public class DashRendererBuilder implements RendererBuilder,
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
));
elapsedRealtimeOffset
,
mainHandler
,
player
));
codecs
.
add
(
format
.
codecs
);
codecs
.
add
(
format
.
codecs
);
}
}
...
@@ -316,7 +317,8 @@ public class DashRendererBuilder implements RendererBuilder,
...
@@ -316,7 +317,8 @@ 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
,
elapsedRealtimeOffset
));
textDataSource
,
textEvaluator
,
LIVE_EDGE_LATENCY_MS
,
elapsedRealtimeOffset
,
mainHandler
,
player
));
}
}
}
}
}
}
...
...
demo/src/main/java/com/google/android/exoplayer/demo/player/DebugTrackRenderer.java
View file @
709fc773
...
@@ -19,6 +19,7 @@ import com.google.android.exoplayer.ExoPlaybackException;
...
@@ -19,6 +19,7 @@ import com.google.android.exoplayer.ExoPlaybackException;
import
com.google.android.exoplayer.MediaCodecTrackRenderer
;
import
com.google.android.exoplayer.MediaCodecTrackRenderer
;
import
com.google.android.exoplayer.TrackRenderer
;
import
com.google.android.exoplayer.TrackRenderer
;
import
com.google.android.exoplayer.chunk.Format
;
import
com.google.android.exoplayer.chunk.Format
;
import
com.google.android.exoplayer.upstream.BandwidthMeter
;
import
android.widget.TextView
;
import
android.widget.TextView
;
...
@@ -31,15 +32,22 @@ import android.widget.TextView;
...
@@ -31,15 +32,22 @@ import android.widget.TextView;
private
final
TextView
textView
;
private
final
TextView
textView
;
private
final
DemoPlayer
player
;
private
final
DemoPlayer
player
;
private
final
MediaCodecTrackRenderer
renderer
;
private
final
MediaCodecTrackRenderer
renderer
;
private
final
BandwidthMeter
bandwidthMeter
;
private
volatile
boolean
pendingFailure
;
private
volatile
boolean
pendingFailure
;
private
volatile
long
currentPositionUs
;
private
volatile
long
currentPositionUs
;
public
DebugTrackRenderer
(
TextView
textView
,
DemoPlayer
player
,
public
DebugTrackRenderer
(
TextView
textView
,
DemoPlayer
player
,
MediaCodecTrackRenderer
renderer
)
{
MediaCodecTrackRenderer
renderer
)
{
this
(
textView
,
player
,
renderer
,
null
);
}
public
DebugTrackRenderer
(
TextView
textView
,
DemoPlayer
player
,
MediaCodecTrackRenderer
renderer
,
BandwidthMeter
bandwidthMeter
)
{
this
.
textView
=
textView
;
this
.
textView
=
textView
;
this
.
player
=
player
;
this
.
player
=
player
;
this
.
renderer
=
renderer
;
this
.
renderer
=
renderer
;
this
.
bandwidthMeter
=
bandwidthMeter
;
}
}
public
void
injectFailure
()
{
public
void
injectFailure
()
{
...
@@ -77,7 +85,12 @@ import android.widget.TextView;
...
@@ -77,7 +85,12 @@ import android.widget.TextView;
}
}
private
String
getRenderString
()
{
private
String
getRenderString
()
{
return
getQualityString
()
+
" "
+
renderer
.
codecCounters
.
getDebugString
();
return
getTimeString
()
+
" "
+
getQualityString
()
+
" "
+
getBandwidthString
()
+
" "
+
renderer
.
codecCounters
.
getDebugString
();
}
private
String
getTimeString
()
{
return
"ms("
+
(
currentPositionUs
/
1000
)
+
")"
;
}
}
private
String
getQualityString
()
{
private
String
getQualityString
()
{
...
@@ -86,6 +99,15 @@ import android.widget.TextView;
...
@@ -86,6 +99,15 @@ import android.widget.TextView;
:
"id:"
+
format
.
id
+
" br:"
+
format
.
bitrate
+
" h:"
+
format
.
height
;
:
"id:"
+
format
.
id
+
" br:"
+
format
.
bitrate
+
" h:"
+
format
.
height
;
}
}
private
String
getBandwidthString
()
{
if
(
bandwidthMeter
==
null
||
bandwidthMeter
.
getBitrateEstimate
()
==
BandwidthMeter
.
NO_ESTIMATE
)
{
return
"bw:?"
;
}
else
{
return
"bw:"
+
(
bandwidthMeter
.
getBitrateEstimate
()
/
1000
);
}
}
@Override
@Override
protected
long
getCurrentPositionUs
()
{
protected
long
getCurrentPositionUs
()
{
return
currentPositionUs
;
return
currentPositionUs
;
...
...
demo/src/main/java/com/google/android/exoplayer/demo/player/DemoPlayer.java
View file @
709fc773
...
@@ -21,11 +21,13 @@ import com.google.android.exoplayer.ExoPlayer;
...
@@ -21,11 +21,13 @@ import com.google.android.exoplayer.ExoPlayer;
import
com.google.android.exoplayer.MediaCodecAudioTrackRenderer
;
import
com.google.android.exoplayer.MediaCodecAudioTrackRenderer
;
import
com.google.android.exoplayer.MediaCodecTrackRenderer.DecoderInitializationException
;
import
com.google.android.exoplayer.MediaCodecTrackRenderer.DecoderInitializationException
;
import
com.google.android.exoplayer.MediaCodecVideoTrackRenderer
;
import
com.google.android.exoplayer.MediaCodecVideoTrackRenderer
;
import
com.google.android.exoplayer.TimeRange
;
import
com.google.android.exoplayer.TrackRenderer
;
import
com.google.android.exoplayer.TrackRenderer
;
import
com.google.android.exoplayer.audio.AudioTrack
;
import
com.google.android.exoplayer.audio.AudioTrack
;
import
com.google.android.exoplayer.chunk.ChunkSampleSource
;
import
com.google.android.exoplayer.chunk.ChunkSampleSource
;
import
com.google.android.exoplayer.chunk.Format
;
import
com.google.android.exoplayer.chunk.Format
;
import
com.google.android.exoplayer.chunk.MultiTrackChunkSource
;
import
com.google.android.exoplayer.chunk.MultiTrackChunkSource
;
import
com.google.android.exoplayer.dash.DashChunkSource
;
import
com.google.android.exoplayer.drm.StreamingDrmSessionManager
;
import
com.google.android.exoplayer.drm.StreamingDrmSessionManager
;
import
com.google.android.exoplayer.hls.HlsSampleSource
;
import
com.google.android.exoplayer.hls.HlsSampleSource
;
import
com.google.android.exoplayer.metadata.MetadataTrackRenderer
;
import
com.google.android.exoplayer.metadata.MetadataTrackRenderer
;
...
@@ -50,7 +52,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
...
@@ -50,7 +52,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
public
class
DemoPlayer
implements
ExoPlayer
.
Listener
,
ChunkSampleSource
.
EventListener
,
public
class
DemoPlayer
implements
ExoPlayer
.
Listener
,
ChunkSampleSource
.
EventListener
,
HlsSampleSource
.
EventListener
,
DefaultBandwidthMeter
.
EventListener
,
HlsSampleSource
.
EventListener
,
DefaultBandwidthMeter
.
EventListener
,
MediaCodecVideoTrackRenderer
.
EventListener
,
MediaCodecAudioTrackRenderer
.
EventListener
,
MediaCodecVideoTrackRenderer
.
EventListener
,
MediaCodecAudioTrackRenderer
.
EventListener
,
StreamingDrmSessionManager
.
EventListener
,
TextRenderer
{
StreamingDrmSessionManager
.
EventListener
,
DashChunkSource
.
EventListener
,
TextRenderer
{
/**
/**
* Builds renderers for the player.
* Builds renderers for the player.
...
@@ -132,6 +134,7 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
...
@@ -132,6 +134,7 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
int
mediaStartTimeMs
,
int
mediaEndTimeMs
,
long
elapsedRealtimeMs
,
long
loadDurationMs
);
int
mediaStartTimeMs
,
int
mediaEndTimeMs
,
long
elapsedRealtimeMs
,
long
loadDurationMs
);
void
onDecoderInitialized
(
String
decoderName
,
long
elapsedRealtimeMs
,
void
onDecoderInitialized
(
String
decoderName
,
long
elapsedRealtimeMs
,
long
initializationDurationMs
);
long
initializationDurationMs
);
void
onSeekRangeChanged
(
TimeRange
seekRange
);
}
}
/**
/**
...
@@ -510,6 +513,13 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
...
@@ -510,6 +513,13 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
processText
(
text
);
processText
(
text
);
}
}
@Override
public
void
onSeekRangeChanged
(
TimeRange
seekRange
)
{
if
(
infoListener
!=
null
)
{
infoListener
.
onSeekRangeChanged
(
seekRange
);
}
}
/* package */
MetadataTrackRenderer
.
MetadataRenderer
<
Map
<
String
,
Object
>>
/* package */
MetadataTrackRenderer
.
MetadataRenderer
<
Map
<
String
,
Object
>>
getId3MetadataRenderer
()
{
getId3MetadataRenderer
()
{
return
new
MetadataTrackRenderer
.
MetadataRenderer
<
Map
<
String
,
Object
>>()
{
return
new
MetadataTrackRenderer
.
MetadataRenderer
<
Map
<
String
,
Object
>>()
{
...
...
demo/src/main/java/com/google/android/exoplayer/demo/player/ExtractorRendererBuilder.java
View file @
709fc773
...
@@ -23,6 +23,7 @@ import com.google.android.exoplayer.demo.player.DemoPlayer.RendererBuilderCallba
...
@@ -23,6 +23,7 @@ import com.google.android.exoplayer.demo.player.DemoPlayer.RendererBuilderCallba
import
com.google.android.exoplayer.extractor.Extractor
;
import
com.google.android.exoplayer.extractor.Extractor
;
import
com.google.android.exoplayer.extractor.ExtractorSampleSource
;
import
com.google.android.exoplayer.extractor.ExtractorSampleSource
;
import
com.google.android.exoplayer.upstream.DataSource
;
import
com.google.android.exoplayer.upstream.DataSource
;
import
com.google.android.exoplayer.upstream.DefaultBandwidthMeter
;
import
com.google.android.exoplayer.upstream.DefaultUriDataSource
;
import
com.google.android.exoplayer.upstream.DefaultUriDataSource
;
import
android.content.Context
;
import
android.content.Context
;
...
@@ -55,7 +56,9 @@ public class ExtractorRendererBuilder implements RendererBuilder {
...
@@ -55,7 +56,9 @@ public class ExtractorRendererBuilder implements RendererBuilder {
@Override
@Override
public
void
buildRenderers
(
DemoPlayer
player
,
RendererBuilderCallback
callback
)
{
public
void
buildRenderers
(
DemoPlayer
player
,
RendererBuilderCallback
callback
)
{
// Build the video and audio renderers.
// Build the video and audio renderers.
DataSource
dataSource
=
new
DefaultUriDataSource
(
context
,
userAgent
);
DefaultBandwidthMeter
bandwidthMeter
=
new
DefaultBandwidthMeter
(
player
.
getMainHandler
(),
null
);
DataSource
dataSource
=
new
DefaultUriDataSource
(
context
,
bandwidthMeter
,
userAgent
);
ExtractorSampleSource
sampleSource
=
new
ExtractorSampleSource
(
uri
,
dataSource
,
extractor
,
2
,
ExtractorSampleSource
sampleSource
=
new
ExtractorSampleSource
(
uri
,
dataSource
,
extractor
,
2
,
BUFFER_SIZE
);
BUFFER_SIZE
);
MediaCodecVideoTrackRenderer
videoRenderer
=
new
MediaCodecVideoTrackRenderer
(
sampleSource
,
MediaCodecVideoTrackRenderer
videoRenderer
=
new
MediaCodecVideoTrackRenderer
(
sampleSource
,
...
@@ -66,7 +69,7 @@ public class ExtractorRendererBuilder implements RendererBuilder {
...
@@ -66,7 +69,7 @@ public class ExtractorRendererBuilder implements RendererBuilder {
// Build the debug renderer.
// Build the debug renderer.
TrackRenderer
debugRenderer
=
debugTextView
!=
null
TrackRenderer
debugRenderer
=
debugTextView
!=
null
?
new
DebugTrackRenderer
(
debugTextView
,
player
,
videoRenderer
)
:
null
;
?
new
DebugTrackRenderer
(
debugTextView
,
player
,
videoRenderer
,
bandwidthMeter
)
:
null
;
// Invoke the callback.
// Invoke the callback.
TrackRenderer
[]
renderers
=
new
TrackRenderer
[
DemoPlayer
.
RENDERER_COUNT
];
TrackRenderer
[]
renderers
=
new
TrackRenderer
[
DemoPlayer
.
RENDERER_COUNT
];
...
...
demo/src/main/java/com/google/android/exoplayer/demo/player/HlsRendererBuilder.java
View file @
709fc773
...
@@ -121,7 +121,7 @@ public class HlsRendererBuilder implements RendererBuilder, ManifestCallback<Hls
...
@@ -121,7 +121,7 @@ public class HlsRendererBuilder implements RendererBuilder, ManifestCallback<Hls
// Build the debug renderer.
// Build the debug renderer.
TrackRenderer
debugRenderer
=
debugTextView
!=
null
TrackRenderer
debugRenderer
=
debugTextView
!=
null
?
new
DebugTrackRenderer
(
debugTextView
,
player
,
videoRenderer
)
:
null
;
?
new
DebugTrackRenderer
(
debugTextView
,
player
,
videoRenderer
,
bandwidthMeter
)
:
null
;
TrackRenderer
[]
renderers
=
new
TrackRenderer
[
DemoPlayer
.
RENDERER_COUNT
];
TrackRenderer
[]
renderers
=
new
TrackRenderer
[
DemoPlayer
.
RENDERER_COUNT
];
renderers
[
DemoPlayer
.
TYPE_VIDEO
]
=
videoRenderer
;
renderers
[
DemoPlayer
.
TYPE_VIDEO
]
=
videoRenderer
;
...
...
demo/src/main/java/com/google/android/exoplayer/demo/player/SmoothStreamingRendererBuilder.java
View file @
709fc773
...
@@ -174,7 +174,7 @@ public class SmoothStreamingRendererBuilder implements RendererBuilder,
...
@@ -174,7 +174,7 @@ public class SmoothStreamingRendererBuilder implements RendererBuilder,
videoRenderer
=
new
MediaCodecVideoTrackRenderer
(
videoSampleSource
,
drmSessionManager
,
true
,
videoRenderer
=
new
MediaCodecVideoTrackRenderer
(
videoSampleSource
,
drmSessionManager
,
true
,
MediaCodec
.
VIDEO_SCALING_MODE_SCALE_TO_FIT
,
5000
,
null
,
mainHandler
,
player
,
50
);
MediaCodec
.
VIDEO_SCALING_MODE_SCALE_TO_FIT
,
5000
,
null
,
mainHandler
,
player
,
50
);
debugRenderer
=
debugTextView
!=
null
debugRenderer
=
debugTextView
!=
null
?
new
DebugTrackRenderer
(
debugTextView
,
player
,
videoRenderer
)
:
null
;
?
new
DebugTrackRenderer
(
debugTextView
,
player
,
videoRenderer
,
bandwidthMeter
)
:
null
;
}
}
// Build the audio renderer.
// Build the audio renderer.
...
...
library/src/main/java/com/google/android/exoplayer/TimeRange.java
0 → 100644
View file @
709fc773
/*
* 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
;
/**
* A container to store a start and end time in microseconds.
*/
public
final
class
TimeRange
{
/**
* Represents a range of time whose bounds change in bulk increments rather than smoothly over
* time.
*/
public
static
final
int
TYPE_SNAPSHOT
=
0
;
/**
* The type of this time range.
*/
public
final
int
type
;
private
final
long
startTimeUs
;
private
final
long
endTimeUs
;
/**
* Create a new {@link TimeRange} of the appropriate type.
*
* @param type The type of the TimeRange.
* @param startTimeUs The beginning of the TimeRange.
* @param endTimeUs The end of the TimeRange.
*/
public
TimeRange
(
int
type
,
long
startTimeUs
,
long
endTimeUs
)
{
this
.
type
=
type
;
this
.
startTimeUs
=
startTimeUs
;
this
.
endTimeUs
=
endTimeUs
;
}
/**
* Returns the start and end times (in milliseconds) of the TimeRange in the provided array,
* or creates a new one.
*
* @param out An array to store the start and end times; can be null.
* @return An array containing the start time (index 0) and end time (index 1) in milliseconds.
*/
public
long
[]
getCurrentBoundsMs
(
long
[]
out
)
{
out
=
getCurrentBoundsUs
(
out
);
out
[
0
]
/=
1000
;
out
[
1
]
/=
1000
;
return
out
;
}
/**
* Returns the start and end times (in microseconds) of the TimeRange in the provided array,
* or creates a new one.
*
* @param out An array to store the start and end times; can be null.
* @return An array containing the start time (index 0) and end time (index 1) in microseconds.
*/
public
long
[]
getCurrentBoundsUs
(
long
[]
out
)
{
if
(
out
==
null
||
out
.
length
<
2
)
{
out
=
new
long
[
2
];
}
out
[
0
]
=
startTimeUs
;
out
[
1
]
=
endTimeUs
;
return
out
;
}
@Override
public
int
hashCode
()
{
int
hashCode
=
0
;
hashCode
|=
type
<<
30
;
hashCode
|=
(((
startTimeUs
+
endTimeUs
)
/
1000
)
&
0x3FFFFFFF
);
return
hashCode
;
}
@Override
public
boolean
equals
(
Object
other
)
{
if
(
other
==
this
)
{
return
true
;
}
if
(
other
instanceof
TimeRange
)
{
TimeRange
otherTimeRange
=
(
TimeRange
)
other
;
return
(
otherTimeRange
.
type
==
type
)
&&
(
otherTimeRange
.
startTimeUs
==
startTimeUs
)
&&
(
otherTimeRange
.
endTimeUs
==
endTimeUs
);
}
else
{
return
false
;
}
}
}
library/src/main/java/com/google/android/exoplayer/dash/DashChunkSource.java
View file @
709fc773
This diff is collapsed.
Click to expand it.
library/src/main/java/com/google/android/exoplayer/extractor/ts/H264Reader.java
View file @
709fc773
...
@@ -37,11 +37,15 @@ import java.util.List;
...
@@ -37,11 +37,15 @@ import java.util.List;
private
static
final
String
TAG
=
"H264Reader"
;
private
static
final
String
TAG
=
"H264Reader"
;
private
static
final
int
NAL_UNIT_TYPE_IDR
=
5
;
private
static
final
int
FRAME_TYPE_I
=
2
;
private
static
final
int
NAL_UNIT_TYPE_SEI
=
6
;
private
static
final
int
FRAME_TYPE_ALL_I
=
7
;
private
static
final
int
NAL_UNIT_TYPE_SPS
=
7
;
private
static
final
int
NAL_UNIT_TYPE_PPS
=
8
;
private
static
final
int
NAL_UNIT_TYPE_IFR
=
1
;
// Coded slice of a non-IDR picture
private
static
final
int
NAL_UNIT_TYPE_AUD
=
9
;
private
static
final
int
NAL_UNIT_TYPE_IDR
=
5
;
// Coded slice of an IDR picture
private
static
final
int
NAL_UNIT_TYPE_SEI
=
6
;
// Supplemental enhancement information
private
static
final
int
NAL_UNIT_TYPE_SPS
=
7
;
// Sequence parameter set
private
static
final
int
NAL_UNIT_TYPE_PPS
=
8
;
// Picture parameter set
private
static
final
int
NAL_UNIT_TYPE_AUD
=
9
;
// Access unit delimiter
private
static
final
int
EXTENDED_SAR
=
0xFF
;
private
static
final
int
EXTENDED_SAR
=
0xFF
;
private
static
final
float
[]
ASPECT_RATIO_IDC_VALUES
=
new
float
[]
{
private
static
final
float
[]
ASPECT_RATIO_IDC_VALUES
=
new
float
[]
{
1
f
/* Unspecified. Assume square */
,
1
f
/* Unspecified. Assume square */
,
...
@@ -69,6 +73,7 @@ import java.util.List;
...
@@ -69,6 +73,7 @@ import java.util.List;
// State that should be reset on seek.
// State that should be reset on seek.
private
final
SeiReader
seiReader
;
private
final
SeiReader
seiReader
;
private
final
boolean
[]
prefixFlags
;
private
final
boolean
[]
prefixFlags
;
private
final
IfrParserBuffer
ifrParserBuffer
;
private
final
NalUnitTargetBuffer
sps
;
private
final
NalUnitTargetBuffer
sps
;
private
final
NalUnitTargetBuffer
pps
;
private
final
NalUnitTargetBuffer
pps
;
private
final
NalUnitTargetBuffer
sei
;
private
final
NalUnitTargetBuffer
sei
;
...
@@ -84,10 +89,11 @@ import java.util.List;
...
@@ -84,10 +89,11 @@ import java.util.List;
private
final
ParsableByteArray
seiWrapper
;
private
final
ParsableByteArray
seiWrapper
;
private
int
[]
scratchEscapePositions
;
private
int
[]
scratchEscapePositions
;
public
H264Reader
(
TrackOutput
output
,
SeiReader
seiReader
)
{
public
H264Reader
(
TrackOutput
output
,
SeiReader
seiReader
,
boolean
idrKeyframesOnly
)
{
super
(
output
);
super
(
output
);
this
.
seiReader
=
seiReader
;
this
.
seiReader
=
seiReader
;
prefixFlags
=
new
boolean
[
3
];
prefixFlags
=
new
boolean
[
3
];
ifrParserBuffer
=
(
idrKeyframesOnly
)
?
null
:
new
IfrParserBuffer
();
sps
=
new
NalUnitTargetBuffer
(
NAL_UNIT_TYPE_SPS
,
128
);
sps
=
new
NalUnitTargetBuffer
(
NAL_UNIT_TYPE_SPS
,
128
);
pps
=
new
NalUnitTargetBuffer
(
NAL_UNIT_TYPE_PPS
,
128
);
pps
=
new
NalUnitTargetBuffer
(
NAL_UNIT_TYPE_PPS
,
128
);
sei
=
new
NalUnitTargetBuffer
(
NAL_UNIT_TYPE_SEI
,
128
);
sei
=
new
NalUnitTargetBuffer
(
NAL_UNIT_TYPE_SEI
,
128
);
...
@@ -102,6 +108,9 @@ import java.util.List;
...
@@ -102,6 +108,9 @@ import java.util.List;
sps
.
reset
();
sps
.
reset
();
pps
.
reset
();
pps
.
reset
();
sei
.
reset
();
sei
.
reset
();
if
(
ifrParserBuffer
!=
null
)
{
ifrParserBuffer
.
reset
();
}
writingSample
=
false
;
writingSample
=
false
;
totalBytesWritten
=
0
;
totalBytesWritten
=
0
;
}
}
...
@@ -132,22 +141,30 @@ import java.util.List;
...
@@ -132,22 +141,30 @@ import java.util.List;
int
nalUnitType
=
H264Util
.
getNalUnitType
(
dataArray
,
nextNalUnitOffset
);
int
nalUnitType
=
H264Util
.
getNalUnitType
(
dataArray
,
nextNalUnitOffset
);
int
bytesWrittenPastNalUnit
=
limit
-
nextNalUnitOffset
;
int
bytesWrittenPastNalUnit
=
limit
-
nextNalUnitOffset
;
if
(
nalUnitType
==
NAL_UNIT_TYPE_AUD
)
{
switch
(
nalUnitType
)
{
if
(
writingSample
)
{
case
NAL_UNIT_TYPE_IDR:
if
(
isKeyframe
&&
!
hasOutputFormat
&&
sps
.
isCompleted
()
&&
pps
.
isCompleted
())
{
isKeyframe
=
true
;
parseMediaFormat
(
sps
,
pps
);
break
;
case
NAL_UNIT_TYPE_AUD:
if
(
writingSample
)
{
if
(
ifrParserBuffer
!=
null
&&
ifrParserBuffer
.
isCompleted
())
{
int
sliceType
=
ifrParserBuffer
.
getSliceType
();
isKeyframe
|=
(
sliceType
==
FRAME_TYPE_I
||
sliceType
==
FRAME_TYPE_ALL_I
);
ifrParserBuffer
.
reset
();
}
if
(
isKeyframe
&&
!
hasOutputFormat
&&
sps
.
isCompleted
()
&&
pps
.
isCompleted
())
{
parseMediaFormat
(
sps
,
pps
);
}
int
flags
=
isKeyframe
?
C
.
SAMPLE_FLAG_SYNC
:
0
;
int
size
=
(
int
)
(
totalBytesWritten
-
samplePosition
)
-
bytesWrittenPastNalUnit
;
output
.
sampleMetadata
(
sampleTimeUs
,
flags
,
size
,
bytesWrittenPastNalUnit
,
null
);
writingSample
=
false
;
}
}
int
flags
=
isKeyframe
?
C
.
SAMPLE_FLAG_SYNC
:
0
;
writingSample
=
true
;
int
size
=
(
int
)
(
totalBytesWritten
-
samplePosition
)
-
bytesWrittenPastNalUnit
;
samplePosition
=
totalBytesWritten
-
bytesWrittenPastNalUnit
;
output
.
sampleMetadata
(
sampleTimeUs
,
flags
,
size
,
bytesWrittenPastNalUnit
,
null
);
sampleTimeUs
=
pesTimeUs
;
writingSample
=
false
;
isKeyframe
=
false
;
}
break
;
writingSample
=
true
;
isKeyframe
=
false
;
sampleTimeUs
=
pesTimeUs
;
samplePosition
=
totalBytesWritten
-
bytesWrittenPastNalUnit
;
}
else
if
(
nalUnitType
==
NAL_UNIT_TYPE_IDR
)
{
isKeyframe
=
true
;
}
}
// If the length to the start of the unit is negative then we wrote too many bytes to the
// If the length to the start of the unit is negative then we wrote too many bytes to the
...
@@ -171,6 +188,9 @@ import java.util.List;
...
@@ -171,6 +188,9 @@ import java.util.List;
}
}
private
void
feedNalUnitTargetBuffersStart
(
int
nalUnitType
)
{
private
void
feedNalUnitTargetBuffersStart
(
int
nalUnitType
)
{
if
(
ifrParserBuffer
!=
null
)
{
ifrParserBuffer
.
startNalUnit
(
nalUnitType
);
}
if
(!
hasOutputFormat
)
{
if
(!
hasOutputFormat
)
{
sps
.
startNalUnit
(
nalUnitType
);
sps
.
startNalUnit
(
nalUnitType
);
pps
.
startNalUnit
(
nalUnitType
);
pps
.
startNalUnit
(
nalUnitType
);
...
@@ -179,6 +199,9 @@ import java.util.List;
...
@@ -179,6 +199,9 @@ import java.util.List;
}
}
private
void
feedNalUnitTargetBuffersData
(
byte
[]
dataArray
,
int
offset
,
int
limit
)
{
private
void
feedNalUnitTargetBuffersData
(
byte
[]
dataArray
,
int
offset
,
int
limit
)
{
if
(
ifrParserBuffer
!=
null
)
{
ifrParserBuffer
.
appendToNalUnit
(
dataArray
,
offset
,
limit
);
}
if
(!
hasOutputFormat
)
{
if
(!
hasOutputFormat
)
{
sps
.
appendToNalUnit
(
dataArray
,
offset
,
limit
);
sps
.
appendToNalUnit
(
dataArray
,
offset
,
limit
);
pps
.
appendToNalUnit
(
dataArray
,
offset
,
limit
);
pps
.
appendToNalUnit
(
dataArray
,
offset
,
limit
);
...
@@ -461,4 +484,99 @@ import java.util.List;
...
@@ -461,4 +484,99 @@ import java.util.List;
}
}
/**
* A buffer specifically for IFR units that can be used to parse the IFR's slice type.
*/
private
static
final
class
IfrParserBuffer
{
private
static
final
int
DEFAULT_BUFFER_SIZE
=
128
;
private
static
final
int
NOT_SET
=
-
1
;
private
final
ParsableBitArray
scratchSliceType
;
private
byte
[]
ifrData
;
private
int
ifrLength
;
private
boolean
isFilling
;
private
int
sliceType
;
public
IfrParserBuffer
()
{
ifrData
=
new
byte
[
DEFAULT_BUFFER_SIZE
];
scratchSliceType
=
new
ParsableBitArray
(
ifrData
);
reset
();
}
/**
* Resets the buffer, clearing any data that it holds.
*/
public
void
reset
()
{
isFilling
=
false
;
ifrLength
=
0
;
sliceType
=
NOT_SET
;
}
/**
* True if enough data was added to the buffer that the slice type was determined.
*/
public
boolean
isCompleted
()
{
return
sliceType
!=
NOT_SET
;
}
/**
* Invoked to indicate that a NAL unit has started, and if it is an IFR then the buffer will
* start.
*/
public
void
startNalUnit
(
int
nalUnitType
)
{
if
(
nalUnitType
==
NAL_UNIT_TYPE_IFR
)
{
reset
();
isFilling
=
true
;
}
}
/**
* Invoked to pass stream data. The data passed should not include 4 byte NAL unit prefixes.
*
* @param data Holds the data being passed.
* @param offset The offset of the data in {@code data}.
* @param limit The limit (exclusive) of the data in {@code data}.
*/
public
void
appendToNalUnit
(
byte
[]
data
,
int
offset
,
int
limit
)
{
if
(!
isFilling
)
{
return
;
}
int
readLength
=
limit
-
offset
;
if
(
ifrData
.
length
<
ifrLength
+
readLength
)
{
ifrData
=
Arrays
.
copyOf
(
ifrData
,
(
ifrLength
+
readLength
)
*
2
);
}
System
.
arraycopy
(
data
,
offset
,
ifrData
,
ifrLength
,
readLength
);
ifrLength
+=
readLength
;
scratchSliceType
.
reset
(
ifrData
,
ifrLength
);
// first_mb_in_slice
int
len
=
scratchSliceType
.
peekExpGolombCodedNumLength
();
if
((
len
==
-
1
)
||
(
len
>
scratchSliceType
.
bitsLeft
()))
{
// Not enough yet
return
;
}
scratchSliceType
.
skipBits
(
len
);
// slice_type
len
=
scratchSliceType
.
peekExpGolombCodedNumLength
();
if
((
len
==
-
1
)
||
(
len
>
scratchSliceType
.
bitsLeft
()))
{
// Not enough yet
return
;
}
sliceType
=
scratchSliceType
.
readUnsignedExpGolombCodedInt
();
isFilling
=
false
;
}
/**
* @return the slice type of the IFR.
*/
public
int
getSliceType
()
{
return
sliceType
;
}
}
}
}
library/src/main/java/com/google/android/exoplayer/extractor/ts/TsExtractor.java
View file @
709fc773
...
@@ -53,6 +53,7 @@ public final class TsExtractor implements Extractor, SeekMap {
...
@@ -53,6 +53,7 @@ public final class TsExtractor implements Extractor, SeekMap {
private
final
ParsableByteArray
tsPacketBuffer
;
private
final
ParsableByteArray
tsPacketBuffer
;
private
final
ParsableBitArray
tsScratch
;
private
final
ParsableBitArray
tsScratch
;
private
final
boolean
idrKeyframesOnly
;
private
final
long
firstSampleTimestampUs
;
private
final
long
firstSampleTimestampUs
;
/* package */
final
SparseBooleanArray
streamTypes
;
/* package */
final
SparseBooleanArray
streamTypes
;
/* package */
final
SparseBooleanArray
allowedPassthroughStreamTypes
;
/* package */
final
SparseBooleanArray
allowedPassthroughStreamTypes
;
...
@@ -65,11 +66,21 @@ public final class TsExtractor implements Extractor, SeekMap {
...
@@ -65,11 +66,21 @@ public final class TsExtractor implements Extractor, SeekMap {
/* package */
Id3Reader
id3Reader
;
/* package */
Id3Reader
id3Reader
;
public
TsExtractor
()
{
public
TsExtractor
()
{
this
(
0
,
null
);
this
(
0
);
}
public
TsExtractor
(
long
firstSampleTimestampUs
)
{
this
(
firstSampleTimestampUs
,
null
);
}
}
public
TsExtractor
(
long
firstSampleTimestampUs
,
AudioCapabilities
audioCapabilities
)
{
public
TsExtractor
(
long
firstSampleTimestampUs
,
AudioCapabilities
audioCapabilities
)
{
this
(
firstSampleTimestampUs
,
audioCapabilities
,
true
);
}
public
TsExtractor
(
long
firstSampleTimestampUs
,
AudioCapabilities
audioCapabilities
,
boolean
idrKeyframesOnly
)
{
this
.
firstSampleTimestampUs
=
firstSampleTimestampUs
;
this
.
firstSampleTimestampUs
=
firstSampleTimestampUs
;
this
.
idrKeyframesOnly
=
idrKeyframesOnly
;
tsScratch
=
new
ParsableBitArray
(
new
byte
[
3
]);
tsScratch
=
new
ParsableBitArray
(
new
byte
[
3
]);
tsPacketBuffer
=
new
ParsableByteArray
(
TS_PACKET_SIZE
);
tsPacketBuffer
=
new
ParsableByteArray
(
TS_PACKET_SIZE
);
streamTypes
=
new
SparseBooleanArray
();
streamTypes
=
new
SparseBooleanArray
();
...
@@ -103,6 +114,8 @@ public final class TsExtractor implements Extractor, SeekMap {
...
@@ -103,6 +114,8 @@ public final class TsExtractor implements Extractor, SeekMap {
return
RESULT_END_OF_INPUT
;
return
RESULT_END_OF_INPUT
;
}
}
// Note: see ISO/IEC 13818-1, section 2.4.3.2 for detailed information on the format of
// the header.
tsPacketBuffer
.
setPosition
(
0
);
tsPacketBuffer
.
setPosition
(
0
);
tsPacketBuffer
.
setLimit
(
TS_PACKET_SIZE
);
tsPacketBuffer
.
setLimit
(
TS_PACKET_SIZE
);
int
syncByte
=
tsPacketBuffer
.
readUnsignedByte
();
int
syncByte
=
tsPacketBuffer
.
readUnsignedByte
();
...
@@ -292,6 +305,8 @@ public final class TsExtractor implements Extractor, SeekMap {
...
@@ -292,6 +305,8 @@ public final class TsExtractor implements Extractor, SeekMap {
data
.
skipBytes
(
pointerField
);
data
.
skipBytes
(
pointerField
);
}
}
// Note: see ISO/IEC 13818-1, section 2.4.4.8 for detailed information on the format of
// the header.
data
.
readBytes
(
pmtScratch
,
3
);
data
.
readBytes
(
pmtScratch
,
3
);
pmtScratch
.
skipBits
(
12
);
// table_id (8), section_syntax_indicator (1), '0' (1), reserved (2)
pmtScratch
.
skipBits
(
12
);
// table_id (8), section_syntax_indicator (1), '0' (1), reserved (2)
int
sectionLength
=
pmtScratch
.
readBits
(
12
);
int
sectionLength
=
pmtScratch
.
readBits
(
12
);
...
@@ -347,7 +362,8 @@ public final class TsExtractor implements Extractor, SeekMap {
...
@@ -347,7 +362,8 @@ public final class TsExtractor implements Extractor, SeekMap {
break
;
break
;
case
TS_STREAM_TYPE_H264:
case
TS_STREAM_TYPE_H264:
SeiReader
seiReader
=
new
SeiReader
(
output
.
track
(
TS_STREAM_TYPE_EIA608
));
SeiReader
seiReader
=
new
SeiReader
(
output
.
track
(
TS_STREAM_TYPE_EIA608
));
pesPayloadReader
=
new
H264Reader
(
output
.
track
(
TS_STREAM_TYPE_H264
),
seiReader
);
pesPayloadReader
=
new
H264Reader
(
output
.
track
(
TS_STREAM_TYPE_H264
),
seiReader
,
idrKeyframesOnly
);
break
;
break
;
case
TS_STREAM_TYPE_ID3:
case
TS_STREAM_TYPE_ID3:
pesPayloadReader
=
id3Reader
;
pesPayloadReader
=
id3Reader
;
...
@@ -502,6 +518,8 @@ public final class TsExtractor implements Extractor, SeekMap {
...
@@ -502,6 +518,8 @@ public final class TsExtractor implements Extractor, SeekMap {
}
}
private
boolean
parseHeader
()
{
private
boolean
parseHeader
()
{
// Note: see ISO/IEC 13818-1, section 2.4.3.6 for detailed information on the format of
// the header.
pesScratch
.
setPosition
(
0
);
pesScratch
.
setPosition
(
0
);
int
startCodePrefix
=
pesScratch
.
readBits
(
24
);
int
startCodePrefix
=
pesScratch
.
readBits
(
24
);
if
(
startCodePrefix
!=
0x000001
)
{
if
(
startCodePrefix
!=
0x000001
)
{
...
@@ -534,7 +552,7 @@ public final class TsExtractor implements Extractor, SeekMap {
...
@@ -534,7 +552,7 @@ public final class TsExtractor implements Extractor, SeekMap {
pesScratch
.
setPosition
(
0
);
pesScratch
.
setPosition
(
0
);
timeUs
=
0
;
timeUs
=
0
;
if
(
ptsFlag
)
{
if
(
ptsFlag
)
{
pesScratch
.
skipBits
(
4
);
// '0010'
pesScratch
.
skipBits
(
4
);
// '0010'
or '0011'
long
pts
=
(
long
)
pesScratch
.
readBits
(
3
)
<<
30
;
long
pts
=
(
long
)
pesScratch
.
readBits
(
3
)
<<
30
;
pesScratch
.
skipBits
(
1
);
// marker_bit
pesScratch
.
skipBits
(
1
);
// marker_bit
pts
|=
pesScratch
.
readBits
(
15
)
<<
15
;
pts
|=
pesScratch
.
readBits
(
15
)
<<
15
;
...
...
library/src/main/java/com/google/android/exoplayer/upstream/MulticastDataSource.java
0 → 100644
View file @
709fc773
/*
* 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
.
upstream
;
import
com.google.android.exoplayer.C
;
import
java.io.IOException
;
import
java.net.DatagramPacket
;
import
java.net.InetAddress
;
import
java.net.MulticastSocket
;
/**
* A multicast {@link DataSource}.
*/
public
class
MulticastDataSource
implements
UriDataSource
{
/**
* Thrown when an error is encountered when trying to read from a {@link MulticastDataSource}.
*/
public
static
final
class
MulticastDataSourceException
extends
IOException
{
public
MulticastDataSourceException
(
String
message
)
{
super
(
message
);
}
public
MulticastDataSourceException
(
IOException
cause
)
{
super
(
cause
);
}
}
public
static
final
int
DEFAULT_MAX_PACKET_SIZE
=
2000
;
public
static
final
int
TRANSFER_LISTENER_PACKET_INTERVAL
=
1000
;
private
final
TransferListener
transferListener
;
private
final
DatagramPacket
packet
;
private
DataSpec
dataSpec
;
private
MulticastSocket
socket
;
private
boolean
opened
;
private
int
packetsReceived
;
private
byte
[]
packetBuffer
;
private
int
packetRemaining
;
public
MulticastDataSource
(
TransferListener
transferListener
)
{
this
(
transferListener
,
DEFAULT_MAX_PACKET_SIZE
);
}
public
MulticastDataSource
(
TransferListener
transferListener
,
int
maxPacketSize
)
{
this
.
transferListener
=
transferListener
;
packetBuffer
=
new
byte
[
maxPacketSize
];
packet
=
new
DatagramPacket
(
packetBuffer
,
0
,
maxPacketSize
);
}
@Override
public
long
open
(
DataSpec
dataSpec
)
throws
MulticastDataSourceException
{
this
.
dataSpec
=
dataSpec
;
String
uri
=
dataSpec
.
uri
.
toString
();
String
host
=
uri
.
substring
(
0
,
uri
.
indexOf
(
':'
));
int
port
=
Integer
.
parseInt
(
uri
.
substring
(
uri
.
indexOf
(
':'
)
+
1
));
try
{
socket
=
new
MulticastSocket
(
port
);
socket
.
joinGroup
(
InetAddress
.
getByName
(
host
));
}
catch
(
IOException
e
)
{
throw
new
MulticastDataSourceException
(
e
);
}
opened
=
true
;
transferListener
.
onTransferStart
();
return
C
.
LENGTH_UNBOUNDED
;
}
@Override
public
void
close
()
{
if
(
opened
)
{
socket
.
close
();
socket
=
null
;
transferListener
.
onTransferEnd
();
packetRemaining
=
0
;
packetsReceived
=
0
;
opened
=
false
;
}
}
@Override
public
int
read
(
byte
[]
buffer
,
int
offset
,
int
readLength
)
throws
MulticastDataSourceException
{
// if we've read all the data, get another packet
if
(
packetRemaining
==
0
)
{
if
(
packetsReceived
==
TRANSFER_LISTENER_PACKET_INTERVAL
)
{
transferListener
.
onTransferEnd
();
transferListener
.
onTransferStart
();
packetsReceived
=
0
;
}
try
{
socket
.
receive
(
packet
);
}
catch
(
IOException
e
)
{
throw
new
MulticastDataSourceException
(
e
);
}
packetRemaining
=
packet
.
getLength
();
transferListener
.
onBytesTransferred
(
packetRemaining
);
packetsReceived
++;
}
// don't try to read too much
if
(
packetRemaining
<
readLength
)
{
readLength
=
packetRemaining
;
}
int
packetOffset
=
packet
.
getLength
()
-
packetRemaining
;
System
.
arraycopy
(
packetBuffer
,
packetOffset
,
buffer
,
offset
,
readLength
);
packetRemaining
-=
readLength
;
return
readLength
;
}
@Override
public
String
getUri
()
{
return
dataSpec
==
null
?
null
:
dataSpec
.
uri
.
toString
();
}
}
library/src/main/java/com/google/android/exoplayer/util/ParsableBitArray.java
View file @
709fc773
...
@@ -26,6 +26,7 @@ public final class ParsableBitArray {
...
@@ -26,6 +26,7 @@ public final class ParsableBitArray {
// byte (from 0 to 7).
// byte (from 0 to 7).
private
int
byteOffset
;
private
int
byteOffset
;
private
int
bitOffset
;
private
int
bitOffset
;
private
int
byteLimit
;
/** Creates a new instance that initially has no backing data. */
/** Creates a new instance that initially has no backing data. */
public
ParsableBitArray
()
{}
public
ParsableBitArray
()
{}
...
@@ -36,7 +37,18 @@ public final class ParsableBitArray {
...
@@ -36,7 +37,18 @@ public final class ParsableBitArray {
* @param data The data to wrap.
* @param data The data to wrap.
*/
*/
public
ParsableBitArray
(
byte
[]
data
)
{
public
ParsableBitArray
(
byte
[]
data
)
{
this
(
data
,
data
.
length
);
}
/**
* Creates a new instance that wraps an existing array.
*
* @param data The data to wrap.
* @param limit The limit in bytes.
*/
public
ParsableBitArray
(
byte
[]
data
,
int
limit
)
{
this
.
data
=
data
;
this
.
data
=
data
;
byteLimit
=
limit
;
}
}
/**
/**
...
@@ -45,9 +57,27 @@ public final class ParsableBitArray {
...
@@ -45,9 +57,27 @@ public final class ParsableBitArray {
* @param data The array to wrap.
* @param data The array to wrap.
*/
*/
public
void
reset
(
byte
[]
data
)
{
public
void
reset
(
byte
[]
data
)
{
reset
(
data
,
data
.
length
);
}
/**
* Updates the instance to wrap {@code data}, and resets the position to zero.
*
* @param data The array to wrap.
* @param limit The limit in bytes.
*/
public
void
reset
(
byte
[]
data
,
int
limit
)
{
this
.
data
=
data
;
this
.
data
=
data
;
byteOffset
=
0
;
byteOffset
=
0
;
bitOffset
=
0
;
bitOffset
=
0
;
byteLimit
=
limit
;
}
/**
* Returns the number of bits yet to be read.
*/
public
int
bitsLeft
()
{
return
(
byteLimit
-
byteOffset
)
*
8
-
bitOffset
;
}
}
/**
/**
...
@@ -67,6 +97,7 @@ public final class ParsableBitArray {
...
@@ -67,6 +97,7 @@ public final class ParsableBitArray {
public
void
setPosition
(
int
position
)
{
public
void
setPosition
(
int
position
)
{
byteOffset
=
position
/
8
;
byteOffset
=
position
/
8
;
bitOffset
=
position
-
(
byteOffset
*
8
);
bitOffset
=
position
-
(
byteOffset
*
8
);
assertValidOffset
();
}
}
/**
/**
...
@@ -81,6 +112,7 @@ public final class ParsableBitArray {
...
@@ -81,6 +112,7 @@ public final class ParsableBitArray {
byteOffset
++;
byteOffset
++;
bitOffset
-=
8
;
bitOffset
-=
8
;
}
}
assertValidOffset
();
}
}
/**
/**
...
@@ -103,12 +135,20 @@ public final class ParsableBitArray {
...
@@ -103,12 +135,20 @@ public final class ParsableBitArray {
return
0
;
return
0
;
}
}
int
ret
val
=
0
;
int
ret
urnValue
=
0
;
// While n >= 8, read whole bytes.
// While n >= 8, read whole bytes.
while
(
n
>=
8
)
{
while
(
n
>=
8
)
{
int
byteValue
;
if
(
bitOffset
!=
0
)
{
byteValue
=
((
data
[
byteOffset
]
&
0xFF
)
<<
bitOffset
)
|
((
data
[
byteOffset
+
1
]
&
0xFF
)
>>>
(
8
-
bitOffset
));
}
else
{
byteValue
=
data
[
byteOffset
];
}
n
-=
8
;
n
-=
8
;
retval
|=
(
readUnsignedByte
()
<<
n
);
returnValue
|=
(
byteValue
&
0xFF
)
<<
n
;
byteOffset
++;
}
}
if
(
n
>
0
)
{
if
(
n
>
0
)
{
...
@@ -117,12 +157,12 @@ public final class ParsableBitArray {
...
@@ -117,12 +157,12 @@ public final class ParsableBitArray {
if
(
nextBit
>
8
)
{
if
(
nextBit
>
8
)
{
// Combine bits from current byte and next byte.
// Combine bits from current byte and next byte.
ret
val
|=
(((
getUnsignedByte
(
byteOffset
)
<<
(
nextBit
-
8
)
ret
urnValue
|=
((((
data
[
byteOffset
]
&
0xFF
)
<<
(
nextBit
-
8
)
|
(
getUnsignedByte
(
byteOffset
+
1
)
>>
(
16
-
nextBit
)))
&
writeMask
));
|
(
(
data
[
byteOffset
+
1
]
&
0xFF
)
>>
(
16
-
nextBit
)))
&
writeMask
));
byteOffset
++;
byteOffset
++;
}
else
{
}
else
{
// Bits to be read only within current byte.
// Bits to be read only within current byte.
ret
val
|=
((
getUnsignedByte
(
byteOffset
)
>>
(
8
-
nextBit
))
&
writeMask
);
ret
urnValue
|=
(((
data
[
byteOffset
]
&
0xFF
)
>>
(
8
-
nextBit
))
&
writeMask
);
if
(
nextBit
==
8
)
{
if
(
nextBit
==
8
)
{
byteOffset
++;
byteOffset
++;
}
}
...
@@ -131,7 +171,27 @@ public final class ParsableBitArray {
...
@@ -131,7 +171,27 @@ public final class ParsableBitArray {
bitOffset
=
nextBit
%
8
;
bitOffset
=
nextBit
%
8
;
}
}
return
retval
;
assertValidOffset
();
return
returnValue
;
}
/**
* Peeks the length of an Exp-Golomb-coded integer (signed or unsigned) starting from the current
* offset, returning the length or -1 if the limit is reached.
*
* @return The length of the Exp-Golob-coded integer, or -1.
*/
public
int
peekExpGolombCodedNumLength
()
{
int
initialByteOffset
=
byteOffset
;
int
initialBitOffset
=
bitOffset
;
int
leadingZeros
=
0
;
while
(
byteOffset
<
byteLimit
&&
!
readBit
())
{
leadingZeros
++;
}
boolean
hitLimit
=
byteOffset
==
byteLimit
;
byteOffset
=
initialByteOffset
;
bitOffset
=
initialBitOffset
;
return
hitLimit
?
-
1
:
leadingZeros
*
2
+
1
;
}
}
/**
/**
...
@@ -153,22 +213,6 @@ public final class ParsableBitArray {
...
@@ -153,22 +213,6 @@ public final class ParsableBitArray {
return
((
codeNum
%
2
)
==
0
?
-
1
:
1
)
*
((
codeNum
+
1
)
/
2
);
return
((
codeNum
%
2
)
==
0
?
-
1
:
1
)
*
((
codeNum
+
1
)
/
2
);
}
}
private
int
readUnsignedByte
()
{
int
value
;
if
(
bitOffset
!=
0
)
{
value
=
((
data
[
byteOffset
]
&
0xFF
)
<<
bitOffset
)
|
((
data
[
byteOffset
+
1
]
&
0xFF
)
>>>
(
8
-
bitOffset
));
}
else
{
value
=
data
[
byteOffset
];
}
byteOffset
++;
return
value
&
0xFF
;
}
private
int
getUnsignedByte
(
int
offset
)
{
return
data
[
offset
]
&
0xFF
;
}
private
int
readExpGolombCodeNum
()
{
private
int
readExpGolombCodeNum
()
{
int
leadingZeros
=
0
;
int
leadingZeros
=
0
;
while
(!
readBit
())
{
while
(!
readBit
())
{
...
@@ -177,4 +221,11 @@ public final class ParsableBitArray {
...
@@ -177,4 +221,11 @@ public final class ParsableBitArray {
return
(
1
<<
leadingZeros
)
-
1
+
(
leadingZeros
>
0
?
readBits
(
leadingZeros
)
:
0
);
return
(
1
<<
leadingZeros
)
-
1
+
(
leadingZeros
>
0
?
readBits
(
leadingZeros
)
:
0
);
}
}
private
void
assertValidOffset
()
{
// It is fine for position to be at the end of the array, but no further.
Assertions
.
checkState
(
byteOffset
>=
0
&&
(
bitOffset
>=
0
&&
bitOffset
<
8
)
&&
(
byteOffset
<
byteLimit
||
(
byteOffset
==
byteLimit
&&
bitOffset
==
0
)));
}
}
}
library/src/main/java/com/google/android/exoplayer/util/Util.java
View file @
709fc773
...
@@ -542,6 +542,22 @@ public final class Util {
...
@@ -542,6 +542,22 @@ public final class Util {
}
}
/**
/**
* Returns a hex string representation of the data provided.
*
* @param data The byte array containing the data to be turned into a hex string.
* @param beginIndex The begin index, inclusive.
* @param endIndex The end index, exclusive.
* @return A string containing the hex representation of the data provided.
*/
public
static
String
getHexStringFromBytes
(
byte
[]
data
,
int
beginIndex
,
int
endIndex
)
{
StringBuffer
dataStringBuffer
=
new
StringBuffer
(
endIndex
-
beginIndex
);
for
(
int
i
=
beginIndex
;
i
<
endIndex
;
i
++)
{
dataStringBuffer
.
append
(
String
.
format
(
"%02X"
,
data
[
i
]));
}
return
dataStringBuffer
.
toString
();
}
/**
* Returns a user agent string based on the given application name and the library version.
* Returns a user agent string based on the given application name and the library version.
*
*
* @param context A valid context of the calling application.
* @param context A valid context of the calling application.
...
...
library/src/test/java/com/google/android/exoplayer/TimeRangeTest.java
0 → 100644
View file @
709fc773
/*
* 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
;
import
junit.framework.TestCase
;
/**
* Unit test for {@link TimeRange}.
*/
public
class
TimeRangeTest
extends
TestCase
{
public
void
testEquals
()
{
TimeRange
timeRange1
=
new
TimeRange
(
TimeRange
.
TYPE_SNAPSHOT
,
0
,
30000000
);
assertTrue
(
timeRange1
.
equals
(
timeRange1
));
TimeRange
timeRange2
=
new
TimeRange
(
TimeRange
.
TYPE_SNAPSHOT
,
0
,
30000000
);
assertTrue
(
timeRange1
.
equals
(
timeRange2
));
TimeRange
timeRange3
=
new
TimeRange
(
TimeRange
.
TYPE_SNAPSHOT
,
0
,
60000000
);
assertFalse
(
timeRange1
.
equals
(
timeRange3
));
}
}
library/src/test/java/com/google/android/exoplayer/dash/DashChunkSourceTest.java
View file @
709fc773
This diff is collapsed.
Click to expand it.
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