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
d3a05c9a
authored
Oct 28, 2014
by
Andrey Udovenko
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Add ID3 Timed Metadata support for HLS #67
parent
ca310100
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
546 additions
and
5 deletions
demo/src/main/java/com/google/android/exoplayer/demo/full/FullPlayerActivity.java
demo/src/main/java/com/google/android/exoplayer/demo/full/player/DemoPlayer.java
demo/src/main/java/com/google/android/exoplayer/demo/full/player/HlsRendererBuilder.java
library/src/main/java/com/google/android/exoplayer/MediaFormat.java
library/src/main/java/com/google/android/exoplayer/metadata/Id3Parser.java
library/src/main/java/com/google/android/exoplayer/metadata/Metadata.java
library/src/main/java/com/google/android/exoplayer/metadata/MetadataParser.java
library/src/main/java/com/google/android/exoplayer/metadata/MetadataTrackRenderer.java
library/src/main/java/com/google/android/exoplayer/parser/ts/BitsArray.java
library/src/main/java/com/google/android/exoplayer/parser/ts/TsExtractor.java
library/src/main/java/com/google/android/exoplayer/util/MimeTypes.java
demo/src/main/java/com/google/android/exoplayer/demo/full/FullPlayerActivity.java
View file @
d3a05c9a
...
...
@@ -25,6 +25,7 @@ import com.google.android.exoplayer.demo.full.player.DemoPlayer;
import
com.google.android.exoplayer.demo.full.player.DemoPlayer.RendererBuilder
;
import
com.google.android.exoplayer.demo.full.player.HlsRendererBuilder
;
import
com.google.android.exoplayer.demo.full.player.SmoothStreamingRendererBuilder
;
import
com.google.android.exoplayer.metadata.Metadata
;
import
com.google.android.exoplayer.text.CaptionStyleCompat
;
import
com.google.android.exoplayer.text.SubtitleView
;
import
com.google.android.exoplayer.util.Util
;
...
...
@@ -38,6 +39,7 @@ import android.graphics.Point;
import
android.net.Uri
;
import
android.os.Bundle
;
import
android.text.TextUtils
;
import
android.util.Log
;
import
android.view.Display
;
import
android.view.Menu
;
import
android.view.MenuItem
;
...
...
@@ -54,11 +56,15 @@ import android.widget.PopupMenu;
import
android.widget.PopupMenu.OnMenuItemClickListener
;
import
android.widget.TextView
;
import
java.util.List
;
/**
* An activity that plays media using {@link DemoPlayer}.
*/
public
class
FullPlayerActivity
extends
Activity
implements
SurfaceHolder
.
Callback
,
OnClickListener
,
DemoPlayer
.
Listener
,
DemoPlayer
.
TextListener
{
DemoPlayer
.
Listener
,
DemoPlayer
.
TextListener
,
DemoPlayer
.
MetadataListener
{
private
static
final
String
TAG
=
"FullPlayerActivity"
;
private
static
final
float
CAPTION_LINE_HEIGHT_RATIO
=
0.0533f
;
private
static
final
int
MENU_GROUP_TRACKS
=
1
;
...
...
@@ -187,6 +193,7 @@ public class FullPlayerActivity extends Activity implements SurfaceHolder.Callba
player
=
new
DemoPlayer
(
getRendererBuilder
());
player
.
addListener
(
this
);
player
.
setTextListener
(
this
);
player
.
setMetadataListener
(
this
);
player
.
seekTo
(
playerPosition
);
playerNeedsPrepare
=
true
;
mediaController
.
setMediaPlayer
(
player
.
getPlayerControl
());
...
...
@@ -403,6 +410,16 @@ public class FullPlayerActivity extends Activity implements SurfaceHolder.Callba
}
}
// DemoPlayer.MetadataListener implementation
@Override
public
void
onMetadata
(
List
<
Metadata
>
metadata
)
{
for
(
int
i
=
0
;
i
<
metadata
.
size
();
i
++)
{
Metadata
next
=
metadata
.
get
(
i
);
Log
.
i
(
TAG
,
"ID3 TimedMetadata: key="
+
next
.
key
+
", value="
+
next
.
value
);
}
}
// SurfaceHolder.Callback implementation
@Override
...
...
demo/src/main/java/com/google/android/exoplayer/demo/full/player/DemoPlayer.java
View file @
d3a05c9a
...
...
@@ -26,6 +26,8 @@ import com.google.android.exoplayer.TrackRenderer;
import
com.google.android.exoplayer.chunk.ChunkSampleSource
;
import
com.google.android.exoplayer.chunk.MultiTrackChunkSource
;
import
com.google.android.exoplayer.drm.StreamingDrmSessionManager
;
import
com.google.android.exoplayer.metadata.Metadata
;
import
com.google.android.exoplayer.metadata.MetadataTrackRenderer
;
import
com.google.android.exoplayer.text.TextTrackRenderer
;
import
com.google.android.exoplayer.upstream.DefaultBandwidthMeter
;
import
com.google.android.exoplayer.util.PlayerControl
;
...
...
@@ -36,6 +38,7 @@ import android.os.Looper;
import
android.view.Surface
;
import
java.io.IOException
;
import
java.util.List
;
import
java.util.concurrent.CopyOnWriteArrayList
;
/**
...
...
@@ -46,7 +49,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
public
class
DemoPlayer
implements
ExoPlayer
.
Listener
,
ChunkSampleSource
.
EventListener
,
DefaultBandwidthMeter
.
EventListener
,
MediaCodecVideoTrackRenderer
.
EventListener
,
MediaCodecAudioTrackRenderer
.
EventListener
,
TextTrackRenderer
.
TextRenderer
,
StreamingDrmSessionManager
.
EventListener
{
MetadataTrackRenderer
.
MetadataRenderer
,
StreamingDrmSessionManager
.
EventListener
{
/**
* Builds renderers for the player.
...
...
@@ -134,6 +137,13 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
void
onText
(
String
text
);
}
/**
* A listener for receiving metadata parsed from the media stream.
*/
public
interface
MetadataListener
{
void
onMetadata
(
List
<
Metadata
>
metadata
);
}
// Constants pulled into this class for convenience.
public
static
final
int
STATE_IDLE
=
ExoPlayer
.
STATE_IDLE
;
public
static
final
int
STATE_PREPARING
=
ExoPlayer
.
STATE_PREPARING
;
...
...
@@ -144,11 +154,12 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
public
static
final
int
DISABLED_TRACK
=
-
1
;
public
static
final
int
PRIMARY_TRACK
=
0
;
public
static
final
int
RENDERER_COUNT
=
4
;
public
static
final
int
RENDERER_COUNT
=
5
;
public
static
final
int
TYPE_VIDEO
=
0
;
public
static
final
int
TYPE_AUDIO
=
1
;
public
static
final
int
TYPE_TEXT
=
2
;
public
static
final
int
TYPE_DEBUG
=
3
;
public
static
final
int
TYPE_TIMED_METADATA
=
3
;
public
static
final
int
TYPE_DEBUG
=
4
;
private
static
final
int
RENDERER_BUILDING_STATE_IDLE
=
1
;
private
static
final
int
RENDERER_BUILDING_STATE_BUILDING
=
2
;
...
...
@@ -173,6 +184,7 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
private
int
[]
selectedTracks
;
private
TextListener
textListener
;
private
MetadataListener
metadataListener
;
private
InternalErrorListener
internalErrorListener
;
private
InfoListener
infoListener
;
...
...
@@ -214,6 +226,10 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
textListener
=
listener
;
}
public
void
setMetadataListener
(
MetadataListener
listener
)
{
metadataListener
=
listener
;
}
public
void
setSurface
(
Surface
surface
)
{
this
.
surface
=
surface
;
pushSurfaceAndVideoTrack
(
false
);
...
...
@@ -459,6 +475,13 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
}
@Override
public
void
onMetadata
(
List
<
Metadata
>
metadata
)
{
if
(
metadataListener
!=
null
)
{
metadataListener
.
onMetadata
(
metadata
);
}
}
@Override
public
void
onPlayWhenReadyCommitted
()
{
// Do nothing.
}
...
...
demo/src/main/java/com/google/android/exoplayer/demo/full/player/HlsRendererBuilder.java
View file @
d3a05c9a
...
...
@@ -28,6 +28,8 @@ import com.google.android.exoplayer.hls.HlsMasterPlaylist;
import
com.google.android.exoplayer.hls.HlsMasterPlaylist.Variant
;
import
com.google.android.exoplayer.hls.HlsMasterPlaylistParser
;
import
com.google.android.exoplayer.hls.HlsSampleSource
;
import
com.google.android.exoplayer.metadata.Id3Parser
;
import
com.google.android.exoplayer.metadata.MetadataTrackRenderer
;
import
com.google.android.exoplayer.upstream.BufferPool
;
import
com.google.android.exoplayer.upstream.DataSource
;
import
com.google.android.exoplayer.upstream.UriDataSource
;
...
...
@@ -97,9 +99,13 @@ public class HlsRendererBuilder implements RendererBuilder, ManifestCallback<Hls
MediaCodec
.
VIDEO_SCALING_MODE_SCALE_TO_FIT
,
0
,
player
.
getMainHandler
(),
player
,
50
);
MediaCodecAudioTrackRenderer
audioRenderer
=
new
MediaCodecAudioTrackRenderer
(
sampleSource
);
MetadataTrackRenderer
metadataRenderer
=
new
MetadataTrackRenderer
(
sampleSource
,
new
Id3Parser
(),
player
,
player
.
getMainHandler
().
getLooper
());
TrackRenderer
[]
renderers
=
new
TrackRenderer
[
DemoPlayer
.
RENDERER_COUNT
];
renderers
[
DemoPlayer
.
TYPE_VIDEO
]
=
videoRenderer
;
renderers
[
DemoPlayer
.
TYPE_AUDIO
]
=
audioRenderer
;
renderers
[
DemoPlayer
.
TYPE_TIMED_METADATA
]
=
metadataRenderer
;
callback
.
onRenderers
(
null
,
null
,
renderers
);
}
...
...
library/src/main/java/com/google/android/exoplayer/MediaFormat.java
View file @
d3a05c9a
...
...
@@ -15,6 +15,7 @@
*/
package
com
.
google
.
android
.
exoplayer
;
import
com.google.android.exoplayer.util.MimeTypes
;
import
com.google.android.exoplayer.util.Util
;
import
android.annotation.SuppressLint
;
...
...
@@ -78,6 +79,11 @@ public class MediaFormat {
sampleRate
,
initializationData
);
}
public
static
MediaFormat
createId3Format
()
{
return
new
MediaFormat
(
MimeTypes
.
APPLICATION_ID3
,
NO_VALUE
,
NO_VALUE
,
NO_VALUE
,
NO_VALUE
,
NO_VALUE
,
NO_VALUE
,
null
);
}
@TargetApi
(
16
)
private
MediaFormat
(
android
.
media
.
MediaFormat
format
)
{
this
.
frameworkMediaFormat
=
format
;
...
...
library/src/main/java/com/google/android/exoplayer/metadata/Id3Parser.java
0 → 100644
View file @
d3a05c9a
/*
* 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
.
metadata
;
import
com.google.android.exoplayer.ParserException
;
import
com.google.android.exoplayer.parser.ts.BitsArray
;
import
com.google.android.exoplayer.util.MimeTypes
;
import
java.io.UnsupportedEncodingException
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.List
;
/**
* Extracts individual TXXX text frames from raw ID3 data.
*/
public
class
Id3Parser
implements
MetadataParser
{
@Override
public
boolean
canParse
(
String
mimeType
)
{
return
mimeType
.
equals
(
MimeTypes
.
APPLICATION_ID3
);
}
@Override
public
List
<
Metadata
>
parse
(
byte
[]
data
,
int
size
)
throws
UnsupportedEncodingException
,
ParserException
{
BitsArray
id3Buffer
=
new
BitsArray
(
data
,
size
);
int
id3Size
=
parseId3Header
(
id3Buffer
);
List
<
Metadata
>
metadata
=
new
ArrayList
<
Metadata
>();
while
(
id3Size
>
0
)
{
int
frameId0
=
id3Buffer
.
readUnsignedByte
();
int
frameId1
=
id3Buffer
.
readUnsignedByte
();
int
frameId2
=
id3Buffer
.
readUnsignedByte
();
int
frameId3
=
id3Buffer
.
readUnsignedByte
();
int
frameSize
=
id3Buffer
.
readSynchSafeInt
();
if
(
frameSize
<=
1
)
{
break
;
}
id3Buffer
.
skipBytes
(
2
);
// Skip frame flags.
// Check Frame ID == TXXX.
if
(
frameId0
==
'T'
&&
frameId1
==
'X'
&&
frameId2
==
'X'
&&
frameId3
==
'X'
)
{
int
encoding
=
id3Buffer
.
readUnsignedByte
();
String
charset
=
getCharsetName
(
encoding
);
byte
[]
frame
=
new
byte
[
frameSize
-
1
];
id3Buffer
.
readBytes
(
frame
,
0
,
frameSize
-
1
);
int
firstZeroIndex
=
indexOf
(
frame
,
0
,
(
byte
)
0
);
String
key
=
new
String
(
frame
,
0
,
firstZeroIndex
,
charset
);
int
valueStartIndex
=
indexOfNot
(
frame
,
firstZeroIndex
,
(
byte
)
0
);
int
valueEndIndex
=
indexOf
(
frame
,
valueStartIndex
,
(
byte
)
0
);
String
value
=
new
String
(
frame
,
valueStartIndex
,
valueEndIndex
-
valueStartIndex
,
charset
);
metadata
.
add
(
new
Metadata
(
key
,
value
));
}
else
{
id3Buffer
.
skipBytes
(
frameSize
);
}
id3Size
-=
frameSize
+
10
/* header size */
;
}
return
Collections
.
unmodifiableList
(
metadata
);
}
private
static
int
indexOf
(
byte
[]
data
,
int
fromIndex
,
byte
key
)
{
for
(
int
i
=
fromIndex
;
i
<
data
.
length
;
i
++)
{
if
(
data
[
i
]
==
key
)
{
return
i
;
}
}
return
data
.
length
;
}
private
static
int
indexOfNot
(
byte
[]
data
,
int
fromIndex
,
byte
key
)
{
for
(
int
i
=
fromIndex
;
i
<
data
.
length
;
i
++)
{
if
(
data
[
i
]
!=
key
)
{
return
i
;
}
}
return
data
.
length
;
}
/**
* Parses ID3 header.
* @param id3Buffer A {@link BitsArray} with raw ID3 data.
* @return The size of data that contains ID3 frames without header and footer.
* @throws ParserException If ID3 file identifier != "ID3".
*/
private
static
int
parseId3Header
(
BitsArray
id3Buffer
)
throws
ParserException
{
int
id1
=
id3Buffer
.
readUnsignedByte
();
int
id2
=
id3Buffer
.
readUnsignedByte
();
int
id3
=
id3Buffer
.
readUnsignedByte
();
if
(
id1
!=
'I'
||
id2
!=
'D'
||
id3
!=
'3'
)
{
throw
new
ParserException
(
String
.
format
(
"Unexpected ID3 file identifier, expected \"ID3\", actual \"%c%c%c\"."
,
id1
,
id2
,
id3
));
}
id3Buffer
.
skipBytes
(
2
);
// Skip version.
int
flags
=
id3Buffer
.
readUnsignedByte
();
int
id3Size
=
id3Buffer
.
readSynchSafeInt
();
// Check if extended header presents.
if
((
flags
&
0x2
)
!=
0
)
{
int
extendedHeaderSize
=
id3Buffer
.
readSynchSafeInt
();
if
(
extendedHeaderSize
>
4
)
{
id3Buffer
.
skipBytes
(
extendedHeaderSize
-
4
);
}
id3Size
-=
extendedHeaderSize
;
}
// Check if footer presents.
if
((
flags
&
0x8
)
!=
0
)
{
id3Size
-=
10
;
}
return
id3Size
;
}
/**
* Maps encoding byte from ID3v2 frame to a Charset.
* @param encodingByte The value of encoding byte from ID3v2 frame.
* @return Charset name.
*/
private
static
String
getCharsetName
(
int
encodingByte
)
{
switch
(
encodingByte
)
{
case
0
:
return
"ISO-8859-1"
;
case
1
:
return
"UTF-16"
;
case
2
:
return
"UTF-16BE"
;
case
3
:
return
"UTF-8"
;
default
:
return
"ISO-8859-1"
;
}
}
}
library/src/main/java/com/google/android/exoplayer/metadata/Metadata.java
0 → 100644
View file @
d3a05c9a
/*
* 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
.
metadata
;
/**
* A metadata that contains textual data associated with time indices.
*/
public
class
Metadata
{
public
final
String
key
;
public
final
String
value
;
public
Metadata
(
String
key
,
String
value
)
{
this
.
key
=
key
;
this
.
value
=
value
;
}
}
library/src/main/java/com/google/android/exoplayer/metadata/MetadataParser.java
0 → 100644
View file @
d3a05c9a
/*
* 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
.
metadata
;
import
java.io.IOException
;
import
java.util.List
;
/**
* Parses {@link Metadata}s from binary data.
*/
public
interface
MetadataParser
{
/**
* Checks whether the parser supports a given mime type.
*
* @param mimeType A subtitle mime type.
* @return Whether the mime type is supported.
*/
public
boolean
canParse
(
String
mimeType
);
/**
* Parses a list of {@link Metadata} objects from the provided binary data.
*
* @param data The raw binary data from which to parse the metadata.
* @param size The size of the input data.
* @return A parsed {@link List} of {@link Metadata} objects.
* @throws IOException If a problem occurred parsing the data.
*/
public
List
<
Metadata
>
parse
(
byte
[]
data
,
int
size
)
throws
IOException
;
}
library/src/main/java/com/google/android/exoplayer/metadata/MetadataTrackRenderer.java
0 → 100644
View file @
d3a05c9a
/*
* 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
.
metadata
;
import
com.google.android.exoplayer.ExoPlaybackException
;
import
com.google.android.exoplayer.MediaFormatHolder
;
import
com.google.android.exoplayer.SampleHolder
;
import
com.google.android.exoplayer.SampleSource
;
import
com.google.android.exoplayer.TrackRenderer
;
import
com.google.android.exoplayer.util.Assertions
;
import
android.os.Handler
;
import
android.os.Handler.Callback
;
import
android.os.Looper
;
import
android.os.Message
;
import
java.io.IOException
;
import
java.util.List
;
/**
* A {@link TrackRenderer} for metadata embedded in a media stream.
*/
public
class
MetadataTrackRenderer
extends
TrackRenderer
implements
Callback
{
/**
* An interface for components that process metadata.
*/
public
interface
MetadataRenderer
{
/**
* Invoked each time there is a metadata associated with current playback time.
*
* @param metadata The metadata to process.
*/
void
onMetadata
(
List
<
Metadata
>
metadata
);
}
private
static
final
int
MSG_INVOKE_RENDERER
=
0
;
private
final
SampleSource
source
;
private
final
MetadataParser
metadataParser
;
private
final
MetadataRenderer
metadataRenderer
;
private
final
Handler
metadataHandler
;
private
final
MediaFormatHolder
formatHolder
;
private
final
SampleHolder
sampleHolder
;
private
int
trackIndex
;
private
long
currentPositionUs
;
private
boolean
inputStreamEnded
;
private
long
pendingMetadataTimestamp
;
private
List
<
Metadata
>
pendingMetadata
;
/**
* @param source A source from which samples containing metadata can be read.
* @param metadataParser A parser for parsing the metadata.
* @param metadataRenderer The metadata renderer to receive the parsed metadata.
* @param metadataRendererLooper The looper associated with the thread on which metadataRenderer
* should be invoked. If the renderer makes use of standard Android UI components, then this
* should normally be the looper associated with the applications' main thread, which can be
* obtained using {@link android.app.Activity#getMainLooper()}. Null may be passed if the
* renderer should be invoked directly on the player's internal rendering thread.
*/
public
MetadataTrackRenderer
(
SampleSource
source
,
MetadataParser
metadataParser
,
MetadataRenderer
metadataRenderer
,
Looper
metadataRendererLooper
)
{
this
.
source
=
Assertions
.
checkNotNull
(
source
);
this
.
metadataParser
=
Assertions
.
checkNotNull
(
metadataParser
);
this
.
metadataRenderer
=
Assertions
.
checkNotNull
(
metadataRenderer
);
this
.
metadataHandler
=
metadataRendererLooper
==
null
?
null
:
new
Handler
(
metadataRendererLooper
,
this
);
formatHolder
=
new
MediaFormatHolder
();
sampleHolder
=
new
SampleHolder
(
SampleHolder
.
BUFFER_REPLACEMENT_MODE_NORMAL
);
}
@Override
protected
int
doPrepare
()
throws
ExoPlaybackException
{
try
{
boolean
sourcePrepared
=
source
.
prepare
();
if
(!
sourcePrepared
)
{
return
TrackRenderer
.
STATE_UNPREPARED
;
}
}
catch
(
IOException
e
)
{
throw
new
ExoPlaybackException
(
e
);
}
for
(
int
i
=
0
;
i
<
source
.
getTrackCount
();
i
++)
{
if
(
metadataParser
.
canParse
(
source
.
getTrackInfo
(
i
).
mimeType
))
{
trackIndex
=
i
;
return
TrackRenderer
.
STATE_PREPARED
;
}
}
return
TrackRenderer
.
STATE_IGNORE
;
}
@Override
protected
void
onEnabled
(
long
positionUs
,
boolean
joining
)
{
source
.
enable
(
trackIndex
,
positionUs
);
seekToInternal
(
positionUs
);
}
@Override
protected
void
seekTo
(
long
positionUs
)
throws
ExoPlaybackException
{
source
.
seekToUs
(
positionUs
);
seekToInternal
(
positionUs
);
}
private
void
seekToInternal
(
long
positionUs
)
{
currentPositionUs
=
positionUs
;
pendingMetadata
=
null
;
inputStreamEnded
=
false
;
}
@Override
protected
void
doSomeWork
(
long
positionUs
,
long
elapsedRealtimeUs
)
throws
ExoPlaybackException
{
currentPositionUs
=
positionUs
;
try
{
source
.
continueBuffering
(
positionUs
);
}
catch
(
IOException
e
)
{
throw
new
ExoPlaybackException
(
e
);
}
if
(!
inputStreamEnded
&&
pendingMetadata
==
null
)
{
try
{
int
result
=
source
.
readData
(
trackIndex
,
positionUs
,
formatHolder
,
sampleHolder
,
false
);
if
(
result
==
SampleSource
.
SAMPLE_READ
)
{
pendingMetadataTimestamp
=
sampleHolder
.
timeUs
;
pendingMetadata
=
metadataParser
.
parse
(
sampleHolder
.
data
.
array
(),
sampleHolder
.
size
);
sampleHolder
.
data
.
clear
();
}
else
if
(
result
==
SampleSource
.
END_OF_STREAM
)
{
inputStreamEnded
=
true
;
}
}
catch
(
IOException
e
)
{
throw
new
ExoPlaybackException
(
e
);
}
}
if
(
pendingMetadata
!=
null
&&
pendingMetadataTimestamp
<=
currentPositionUs
)
{
invokeRenderer
(
pendingMetadata
);
pendingMetadata
=
null
;
}
}
@Override
protected
void
onDisabled
()
{
pendingMetadata
=
null
;
source
.
disable
(
trackIndex
);
}
@Override
protected
long
getDurationUs
()
{
return
source
.
getTrackInfo
(
trackIndex
).
durationUs
;
}
@Override
protected
long
getCurrentPositionUs
()
{
return
currentPositionUs
;
}
@Override
protected
long
getBufferedPositionUs
()
{
return
TrackRenderer
.
END_OF_TRACK_US
;
}
@Override
protected
boolean
isEnded
()
{
return
inputStreamEnded
;
}
@Override
protected
boolean
isReady
()
{
return
true
;
}
private
void
invokeRenderer
(
List
<
Metadata
>
metadata
)
{
if
(
metadataHandler
!=
null
)
{
metadataHandler
.
obtainMessage
(
MSG_INVOKE_RENDERER
,
metadata
).
sendToTarget
();
}
else
{
invokeRendererInternal
(
metadata
);
}
}
@SuppressWarnings
(
"unchecked"
)
@Override
public
boolean
handleMessage
(
Message
msg
)
{
switch
(
msg
.
what
)
{
case
MSG_INVOKE_RENDERER:
invokeRendererInternal
((
List
<
Metadata
>)
msg
.
obj
);
return
true
;
}
return
false
;
}
private
void
invokeRendererInternal
(
List
<
Metadata
>
metadata
)
{
metadataRenderer
.
onMetadata
(
metadata
);
}
}
library/src/main/java/com/google/android/exoplayer/parser/ts/BitsArray.java
View file @
d3a05c9a
...
...
@@ -33,6 +33,14 @@ public final class BitsArray {
private
int
byteOffset
;
private
int
bitOffset
;
public
BitsArray
()
{
}
public
BitsArray
(
byte
[]
data
,
int
limit
)
{
this
.
data
=
data
;
this
.
limit
=
limit
;
}
/**
* Resets the state.
*/
...
...
@@ -240,6 +248,22 @@ public final class BitsArray {
return
limit
==
0
;
}
/**
* Reads a Synchsafe integer.
* Synchsafe integers are integers that keep the highest bit of every byte zeroed.
* A 32 bit synchsafe integer can store 28 bits of information.
*
* @return The value of the parsed Synchsafe integer.
*/
public
int
readSynchSafeInt
()
{
int
b1
=
readUnsignedByte
();
int
b2
=
readUnsignedByte
();
int
b3
=
readUnsignedByte
();
int
b4
=
readUnsignedByte
();
return
(
b1
<<
21
)
|
(
b2
<<
14
)
|
(
b3
<<
7
)
|
b4
;
}
// TODO: Find a better place for this method.
/**
* Finds the next Adts sync word.
...
...
library/src/main/java/com/google/android/exoplayer/parser/ts/TsExtractor.java
View file @
d3a05c9a
...
...
@@ -58,6 +58,7 @@ public final class TsExtractor {
private
static
final
int
TS_STREAM_TYPE_AAC
=
0x0F
;
private
static
final
int
TS_STREAM_TYPE_H264
=
0x1B
;
private
static
final
int
TS_STREAM_TYPE_ID3
=
0x15
;
private
static
final
int
DEFAULT_BUFFER_SEGMENT_SIZE
=
64
*
1024
;
...
...
@@ -345,6 +346,9 @@ public final class TsExtractor {
case
TS_STREAM_TYPE_H264:
pesPayloadReader
=
new
H264Reader
();
break
;
case
TS_STREAM_TYPE_ID3:
pesPayloadReader
=
new
Id3Reader
();
break
;
}
if
(
pesPayloadReader
!=
null
)
{
...
...
@@ -689,8 +693,25 @@ public final class TsExtractor {
}
/**
*
Simplified version of SampleHolder for internal buffering
.
*
Parses ID3 data and extracts individual text information frames
.
*/
private
class
Id3Reader
extends
PesPayloadReader
{
public
Id3Reader
()
{
setMediaFormat
(
MediaFormat
.
createId3Format
());
}
@SuppressLint
(
"InlinedApi"
)
@Override
public
void
read
(
BitsArray
pesBuffer
,
int
pesPayloadSize
,
long
pesTimeUs
)
{
addSample
(
pesBuffer
,
pesPayloadSize
,
pesTimeUs
,
MediaExtractor
.
SAMPLE_FLAG_SYNC
);
}
}
/**
* Simplified version of SampleHolder for internal buffering.
*/
private
static
class
Sample
{
public
byte
[]
data
;
...
...
library/src/main/java/com/google/android/exoplayer/util/MimeTypes.java
View file @
d3a05c9a
...
...
@@ -37,6 +37,7 @@ public class MimeTypes {
public
static
final
String
TEXT_VTT
=
BASE_TYPE_TEXT
+
"/vtt"
;
public
static
final
String
APPLICATION_ID3
=
BASE_TYPE_APPLICATION
+
"/id3"
;
public
static
final
String
APPLICATION_TTML
=
BASE_TYPE_APPLICATION
+
"/ttml+xml"
;
private
MimeTypes
()
{}
...
...
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