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
5b952294
authored
Feb 04, 2022
by
Dustin
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Refactor to ChunkHander, add Mp3ChunkHandler
parent
aee15f6c
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
372 additions
and
240 deletions
library/common/src/main/java/com/google/android/exoplayer2/util/ParsableByteArray.java
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/AvcChunkPeeker.java → library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/AvcChunkHandler.java
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/AviExtractor.java
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/AviSeekMap.java
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/LinearClock.java → library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/ChunkClock.java
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/AviTrack.java → library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/ChunkHandler.java
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/ChunkPeeker.java
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/Mp3ChunkHandler.java
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/Mp4vChunkPeeker.java → library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/Mp4vChunkHandler.java
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/NalChunkPeeker.java
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/PicCountClock.java
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/AvcChunkPeekerTest.java
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/AviExtractorRoboTest.java
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/AviExtractorTest.java
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/AviSeekMapTest.java
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/AviTrackTest.java → library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/ChunkHandlerTest.java
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/DataHelper.java
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/LinearClockTest.java
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/MockNalChunkPeeker.java
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/Mp4vChunkPeekerTest.java
library/common/src/main/java/com/google/android/exoplayer2/util/ParsableByteArray.java
View file @
5b952294
...
@@ -565,4 +565,22 @@ public final class ParsableByteArray {
...
@@ -565,4 +565,22 @@ public final class ParsableByteArray {
position
+=
length
;
position
+=
length
;
return
value
;
return
value
;
}
}
/**
* The data from the end of the buffer is copied to the front
* The limit() because the bytesLeft() and position is zero
*/
public
void
compact
()
{
if
(
bytesLeft
()
==
0
)
{
limit
=
0
;
}
else
{
final
ByteBuffer
byteBuffer
=
ByteBuffer
.
wrap
(
data
);
byteBuffer
.
limit
(
limit
);
byteBuffer
.
position
(
position
);
byteBuffer
.
compact
();
byteBuffer
.
flip
();
limit
=
byteBuffer
.
limit
();
}
position
=
0
;
}
}
}
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/AvcChunk
Peek
er.java
→
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/AvcChunk
Handl
er.java
View file @
5b952294
...
@@ -15,6 +15,7 @@
...
@@ -15,6 +15,7 @@
*/
*/
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
avi
;
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
avi
;
import
androidx.annotation.NonNull
;
import
androidx.annotation.VisibleForTesting
;
import
androidx.annotation.VisibleForTesting
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.extractor.ExtractorInput
;
import
com.google.android.exoplayer2.extractor.ExtractorInput
;
...
@@ -27,7 +28,7 @@ import java.io.IOException;
...
@@ -27,7 +28,7 @@ import java.io.IOException;
* Corrects the time and PAR for H264 streams
* Corrects the time and PAR for H264 streams
* AVC is very rare in AVI due to the rise of the mp4 container
* AVC is very rare in AVI due to the rise of the mp4 container
*/
*/
public
class
AvcChunk
Peek
er
extends
NalChunkPeeker
{
public
class
AvcChunk
Handl
er
extends
NalChunkPeeker
{
private
static
final
int
NAL_TYPE_MASK
=
0x1f
;
private
static
final
int
NAL_TYPE_MASK
=
0x1f
;
private
static
final
int
NAL_TYPE_IDR
=
5
;
//I Frame
private
static
final
int
NAL_TYPE_IDR
=
5
;
//I Frame
private
static
final
int
NAL_TYPE_SEI
=
6
;
private
static
final
int
NAL_TYPE_SEI
=
6
;
...
@@ -35,22 +36,21 @@ public class AvcChunkPeeker extends NalChunkPeeker {
...
@@ -35,22 +36,21 @@ public class AvcChunkPeeker extends NalChunkPeeker {
private
static
final
int
NAL_TYPE_PPS
=
8
;
private
static
final
int
NAL_TYPE_PPS
=
8
;
private
static
final
int
NAL_TYPE_AUD
=
9
;
private
static
final
int
NAL_TYPE_AUD
=
9
;
private
final
PicCountClock
picCountClock
;
private
final
Format
.
Builder
formatBuilder
;
private
final
Format
.
Builder
formatBuilder
;
private
final
TrackOutput
trackOutput
;
private
float
pixelWidthHeightRatio
=
1
f
;
private
float
pixelWidthHeightRatio
=
1
f
;
private
NalUnitUtil
.
SpsData
spsData
;
private
NalUnitUtil
.
SpsData
spsData
;
public
AvcChunkPeeker
(
Format
.
Builder
formatBuilder
,
TrackOutput
trackOutput
,
LinearClock
clock
)
{
public
AvcChunkHandler
(
int
id
,
@NonNull
TrackOutput
trackOutput
,
super
(
16
);
@NonNull
ChunkClock
clock
,
Format
.
Builder
formatBuilder
)
{
super
(
id
,
trackOutput
,
new
PicCountClock
(
clock
.
durationUs
,
clock
.
chunks
),
16
);
this
.
formatBuilder
=
formatBuilder
;
this
.
formatBuilder
=
formatBuilder
;
this
.
trackOutput
=
trackOutput
;
picCountClock
=
new
PicCountClock
(
clock
.
durationUs
,
clock
.
length
);
}
}
@NonNull
@Override
public
PicCountClock
getClock
()
{
public
PicCountClock
getClock
()
{
return
picCountC
lock
;
return
(
PicCountClock
)
c
lock
;
}
}
@Override
@Override
...
@@ -84,13 +84,13 @@ public class AvcChunkPeeker extends NalChunkPeeker {
...
@@ -84,13 +84,13 @@ public class AvcChunkPeeker extends NalChunkPeeker {
if
(
spsData
.
picOrderCountType
==
0
)
{
if
(
spsData
.
picOrderCountType
==
0
)
{
int
picOrderCountLsb
=
in
.
readBits
(
spsData
.
picOrderCntLsbLength
);
int
picOrderCountLsb
=
in
.
readBits
(
spsData
.
picOrderCntLsbLength
);
//Log.d("Test", "FrameNum: " + frame + " cnt=" + picOrderCountLsb);
//Log.d("Test", "FrameNum: " + frame + " cnt=" + picOrderCountLsb);
picCountClock
.
setPicCount
(
picOrderCountLsb
);
getClock
()
.
setPicCount
(
picOrderCountLsb
);
return
;
return
;
}
else
if
(
spsData
.
picOrderCountType
==
2
)
{
}
else
if
(
spsData
.
picOrderCountType
==
2
)
{
picCountClock
.
setPicCount
(
frameNum
);
getClock
()
.
setPicCount
(
frameNum
);
return
;
return
;
}
}
picCountClock
.
setIndex
(
picCountC
lock
.
getIndex
());
clock
.
setIndex
(
c
lock
.
getIndex
());
}
}
@VisibleForTesting
@VisibleForTesting
...
@@ -99,10 +99,10 @@ public class AvcChunkPeeker extends NalChunkPeeker {
...
@@ -99,10 +99,10 @@ public class AvcChunkPeeker extends NalChunkPeeker {
nalTypeOffset
=
seekNextNal
(
input
,
spsStart
);
nalTypeOffset
=
seekNextNal
(
input
,
spsStart
);
spsData
=
NalUnitUtil
.
parseSpsNalUnitPayload
(
buffer
,
spsStart
,
pos
);
spsData
=
NalUnitUtil
.
parseSpsNalUnitPayload
(
buffer
,
spsStart
,
pos
);
if
(
spsData
.
picOrderCountType
==
0
)
{
if
(
spsData
.
picOrderCountType
==
0
)
{
picCountClock
.
setMaxPicCount
(
1
<<
spsData
.
picOrderCntLsbLength
,
2
);
getClock
()
.
setMaxPicCount
(
1
<<
spsData
.
picOrderCntLsbLength
,
2
);
}
else
if
(
spsData
.
picOrderCountType
==
2
)
{
}
else
if
(
spsData
.
picOrderCountType
==
2
)
{
//Plus one because we double the frame number
//Plus one because we double the frame number
picCountClock
.
setMaxPicCount
(
1
<<
spsData
.
frameNumLength
,
1
);
getClock
()
.
setMaxPicCount
(
1
<<
spsData
.
frameNumLength
,
1
);
}
}
if
(
spsData
.
pixelWidthHeightRatio
!=
pixelWidthHeightRatio
)
{
if
(
spsData
.
pixelWidthHeightRatio
!=
pixelWidthHeightRatio
)
{
pixelWidthHeightRatio
=
spsData
.
pixelWidthHeightRatio
;
pixelWidthHeightRatio
=
spsData
.
pixelWidthHeightRatio
;
...
@@ -124,7 +124,7 @@ public class AvcChunkPeeker extends NalChunkPeeker {
...
@@ -124,7 +124,7 @@ public class AvcChunkPeeker extends NalChunkPeeker {
updatePicCountClock
(
nalTypeOffset
);
updatePicCountClock
(
nalTypeOffset
);
return
;
return
;
case
NAL_TYPE_IDR:
case
NAL_TYPE_IDR:
picCountClock
.
syncIndexes
();
getClock
()
.
syncIndexes
();
return
;
return
;
case
NAL_TYPE_AUD:
case
NAL_TYPE_AUD:
case
NAL_TYPE_SEI:
case
NAL_TYPE_SEI:
...
...
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/AviExtractor.java
View file @
5b952294
...
@@ -103,7 +103,7 @@ public class AviExtractor implements Extractor {
...
@@ -103,7 +103,7 @@ public class AviExtractor implements Extractor {
@VisibleForTesting
@VisibleForTesting
static
final
int
STATE_READ_IDX1
=
2
;
static
final
int
STATE_READ_IDX1
=
2
;
@VisibleForTesting
@VisibleForTesting
static
final
int
STATE_READ_
SAMPLE
S
=
3
;
static
final
int
STATE_READ_
CHUNK
S
=
3
;
@VisibleForTesting
@VisibleForTesting
static
final
int
STATE_SEEK_START
=
4
;
static
final
int
STATE_SEEK_START
=
4
;
...
@@ -127,9 +127,9 @@ public class AviExtractor implements Extractor {
...
@@ -127,9 +127,9 @@ public class AviExtractor implements Extractor {
private
AviHeaderBox
aviHeader
;
private
AviHeaderBox
aviHeader
;
private
long
durationUs
=
C
.
TIME_UNSET
;
private
long
durationUs
=
C
.
TIME_UNSET
;
/**
/**
*
AviTrack
s by StreamId
*
ChunkHandler
s by StreamId
*/
*/
private
AviTrack
[]
aviTracks
=
new
AviTrack
[
0
];
private
ChunkHandler
[]
chunkHandlers
=
new
ChunkHandler
[
0
];
//At the start of the movi tag
//At the start of the movi tag
private
long
moviOffset
;
private
long
moviOffset
;
private
long
moviEnd
;
private
long
moviEnd
;
...
@@ -137,7 +137,7 @@ public class AviExtractor implements Extractor {
...
@@ -137,7 +137,7 @@ public class AviExtractor implements Extractor {
AviSeekMap
aviSeekMap
;
AviSeekMap
aviSeekMap
;
//Set if a chunk is only partially read
//Set if a chunk is only partially read
private
transient
AviTrack
chunkHandler
;
private
transient
ChunkHandler
chunkHandler
;
/**
/**
*
*
...
@@ -218,7 +218,7 @@ public class AviExtractor implements Extractor {
...
@@ -218,7 +218,7 @@ public class AviExtractor implements Extractor {
}
}
@VisibleForTesting
@VisibleForTesting
AviTrack
parseStream
(
final
ListBox
streamList
,
int
streamId
)
{
ChunkHandler
parseStream
(
final
ListBox
streamList
,
int
streamId
)
{
final
StreamHeaderBox
streamHeader
=
streamList
.
getChild
(
StreamHeaderBox
.
class
);
final
StreamHeaderBox
streamHeader
=
streamList
.
getChild
(
StreamHeaderBox
.
class
);
final
StreamFormatBox
streamFormat
=
streamList
.
getChild
(
StreamFormatBox
.
class
);
final
StreamFormatBox
streamFormat
=
streamList
.
getChild
(
StreamFormatBox
.
class
);
if
(
streamHeader
==
null
)
{
if
(
streamHeader
==
null
)
{
...
@@ -243,7 +243,8 @@ public class AviExtractor implements Extractor {
...
@@ -243,7 +243,8 @@ public class AviExtractor implements Extractor {
if
(
streamName
!=
null
)
{
if
(
streamName
!=
null
)
{
builder
.
setLabel
(
streamName
.
getName
());
builder
.
setLabel
(
streamName
.
getName
());
}
}
final
AviTrack
aviTrack
;
final
ChunkClock
clock
=
new
ChunkClock
(
durationUs
,
length
);
final
ChunkHandler
chunkHandler
;
if
(
streamHeader
.
isVideo
())
{
if
(
streamHeader
.
isVideo
())
{
final
VideoFormat
videoFormat
=
streamFormat
.
getVideoFormat
();
final
VideoFormat
videoFormat
=
streamFormat
.
getVideoFormat
();
final
String
mimeType
=
videoFormat
.
getMimeType
();
final
String
mimeType
=
videoFormat
.
getMimeType
();
...
@@ -257,17 +258,12 @@ public class AviExtractor implements Extractor {
...
@@ -257,17 +258,12 @@ public class AviExtractor implements Extractor {
builder
.
setFrameRate
(
streamHeader
.
getFrameRate
());
builder
.
setFrameRate
(
streamHeader
.
getFrameRate
());
builder
.
setSampleMimeType
(
mimeType
);
builder
.
setSampleMimeType
(
mimeType
);
final
LinearClock
clock
=
new
LinearClock
(
durationUs
,
length
);
aviTrack
=
new
AviTrack
(
streamId
,
AviTrack
.
CHUNK_TYPE_VIDEO
,
clock
,
trackOutput
);
if
(
MimeTypes
.
VIDEO_H264
.
equals
(
mimeType
))
{
if
(
MimeTypes
.
VIDEO_H264
.
equals
(
mimeType
))
{
final
AvcChunkPeeker
avcChunkPeeker
=
new
AvcChunkPeeker
(
builder
,
trackOutput
,
clock
);
chunkHandler
=
new
AvcChunkHandler
(
streamId
,
trackOutput
,
clock
,
builder
);
aviTrack
.
setClock
(
avcChunkPeeker
.
getClock
());
}
else
if
(
MimeTypes
.
VIDEO_MP4V
.
equals
(
mimeType
))
{
aviTrack
.
setChunkPeeker
(
avcChunkPeek
er
);
chunkHandler
=
new
Mp4vChunkHandler
(
streamId
,
trackOutput
,
clock
,
build
er
);
}
else
{
}
else
{
if
(
MimeTypes
.
VIDEO_MP4V
.
equals
(
mimeType
))
{
chunkHandler
=
new
ChunkHandler
(
streamId
,
ChunkHandler
.
TYPE_VIDEO
,
trackOutput
,
clock
);
aviTrack
.
setChunkPeeker
(
new
Mp4vChunkPeeker
(
builder
,
trackOutput
));
}
}
}
trackOutput
.
format
(
builder
.
build
());
trackOutput
.
format
(
builder
.
build
());
this
.
durationUs
=
durationUs
;
this
.
durationUs
=
durationUs
;
...
@@ -294,13 +290,18 @@ public class AviExtractor implements Extractor {
...
@@ -294,13 +290,18 @@ public class AviExtractor implements Extractor {
builder
.
setInitializationData
(
Collections
.
singletonList
(
audioFormat
.
getCodecData
()));
builder
.
setInitializationData
(
Collections
.
singletonList
(
audioFormat
.
getCodecData
()));
}
}
trackOutput
.
format
(
builder
.
build
());
trackOutput
.
format
(
builder
.
build
());
aviTrack
=
new
AviTrack
(
streamId
,
AviTrack
.
CHUNK_TYPE_AUDIO
,
if
(
MimeTypes
.
AUDIO_MPEG
.
equals
(
mimeType
))
{
new
LinearClock
(
durationUs
,
length
),
trackOutput
);
chunkHandler
=
new
Mp3ChunkHandler
(
streamId
,
trackOutput
,
clock
,
aviTrack
.
setKeyFrames
(
AviTrack
.
ALL_KEY_FRAMES
);
audioFormat
.
getSamplesPerSecond
());
}
else
{
chunkHandler
=
new
ChunkHandler
(
streamId
,
ChunkHandler
.
TYPE_AUDIO
,
trackOutput
,
clock
);
}
chunkHandler
.
setKeyFrames
(
ChunkHandler
.
ALL_KEY_FRAMES
);
}
else
{
}
else
{
aviTrack
=
null
;
chunkHandler
=
null
;
}
}
return
aviTrack
;
return
chunkHandler
;
}
}
private
int
readTracks
(
ExtractorInput
input
)
throws
IOException
{
private
int
readTracks
(
ExtractorInput
input
)
throws
IOException
{
...
@@ -312,7 +313,7 @@ public class AviExtractor implements Extractor {
...
@@ -312,7 +313,7 @@ public class AviExtractor implements Extractor {
if
(
aviHeader
==
null
)
{
if
(
aviHeader
==
null
)
{
throw
new
IOException
(
"AviHeader not found"
);
throw
new
IOException
(
"AviHeader not found"
);
}
}
aviTracks
=
new
AviTrack
[
aviHeader
.
getStreams
()];
chunkHandlers
=
new
ChunkHandler
[
aviHeader
.
getStreams
()];
//This is usually wrong, so it will be overwritten by video if present
//This is usually wrong, so it will be overwritten by video if present
durationUs
=
aviHeader
.
getTotalFrames
()
*
(
long
)
aviHeader
.
getMicroSecPerFrame
();
durationUs
=
aviHeader
.
getTotalFrames
()
*
(
long
)
aviHeader
.
getMicroSecPerFrame
();
...
@@ -320,7 +321,7 @@ public class AviExtractor implements Extractor {
...
@@ -320,7 +321,7 @@ public class AviExtractor implements Extractor {
for
(
Box
box
:
headerList
.
getChildren
())
{
for
(
Box
box
:
headerList
.
getChildren
())
{
if
(
box
instanceof
ListBox
&&
((
ListBox
)
box
).
getListType
()
==
ListBox
.
TYPE_STRL
)
{
if
(
box
instanceof
ListBox
&&
((
ListBox
)
box
).
getListType
()
==
ListBox
.
TYPE_STRL
)
{
final
ListBox
streamList
=
(
ListBox
)
box
;
final
ListBox
streamList
=
(
ListBox
)
box
;
aviTrack
s
[
streamId
]
=
parseStream
(
streamList
,
streamId
);
chunkHandler
s
[
streamId
]
=
parseStream
(
streamList
,
streamId
);
streamId
++;
streamId
++;
}
}
}
}
...
@@ -356,32 +357,32 @@ public class AviExtractor implements Extractor {
...
@@ -356,32 +357,32 @@ public class AviExtractor implements Extractor {
}
}
@VisibleForTesting
@VisibleForTesting
AviTrack
getVideoTrack
()
{
ChunkHandler
getVideoTrack
()
{
for
(
@Nullable
AviTrack
aviTrack
:
aviTrack
s
)
{
for
(
@Nullable
ChunkHandler
chunkHandler
:
chunkHandler
s
)
{
if
(
aviTrack
!=
null
&&
aviTrack
.
isVideo
())
{
if
(
chunkHandler
!=
null
&&
chunkHandler
.
isVideo
())
{
return
aviTrack
;
return
chunkHandler
;
}
}
}
}
return
null
;
return
null
;
}
}
void
fixTimings
(
final
int
[]
keyFrameCounts
,
final
long
videoDuration
)
{
void
fixTimings
(
final
int
[]
keyFrameCounts
,
final
long
videoDuration
)
{
for
(
final
AviTrack
aviTrack
:
aviTrack
s
)
{
for
(
final
ChunkHandler
chunkHandler
:
chunkHandler
s
)
{
if
(
aviTrack
!=
null
)
{
if
(
chunkHandler
!=
null
)
{
if
(
aviTrack
.
isAudio
())
{
if
(
chunkHandler
.
isAudio
())
{
final
long
durationUs
=
aviTrack
.
getClock
().
durationUs
;
final
long
durationUs
=
chunkHandler
.
getClock
().
durationUs
;
i
(
"Audio #"
+
aviTrack
.
getId
()
+
" chunks: "
+
aviTrack
.
chunks
+
" us="
+
durationUs
+
i
(
"Audio #"
+
chunkHandler
.
getId
()
+
" chunks: "
+
chunkHandler
.
chunks
+
" us="
+
durationUs
+
" size="
+
aviTrack
.
size
);
" size="
+
chunkHandler
.
size
);
final
LinearClock
linearClock
=
aviTrack
.
getClock
();
final
ChunkClock
linearClock
=
chunkHandler
.
getClock
();
//If the audio track duration is off from the video by >5 % recalc using video
//If the audio track duration is off from the video by >5 % recalc using video
if
((
durationUs
-
videoDuration
)
/
(
float
)
videoDuration
>
.
05
f
)
{
if
((
durationUs
-
videoDuration
)
/
(
float
)
videoDuration
>
.
05
f
)
{
w
(
"Audio #"
+
aviTrack
.
getId
()
+
" duration is off using videoDuration"
);
w
(
"Audio #"
+
chunkHandler
.
getId
()
+
" duration is off using videoDuration"
);
linearClock
.
setDuration
(
videoDuration
);
linearClock
.
setDuration
(
videoDuration
);
}
}
linearClock
.
set
Length
(
aviTrack
.
chunks
);
linearClock
.
set
Chunks
(
chunkHandler
.
chunks
);
if
(
aviTrack
.
chunks
!=
keyFrameCounts
[
aviTrack
.
getId
()])
{
if
(
chunkHandler
.
chunks
!=
keyFrameCounts
[
chunkHandler
.
getId
()])
{
w
(
"Audio is not all key frames chunks="
+
aviTrack
.
chunks
+
" keyFrames="
+
w
(
"Audio is not all key frames chunks="
+
chunkHandler
.
chunks
+
" keyFrames="
+
keyFrameCounts
[
aviTrack
.
getId
()]);
keyFrameCounts
[
chunkHandler
.
getId
()]);
}
}
}
}
}
}
...
@@ -392,7 +393,7 @@ public class AviExtractor implements Extractor {
...
@@ -392,7 +393,7 @@ public class AviExtractor implements Extractor {
* Reads the index and sets the keyFrames and creates the SeekMap
* Reads the index and sets the keyFrames and creates the SeekMap
*/
*/
void
readIdx1
(
ExtractorInput
input
,
int
remaining
)
throws
IOException
{
void
readIdx1
(
ExtractorInput
input
,
int
remaining
)
throws
IOException
{
final
AviTrack
videoTrack
=
getVideoTrack
();
final
ChunkHandler
videoTrack
=
getVideoTrack
();
if
(
videoTrack
==
null
)
{
if
(
videoTrack
==
null
)
{
output
.
seekMap
(
new
SeekMap
.
Unseekable
(
getDuration
()));
output
.
seekMap
(
new
SeekMap
.
Unseekable
(
getDuration
()));
w
(
"No video track found"
);
w
(
"No video track found"
);
...
@@ -412,8 +413,8 @@ public class AviExtractor implements Extractor {
...
@@ -412,8 +413,8 @@ public class AviExtractor implements Extractor {
//These are ints/2
//These are ints/2
final
UnboundedIntArray
keyFrameOffsetsDiv2
=
new
UnboundedIntArray
();
final
UnboundedIntArray
keyFrameOffsetsDiv2
=
new
UnboundedIntArray
();
final
int
[]
keyFrameCounts
=
new
int
[
aviTrack
s
.
length
];
final
int
[]
keyFrameCounts
=
new
int
[
chunkHandler
s
.
length
];
final
UnboundedIntArray
[]
seekIndexes
=
new
UnboundedIntArray
[
aviTrack
s
.
length
];
final
UnboundedIntArray
[]
seekIndexes
=
new
UnboundedIntArray
[
chunkHandler
s
.
length
];
for
(
int
i
=
0
;
i
<
seekIndexes
.
length
;
i
++)
{
for
(
int
i
=
0
;
i
<
seekIndexes
.
length
;
i
++)
{
seekIndexes
[
i
]
=
new
UnboundedIntArray
();
seekIndexes
[
i
]
=
new
UnboundedIntArray
();
}
}
...
@@ -435,8 +436,8 @@ public class AviExtractor implements Extractor {
...
@@ -435,8 +436,8 @@ public class AviExtractor implements Extractor {
count
+=
1
;
count
+=
1
;
}
}
tagMap
.
put
(
chunkId
,
count
);
tagMap
.
put
(
chunkId
,
count
);
final
AviTrack
aviTrack
=
getAviTrack
(
chunkId
);
final
ChunkHandler
chunkHandler
=
getChunkHandler
(
chunkId
);
if
(
aviTrack
==
null
)
{
if
(
chunkHandler
==
null
)
{
if
(
chunkId
!=
AviExtractor
.
REC_
)
{
if
(
chunkId
!=
AviExtractor
.
REC_
)
{
w
(
"Unknown Track Type: "
+
toString
(
chunkId
));
w
(
"Unknown Track Type: "
+
toString
(
chunkId
));
}
}
...
@@ -447,26 +448,26 @@ public class AviExtractor implements Extractor {
...
@@ -447,26 +448,26 @@ public class AviExtractor implements Extractor {
final
int
offset
=
indexByteBuffer
.
getInt
();
final
int
offset
=
indexByteBuffer
.
getInt
();
final
int
size
=
indexByteBuffer
.
getInt
();
final
int
size
=
indexByteBuffer
.
getInt
();
if
((
flags
&
AVIIF_KEYFRAME
)
==
AVIIF_KEYFRAME
)
{
if
((
flags
&
AVIIF_KEYFRAME
)
==
AVIIF_KEYFRAME
)
{
if
(
aviTrack
.
isVideo
())
{
if
(
chunkHandler
.
isVideo
())
{
int
indexSize
=
seekIndexes
[
videoId
].
getSize
();
int
indexSize
=
seekIndexes
[
videoId
].
getSize
();
if
(
indexSize
==
0
||
aviTrack
.
chunks
-
seekIndexes
[
videoId
].
get
(
indexSize
-
1
)
>=
chunksPerKeyFrame
)
{
if
(
indexSize
==
0
||
chunkHandler
.
chunks
-
seekIndexes
[
videoId
].
get
(
indexSize
-
1
)
>=
chunksPerKeyFrame
)
{
keyFrameOffsetsDiv2
.
add
(
offset
/
2
);
keyFrameOffsetsDiv2
.
add
(
offset
/
2
);
for
(
AviTrack
seekTrack
:
aviTrack
s
)
{
for
(
ChunkHandler
seekTrack
:
chunkHandler
s
)
{
if
(
seekTrack
!=
null
)
{
if
(
seekTrack
!=
null
)
{
seekIndexes
[
seekTrack
.
getId
()].
add
(
seekTrack
.
chunks
);
seekIndexes
[
seekTrack
.
getId
()].
add
(
seekTrack
.
chunks
);
}
}
}
}
}
}
}
}
keyFrameCounts
[
aviTrack
.
getId
()]++;
keyFrameCounts
[
chunkHandler
.
getId
()]++;
}
}
aviTrack
.
chunks
++;
chunkHandler
.
chunks
++;
aviTrack
.
size
+=
size
;
chunkHandler
.
size
+=
size
;
}
}
indexByteBuffer
.
compact
();
indexByteBuffer
.
compact
();
}
}
if
(
videoTrack
.
chunks
==
keyFrameCounts
[
videoTrack
.
getId
()])
{
if
(
videoTrack
.
chunks
==
keyFrameCounts
[
videoTrack
.
getId
()])
{
videoTrack
.
setKeyFrames
(
AviTrack
.
ALL_KEY_FRAMES
);
videoTrack
.
setKeyFrames
(
ChunkHandler
.
ALL_KEY_FRAMES
);
}
else
{
}
else
{
videoTrack
.
setKeyFrames
(
seekIndexes
[
videoId
].
getArray
());
videoTrack
.
setKeyFrames
(
seekIndexes
[
videoId
].
getArray
());
}
}
...
@@ -485,16 +486,16 @@ public class AviExtractor implements Extractor {
...
@@ -485,16 +486,16 @@ public class AviExtractor implements Extractor {
@Nullable
@Nullable
@VisibleForTesting
@VisibleForTesting
AviTrack
getAviTrack
(
int
chunkId
)
{
ChunkHandler
getChunkHandler
(
int
chunkId
)
{
for
(
AviTrack
aviTrack
:
aviTrack
s
)
{
for
(
ChunkHandler
chunkHandler
:
chunkHandler
s
)
{
if
(
aviTrack
!=
null
&&
aviTrack
.
handlesChunkId
(
chunkId
))
{
if
(
chunkHandler
!=
null
&&
chunkHandler
.
handlesChunkId
(
chunkId
))
{
return
aviTrack
;
return
chunkHandler
;
}
}
}
}
return
null
;
return
null
;
}
}
int
read
Sample
s
(
@NonNull
ExtractorInput
input
)
throws
IOException
{
int
read
Chunk
s
(
@NonNull
ExtractorInput
input
)
throws
IOException
{
if
(
chunkHandler
!=
null
)
{
if
(
chunkHandler
!=
null
)
{
if
(
chunkHandler
.
resume
(
input
))
{
if
(
chunkHandler
.
resume
(
input
))
{
chunkHandler
=
null
;
chunkHandler
=
null
;
...
@@ -527,21 +528,21 @@ public class AviExtractor implements Extractor {
...
@@ -527,21 +528,21 @@ public class AviExtractor implements Extractor {
alignInput
(
input
);
alignInput
(
input
);
return
RESULT_CONTINUE
;
return
RESULT_CONTINUE
;
}
}
final
AviTrack
aviTrack
=
getAviTrack
(
chunkId
);
final
ChunkHandler
chunkHandler
=
getChunkHandler
(
chunkId
);
if
(
aviTrack
==
null
)
{
if
(
chunkHandler
==
null
)
{
input
.
skipFully
(
size
);
input
.
skipFully
(
size
);
alignInput
(
input
);
alignInput
(
input
);
w
(
"Unknown tag="
+
toString
(
chunkId
)
+
" pos="
+
(
input
.
getPosition
()
-
8
)
w
(
"Unknown tag="
+
toString
(
chunkId
)
+
" pos="
+
(
input
.
getPosition
()
-
8
)
+
" size="
+
size
+
" moviEnd="
+
moviEnd
);
+
" size="
+
size
+
" moviEnd="
+
moviEnd
);
return
RESULT_CONTINUE
;
return
RESULT_CONTINUE
;
}
}
if
(
aviTrack
.
newChunk
(
chunkId
,
size
,
input
))
{
if
(
chunkHandler
.
newChunk
(
chunkId
,
size
,
input
))
{
alignInput
(
input
);
alignInput
(
input
);
}
else
{
}
else
{
chunkHandler
=
aviTrack
;
this
.
chunkHandler
=
chunkHandler
;
}
}
}
}
if
(
input
.
getPosition
()
==
input
.
getLength
()
)
{
if
(
input
.
getPosition
()
>=
moviEnd
)
{
return
C
.
RESULT_END_OF_INPUT
;
return
C
.
RESULT_END_OF_INPUT
;
}
}
return
RESULT_CONTINUE
;
return
RESULT_CONTINUE
;
...
@@ -550,10 +551,10 @@ public class AviExtractor implements Extractor {
...
@@ -550,10 +551,10 @@ public class AviExtractor implements Extractor {
@Override
@Override
public
int
read
(
@NonNull
ExtractorInput
input
,
@NonNull
PositionHolder
seekPosition
)
throws
IOException
{
public
int
read
(
@NonNull
ExtractorInput
input
,
@NonNull
PositionHolder
seekPosition
)
throws
IOException
{
switch
(
state
)
{
switch
(
state
)
{
case
STATE_READ_
SAMPLE
S:
case
STATE_READ_
CHUNK
S:
return
read
Sample
s
(
input
);
return
read
Chunk
s
(
input
);
case
STATE_SEEK_START:
case
STATE_SEEK_START:
state
=
STATE_READ_
SAMPLE
S
;
state
=
STATE_READ_
CHUNK
S
;
seekPosition
.
position
=
moviOffset
+
4
;
seekPosition
.
position
=
moviOffset
+
4
;
return
RESULT_SEEK
;
return
RESULT_SEEK
;
case
STATE_READ_TRACKS:
case
STATE_READ_TRACKS:
...
@@ -573,7 +574,7 @@ public class AviExtractor implements Extractor {
...
@@ -573,7 +574,7 @@ public class AviExtractor implements Extractor {
output
.
seekMap
(
new
SeekMap
.
Unseekable
(
getDuration
()));
output
.
seekMap
(
new
SeekMap
.
Unseekable
(
getDuration
()));
}
}
seekPosition
.
position
=
moviOffset
+
4
;
seekPosition
.
position
=
moviOffset
+
4
;
state
=
STATE_READ_
SAMPLE
S
;
state
=
STATE_READ_
CHUNK
S
;
return
RESULT_SEEK
;
return
RESULT_SEEK
;
}
}
}
}
...
@@ -591,15 +592,15 @@ public class AviExtractor implements Extractor {
...
@@ -591,15 +592,15 @@ public class AviExtractor implements Extractor {
}
}
}
else
{
}
else
{
if
(
aviSeekMap
!=
null
)
{
if
(
aviSeekMap
!=
null
)
{
aviSeekMap
.
setFrames
(
position
,
timeUs
,
aviTrack
s
);
aviSeekMap
.
setFrames
(
position
,
timeUs
,
chunkHandler
s
);
}
}
}
}
}
}
void
resetClocks
()
{
void
resetClocks
()
{
for
(
@Nullable
AviTrack
aviTrack
:
aviTrack
s
)
{
for
(
@Nullable
ChunkHandler
chunkHandler
:
chunkHandler
s
)
{
if
(
aviTrack
!=
null
)
{
if
(
chunkHandler
!=
null
)
{
aviTrack
.
getClock
().
setIndex
(
0
);
chunkHandler
.
getClock
().
setIndex
(
0
);
}
}
}
}
}
}
...
@@ -610,8 +611,8 @@ public class AviExtractor implements Extractor {
...
@@ -610,8 +611,8 @@ public class AviExtractor implements Extractor {
}
}
@VisibleForTesting
@VisibleForTesting
void
set
AviTracks
(
AviTrack
[]
aviTrack
s
)
{
void
set
ChunkHandlers
(
ChunkHandler
[]
chunkHandler
s
)
{
this
.
aviTracks
=
aviTrack
s
;
this
.
chunkHandlers
=
chunkHandler
s
;
}
}
@VisibleForTesting
(
otherwise
=
VisibleForTesting
.
NONE
)
@VisibleForTesting
(
otherwise
=
VisibleForTesting
.
NONE
)
...
@@ -626,13 +627,13 @@ public class AviExtractor implements Extractor {
...
@@ -626,13 +627,13 @@ public class AviExtractor implements Extractor {
}
}
@VisibleForTesting
(
otherwise
=
VisibleForTesting
.
NONE
)
@VisibleForTesting
(
otherwise
=
VisibleForTesting
.
NONE
)
AviTrack
getChunkHandler
()
{
ChunkHandler
getChunkHandler
()
{
return
chunkHandler
;
return
chunkHandler
;
}
}
@VisibleForTesting
(
otherwise
=
VisibleForTesting
.
NONE
)
@VisibleForTesting
(
otherwise
=
VisibleForTesting
.
NONE
)
void
setChunkHandler
(
final
AviTrack
aviTrack
)
{
void
setChunkHandler
(
final
ChunkHandler
chunkHandler
)
{
chunkHandler
=
aviTrack
;
this
.
chunkHandler
=
chunkHandler
;
}
}
@VisibleForTesting
(
otherwise
=
VisibleForTesting
.
NONE
)
@VisibleForTesting
(
otherwise
=
VisibleForTesting
.
NONE
)
...
...
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/AviSeekMap.java
View file @
5b952294
...
@@ -99,17 +99,18 @@ public class AviSeekMap implements SeekMap {
...
@@ -99,17 +99,18 @@ public class AviSeekMap implements SeekMap {
//Log.d(AviExtractor.TAG, "SeekPoint: us=" + outUs + " pos=" + position);
//Log.d(AviExtractor.TAG, "SeekPoint: us=" + outUs + " pos=" + position);
}
}
public
void
setFrames
(
final
long
position
,
final
long
timeUs
,
final
AviTrack
[]
aviTrack
s
)
{
public
void
setFrames
(
final
long
position
,
final
long
timeUs
,
final
ChunkHandler
[]
chunkHandler
s
)
{
final
int
index
=
Arrays
.
binarySearch
(
keyFrameOffsetsDiv2
,
(
int
)((
position
-
seekOffset
)
/
2
));
final
int
index
=
Arrays
.
binarySearch
(
keyFrameOffsetsDiv2
,
(
int
)((
position
-
seekOffset
)
/
2
));
if
(
index
<
0
)
{
if
(
index
<
0
)
{
throw
new
IllegalArgumentException
(
"Position: "
+
position
);
throw
new
IllegalArgumentException
(
"Position: "
+
position
);
}
}
for
(
int
i
=
0
;
i
<
aviTracks
.
length
;
i
++)
{
for
(
int
i
=
0
;
i
<
chunkHandlers
.
length
;
i
++)
{
final
AviTrack
aviTrack
=
aviTracks
[
i
];
final
ChunkHandler
chunkHandler
=
chunkHandlers
[
i
];
final
LinearClock
clock
=
aviTrack
.
getClock
();
if
(
chunkHandler
!=
null
)
{
clock
.
setIndex
(
seekIndexes
[
i
][
index
]);
// Log.d(AviExtractor.TAG, "Frame: " + (chunkHandler.isVideo()? 'V' : 'A') + " us=" + clock.getUs() + " frame=" + clock.getIndex() + " key=" + chunkHandler.isKeyFrame());
// Log.d(AviExtractor.TAG, "Frame: " + (aviTrack.isVideo()? 'V' : 'A') + " us=" + clock.getUs() + " frame=" + clock.getIndex() + " key=" + aviTrack.isKeyFrame());
chunkHandler
.
setIndex
(
seekIndexes
[
i
][
index
]);
}
}
}
}
}
}
}
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/
Linear
Clock.java
→
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/
Chunk
Clock.java
View file @
5b952294
...
@@ -18,23 +18,23 @@ package com.google.android.exoplayer2.extractor.avi;
...
@@ -18,23 +18,23 @@ package com.google.android.exoplayer2.extractor.avi;
/**
/**
* A clock that is linearly derived from the current chunk index of a given stream
* A clock that is linearly derived from the current chunk index of a given stream
*/
*/
public
class
Linear
Clock
{
public
class
Chunk
Clock
{
long
durationUs
;
long
durationUs
;
int
length
;
int
chunks
;
int
index
;
int
index
;
public
LinearClock
(
long
durationUs
,
int
length
)
{
public
ChunkClock
(
long
durationUs
,
int
chunks
)
{
this
.
durationUs
=
durationUs
;
this
.
durationUs
=
durationUs
;
this
.
length
=
length
;
this
.
chunks
=
chunks
;
}
}
public
void
setDuration
(
long
durationUs
)
{
public
void
setDuration
(
long
durationUs
)
{
this
.
durationUs
=
durationUs
;
this
.
durationUs
=
durationUs
;
}
}
public
void
set
Length
(
int
length
)
{
public
void
set
Chunks
(
int
length
)
{
this
.
length
=
length
;
this
.
chunks
=
length
;
}
}
public
int
getIndex
()
{
public
int
getIndex
()
{
...
@@ -55,6 +55,6 @@ public class LinearClock {
...
@@ -55,6 +55,6 @@ public class LinearClock {
long
getUs
(
int
index
)
{
long
getUs
(
int
index
)
{
//Doing this the hard way lessens round errors
//Doing this the hard way lessens round errors
return
durationUs
*
index
/
length
;
return
durationUs
*
index
/
chunks
;
}
}
}
}
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/
AviTrack
.java
→
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/
ChunkHandler
.java
View file @
5b952294
...
@@ -16,11 +16,11 @@
...
@@ -16,11 +16,11 @@
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
avi
;
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
avi
;
import
androidx.annotation.NonNull
;
import
androidx.annotation.NonNull
;
import
androidx.annotation.Nullable
;
import
androidx.annotation.VisibleForTesting
;
import
androidx.annotation.VisibleForTesting
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.extractor.ExtractorInput
;
import
com.google.android.exoplayer2.extractor.ExtractorInput
;
import
com.google.android.exoplayer2.extractor.TrackOutput
;
import
com.google.android.exoplayer2.extractor.TrackOutput
;
import
com.google.android.exoplayer2.util.Log
;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.util.Arrays
;
import
java.util.Arrays
;
...
@@ -28,13 +28,13 @@ import java.util.Arrays;
...
@@ -28,13 +28,13 @@ import java.util.Arrays;
* Collection of info about a track.
* Collection of info about a track.
* This acts a bridge between AVI and ExoPlayer structures
* This acts a bridge between AVI and ExoPlayer structures
*/
*/
public
class
AviTrack
{
public
class
ChunkHandler
{
public
static
final
int
[]
ALL_KEY_FRAMES
=
new
int
[
0
];
public
static
final
int
[]
ALL_KEY_FRAMES
=
new
int
[
0
];
public
static
int
CHUNK_
TYPE_VIDEO
=
(
'd'
<<
16
)
|
(
'c'
<<
24
);
public
static
int
TYPE_VIDEO
=
(
'd'
<<
16
)
|
(
'c'
<<
24
);
public
static
int
CHUNK_
TYPE_AUDIO
=
(
'w'
<<
16
)
|
(
'b'
<<
24
);
public
static
int
TYPE_AUDIO
=
(
'w'
<<
16
)
|
(
'b'
<<
24
);
@NonNull
@NonNull
Linear
Clock
clock
;
Chunk
Clock
clock
;
@NonNull
@NonNull
final
TrackOutput
trackOutput
;
final
TrackOutput
trackOutput
;
...
@@ -42,9 +42,6 @@ public class AviTrack {
...
@@ -42,9 +42,6 @@ public class AviTrack {
final
int
chunkId
;
final
int
chunkId
;
final
int
chunkIdAlt
;
final
int
chunkIdAlt
;
@Nullable
ChunkPeeker
chunkPeeker
;
int
chunks
;
int
chunks
;
int
size
;
int
size
;
...
@@ -63,8 +60,7 @@ public class AviTrack {
...
@@ -63,8 +60,7 @@ public class AviTrack {
return
(
'0'
+
tens
)
|
((
'0'
+
ones
)
<<
8
);
return
(
'0'
+
tens
)
|
((
'0'
+
ones
)
<<
8
);
}
}
AviTrack
(
int
id
,
int
chunkType
,
@NonNull
LinearClock
clock
,
ChunkHandler
(
int
id
,
int
chunkType
,
@NonNull
TrackOutput
trackOutput
,
@NonNull
ChunkClock
clock
)
{
@NonNull
TrackOutput
trackOutput
)
{
this
.
chunkId
=
getChunkIdLower
(
id
)
|
chunkType
;
this
.
chunkId
=
getChunkIdLower
(
id
)
|
chunkType
;
this
.
clock
=
clock
;
this
.
clock
=
clock
;
this
.
trackOutput
=
trackOutput
;
this
.
trackOutput
=
trackOutput
;
...
@@ -80,18 +76,14 @@ public class AviTrack {
...
@@ -80,18 +76,14 @@ public class AviTrack {
}
}
@NonNull
@NonNull
public
Linear
Clock
getClock
()
{
public
Chunk
Clock
getClock
()
{
return
clock
;
return
clock
;
}
}
public
void
setClock
(
@NonNull
Linear
Clock
clock
)
{
public
void
setClock
(
@NonNull
Chunk
Clock
clock
)
{
this
.
clock
=
clock
;
this
.
clock
=
clock
;
}
}
public
void
setChunkPeeker
(
ChunkPeeker
chunkPeeker
)
{
this
.
chunkPeeker
=
chunkPeeker
;
}
/**
/**
*
*
* @param keyFrames null means all key frames
* @param keyFrames null means all key frames
...
@@ -105,17 +97,14 @@ public class AviTrack {
...
@@ -105,17 +97,14 @@ public class AviTrack {
}
}
public
boolean
isVideo
()
{
public
boolean
isVideo
()
{
return
(
chunkId
&
CHUNK_TYPE_VIDEO
)
==
CHUNK_
TYPE_VIDEO
;
return
(
chunkId
&
TYPE_VIDEO
)
==
TYPE_VIDEO
;
}
}
public
boolean
isAudio
()
{
public
boolean
isAudio
()
{
return
(
chunkId
&
CHUNK_TYPE_AUDIO
)
==
CHUNK_
TYPE_AUDIO
;
return
(
chunkId
&
TYPE_AUDIO
)
==
TYPE_AUDIO
;
}
}
public
boolean
newChunk
(
int
tag
,
int
size
,
ExtractorInput
input
)
throws
IOException
{
public
boolean
newChunk
(
int
tag
,
int
size
,
ExtractorInput
input
)
throws
IOException
{
if
(
chunkPeeker
!=
null
)
{
chunkPeeker
.
peek
(
input
,
size
);
}
final
int
remaining
=
size
-
trackOutput
.
sampleData
(
input
,
size
,
false
);
final
int
remaining
=
size
-
trackOutput
.
sampleData
(
input
,
size
,
false
);
if
(
remaining
==
0
)
{
if
(
remaining
==
0
)
{
done
(
size
);
done
(
size
);
...
@@ -152,7 +141,7 @@ public class AviTrack {
...
@@ -152,7 +141,7 @@ public class AviTrack {
trackOutput
.
sampleMetadata
(
trackOutput
.
sampleMetadata
(
clock
.
getUs
(),
(
isKeyFrame
()
?
C
.
BUFFER_FLAG_KEY_FRAME
:
0
),
size
,
0
,
null
);
clock
.
getUs
(),
(
isKeyFrame
()
?
C
.
BUFFER_FLAG_KEY_FRAME
:
0
),
size
,
0
,
null
);
}
}
final
Linear
Clock
clock
=
getClock
();
final
Chunk
Clock
clock
=
getClock
();
//Log.d(AviExtractor.TAG, "Frame: " + (isVideo()? 'V' : 'A') + " us=" + clock.getUs() + " size=" + size + " frame=" + clock.getIndex() + " key=" + isKeyFrame());
//Log.d(AviExtractor.TAG, "Frame: " + (isVideo()? 'V' : 'A') + " us=" + clock.getUs() + " size=" + size + " frame=" + clock.getIndex() + " key=" + isKeyFrame());
clock
.
advance
();
clock
.
advance
();
}
}
...
@@ -160,4 +149,11 @@ public class AviTrack {
...
@@ -160,4 +149,11 @@ public class AviTrack {
public
int
getId
()
{
public
int
getId
()
{
return
((
chunkId
>>
8
)
&
0xf
)
+
(
chunkId
&
0xf
)
*
10
;
return
((
chunkId
>>
8
)
&
0xf
)
+
(
chunkId
&
0xf
)
*
10
;
}
}
/**
* A seek occurred
*/
public
void
setIndex
(
int
index
)
{
getClock
().
setIndex
(
index
);
}
}
}
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/ChunkPeeker.java
deleted
100644 → 0
View file @
aee15f6c
/*
* Copyright (C) 2022 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
.
exoplayer2
.
extractor
.
avi
;
import
com.google.android.exoplayer2.extractor.ExtractorInput
;
import
java.io.IOException
;
/**
* Peeks for import data in the chunk stream.
*/
public
interface
ChunkPeeker
{
void
peek
(
ExtractorInput
input
,
final
int
size
)
throws
IOException
;
}
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/Mp3ChunkHandler.java
0 → 100644
View file @
5b952294
/*
* Copyright (C) 2022 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
.
exoplayer2
.
extractor
.
avi
;
import
androidx.annotation.NonNull
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.audio.MpegAudioUtil
;
import
com.google.android.exoplayer2.extractor.ExtractorInput
;
import
com.google.android.exoplayer2.extractor.TrackOutput
;
import
com.google.android.exoplayer2.util.Log
;
import
com.google.android.exoplayer2.util.ParsableByteArray
;
import
java.io.IOException
;
public
class
Mp3ChunkHandler
extends
ChunkHandler
{
private
final
MpegAudioUtil
.
Header
header
=
new
MpegAudioUtil
.
Header
();
private
final
ParsableByteArray
scratch
=
new
ParsableByteArray
(
0
);
private
final
int
fps
;
private
int
frameRemaining
;
private
long
us
=
0L
;
Mp3ChunkHandler
(
int
id
,
@NonNull
TrackOutput
trackOutput
,
@NonNull
ChunkClock
clock
,
int
fps
)
{
super
(
id
,
TYPE_AUDIO
,
trackOutput
,
clock
);
this
.
fps
=
fps
;
}
@Override
public
boolean
newChunk
(
int
tag
,
int
size
,
ExtractorInput
input
)
throws
IOException
{
if
(
size
==
0
)
{
clock
.
advance
();
syncUs
();
//Log.d(AviExtractor.TAG, "Blank Frame: us=" + us);
return
true
;
}
chunkRemaining
=
size
;
if
(
process
(
input
))
{
//If we scratch is the entire buffer, we didn't find a MP3 header, so just dump the chunk
if
(
scratch
.
limit
()
==
size
)
{
scratch
.
setPosition
(
0
);
trackOutput
.
sampleData
(
scratch
,
size
);
scratch
.
reset
(
0
);
}
clock
.
advance
();
return
true
;
}
return
false
;
}
@Override
boolean
resume
(
ExtractorInput
input
)
throws
IOException
{
if
(
process
(
input
))
{
clock
.
advance
();
return
true
;
}
return
false
;
}
int
readScratch
(
ExtractorInput
input
,
int
bytes
)
throws
IOException
{
final
int
toRead
=
Math
.
min
(
bytes
,
chunkRemaining
);
final
int
read
=
input
.
read
(
scratch
.
getData
(),
scratch
.
limit
(),
toRead
);
if
(
read
==
C
.
RESULT_END_OF_INPUT
)
{
return
read
;
}
chunkRemaining
-=
read
;
scratch
.
setLimit
(
scratch
.
limit
()
+
read
);
return
read
;
}
private
boolean
findFrame
(
ExtractorInput
input
)
throws
IOException
{
scratch
.
reset
(
0
);
scratch
.
ensureCapacity
(
scratch
.
limit
()
+
chunkRemaining
);
int
toRead
=
4
;
while
(
chunkRemaining
>
0
&&
readScratch
(
input
,
toRead
)
!=
C
.
RESULT_END_OF_INPUT
)
{
readScratch
(
input
,
toRead
);
while
(
scratch
.
bytesLeft
()
>=
4
)
{
if
(
header
.
setForHeaderData
(
scratch
.
readInt
()))
{
scratch
.
skipBytes
(-
4
);
return
true
;
}
scratch
.
skipBytes
(-
3
);
}
toRead
=
Math
.
min
(
chunkRemaining
,
128
);
}
return
false
;
}
private
boolean
process
(
ExtractorInput
input
)
throws
IOException
{
if
(
frameRemaining
==
0
)
{
if
(
findFrame
(
input
))
{
final
int
scratchBytes
=
scratch
.
bytesLeft
();
trackOutput
.
sampleData
(
scratch
,
scratchBytes
);
frameRemaining
=
header
.
frameSize
-
scratchBytes
;
}
else
{
return
chunkRemaining
==
0
;
}
}
final
int
bytes
=
trackOutput
.
sampleData
(
input
,
Math
.
min
(
frameRemaining
,
chunkRemaining
),
false
);
if
(
bytes
==
C
.
RESULT_END_OF_INPUT
)
{
return
true
;
}
frameRemaining
-=
bytes
;
if
(
frameRemaining
==
0
)
{
trackOutput
.
sampleMetadata
(
us
,
C
.
BUFFER_FLAG_KEY_FRAME
,
header
.
frameSize
,
0
,
null
);
//Log.d(AviExtractor.TAG, "MP3: us=" + us);
us
+=
header
.
samplesPerFrame
*
C
.
MICROS_PER_SECOND
/
fps
;
}
chunkRemaining
-=
bytes
;
return
chunkRemaining
==
0
;
}
@Override
public
void
setIndex
(
int
index
)
{
super
.
setIndex
(
index
);
syncUs
();
}
private
void
syncUs
()
{
us
=
clock
.
getUs
();
frameRemaining
=
0
;
}
}
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/Mp4vChunk
Peek
er.java
→
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/Mp4vChunk
Handl
er.java
View file @
5b952294
...
@@ -26,7 +26,7 @@ import java.io.IOException;
...
@@ -26,7 +26,7 @@ import java.io.IOException;
/**
/**
* Peeks an MP4V stream looking for pixelWidthHeightRatio data
* Peeks an MP4V stream looking for pixelWidthHeightRatio data
*/
*/
public
class
Mp4vChunk
Peek
er
extends
NalChunkPeeker
{
public
class
Mp4vChunk
Handl
er
extends
NalChunkPeeker
{
@VisibleForTesting
@VisibleForTesting
static
final
byte
SEQUENCE_START_CODE
=
(
byte
)
0xb0
;
static
final
byte
SEQUENCE_START_CODE
=
(
byte
)
0xb0
;
@VisibleForTesting
@VisibleForTesting
...
@@ -36,15 +36,14 @@ public class Mp4vChunkPeeker extends NalChunkPeeker {
...
@@ -36,15 +36,14 @@ public class Mp4vChunkPeeker extends NalChunkPeeker {
static
final
int
Extended_PAR
=
0xf
;
static
final
int
Extended_PAR
=
0xf
;
private
final
Format
.
Builder
formatBuilder
;
private
final
Format
.
Builder
formatBuilder
;
private
final
TrackOutput
trackOutput
;
@VisibleForTesting
()
@VisibleForTesting
()
float
pixelWidthHeightRatio
=
1
f
;
float
pixelWidthHeightRatio
=
1
f
;
public
Mp4vChunkPeeker
(
@NonNull
Format
.
Builder
formatBuilder
,
@NonNull
TrackOutput
trackOutput
)
{
public
Mp4vChunkHandler
(
int
id
,
@NonNull
TrackOutput
trackOutput
,
super
(
5
);
@NonNull
ChunkClock
clock
,
@NonNull
Format
.
Builder
formatBuilder
)
{
super
(
id
,
trackOutput
,
clock
,
5
);
this
.
formatBuilder
=
formatBuilder
;
this
.
formatBuilder
=
formatBuilder
;
this
.
trackOutput
=
trackOutput
;
}
}
@Override
@Override
...
...
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/NalChunkPeeker.java
View file @
5b952294
...
@@ -15,7 +15,9 @@
...
@@ -15,7 +15,9 @@
*/
*/
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
avi
;
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
avi
;
import
androidx.annotation.NonNull
;
import
com.google.android.exoplayer2.extractor.ExtractorInput
;
import
com.google.android.exoplayer2.extractor.ExtractorInput
;
import
com.google.android.exoplayer2.extractor.TrackOutput
;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.util.Arrays
;
import
java.util.Arrays
;
...
@@ -23,7 +25,7 @@ import java.util.Arrays;
...
@@ -23,7 +25,7 @@ import java.util.Arrays;
* Generic base class for NAL (0x00 0x00 0x01) chunk headers
* Generic base class for NAL (0x00 0x00 0x01) chunk headers
* Theses are used by AVC and MP4V (XVID)
* Theses are used by AVC and MP4V (XVID)
*/
*/
public
abstract
class
NalChunkPeeker
implements
ChunkPeek
er
{
public
abstract
class
NalChunkPeeker
extends
ChunkHandl
er
{
private
static
final
int
SEEK_PEEK_SIZE
=
256
;
private
static
final
int
SEEK_PEEK_SIZE
=
256
;
private
final
int
peekSize
;
private
final
int
peekSize
;
...
@@ -31,6 +33,15 @@ public abstract class NalChunkPeeker implements ChunkPeeker {
...
@@ -31,6 +33,15 @@ public abstract class NalChunkPeeker implements ChunkPeeker {
transient
byte
[]
buffer
;
transient
byte
[]
buffer
;
transient
int
pos
;
transient
int
pos
;
NalChunkPeeker
(
int
id
,
@NonNull
TrackOutput
trackOutput
,
@NonNull
ChunkClock
clock
,
int
peakSize
)
{
super
(
id
,
TYPE_VIDEO
,
trackOutput
,
clock
);
if
(
peakSize
<
5
)
{
throw
new
IllegalArgumentException
(
"Peak size must at least be 5"
);
}
this
.
peekSize
=
peakSize
;
}
abstract
void
processChunk
(
ExtractorInput
input
,
int
nalTypeOffset
)
throws
IOException
;
abstract
void
processChunk
(
ExtractorInput
input
,
int
nalTypeOffset
)
throws
IOException
;
/**
/**
...
@@ -100,15 +111,13 @@ public abstract class NalChunkPeeker implements ChunkPeeker {
...
@@ -100,15 +111,13 @@ public abstract class NalChunkPeeker implements ChunkPeeker {
return
-
1
;
return
-
1
;
}
}
public
NalChunkPeeker
(
int
peakSize
)
{
if
(
peakSize
<
5
)
{
throw
new
IllegalArgumentException
(
"Peak size must at least be 5"
);
}
this
.
peekSize
=
peakSize
;
}
abstract
boolean
skip
(
byte
nalType
);
abstract
boolean
skip
(
byte
nalType
);
public
boolean
newChunk
(
int
tag
,
int
size
,
ExtractorInput
input
)
throws
IOException
{
peek
(
input
,
size
);
return
super
.
newChunk
(
tag
,
size
,
input
);
}
public
void
peek
(
ExtractorInput
input
,
final
int
size
)
throws
IOException
{
public
void
peek
(
ExtractorInput
input
,
final
int
size
)
throws
IOException
{
buffer
=
new
byte
[
peekSize
];
buffer
=
new
byte
[
peekSize
];
if
(!
input
.
peekFully
(
buffer
,
0
,
peekSize
,
true
))
{
if
(!
input
.
peekFully
(
buffer
,
0
,
peekSize
,
true
))
{
...
...
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/PicCountClock.java
View file @
5b952294
...
@@ -20,7 +20,7 @@ import androidx.annotation.VisibleForTesting;
...
@@ -20,7 +20,7 @@ import androidx.annotation.VisibleForTesting;
/**
/**
* Properly calculates the frame time for H264 frames using PicCount
* Properly calculates the frame time for H264 frames using PicCount
*/
*/
public
class
PicCountClock
extends
Linear
Clock
{
public
class
PicCountClock
extends
Chunk
Clock
{
//The frame as a calculated from the picCount
//The frame as a calculated from the picCount
private
int
picIndex
;
private
int
picIndex
;
private
int
lastPicCount
;
private
int
lastPicCount
;
...
...
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/AvcChunkPeekerTest.java
View file @
5b952294
...
@@ -39,13 +39,13 @@ public class AvcChunkPeekerTest {
...
@@ -39,13 +39,13 @@ public class AvcChunkPeekerTest {
(
byte
)
0xFE
,(
byte
)
0x9E
,
0x10
,
00
,
00
};
(
byte
)
0xFE
,(
byte
)
0x9E
,
0x10
,
00
,
00
};
private
FakeTrackOutput
fakeTrackOutput
;
private
FakeTrackOutput
fakeTrackOutput
;
private
AvcChunk
Peek
er
avcChunkPeeker
;
private
AvcChunk
Handl
er
avcChunkPeeker
;
@Before
@Before
public
void
before
()
{
public
void
before
()
{
fakeTrackOutput
=
new
FakeTrackOutput
(
false
);
fakeTrackOutput
=
new
FakeTrackOutput
(
false
);
avcChunkPeeker
=
new
AvcChunk
Peeker
(
FORMAT_BUILDER_AVC
,
fakeTrackOutput
,
avcChunkPeeker
=
new
AvcChunk
Handler
(
0
,
fakeTrackOutput
,
new
LinearClock
(
10_000_000L
,
24
*
10
)
);
new
ChunkClock
(
10_000_000L
,
24
*
10
),
FORMAT_BUILDER_AVC
);
}
}
private
void
peekStreamHeader
()
throws
IOException
{
private
void
peekStreamHeader
()
throws
IOException
{
...
...
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/AviExtractorRoboTest.java
View file @
5b952294
...
@@ -108,26 +108,26 @@ public class AviExtractorRoboTest {
...
@@ -108,26 +108,26 @@ public class AviExtractorRoboTest {
Assert
.
assertEquals
(
AviExtractor
.
STATE_FIND_MOVI
,
aviExtractor
.
state
);
Assert
.
assertEquals
(
AviExtractor
.
STATE_FIND_MOVI
,
aviExtractor
.
state
);
final
AviTrack
aviTrack
=
aviExtractor
.
getVideoTrack
();
final
ChunkHandler
chunkHandler
=
aviExtractor
.
getVideoTrack
();
Assert
.
assertEquals
(
aviTrack
.
getClock
().
durationUs
,
streamHeaderBox
.
getDurationUs
());
Assert
.
assertEquals
(
chunkHandler
.
getClock
().
durationUs
,
streamHeaderBox
.
getDurationUs
());
}
}
@Test
@Test
public
void
readSamples_fragmentedChunk
()
throws
IOException
{
public
void
readSamples_fragmentedChunk
()
throws
IOException
{
AviExtractor
aviExtractor
=
AviExtractorTest
.
setupVideoAviExtractor
();
AviExtractor
aviExtractor
=
AviExtractorTest
.
setupVideoAviExtractor
();
final
AviTrack
aviTrack
=
aviExtractor
.
getVideoTrack
();
final
ChunkHandler
chunkHandler
=
aviExtractor
.
getVideoTrack
();
final
int
size
=
24
+
16
;
final
int
size
=
24
+
16
;
final
ByteBuffer
byteBuffer
=
AviExtractor
.
allocate
(
size
+
8
);
final
ByteBuffer
byteBuffer
=
AviExtractor
.
allocate
(
size
+
8
);
byteBuffer
.
putInt
(
aviTrack
.
chunkId
);
byteBuffer
.
putInt
(
chunkHandler
.
chunkId
);
byteBuffer
.
putInt
(
size
);
byteBuffer
.
putInt
(
size
);
final
ExtractorInput
chunk
=
new
FakeExtractorInput
.
Builder
().
setData
(
byteBuffer
.
array
()).
final
ExtractorInput
chunk
=
new
FakeExtractorInput
.
Builder
().
setData
(
byteBuffer
.
array
()).
setSimulatePartialReads
(
true
).
build
();
setSimulatePartialReads
(
true
).
build
();
Assert
.
assertEquals
(
Extractor
.
RESULT_CONTINUE
,
aviExtractor
.
read
(
chunk
,
new
PositionHolder
()));
Assert
.
assertEquals
(
Extractor
.
RESULT_CONTINUE
,
aviExtractor
.
read
(
chunk
,
new
PositionHolder
()));
Assert
.
assertEquals
(
Extractor
.
RESULT_
END_OF_INPUT
,
aviExtractor
.
read
(
chunk
,
new
PositionHolder
()));
Assert
.
assertEquals
(
Extractor
.
RESULT_
CONTINUE
,
aviExtractor
.
read
(
chunk
,
new
PositionHolder
()));
final
FakeTrackOutput
fakeTrackOutput
=
(
FakeTrackOutput
)
aviTrack
.
trackOutput
;
final
FakeTrackOutput
fakeTrackOutput
=
(
FakeTrackOutput
)
chunkHandler
.
trackOutput
;
Assert
.
assertEquals
(
size
,
fakeTrackOutput
.
getSampleData
(
0
).
length
);
Assert
.
assertEquals
(
size
,
fakeTrackOutput
.
getSampleData
(
0
).
length
);
}
}
}
}
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/AviExtractorTest.java
View file @
5b952294
...
@@ -165,7 +165,7 @@ public class AviExtractorTest {
...
@@ -165,7 +165,7 @@ public class AviExtractorTest {
Assert
.
assertEquals
(
1
,
AviExtractor
.
getStreamId
(
'0'
|
(
'1'
<<
8
)
|
(
'd'
<<
16
)
|
(
'c'
<<
24
)));
Assert
.
assertEquals
(
1
,
AviExtractor
.
getStreamId
(
'0'
|
(
'1'
<<
8
)
|
(
'd'
<<
16
)
|
(
'c'
<<
24
)));
}
}
private
void
assertIdx1
(
AviSeekMap
aviSeekMap
,
AviTrack
videoTrack
,
int
keyFrames
,
private
void
assertIdx1
(
AviSeekMap
aviSeekMap
,
ChunkHandler
videoTrack
,
int
keyFrames
,
int
keyFrameRate
)
{
int
keyFrameRate
)
{
Assert
.
assertEquals
(
keyFrames
,
videoTrack
.
keyFrames
.
length
);
Assert
.
assertEquals
(
keyFrames
,
videoTrack
.
keyFrames
.
length
);
...
@@ -192,9 +192,9 @@ public class AviExtractorTest {
...
@@ -192,9 +192,9 @@ public class AviExtractorTest {
final
int
keyFrameRate
=
3
*
DataHelper
.
FPS
;
// Keyframe every 3 seconds
final
int
keyFrameRate
=
3
*
DataHelper
.
FPS
;
// Keyframe every 3 seconds
final
int
keyFrames
=
secs
*
DataHelper
.
FPS
/
keyFrameRate
;
final
int
keyFrames
=
secs
*
DataHelper
.
FPS
/
keyFrameRate
;
final
ByteBuffer
idx1
=
DataHelper
.
getIndex
(
secs
,
keyFrameRate
);
final
ByteBuffer
idx1
=
DataHelper
.
getIndex
(
secs
,
keyFrameRate
);
final
AviTrack
videoTrack
=
DataHelper
.
getVideoAviTrack
(
secs
);
final
ChunkHandler
videoTrack
=
DataHelper
.
getVideoChunkHandler
(
secs
);
final
AviTrack
audioTrack
=
DataHelper
.
getAudioAviTrack
(
secs
);
final
ChunkHandler
audioTrack
=
DataHelper
.
getAudioChunkHandler
(
secs
);
aviExtractor
.
set
AviTracks
(
new
AviTrack
[]{
videoTrack
,
audioTrack
});
aviExtractor
.
set
ChunkHandlers
(
new
ChunkHandler
[]{
videoTrack
,
audioTrack
});
aviExtractor
.
setAviHeader
(
DataHelper
.
createAviHeaderBox
());
aviExtractor
.
setAviHeader
(
DataHelper
.
createAviHeaderBox
());
aviExtractor
.
state
=
AviExtractor
.
STATE_READ_IDX1
;
aviExtractor
.
state
=
AviExtractor
.
STATE_READ_IDX1
;
aviExtractor
.
setMovi
(
DataHelper
.
MOVI_OFFSET
,
128
*
1024
);
aviExtractor
.
setMovi
(
DataHelper
.
MOVI_OFFSET
,
128
*
1024
);
...
@@ -213,7 +213,7 @@ public class AviExtractorTest {
...
@@ -213,7 +213,7 @@ public class AviExtractorTest {
final
AviSeekMap
aviSeekMap
=
aviExtractor
.
aviSeekMap
;
final
AviSeekMap
aviSeekMap
=
aviExtractor
.
aviSeekMap
;
assertIdx1
(
aviSeekMap
,
videoTrack
,
keyFrames
,
keyFrameRate
);
assertIdx1
(
aviSeekMap
,
videoTrack
,
keyFrames
,
keyFrameRate
);
Assert
.
assertEquals
(
AviExtractor
.
STATE_READ_
SAMPLE
S
,
aviExtractor
.
state
);
Assert
.
assertEquals
(
AviExtractor
.
STATE_READ_
CHUNK
S
,
aviExtractor
.
state
);
Assert
.
assertEquals
(
DataHelper
.
MOVI_OFFSET
+
4
,
positionHolder
.
position
);
Assert
.
assertEquals
(
DataHelper
.
MOVI_OFFSET
+
4
,
positionHolder
.
position
);
}
}
...
@@ -225,8 +225,8 @@ public class AviExtractorTest {
...
@@ -225,8 +225,8 @@ public class AviExtractorTest {
final
int
secs
=
9
;
final
int
secs
=
9
;
final
int
keyFrameRate
=
3
*
DataHelper
.
FPS
;
// Keyframe every 3 seconds
final
int
keyFrameRate
=
3
*
DataHelper
.
FPS
;
// Keyframe every 3 seconds
final
ByteBuffer
idx1
=
DataHelper
.
getIndex
(
secs
,
keyFrameRate
);
final
ByteBuffer
idx1
=
DataHelper
.
getIndex
(
secs
,
keyFrameRate
);
final
AviTrack
audioTrack
=
DataHelper
.
getAudioAviTrack
(
secs
);
final
ChunkHandler
audioTrack
=
DataHelper
.
getAudioChunkHandler
(
secs
);
aviExtractor
.
set
AviTracks
(
new
AviTrack
[]{
audioTrack
});
aviExtractor
.
set
ChunkHandlers
(
new
ChunkHandler
[]{
audioTrack
});
final
FakeExtractorInput
fakeExtractorInput
=
new
FakeExtractorInput
.
Builder
()
final
FakeExtractorInput
fakeExtractorInput
=
new
FakeExtractorInput
.
Builder
()
.
setData
(
idx1
.
array
()).
build
();
.
setData
(
idx1
.
array
()).
build
();
...
@@ -250,9 +250,9 @@ public class AviExtractorTest {
...
@@ -250,9 +250,9 @@ public class AviExtractorTest {
junk
.
putInt
(
0
);
junk
.
putInt
(
0
);
idx1
.
flip
();
idx1
.
flip
();
junk
.
put
(
idx1
);
junk
.
put
(
idx1
);
final
AviTrack
videoTrack
=
DataHelper
.
getVideoAviTrack
(
secs
);
final
ChunkHandler
videoTrack
=
DataHelper
.
getVideoChunkHandler
(
secs
);
final
AviTrack
audioTrack
=
DataHelper
.
getAudioAviTrack
(
secs
);
final
ChunkHandler
audioTrack
=
DataHelper
.
getAudioChunkHandler
(
secs
);
aviExtractor
.
set
AviTracks
(
new
AviTrack
[]{
videoTrack
,
audioTrack
});
aviExtractor
.
set
ChunkHandlers
(
new
ChunkHandler
[]{
videoTrack
,
audioTrack
});
final
FakeExtractorInput
fakeExtractorInput
=
new
FakeExtractorInput
.
Builder
().
final
FakeExtractorInput
fakeExtractorInput
=
new
FakeExtractorInput
.
Builder
().
setData
(
junk
.
array
()).
build
();
setData
(
junk
.
array
()).
build
();
...
@@ -268,16 +268,16 @@ public class AviExtractorTest {
...
@@ -268,16 +268,16 @@ public class AviExtractorTest {
aviExtractor
.
init
(
fakeExtractorOutput
);
aviExtractor
.
init
(
fakeExtractorOutput
);
final
int
secs
=
4
;
final
int
secs
=
4
;
final
ByteBuffer
idx1
=
DataHelper
.
getIndex
(
secs
,
1
);
final
ByteBuffer
idx1
=
DataHelper
.
getIndex
(
secs
,
1
);
final
AviTrack
videoTrack
=
DataHelper
.
getVideoAviTrack
(
secs
);
final
ChunkHandler
videoTrack
=
DataHelper
.
getVideoChunkHandler
(
secs
);
final
AviTrack
audioTrack
=
DataHelper
.
getAudioAviTrack
(
secs
);
final
ChunkHandler
audioTrack
=
DataHelper
.
getAudioChunkHandler
(
secs
);
aviExtractor
.
set
AviTracks
(
new
AviTrack
[]{
videoTrack
,
audioTrack
});
aviExtractor
.
set
ChunkHandlers
(
new
ChunkHandler
[]{
videoTrack
,
audioTrack
});
final
FakeExtractorInput
fakeExtractorInput
=
new
FakeExtractorInput
.
Builder
().
final
FakeExtractorInput
fakeExtractorInput
=
new
FakeExtractorInput
.
Builder
().
setData
(
idx1
.
array
()).
build
();
setData
(
idx1
.
array
()).
build
();
aviExtractor
.
readIdx1
(
fakeExtractorInput
,
(
int
)
fakeExtractorInput
.
getLength
());
aviExtractor
.
readIdx1
(
fakeExtractorInput
,
(
int
)
fakeExtractorInput
.
getLength
());
//We should be throttled to 2 key frame per second
//We should be throttled to 2 key frame per second
Assert
.
assertSame
(
AviTrack
.
ALL_KEY_FRAMES
,
videoTrack
.
keyFrames
);
Assert
.
assertSame
(
ChunkHandler
.
ALL_KEY_FRAMES
,
videoTrack
.
keyFrames
);
}
}
@Test
@Test
...
@@ -389,12 +389,12 @@ public class AviExtractorTest {
...
@@ -389,12 +389,12 @@ public class AviExtractorTest {
final
FakeExtractorOutput
fakeExtractorOutput
=
new
FakeExtractorOutput
();
final
FakeExtractorOutput
fakeExtractorOutput
=
new
FakeExtractorOutput
();
aviExtractor
.
init
(
fakeExtractorOutput
);
aviExtractor
.
init
(
fakeExtractorOutput
);
final
AviTrack
aviTrack
=
DataHelper
.
getVideoAviTrack
(
9
);
final
ChunkHandler
chunkHandler
=
DataHelper
.
getVideoChunkHandler
(
9
);
aviExtractor
.
set
AviTracks
(
new
AviTrack
[]{
aviTrack
});
aviExtractor
.
set
ChunkHandlers
(
new
ChunkHandler
[]{
chunkHandler
});
final
Format
format
=
new
Format
.
Builder
().
setSampleMimeType
(
MimeTypes
.
VIDEO_MP4V
).
build
();
final
Format
format
=
new
Format
.
Builder
().
setSampleMimeType
(
MimeTypes
.
VIDEO_MP4V
).
build
();
aviTrack
.
trackOutput
.
format
(
format
);
chunkHandler
.
trackOutput
.
format
(
format
);
aviExtractor
.
state
=
AviExtractor
.
STATE_READ_
SAMPLE
S
;
aviExtractor
.
state
=
AviExtractor
.
STATE_READ_
CHUNK
S
;
aviExtractor
.
setMovi
(
DataHelper
.
MOVI_OFFSET
,
128
*
1024
);
aviExtractor
.
setMovi
(
DataHelper
.
MOVI_OFFSET
,
128
*
1024
);
return
aviExtractor
;
return
aviExtractor
;
}
}
...
@@ -403,9 +403,9 @@ public class AviExtractorTest {
...
@@ -403,9 +403,9 @@ public class AviExtractorTest {
public
void
readSamples_givenAtEndOfInput
()
throws
IOException
{
public
void
readSamples_givenAtEndOfInput
()
throws
IOException
{
AviExtractor
aviExtractor
=
setupVideoAviExtractor
();
AviExtractor
aviExtractor
=
setupVideoAviExtractor
();
aviExtractor
.
setMovi
(
0
,
0
);
aviExtractor
.
setMovi
(
0
,
0
);
final
AviTrack
aviTrack
=
aviExtractor
.
getVideoTrack
();
final
ChunkHandler
chunkHandler
=
aviExtractor
.
getVideoTrack
();
final
ByteBuffer
byteBuffer
=
AviExtractor
.
allocate
(
32
);
final
ByteBuffer
byteBuffer
=
AviExtractor
.
allocate
(
32
);
byteBuffer
.
putInt
(
aviTrack
.
chunkId
);
byteBuffer
.
putInt
(
chunkHandler
.
chunkId
);
byteBuffer
.
putInt
(
24
);
byteBuffer
.
putInt
(
24
);
final
ExtractorInput
input
=
new
FakeExtractorInput
.
Builder
().
setData
(
byteBuffer
.
array
()).
build
();
final
ExtractorInput
input
=
new
FakeExtractorInput
.
Builder
().
setData
(
byteBuffer
.
array
()).
build
();
...
@@ -415,47 +415,47 @@ public class AviExtractorTest {
...
@@ -415,47 +415,47 @@ public class AviExtractorTest {
@Test
@Test
public
void
readSamples_completeChunk
()
throws
IOException
{
public
void
readSamples_completeChunk
()
throws
IOException
{
AviExtractor
aviExtractor
=
setupVideoAviExtractor
();
AviExtractor
aviExtractor
=
setupVideoAviExtractor
();
final
AviTrack
aviTrack
=
aviExtractor
.
getVideoTrack
();
final
ChunkHandler
chunkHandler
=
aviExtractor
.
getVideoTrack
();
final
ByteBuffer
byteBuffer
=
AviExtractor
.
allocate
(
32
);
final
ByteBuffer
byteBuffer
=
AviExtractor
.
allocate
(
32
);
byteBuffer
.
putInt
(
aviTrack
.
chunkId
);
byteBuffer
.
putInt
(
chunkHandler
.
chunkId
);
byteBuffer
.
putInt
(
24
);
byteBuffer
.
putInt
(
24
);
final
ExtractorInput
input
=
new
FakeExtractorInput
.
Builder
().
setData
(
byteBuffer
.
array
())
final
ExtractorInput
input
=
new
FakeExtractorInput
.
Builder
().
setData
(
byteBuffer
.
array
())
.
build
();
.
build
();
Assert
.
assertEquals
(
Extractor
.
RESULT_
END_OF_INPUT
,
aviExtractor
.
read
(
input
,
new
PositionHolder
()));
Assert
.
assertEquals
(
Extractor
.
RESULT_
CONTINUE
,
aviExtractor
.
read
(
input
,
new
PositionHolder
()));
final
FakeTrackOutput
fakeTrackOutput
=
(
FakeTrackOutput
)
aviTrack
.
trackOutput
;
final
FakeTrackOutput
fakeTrackOutput
=
(
FakeTrackOutput
)
chunkHandler
.
trackOutput
;
Assert
.
assertEquals
(
24
,
fakeTrackOutput
.
getSampleData
(
0
).
length
);
Assert
.
assertEquals
(
24
,
fakeTrackOutput
.
getSampleData
(
0
).
length
);
}
}
@Test
@Test
public
void
readSamples_givenLeadingZeros
()
throws
IOException
{
public
void
readSamples_givenLeadingZeros
()
throws
IOException
{
AviExtractor
aviExtractor
=
setupVideoAviExtractor
();
AviExtractor
aviExtractor
=
setupVideoAviExtractor
();
final
AviTrack
aviTrack
=
aviExtractor
.
getVideoTrack
();
final
ChunkHandler
chunkHandler
=
aviExtractor
.
getVideoTrack
();
final
ByteBuffer
byteBuffer
=
AviExtractor
.
allocate
(
48
);
final
ByteBuffer
byteBuffer
=
AviExtractor
.
allocate
(
48
);
byteBuffer
.
position
(
16
);
byteBuffer
.
position
(
16
);
byteBuffer
.
putInt
(
aviTrack
.
chunkId
);
byteBuffer
.
putInt
(
chunkHandler
.
chunkId
);
byteBuffer
.
putInt
(
24
);
byteBuffer
.
putInt
(
24
);
final
ExtractorInput
input
=
new
FakeExtractorInput
.
Builder
().
setData
(
byteBuffer
.
array
())
final
ExtractorInput
input
=
new
FakeExtractorInput
.
Builder
().
setData
(
byteBuffer
.
array
())
.
build
();
.
build
();
Assert
.
assertEquals
(
Extractor
.
RESULT_
END_OF_INPUT
,
aviExtractor
.
read
(
input
,
new
PositionHolder
()));
Assert
.
assertEquals
(
Extractor
.
RESULT_
CONTINUE
,
aviExtractor
.
read
(
input
,
new
PositionHolder
()));
final
FakeTrackOutput
fakeTrackOutput
=
(
FakeTrackOutput
)
aviTrack
.
trackOutput
;
final
FakeTrackOutput
fakeTrackOutput
=
(
FakeTrackOutput
)
chunkHandler
.
trackOutput
;
Assert
.
assertEquals
(
24
,
fakeTrackOutput
.
getSampleData
(
0
).
length
);
Assert
.
assertEquals
(
24
,
fakeTrackOutput
.
getSampleData
(
0
).
length
);
}
}
@Test
@Test
public
void
seek_givenPosition0
()
throws
IOException
{
public
void
seek_givenPosition0
()
throws
IOException
{
final
AviExtractor
aviExtractor
=
setupVideoAviExtractor
();
final
AviExtractor
aviExtractor
=
setupVideoAviExtractor
();
final
AviTrack
aviTrack
=
aviExtractor
.
getVideoTrack
();
final
ChunkHandler
chunkHandler
=
aviExtractor
.
getVideoTrack
();
aviExtractor
.
setChunkHandler
(
aviTrack
);
aviExtractor
.
setChunkHandler
(
chunkHandler
);
aviTrack
.
getClock
().
setIndex
(
10
);
chunkHandler
.
getClock
().
setIndex
(
10
);
aviExtractor
.
seek
(
0L
,
0L
);
aviExtractor
.
seek
(
0L
,
0L
);
Assert
.
assertNull
(
aviExtractor
.
getChunkHandler
());
Assert
.
assertNull
(
aviExtractor
.
getChunkHandler
());
Assert
.
assertEquals
(
0
,
aviTrack
.
getClock
().
getIndex
());
Assert
.
assertEquals
(
0
,
chunkHandler
.
getClock
().
getIndex
());
Assert
.
assertEquals
(
aviExtractor
.
state
,
AviExtractor
.
STATE_SEEK_START
);
Assert
.
assertEquals
(
aviExtractor
.
state
,
AviExtractor
.
STATE_SEEK_START
);
...
@@ -470,18 +470,18 @@ public class AviExtractorTest {
...
@@ -470,18 +470,18 @@ public class AviExtractorTest {
final
AviExtractor
aviExtractor
=
setupVideoAviExtractor
();
final
AviExtractor
aviExtractor
=
setupVideoAviExtractor
();
final
AviSeekMap
aviSeekMap
=
DataHelper
.
getAviSeekMap
();
final
AviSeekMap
aviSeekMap
=
DataHelper
.
getAviSeekMap
();
aviExtractor
.
aviSeekMap
=
aviSeekMap
;
aviExtractor
.
aviSeekMap
=
aviSeekMap
;
final
AviTrack
aviTrack
=
aviExtractor
.
getVideoTrack
();
final
ChunkHandler
chunkHandler
=
aviExtractor
.
getVideoTrack
();
final
long
position
=
DataHelper
.
MOVI_OFFSET
+
aviSeekMap
.
keyFrameOffsetsDiv2
[
1
]
*
2L
;
final
long
position
=
DataHelper
.
MOVI_OFFSET
+
aviSeekMap
.
keyFrameOffsetsDiv2
[
1
]
*
2L
;
aviExtractor
.
seek
(
position
,
0L
);
aviExtractor
.
seek
(
position
,
0L
);
Assert
.
assertEquals
(
aviSeekMap
.
seekIndexes
[
aviTrack
.
getId
()][
1
],
aviTrack
.
getClock
().
getIndex
());
Assert
.
assertEquals
(
aviSeekMap
.
seekIndexes
[
chunkHandler
.
getId
()][
1
],
chunkHandler
.
getClock
().
getIndex
());
}
}
@Test
@Test
public
void
get
AviTrack
_givenListWithNull
()
{
public
void
get
ChunkHandler
_givenListWithNull
()
{
final
AviExtractor
aviExtractor
=
new
AviExtractor
();
final
AviExtractor
aviExtractor
=
new
AviExtractor
();
final
AviTrack
aviTrack
=
DataHelper
.
getAudioAviTrack
(
9
);
final
ChunkHandler
chunkHandler
=
DataHelper
.
getAudioChunkHandler
(
9
);
aviExtractor
.
set
AviTracks
(
new
AviTrack
[]{
null
,
aviTrack
});
aviExtractor
.
set
ChunkHandlers
(
new
ChunkHandler
[]{
null
,
chunkHandler
});
Assert
.
assertSame
(
aviTrack
,
aviExtractor
.
getAviTrack
(
aviTrack
.
chunkId
));
Assert
.
assertSame
(
chunkHandler
,
aviExtractor
.
getChunkHandler
(
chunkHandler
.
chunkId
));
}
}
@Test
@Test
...
...
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/AviSeekMapTest.java
View file @
5b952294
...
@@ -27,22 +27,22 @@ public class AviSeekMapTest {
...
@@ -27,22 +27,22 @@ public class AviSeekMapTest {
final
AviSeekMap
aviSeekMap
=
DataHelper
.
getAviSeekMap
();
final
AviSeekMap
aviSeekMap
=
DataHelper
.
getAviSeekMap
();
final
long
position
=
aviSeekMap
.
keyFrameOffsetsDiv2
[
1
]
*
2L
+
aviSeekMap
.
seekOffset
;
final
long
position
=
aviSeekMap
.
keyFrameOffsetsDiv2
[
1
]
*
2L
+
aviSeekMap
.
seekOffset
;
final
int
secs
=
4
;
final
int
secs
=
4
;
final
AviTrack
[]
aviTracks
=
new
AviTrack
[]{
DataHelper
.
getVideoAviTrack
(
secs
),
final
ChunkHandler
[]
chunkHandlers
=
new
ChunkHandler
[]{
DataHelper
.
getVideoChunkHandler
(
secs
),
DataHelper
.
getAudio
AviTrack
(
secs
)};
DataHelper
.
getAudio
ChunkHandler
(
secs
)};
aviSeekMap
.
setFrames
(
position
,
C
.
MICROS_PER_SECOND
,
aviTrack
s
);
aviSeekMap
.
setFrames
(
position
,
C
.
MICROS_PER_SECOND
,
chunkHandler
s
);
for
(
int
i
=
0
;
i
<
aviTrack
s
.
length
;
i
++)
{
for
(
int
i
=
0
;
i
<
chunkHandler
s
.
length
;
i
++)
{
Assert
.
assertEquals
(
aviSeekMap
.
seekIndexes
[
i
][
1
],
aviTrack
s
[
i
].
getClock
().
getIndex
());
Assert
.
assertEquals
(
aviSeekMap
.
seekIndexes
[
i
][
1
],
chunkHandler
s
[
i
].
getClock
().
getIndex
());
}
}
}
}
@Test
@Test
public
void
setFrames_givenBadPosition
()
{
public
void
setFrames_givenBadPosition
()
{
final
AviSeekMap
aviSeekMap
=
DataHelper
.
getAviSeekMap
();
final
AviSeekMap
aviSeekMap
=
DataHelper
.
getAviSeekMap
();
final
AviTrack
[]
aviTracks
=
new
AviTrack
[
2
];
final
ChunkHandler
[]
chunkHandlers
=
new
ChunkHandler
[
2
];
try
{
try
{
aviSeekMap
.
setFrames
(
1L
,
C
.
MICROS_PER_SECOND
,
aviTrack
s
);
aviSeekMap
.
setFrames
(
1L
,
C
.
MICROS_PER_SECOND
,
chunkHandler
s
);
Assert
.
fail
();
Assert
.
fail
();
}
catch
(
IllegalArgumentException
e
)
{
}
catch
(
IllegalArgumentException
e
)
{
//Intentionally blank
//Intentionally blank
...
...
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/
AviTrack
Test.java
→
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/
ChunkHandler
Test.java
View file @
5b952294
...
@@ -18,13 +18,13 @@ package com.google.android.exoplayer2.extractor.avi;
...
@@ -18,13 +18,13 @@ package com.google.android.exoplayer2.extractor.avi;
import
org.junit.Assert
;
import
org.junit.Assert
;
import
org.junit.Test
;
import
org.junit.Test
;
public
class
AviTrack
Test
{
public
class
ChunkHandler
Test
{
@Test
@Test
public
void
setClock_givenLinearClock
()
{
public
void
setClock_givenLinearClock
()
{
final
LinearClock
linearClock
=
new
Linear
Clock
(
1_000_000L
,
30
);
final
ChunkClock
linearClock
=
new
Chunk
Clock
(
1_000_000L
,
30
);
final
AviTrack
aviTrack
=
DataHelper
.
getVideoAviTrack
(
1
);
final
ChunkHandler
chunkHandler
=
DataHelper
.
getVideoChunkHandler
(
1
);
aviTrack
.
setClock
(
linearClock
);
chunkHandler
.
setClock
(
linearClock
);
Assert
.
assertSame
(
linearClock
,
aviTrack
.
getClock
());
Assert
.
assertSame
(
linearClock
,
chunkHandler
.
getClock
());
}
}
}
}
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/DataHelper.java
View file @
5b952294
...
@@ -17,7 +17,6 @@ package com.google.android.exoplayer2.extractor.avi;
...
@@ -17,7 +17,6 @@ package com.google.android.exoplayer2.extractor.avi;
import
android.content.Context
;
import
android.content.Context
;
import
androidx.test.core.app.ApplicationProvider
;
import
androidx.test.core.app.ApplicationProvider
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.testutil.FakeTrackOutput
;
import
com.google.android.exoplayer2.testutil.FakeTrackOutput
;
import
com.google.android.exoplayer2.testutil.TestUtil
;
import
com.google.android.exoplayer2.testutil.TestUtil
;
import
java.io.IOException
;
import
java.io.IOException
;
...
@@ -104,18 +103,16 @@ public class DataHelper {
...
@@ -104,18 +103,16 @@ public class DataHelper {
return
byteBuffer
;
return
byteBuffer
;
}
}
public
static
AviTrack
getVideoAviTrack
(
int
sec
)
{
public
static
ChunkHandler
getVideoChunkHandler
(
int
sec
)
{
final
FakeTrackOutput
fakeTrackOutput
=
new
FakeTrackOutput
(
false
);
final
FakeTrackOutput
fakeTrackOutput
=
new
FakeTrackOutput
(
false
);
return
new
AviTrack
(
0
,
AviTrack
.
CHUNK_TYPE_VIDEO
,
return
new
ChunkHandler
(
0
,
ChunkHandler
.
TYPE_VIDEO
,
fakeTrackOutput
,
new
LinearClock
(
sec
*
1_000_000L
,
sec
*
FPS
),
new
ChunkClock
(
sec
*
1_000_000L
,
sec
*
FPS
));
fakeTrackOutput
);
}
}
public
static
AviTrack
getAudioAviTrack
(
int
sec
)
{
public
static
ChunkHandler
getAudioChunkHandler
(
int
sec
)
{
final
FakeTrackOutput
fakeTrackOutput
=
new
FakeTrackOutput
(
false
);
final
FakeTrackOutput
fakeTrackOutput
=
new
FakeTrackOutput
(
false
);
return
new
AviTrack
(
AUDIO_ID
,
AviTrack
.
CHUNK_TYPE_AUDIO
,
return
new
ChunkHandler
(
AUDIO_ID
,
ChunkHandler
.
TYPE_AUDIO
,
fakeTrackOutput
,
new
LinearClock
(
sec
*
1_000_000L
,
sec
*
FPS
*
AUDIO_PER_VIDEO
),
new
ChunkClock
(
sec
*
1_000_000L
,
sec
*
FPS
*
AUDIO_PER_VIDEO
));
fakeTrackOutput
);
}
}
public
static
AviSeekMap
getAviSeekMap
()
{
public
static
AviSeekMap
getAviSeekMap
()
{
...
@@ -153,8 +150,8 @@ public class DataHelper {
...
@@ -153,8 +150,8 @@ public class DataHelper {
*/
*/
public
static
ByteBuffer
getIndex
(
final
int
secs
,
final
int
keyFrameRate
,
int
offset
)
{
public
static
ByteBuffer
getIndex
(
final
int
secs
,
final
int
keyFrameRate
,
int
offset
)
{
final
int
videoFrames
=
secs
*
FPS
;
final
int
videoFrames
=
secs
*
FPS
;
final
int
videoChunkId
=
AviTrack
.
CHUNK_TYPE_VIDEO
|
AviTrack
.
getChunkIdLower
(
0
);
final
int
videoChunkId
=
ChunkHandler
.
TYPE_VIDEO
|
ChunkHandler
.
getChunkIdLower
(
0
);
final
int
audioChunkId
=
AviTrack
.
CHUNK_TYPE_AUDIO
|
AviTrack
.
getChunkIdLower
(
1
);
final
int
audioChunkId
=
ChunkHandler
.
TYPE_AUDIO
|
ChunkHandler
.
getChunkIdLower
(
1
);
final
ByteBuffer
byteBuffer
=
AviExtractor
.
allocate
((
videoFrames
+
videoFrames
*
AUDIO_PER_VIDEO
)
*
16
);
final
ByteBuffer
byteBuffer
=
AviExtractor
.
allocate
((
videoFrames
+
videoFrames
*
AUDIO_PER_VIDEO
)
*
16
);
for
(
int
v
=
0
;
v
<
videoFrames
;
v
++)
{
for
(
int
v
=
0
;
v
<
videoFrames
;
v
++)
{
...
...
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/LinearClockTest.java
View file @
5b952294
...
@@ -24,7 +24,7 @@ import org.junit.Test;
...
@@ -24,7 +24,7 @@ import org.junit.Test;
public
class
LinearClockTest
{
public
class
LinearClockTest
{
@Test
@Test
public
void
advance
()
{
public
void
advance
()
{
final
LinearClock
linearClock
=
new
Linear
Clock
(
1_000L
,
10
);
final
ChunkClock
linearClock
=
new
Chunk
Clock
(
1_000L
,
10
);
linearClock
.
setIndex
(
2
);
linearClock
.
setIndex
(
2
);
Assert
.
assertEquals
(
200
,
linearClock
.
getUs
());
Assert
.
assertEquals
(
200
,
linearClock
.
getUs
());
linearClock
.
advance
();
linearClock
.
advance
();
...
...
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/MockNalChunkPeeker.java
View file @
5b952294
...
@@ -16,12 +16,13 @@
...
@@ -16,12 +16,13 @@
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
avi
;
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
avi
;
import
com.google.android.exoplayer2.extractor.ExtractorInput
;
import
com.google.android.exoplayer2.extractor.ExtractorInput
;
import
com.google.android.exoplayer2.testutil.FakeTrackOutput
;
import
java.io.IOException
;
import
java.io.IOException
;
public
class
MockNalChunkPeeker
extends
NalChunkPeeker
{
public
class
MockNalChunkPeeker
extends
NalChunkPeeker
{
private
boolean
skip
;
private
boolean
skip
;
public
MockNalChunkPeeker
(
int
peakSize
,
boolean
skip
)
{
public
MockNalChunkPeeker
(
int
peakSize
,
boolean
skip
)
{
super
(
peakSize
);
super
(
0
,
new
FakeTrackOutput
(
false
),
new
ChunkClock
(
1_000_000L
,
24
),
peakSize
);
this
.
skip
=
skip
;
this
.
skip
=
skip
;
}
}
...
...
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/Mp4vChunkPeekerTest.java
View file @
5b952294
...
@@ -32,7 +32,7 @@ import org.junit.runner.RunWith;
...
@@ -32,7 +32,7 @@ import org.junit.runner.RunWith;
public
class
Mp4vChunkPeekerTest
{
public
class
Mp4vChunkPeekerTest
{
private
ByteBuffer
makeSequence
()
{
private
ByteBuffer
makeSequence
()
{
return
DataHelper
.
appendNal
(
AviExtractor
.
allocate
(
32
),
Mp4vChunkPeek
er
.
SEQUENCE_START_CODE
);
return
DataHelper
.
appendNal
(
AviExtractor
.
allocate
(
32
),
Mp4vChunkHandl
er
.
SEQUENCE_START_CODE
);
}
}
@Test
@Test
...
@@ -42,7 +42,8 @@ public class Mp4vChunkPeekerTest {
...
@@ -42,7 +42,8 @@ public class Mp4vChunkPeekerTest {
final
Format
.
Builder
formatBuilder
=
new
Format
.
Builder
();
final
Format
.
Builder
formatBuilder
=
new
Format
.
Builder
();
final
FakeExtractorInput
input
=
new
FakeExtractorInput
.
Builder
().
setData
(
byteBuffer
.
array
())
final
FakeExtractorInput
input
=
new
FakeExtractorInput
.
Builder
().
setData
(
byteBuffer
.
array
())
.
build
();
.
build
();
final
Mp4vChunkPeeker
mp4vChunkPeeker
=
new
Mp4vChunkPeeker
(
formatBuilder
,
fakeTrackOutput
);
final
Mp4vChunkHandler
mp4vChunkPeeker
=
new
Mp4vChunkHandler
(
0
,
fakeTrackOutput
,
new
ChunkClock
(
1_000_000L
,
24
),
formatBuilder
);
mp4vChunkPeeker
.
peek
(
input
,
(
int
)
input
.
getLength
());
mp4vChunkPeeker
.
peek
(
input
,
(
int
)
input
.
getLength
());
Assert
.
assertEquals
(
1
f
,
mp4vChunkPeeker
.
pixelWidthHeightRatio
,
0.01
);
Assert
.
assertEquals
(
1
f
,
mp4vChunkPeeker
.
pixelWidthHeightRatio
,
0.01
);
}
}
...
@@ -54,7 +55,8 @@ public class Mp4vChunkPeekerTest {
...
@@ -54,7 +55,8 @@ public class Mp4vChunkPeekerTest {
final
Context
context
=
ApplicationProvider
.
getApplicationContext
();
final
Context
context
=
ApplicationProvider
.
getApplicationContext
();
final
byte
[]
bytes
=
TestUtil
.
getByteArray
(
context
,
"extractordumps/avi/mp4v_sequence.dump"
);
final
byte
[]
bytes
=
TestUtil
.
getByteArray
(
context
,
"extractordumps/avi/mp4v_sequence.dump"
);
final
FakeExtractorInput
input
=
new
FakeExtractorInput
.
Builder
().
setData
(
bytes
).
build
();
final
FakeExtractorInput
input
=
new
FakeExtractorInput
.
Builder
().
setData
(
bytes
).
build
();
final
Mp4vChunkPeeker
mp4vChunkPeeker
=
new
Mp4vChunkPeeker
(
formatBuilder
,
fakeTrackOutput
);
final
Mp4vChunkHandler
mp4vChunkPeeker
=
new
Mp4vChunkHandler
(
0
,
fakeTrackOutput
,
new
ChunkClock
(
1_000_000L
,
24
),
formatBuilder
);
mp4vChunkPeeker
.
peek
(
input
,
(
int
)
input
.
getLength
());
mp4vChunkPeeker
.
peek
(
input
,
(
int
)
input
.
getLength
());
Assert
.
assertEquals
(
1.2121212
,
mp4vChunkPeeker
.
pixelWidthHeightRatio
,
0.01
);
Assert
.
assertEquals
(
1.2121212
,
mp4vChunkPeeker
.
pixelWidthHeightRatio
,
0.01
);
...
@@ -64,14 +66,14 @@ public class Mp4vChunkPeekerTest {
...
@@ -64,14 +66,14 @@ public class Mp4vChunkPeekerTest {
public
void
peek_givenCustomAspectRatio
()
throws
IOException
{
public
void
peek_givenCustomAspectRatio
()
throws
IOException
{
ByteBuffer
byteBuffer
=
makeSequence
();
ByteBuffer
byteBuffer
=
makeSequence
();
byteBuffer
.
putInt
(
0x5555
);
byteBuffer
.
putInt
(
0x5555
);
DataHelper
.
appendNal
(
byteBuffer
,
(
byte
)
Mp4vChunkPeek
er
.
LAYER_START_CODE
);
DataHelper
.
appendNal
(
byteBuffer
,
(
byte
)
Mp4vChunkHandl
er
.
LAYER_START_CODE
);
BitBuffer
bitBuffer
=
new
BitBuffer
();
BitBuffer
bitBuffer
=
new
BitBuffer
();
bitBuffer
.
push
(
false
);
//random_accessible_vol
bitBuffer
.
push
(
false
);
//random_accessible_vol
bitBuffer
.
push
(
8
,
8
);
//video_object_type_indication
bitBuffer
.
push
(
8
,
8
);
//video_object_type_indication
bitBuffer
.
push
(
true
);
// is_object_layer_identifier
bitBuffer
.
push
(
true
);
// is_object_layer_identifier
bitBuffer
.
push
(
7
,
7
);
// video_object_layer_verid, video_object_layer_priority
bitBuffer
.
push
(
7
,
7
);
// video_object_layer_verid, video_object_layer_priority
bitBuffer
.
push
(
4
,
Mp4vChunk
Peek
er
.
Extended_PAR
);
bitBuffer
.
push
(
4
,
Mp4vChunk
Handl
er
.
Extended_PAR
);
bitBuffer
.
push
(
8
,
16
);
bitBuffer
.
push
(
8
,
16
);
bitBuffer
.
push
(
8
,
9
);
bitBuffer
.
push
(
8
,
9
);
final
byte
bytes
[]
=
bitBuffer
.
getBytes
();
final
byte
bytes
[]
=
bitBuffer
.
getBytes
();
...
@@ -81,7 +83,8 @@ public class Mp4vChunkPeekerTest {
...
@@ -81,7 +83,8 @@ public class Mp4vChunkPeekerTest {
final
Format
.
Builder
formatBuilder
=
new
Format
.
Builder
();
final
Format
.
Builder
formatBuilder
=
new
Format
.
Builder
();
final
FakeExtractorInput
input
=
new
FakeExtractorInput
.
Builder
().
setData
(
byteBuffer
.
array
())
final
FakeExtractorInput
input
=
new
FakeExtractorInput
.
Builder
().
setData
(
byteBuffer
.
array
())
.
build
();
.
build
();
final
Mp4vChunkPeeker
mp4vChunkPeeker
=
new
Mp4vChunkPeeker
(
formatBuilder
,
fakeTrackOutput
);
final
Mp4vChunkHandler
mp4vChunkPeeker
=
new
Mp4vChunkHandler
(
0
,
fakeTrackOutput
,
new
ChunkClock
(
1_000_000L
,
24
),
formatBuilder
);
mp4vChunkPeeker
.
peek
(
input
,
(
int
)
input
.
getLength
());
mp4vChunkPeeker
.
peek
(
input
,
(
int
)
input
.
getLength
());
Assert
.
assertEquals
(
16
f
/
9
f
,
mp4vChunkPeeker
.
pixelWidthHeightRatio
,
0.01
);
Assert
.
assertEquals
(
16
f
/
9
f
,
mp4vChunkPeeker
.
pixelWidthHeightRatio
,
0.01
);
}
}
...
...
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