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
99960ace
authored
May 14, 2020
by
Will
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Make FLV video seekable by a seekMap.
parent
535e14cb
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
65 additions
and
4 deletions
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/flv/FlvExtractor.java
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/flv/ScriptTagPayloadReader.java
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/flv/FlvExtractor.java
View file @
99960ace
...
@@ -17,6 +17,7 @@ package com.google.android.exoplayer2.extractor.flv;
...
@@ -17,6 +17,7 @@ package com.google.android.exoplayer2.extractor.flv;
import
androidx.annotation.IntDef
;
import
androidx.annotation.IntDef
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.extractor.ChunkIndex
;
import
com.google.android.exoplayer2.extractor.Extractor
;
import
com.google.android.exoplayer2.extractor.Extractor
;
import
com.google.android.exoplayer2.extractor.ExtractorInput
;
import
com.google.android.exoplayer2.extractor.ExtractorInput
;
import
com.google.android.exoplayer2.extractor.ExtractorOutput
;
import
com.google.android.exoplayer2.extractor.ExtractorOutput
;
...
@@ -29,6 +30,7 @@ import java.io.IOException;
...
@@ -29,6 +30,7 @@ import java.io.IOException;
import
java.lang.annotation.Documented
;
import
java.lang.annotation.Documented
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.RetentionPolicy
;
import
java.lang.annotation.RetentionPolicy
;
import
java.util.List
;
import
org.checkerframework.checker.nullness.qual.MonotonicNonNull
;
import
org.checkerframework.checker.nullness.qual.MonotonicNonNull
;
import
org.checkerframework.checker.nullness.qual.RequiresNonNull
;
import
org.checkerframework.checker.nullness.qual.RequiresNonNull
;
...
@@ -83,6 +85,7 @@ public final class FlvExtractor implements Extractor {
...
@@ -83,6 +85,7 @@ public final class FlvExtractor implements Extractor {
private
int
tagDataSize
;
private
int
tagDataSize
;
private
long
tagTimestampUs
;
private
long
tagTimestampUs
;
private
boolean
outputSeekMap
;
private
boolean
outputSeekMap
;
private
boolean
seekMapIsSeekable
;
private
@MonotonicNonNull
AudioTagPayloadReader
audioReader
;
private
@MonotonicNonNull
AudioTagPayloadReader
audioReader
;
private
@MonotonicNonNull
VideoTagPayloadReader
videoReader
;
private
@MonotonicNonNull
VideoTagPayloadReader
videoReader
;
...
@@ -133,7 +136,12 @@ public final class FlvExtractor implements Extractor {
...
@@ -133,7 +136,12 @@ public final class FlvExtractor implements Extractor {
@Override
@Override
public
void
seek
(
long
position
,
long
timeUs
)
{
public
void
seek
(
long
position
,
long
timeUs
)
{
if
(
seekMapIsSeekable
)
{
state
=
STATE_READING_TAG_HEADER
;
}
else
{
state
=
STATE_READING_FLV_HEADER
;
state
=
STATE_READING_FLV_HEADER
;
mediaTagTimestampOffsetUs
=
C
.
TIME_UNSET
;
}
outputFirstSample
=
false
;
outputFirstSample
=
false
;
bytesToNextTagHeader
=
0
;
bytesToNextTagHeader
=
0
;
}
}
...
@@ -263,11 +271,13 @@ public final class FlvExtractor implements Extractor {
...
@@ -263,11 +271,13 @@ public final class FlvExtractor implements Extractor {
wasSampleOutput
=
videoReader
.
consume
(
prepareTagData
(
input
),
timestampUs
);
wasSampleOutput
=
videoReader
.
consume
(
prepareTagData
(
input
),
timestampUs
);
}
else
if
(
tagType
==
TAG_TYPE_SCRIPT_DATA
&&
!
outputSeekMap
)
{
}
else
if
(
tagType
==
TAG_TYPE_SCRIPT_DATA
&&
!
outputSeekMap
)
{
wasSampleOutput
=
metadataReader
.
consume
(
prepareTagData
(
input
),
timestampUs
);
wasSampleOutput
=
metadataReader
.
consume
(
prepareTagData
(
input
),
timestampUs
);
long
durationUs
=
metadataReader
.
getDurationUs
();
SeekMap
seekMap
=
buildSeekMap
(
metadataReader
.
getSeekMapTimes
(),
if
(
durationUs
!=
C
.
TIME_UNSET
)
{
metadataReader
.
getSeekMapFilePositions
(),
extractorOutput
.
seekMap
(
new
SeekMap
.
Unseekable
(
durationUs
));
metadataReader
.
getDurationUs
(),
input
.
getLength
());
seekMapIsSeekable
=
seekMap
.
isSeekable
();
extractorOutput
.
seekMap
(
seekMap
);
outputSeekMap
=
true
;
outputSeekMap
=
true
;
}
}
else
{
}
else
{
input
.
skipFully
(
tagDataSize
);
input
.
skipFully
(
tagDataSize
);
wasConsumed
=
false
;
wasConsumed
=
false
;
...
@@ -301,6 +311,32 @@ public final class FlvExtractor implements Extractor {
...
@@ -301,6 +311,32 @@ public final class FlvExtractor implements Extractor {
}
}
}
}
private
SeekMap
buildSeekMap
(
List
<
Double
>
times
,
List
<
Double
>
filePositions
,
long
durationUs
,
long
flvDataSize
)
{
if
(
durationUs
==
C
.
TIME_UNSET
||
times
==
null
||
times
.
size
()
==
0
||
filePositions
==
null
||
filePositions
.
size
()
!=
times
.
size
())
{
// Key frames information is missing or incomplete.
return
new
SeekMap
.
Unseekable
(
durationUs
);
}
int
keyFrameSize
=
times
.
size
();
int
[]
sizes
=
new
int
[
keyFrameSize
];
long
[]
offsets
=
new
long
[
keyFrameSize
];
long
[]
durationsUs
=
new
long
[
keyFrameSize
];
long
[]
timesUs
=
new
long
[
keyFrameSize
];
for
(
int
i
=
0
;
i
<
keyFrameSize
;
i
++)
{
timesUs
[
i
]
=
(
long
)
(
times
.
get
(
i
)
*
C
.
MICROS_PER_SECOND
);
offsets
[
i
]
=
(
long
)
(
filePositions
.
get
(
i
)
+
0
);
}
for
(
int
i
=
0
;
i
<
keyFrameSize
-
1
;
i
++)
{
sizes
[
i
]
=
(
int
)
(
offsets
[
i
+
1
]
-
offsets
[
i
]);
durationsUs
[
i
]
=
timesUs
[
i
+
1
]
-
timesUs
[
i
];
}
sizes
[
keyFrameSize
-
1
]
=
(
int
)
(
flvDataSize
-
sizes
[
keyFrameSize
-
2
]);
durationsUs
[
keyFrameSize
-
1
]
=
durationUs
-
timesUs
[
keyFrameSize
-
1
];
return
new
ChunkIndex
(
sizes
,
offsets
,
durationsUs
,
timesUs
);
}
private
long
getCurrentTimestampUs
()
{
private
long
getCurrentTimestampUs
()
{
return
outputFirstSample
return
outputFirstSample
?
(
mediaTagTimestampOffsetUs
+
tagTimestampUs
)
?
(
mediaTagTimestampOffsetUs
+
tagTimestampUs
)
...
...
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/flv/ScriptTagPayloadReader.java
View file @
99960ace
...
@@ -23,6 +23,7 @@ import com.google.android.exoplayer2.util.ParsableByteArray;
...
@@ -23,6 +23,7 @@ import com.google.android.exoplayer2.util.ParsableByteArray;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.Date
;
import
java.util.Date
;
import
java.util.HashMap
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Map
;
/**
/**
...
@@ -32,6 +33,9 @@ import java.util.Map;
...
@@ -32,6 +33,9 @@ import java.util.Map;
private
static
final
String
NAME_METADATA
=
"onMetaData"
;
private
static
final
String
NAME_METADATA
=
"onMetaData"
;
private
static
final
String
KEY_DURATION
=
"duration"
;
private
static
final
String
KEY_DURATION
=
"duration"
;
private
static
final
String
KEY_KEY_FRAMES
=
"keyframes"
;
private
static
final
String
KEY_FILE_POSITIONS
=
"filepositions"
;
private
static
final
String
KEY_TIMES
=
"times"
;
// AMF object types
// AMF object types
private
static
final
int
AMF_TYPE_NUMBER
=
0
;
private
static
final
int
AMF_TYPE_NUMBER
=
0
;
...
@@ -45,6 +49,9 @@ import java.util.Map;
...
@@ -45,6 +49,9 @@ import java.util.Map;
private
long
durationUs
;
private
long
durationUs
;
private
List
<
Double
>
seekMapFilePositions
;
private
List
<
Double
>
seekMapTimes
;
public
ScriptTagPayloadReader
()
{
public
ScriptTagPayloadReader
()
{
super
(
new
DummyTrackOutput
());
super
(
new
DummyTrackOutput
());
durationUs
=
C
.
TIME_UNSET
;
durationUs
=
C
.
TIME_UNSET
;
...
@@ -89,6 +96,16 @@ import java.util.Map;
...
@@ -89,6 +96,16 @@ import java.util.Map;
durationUs
=
(
long
)
(
durationSeconds
*
C
.
MICROS_PER_SECOND
);
durationUs
=
(
long
)
(
durationSeconds
*
C
.
MICROS_PER_SECOND
);
}
}
}
}
if
(
metadata
.
containsKey
(
KEY_KEY_FRAMES
))
{
Object
frames
=
metadata
.
get
(
KEY_KEY_FRAMES
);
if
(
frames
instanceof
Map
)
{
Map
framesMap
=
(
Map
)
metadata
.
get
(
KEY_KEY_FRAMES
);
if
(
framesMap
.
size
()
>
0
)
{
seekMapFilePositions
=
(
List
<
Double
>)
framesMap
.
get
(
KEY_FILE_POSITIONS
);
seekMapTimes
=
(
List
<
Double
>)
framesMap
.
get
(
KEY_TIMES
);
}
}
}
return
false
;
return
false
;
}
}
...
@@ -224,4 +241,12 @@ import java.util.Map;
...
@@ -224,4 +241,12 @@ import java.util.Map;
return
null
;
return
null
;
}
}
}
}
public
List
<
Double
>
getSeekMapFilePositions
()
{
return
seekMapFilePositions
;
}
public
List
<
Double
>
getSeekMapTimes
()
{
return
seekMapTimes
;
}
}
}
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