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
f1d007e6
authored
Jan 25, 2022
by
Dustin
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Fix issue where reading mime type wrong in video. More tests
parent
7ea2d75f
Show whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
364 additions
and
110 deletions
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/AudioFormat.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/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/AviTrack.java
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/IStreamFormat.java
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/PicCountClock.java
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/StreamHeaderBox.java
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/VideoFormat.java
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/AudioFormatTest.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/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/PicCountClockTest.java
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/StreamHeaderBoxTest.java
testdata/src/test/assets/extractordumps/avi/auds_stream_header.dump
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/AudioFormat.java
View file @
f1d007e6
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
avi
;
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
avi
;
import
android.util.SparseArray
;
import
android.util.SparseArray
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.util.MimeTypes
;
import
com.google.android.exoplayer2.util.MimeTypes
;
import
java.nio.ByteBuffer
;
import
java.nio.ByteBuffer
;
public
class
AudioFormat
{
public
class
AudioFormat
implements
IStreamFormat
{
public
static
final
short
WAVE_FORMAT_PCM
=
1
;
public
static
final
short
WAVE_FORMAT_PCM
=
1
;
static
final
short
WAVE_FORMAT_AAC
=
0xff
;
static
final
short
WAVE_FORMAT_AAC
=
0xff
;
private
static
final
short
WAVE_FORMAT_MPEGLAYER3
=
0x55
;
private
static
final
short
WAVE_FORMAT_MPEGLAYER3
=
0x55
;
...
@@ -60,5 +61,16 @@ public class AudioFormat {
...
@@ -60,5 +61,16 @@ public class AudioFormat {
temp
.
get
(
data
);
temp
.
get
(
data
);
return
data
;
return
data
;
}
}
@Override
public
boolean
isAllKeyFrames
()
{
return
true
;
}
@Override
public
@C
.
TrackType
int
getTrackType
()
{
return
C
.
TRACK_TYPE_AUDIO
;
}
//TODO: Deal with WAVEFORMATEXTENSIBLE
//TODO: Deal with WAVEFORMATEXTENSIBLE
}
}
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/AvcChunkPeeker.java
View file @
f1d007e6
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
avi
;
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
avi
;
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
;
import
com.google.android.exoplayer2.extractor.TrackOutput
;
import
com.google.android.exoplayer2.extractor.TrackOutput
;
...
@@ -37,6 +38,12 @@ public class AvcChunkPeeker extends NalChunkPeeker {
...
@@ -37,6 +38,12 @@ public class AvcChunkPeeker extends NalChunkPeeker {
return
false
;
return
false
;
}
}
/**
* Greatly simplified way to calculate the picOrder
* Full logic is here
* https://chromium.googlesource.com/chromium/src/media/+/refs/heads/main/video/h264_poc.cc
* @param nalTypeOffset
*/
void
updatePicCountClock
(
final
int
nalTypeOffset
)
{
void
updatePicCountClock
(
final
int
nalTypeOffset
)
{
final
ParsableNalUnitBitArray
in
=
new
ParsableNalUnitBitArray
(
buffer
,
nalTypeOffset
+
1
,
buffer
.
length
);
final
ParsableNalUnitBitArray
in
=
new
ParsableNalUnitBitArray
(
buffer
,
nalTypeOffset
+
1
,
buffer
.
length
);
//slide_header()
//slide_header()
...
@@ -63,7 +70,8 @@ public class AvcChunkPeeker extends NalChunkPeeker {
...
@@ -63,7 +70,8 @@ public class AvcChunkPeeker extends NalChunkPeeker {
picCountClock
.
setIndex
(
picCountClock
.
getIndex
());
picCountClock
.
setIndex
(
picCountClock
.
getIndex
());
}
}
private
int
readSps
(
ExtractorInput
input
,
int
nalTypeOffset
)
throws
IOException
{
@VisibleForTesting
int
readSps
(
ExtractorInput
input
,
int
nalTypeOffset
)
throws
IOException
{
final
int
spsStart
=
nalTypeOffset
+
1
;
final
int
spsStart
=
nalTypeOffset
+
1
;
nalTypeOffset
=
seekNextNal
(
input
,
spsStart
);
nalTypeOffset
=
seekNextNal
(
input
,
spsStart
);
spsData
=
NalUnitUtil
.
parseSpsNalUnitPayload
(
buffer
,
spsStart
,
pos
);
spsData
=
NalUnitUtil
.
parseSpsNalUnitPayload
(
buffer
,
spsStart
,
pos
);
...
...
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/AviExtractor.java
View file @
f1d007e6
...
@@ -39,6 +39,21 @@ public class AviExtractor implements Extractor {
...
@@ -39,6 +39,21 @@ public class AviExtractor implements Extractor {
return
sb
.
toString
();
return
sb
.
toString
();
}
}
static
long
alignPosition
(
long
position
)
{
if
((
position
&
1
)
==
1
)
{
position
++;
}
return
position
;
}
static
void
alignInput
(
ExtractorInput
input
)
throws
IOException
{
// This isn't documented anywhere, but most files are aligned to even bytes
// and can have gaps of zeros
if
((
input
.
getPosition
()
&
1
)
==
1
)
{
input
.
skipFully
(
1
);
}
}
static
final
String
TAG
=
"AviExtractor"
;
static
final
String
TAG
=
"AviExtractor"
;
@VisibleForTesting
@VisibleForTesting
static
final
int
PEEK_BYTES
=
28
;
static
final
int
PEEK_BYTES
=
28
;
...
@@ -81,28 +96,14 @@ public class AviExtractor implements Extractor {
...
@@ -81,28 +96,14 @@ public class AviExtractor implements Extractor {
//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
;
private
AviSeekMap
aviSeekMap
;
@VisibleForTesting
AviSeekMap
aviSeekMap
;
// private long indexOffset; //Usually chunkStart
// private long indexOffset; //Usually chunkStart
//If partial read
//If partial read
private
transient
AviTrack
chunkHandler
;
private
transient
AviTrack
chunkHandler
;
static
void
alignInput
(
ExtractorInput
input
)
throws
IOException
{
// This isn't documented anywhere, but most files are aligned to even bytes
// and can have gaps of zeros
if
((
input
.
getPosition
()
&
1
)
==
1
)
{
input
.
skipFully
(
1
);
}
}
static
long
alignPosition
(
long
position
)
{
if
((
position
&
1
)
==
1
)
{
position
++;
}
return
position
;
}
/**
/**
*
*
* @param input
* @param input
...
@@ -161,7 +162,20 @@ public class AviExtractor implements Extractor {
...
@@ -161,7 +162,20 @@ public class AviExtractor implements Extractor {
return
byteBuffer
;
return
byteBuffer
;
}
}
private
void
setSeekMap
(
AviSeekMap
aviSeekMap
)
{
@VisibleForTesting
static
int
getStreamId
(
int
chunkId
)
{
final
int
upperChar
=
chunkId
&
0xff
;
if
(
Character
.
isDigit
(
upperChar
))
{
final
int
lowerChar
=
(
chunkId
>>
8
)
&
0xff
;
if
(
Character
.
isDigit
(
upperChar
))
{
return
(
lowerChar
&
0xf
)
+
((
upperChar
&
0xf
)
*
10
);
}
}
return
-
1
;
}
@VisibleForTesting
void
setSeekMap
(
AviSeekMap
aviSeekMap
)
{
this
.
aviSeekMap
=
aviSeekMap
;
this
.
aviSeekMap
=
aviSeekMap
;
output
.
seekMap
(
aviSeekMap
);
output
.
seekMap
(
aviSeekMap
);
}
}
...
@@ -191,16 +205,17 @@ public class AviExtractor implements Extractor {
...
@@ -191,16 +205,17 @@ public class AviExtractor implements Extractor {
this
.
output
=
output
;
this
.
output
=
output
;
}
}
private
void
parseStream
(
final
ListBox
streamList
,
int
streamId
)
{
@VisibleForTesting
AviTrack
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
)
{
Log
.
w
(
TAG
,
"Missing Stream Header"
);
Log
.
w
(
TAG
,
"Missing Stream Header"
);
return
;
return
null
;
}
}
if
(
streamFormat
==
null
)
{
if
(
streamFormat
==
null
)
{
Log
.
w
(
TAG
,
"Missing Stream Format"
);
Log
.
w
(
TAG
,
"Missing Stream Format"
);
return
;
return
null
;
}
}
final
Format
.
Builder
builder
=
new
Format
.
Builder
();
final
Format
.
Builder
builder
=
new
Format
.
Builder
();
builder
.
setId
(
streamId
);
builder
.
setId
(
streamId
);
...
@@ -212,31 +227,33 @@ public class AviExtractor implements Extractor {
...
@@ -212,31 +227,33 @@ public class AviExtractor implements Extractor {
if
(
streamName
!=
null
)
{
if
(
streamName
!=
null
)
{
builder
.
setLabel
(
streamName
.
getName
());
builder
.
setLabel
(
streamName
.
getName
());
}
}
final
AviTrack
aviTrack
;
if
(
streamHeader
.
isVideo
())
{
if
(
streamHeader
.
isVideo
())
{
final
String
mimeType
=
streamHeader
.
getMimeType
();
final
VideoFormat
videoFormat
=
streamFormat
.
getVideoFormat
();
final
String
mimeType
=
videoFormat
.
getMimeType
();
if
(
mimeType
==
null
)
{
if
(
mimeType
==
null
)
{
Log
.
w
(
TAG
,
"Unknown FourCC: "
+
toString
(
streamHeader
.
getFourCC
()));
Log
.
w
(
TAG
,
"Unknown FourCC: "
+
toString
(
streamHeader
.
getFourCC
()));
return
;
return
null
;
}
}
final
VideoFormat
videoFormat
=
streamFormat
.
getVideoFormat
();
final
TrackOutput
trackOutput
=
output
.
track
(
streamId
,
C
.
TRACK_TYPE_VIDEO
);
final
TrackOutput
trackOutput
=
output
.
track
(
streamId
,
C
.
TRACK_TYPE_VIDEO
);
builder
.
setWidth
(
videoFormat
.
getWidth
());
builder
.
setWidth
(
videoFormat
.
getWidth
());
builder
.
setHeight
(
videoFormat
.
getHeight
());
builder
.
setHeight
(
videoFormat
.
getHeight
());
builder
.
setFrameRate
(
streamHeader
.
getFrameRate
());
builder
.
setFrameRate
(
streamHeader
.
getFrameRate
());
builder
.
setSampleMimeType
(
mimeType
);
builder
.
setSampleMimeType
(
mimeType
);
final
AviTrack
aviTrack
=
new
AviTrack
(
streamId
,
streamHeader
,
trackOutput
);
if
(
MimeTypes
.
VIDEO_H264
.
equals
(
mimeType
))
{
if
(
MimeTypes
.
VIDEO_MP4V
.
equals
(
mimeType
))
{
Mp4vChunkPeeker
mp4vChunkPeeker
=
new
Mp4vChunkPeeker
(
builder
,
trackOutput
);
aviTrack
.
setChunkPeeker
(
mp4vChunkPeeker
);
}
else
if
(
MimeTypes
.
VIDEO_H264
.
equals
(
mimeType
))
{
final
AvcChunkPeeker
avcChunkPeeker
=
new
AvcChunkPeeker
(
builder
,
trackOutput
,
streamHeader
.
getUsPerSample
());
final
AvcChunkPeeker
avcChunkPeeker
=
new
AvcChunkPeeker
(
builder
,
trackOutput
,
streamHeader
.
getUsPerSample
());
aviTrack
.
setClock
(
avcChunkPeeker
.
getPicCountClock
()
);
aviTrack
=
new
AviTrack
(
streamId
,
videoFormat
,
avcChunkPeeker
.
getPicCountClock
(),
trackOutput
);
aviTrack
.
setChunkPeeker
(
avcChunkPeeker
);
aviTrack
.
setChunkPeeker
(
avcChunkPeeker
);
}
else
{
aviTrack
=
new
AviTrack
(
streamId
,
videoFormat
,
new
LinearClock
(
streamHeader
.
getUsPerSample
()),
trackOutput
);
if
(
MimeTypes
.
VIDEO_MP4V
.
equals
(
mimeType
))
{
aviTrack
.
setChunkPeeker
(
new
Mp4vChunkPeeker
(
builder
,
trackOutput
));
}
}
}
trackOutput
.
format
(
builder
.
build
());
trackOutput
.
format
(
builder
.
build
());
durationUs
=
streamHeader
.
getUsPerSample
()
*
streamHeader
.
getLength
();
durationUs
=
streamHeader
.
getUsPerSample
()
*
streamHeader
.
getLength
();
aviTracks
[
streamId
]
=
aviTrack
;
}
else
if
(
streamHeader
.
isAudio
())
{
}
else
if
(
streamHeader
.
isAudio
())
{
final
AudioFormat
audioFormat
=
streamFormat
.
getAudioFormat
();
final
AudioFormat
audioFormat
=
streamFormat
.
getAudioFormat
();
final
TrackOutput
trackOutput
=
output
.
track
(
streamId
,
C
.
TRACK_TYPE_AUDIO
);
final
TrackOutput
trackOutput
=
output
.
track
(
streamId
,
C
.
TRACK_TYPE_AUDIO
);
...
@@ -257,8 +274,12 @@ public class AviExtractor implements Extractor {
...
@@ -257,8 +274,12 @@ 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
());
aviTracks
[
streamId
]
=
new
AviTrack
(
streamId
,
streamHeader
,
trackOutput
);
aviTrack
=
new
AviTrack
(
streamId
,
audioFormat
,
new
LinearClock
(
streamHeader
.
getUsPerSample
()),
trackOutput
);
}
else
{
aviTrack
=
null
;
}
}
return
aviTrack
;
}
}
private
int
readTracks
(
ExtractorInput
input
)
throws
IOException
{
private
int
readTracks
(
ExtractorInput
input
)
throws
IOException
{
...
@@ -278,7 +299,7 @@ public class AviExtractor implements Extractor {
...
@@ -278,7 +299,7 @@ public class AviExtractor implements Extractor {
for
(
Box
box
:
headerList
.
getChildren
())
{
for
(
Box
box
:
headerList
.
getChildren
())
{
if
(
box
instanceof
ListBox
&&
((
ListBox
)
box
).
getListType
()
==
STRL
)
{
if
(
box
instanceof
ListBox
&&
((
ListBox
)
box
).
getListType
()
==
STRL
)
{
final
ListBox
streamList
=
(
ListBox
)
box
;
final
ListBox
streamList
=
(
ListBox
)
box
;
parseStream
(
streamList
,
streamId
);
aviTracks
[
streamId
]
=
parseStream
(
streamList
,
streamId
);
streamId
++;
streamId
++;
}
}
}
}
...
@@ -343,7 +364,8 @@ public class AviExtractor implements Extractor {
...
@@ -343,7 +364,8 @@ public class AviExtractor implements Extractor {
for
(
int
i
=
0
;
i
<
seekOffsets
.
length
;
i
++)
{
for
(
int
i
=
0
;
i
<
seekOffsets
.
length
;
i
++)
{
seekOffsets
[
i
]
=
new
UnboundedIntArray
();
seekOffsets
[
i
]
=
new
UnboundedIntArray
();
}
}
final
int
seekFrameRate
=
(
int
)(
videoTrack
.
streamHeaderBox
.
getFrameRate
()
*
2
);
//TODO: Change this to min frame rate
final
int
seekFrameRate
=
(
int
)(
1
f
/(
videoTrack
.
getClock
().
usPerChunk
/
1_000_000
f
)
*
2
);
final
UnboundedIntArray
keyFrameList
=
new
UnboundedIntArray
();
final
UnboundedIntArray
keyFrameList
=
new
UnboundedIntArray
();
while
(
remaining
>
0
)
{
while
(
remaining
>
0
)
{
...
@@ -406,17 +428,6 @@ public class AviExtractor implements Extractor {
...
@@ -406,17 +428,6 @@ public class AviExtractor implements Extractor {
setSeekMap
(
seekMap
);
setSeekMap
(
seekMap
);
}
}
private
static
int
getStreamId
(
int
chunkId
)
{
final
int
upperChar
=
chunkId
&
0xff
;
if
(
Character
.
isDigit
(
upperChar
))
{
final
int
lowerChar
=
(
chunkId
>>
8
)
&
0xff
;
if
(
Character
.
isDigit
(
upperChar
))
{
return
(
lowerChar
&
0xf
)
+
((
upperChar
&
0xf
)
*
10
);
}
}
return
-
1
;
}
@Nullable
@Nullable
private
AviTrack
getAviTrack
(
int
chunkId
)
{
private
AviTrack
getAviTrack
(
int
chunkId
)
{
final
int
streamId
=
getStreamId
(
chunkId
);
final
int
streamId
=
getStreamId
(
chunkId
);
...
...
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/AviSeekMap.java
View file @
f1d007e6
...
@@ -3,7 +3,6 @@ package com.google.android.exoplayer2.extractor.avi;
...
@@ -3,7 +3,6 @@ package com.google.android.exoplayer2.extractor.avi;
import
androidx.annotation.NonNull
;
import
androidx.annotation.NonNull
;
import
com.google.android.exoplayer2.extractor.SeekMap
;
import
com.google.android.exoplayer2.extractor.SeekMap
;
import
com.google.android.exoplayer2.extractor.SeekPoint
;
import
com.google.android.exoplayer2.extractor.SeekPoint
;
import
com.google.android.exoplayer2.util.Log
;
public
class
AviSeekMap
implements
SeekMap
{
public
class
AviSeekMap
implements
SeekMap
{
final
long
videoUsPerChunk
;
final
long
videoUsPerChunk
;
...
@@ -58,7 +57,7 @@ public class AviSeekMap implements SeekMap {
...
@@ -58,7 +57,7 @@ public class AviSeekMap implements SeekMap {
int
offset
=
seekOffsets
[
videoStreamId
][
seekFrameIndex
];
int
offset
=
seekOffsets
[
videoStreamId
][
seekFrameIndex
];
final
long
outUs
=
seekFrameIndex
*
seekIndexFactor
*
videoUsPerChunk
;
final
long
outUs
=
seekFrameIndex
*
seekIndexFactor
*
videoUsPerChunk
;
final
long
position
=
offset
+
moviOffset
;
final
long
position
=
offset
+
moviOffset
;
Log
.
d
(
AviExtractor
.
TAG
,
"SeekPoint: us="
+
outUs
+
" pos="
+
position
);
//
Log.d(AviExtractor.TAG, "SeekPoint: us=" + outUs + " pos=" + position);
return
new
SeekPoints
(
new
SeekPoint
(
outUs
,
position
));
return
new
SeekPoints
(
new
SeekPoint
(
outUs
,
position
));
}
}
...
...
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/AviTrack.java
View file @
f1d007e6
...
@@ -5,7 +5,6 @@ import androidx.annotation.Nullable;
...
@@ -5,7 +5,6 @@ import androidx.annotation.Nullable;
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.MimeTypes
;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.util.Arrays
;
import
java.util.Arrays
;
...
@@ -16,23 +15,22 @@ public class AviTrack {
...
@@ -16,23 +15,22 @@ public class AviTrack {
final
int
id
;
final
int
id
;
@NonNull
@NonNull
final
StreamHeaderBox
streamHeaderBox
;
final
LinearClock
clock
;
@NonNull
LinearClock
clock
;
@Nullable
ChunkPeeker
chunkPeeker
;
/**
/**
* True indicates all frames are key frames (e.g. Audio, MJPEG)
* True indicates all frames are key frames (e.g. Audio, MJPEG)
*/
*/
boolean
allKeyFrames
;
final
boolean
allKeyFrames
;
final
@C
.
TrackType
int
trackType
;
@NonNull
final
TrackOutput
trackOutput
;
boolean
forceKeyFrame
;
boolean
forceKeyFrame
;
@N
onNull
@N
ullable
TrackOutput
trackOutput
;
ChunkPeeker
chunkPeeker
;
/**
/**
* Key is frame number value is offset
* Key is frame number value is offset
...
@@ -43,22 +41,19 @@ public class AviTrack {
...
@@ -43,22 +41,19 @@ public class AviTrack {
transient
int
chunkSize
;
transient
int
chunkSize
;
transient
int
chunkRemaining
;
transient
int
chunkRemaining
;
AviTrack
(
int
id
,
@NonNull
StreamHeaderBox
streamHeaderBox
,
@NonNull
TrackOutput
trackOutput
)
{
AviTrack
(
int
id
,
@NonNull
IStreamFormat
streamFormat
,
@NonNull
LinearClock
clock
,
@NonNull
TrackOutput
trackOutput
)
{
this
.
id
=
id
;
this
.
id
=
id
;
this
.
clock
=
clock
;
this
.
allKeyFrames
=
streamFormat
.
isAllKeyFrames
();
this
.
trackType
=
streamFormat
.
getTrackType
();
this
.
trackOutput
=
trackOutput
;
this
.
trackOutput
=
trackOutput
;
this
.
streamHeaderBox
=
streamHeaderBox
;
clock
=
new
LinearClock
(
streamHeaderBox
.
getUsPerSample
());
this
.
allKeyFrames
=
streamHeaderBox
.
isAudio
()
||
(
MimeTypes
.
VIDEO_MJPEG
.
equals
(
streamHeaderBox
.
getMimeType
()));
}
}
public
LinearClock
getClock
()
{
public
LinearClock
getClock
()
{
return
clock
;
return
clock
;
}
}
public
void
setClock
(
LinearClock
clock
)
{
this
.
clock
=
clock
;
}
public
void
setChunkPeeker
(
ChunkPeeker
chunkPeeker
)
{
public
void
setChunkPeeker
(
ChunkPeeker
chunkPeeker
)
{
this
.
chunkPeeker
=
chunkPeeker
;
this
.
chunkPeeker
=
chunkPeeker
;
}
}
...
@@ -78,8 +73,6 @@ public class AviTrack {
...
@@ -78,8 +73,6 @@ public class AviTrack {
if
(
keyFrames
!=
null
)
{
if
(
keyFrames
!=
null
)
{
return
Arrays
.
binarySearch
(
keyFrames
,
clock
.
getIndex
())
>=
0
;
return
Arrays
.
binarySearch
(
keyFrames
,
clock
.
getIndex
())
>=
0
;
}
}
//Hack: Exo needs at least one frame before it starts playback
//return clock.getIndex() == 0;
return
false
;
return
false
;
}
}
...
@@ -92,11 +85,11 @@ public class AviTrack {
...
@@ -92,11 +85,11 @@ public class AviTrack {
}
}
public
boolean
isVideo
()
{
public
boolean
isVideo
()
{
return
streamHeaderBox
.
isVideo
()
;
return
trackType
==
C
.
TRACK_TYPE_VIDEO
;
}
}
public
boolean
isAudio
()
{
public
boolean
isAudio
()
{
return
streamHeaderBox
.
isAudio
()
;
return
trackType
==
C
.
TRACK_TYPE_AUDIO
;
}
}
public
boolean
newChunk
(
int
tag
,
int
size
,
ExtractorInput
input
)
throws
IOException
{
public
boolean
newChunk
(
int
tag
,
int
size
,
ExtractorInput
input
)
throws
IOException
{
...
@@ -114,7 +107,13 @@ public class AviTrack {
...
@@ -114,7 +107,13 @@ public class AviTrack {
}
}
}
}
public
boolean
resume
(
ExtractorInput
input
)
throws
IOException
{
/**
* Resume a partial read of a chunk
* @param input
* @return
* @throws IOException
*/
boolean
resume
(
ExtractorInput
input
)
throws
IOException
{
chunkRemaining
-=
trackOutput
.
sampleData
(
input
,
chunkRemaining
,
false
);
chunkRemaining
-=
trackOutput
.
sampleData
(
input
,
chunkRemaining
,
false
);
if
(
chunkRemaining
==
0
)
{
if
(
chunkRemaining
==
0
)
{
done
(
chunkSize
);
done
(
chunkSize
);
...
@@ -124,6 +123,10 @@ public class AviTrack {
...
@@ -124,6 +123,10 @@ public class AviTrack {
}
}
}
}
/**
* Done reading a chunk
* @param size
*/
void
done
(
final
int
size
)
{
void
done
(
final
int
size
)
{
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
);
...
...
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/IStreamFormat.java
0 → 100644
View file @
f1d007e6
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
avi
;
import
com.google.android.exoplayer2.C
;
public
interface
IStreamFormat
{
String
getMimeType
();
boolean
isAllKeyFrames
();
@C
.
TrackType
int
getTrackType
();
}
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/PicCountClock.java
View file @
f1d007e6
...
@@ -4,6 +4,8 @@ package com.google.android.exoplayer2.extractor.avi;
...
@@ -4,6 +4,8 @@ package com.google.android.exoplayer2.extractor.avi;
* Properly calculates the frame time for H264 frames using PicCount
* Properly calculates the frame time for H264 frames using PicCount
*/
*/
public
class
PicCountClock
extends
LinearClock
{
public
class
PicCountClock
extends
LinearClock
{
//I believe this is 2 because there is a bottom pic order and a top pic order
private
static
final
int
STEP
=
2
;
//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
;
...
@@ -19,7 +21,7 @@ public class PicCountClock extends LinearClock {
...
@@ -19,7 +21,7 @@ public class PicCountClock extends LinearClock {
public
void
setMaxPicCount
(
int
maxPicCount
)
{
public
void
setMaxPicCount
(
int
maxPicCount
)
{
this
.
maxPicCount
=
maxPicCount
;
this
.
maxPicCount
=
maxPicCount
;
posHalf
=
maxPicCount
/
2
;
//Not sure why pics are 2x
posHalf
=
maxPicCount
/
STEP
;
negHalf
=
-
posHalf
;
negHalf
=
-
posHalf
;
}
}
...
@@ -40,7 +42,7 @@ public class PicCountClock extends LinearClock {
...
@@ -40,7 +42,7 @@ public class PicCountClock extends LinearClock {
}
else
if
(
delta
>
posHalf
)
{
}
else
if
(
delta
>
posHalf
)
{
delta
-=
maxPicCount
;
delta
-=
maxPicCount
;
}
}
picIndex
+=
delta
/
2
;
picIndex
+=
delta
/
STEP
;
lastPicCount
=
picCount
;
lastPicCount
=
picCount
;
if
(
maxPicIndex
<
picIndex
)
{
if
(
maxPicIndex
<
picIndex
)
{
maxPicIndex
=
picIndex
;
maxPicIndex
=
picIndex
;
...
...
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/StreamHeaderBox.java
View file @
f1d007e6
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
avi
;
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
avi
;
import
android.util.SparseArray
;
import
com.google.android.exoplayer2.util.MimeTypes
;
import
java.nio.ByteBuffer
;
import
java.nio.ByteBuffer
;
/**
/**
...
@@ -16,31 +14,6 @@ public class StreamHeaderBox extends ResidentBox {
...
@@ -16,31 +14,6 @@ public class StreamHeaderBox extends ResidentBox {
//Videos Stream
//Videos Stream
static
final
int
VIDS
=
'v'
|
(
'i'
<<
8
)
|
(
'd'
<<
16
)
|
(
's'
<<
24
);
static
final
int
VIDS
=
'v'
|
(
'i'
<<
8
)
|
(
'd'
<<
16
)
|
(
's'
<<
24
);
static
final
int
XVID
=
'X'
|
(
'V'
<<
8
)
|
(
'I'
<<
16
)
|
(
'D'
<<
24
);
private
static
final
SparseArray
<
String
>
STREAM_MAP
=
new
SparseArray
<>();
static
{
//Although other types are technically supported, AVI is almost exclusively MP4V and MJPEG
final
String
mimeType
=
MimeTypes
.
VIDEO_MP4V
;
//final String mimeType = MimeTypes.VIDEO_H263;
//I've never seen an Android devices that actually supports MP42
STREAM_MAP
.
put
(
'M'
|
(
'P'
<<
8
)
|
(
'4'
<<
16
)
|
(
'2'
<<
24
),
MimeTypes
.
BASE_TYPE_VIDEO
+
"/mp42"
);
//Samsung seems to support the rare MP43.
STREAM_MAP
.
put
(
'M'
|
(
'P'
<<
8
)
|
(
'4'
<<
16
)
|
(
'3'
<<
24
),
MimeTypes
.
BASE_TYPE_VIDEO
+
"/mp43"
);
STREAM_MAP
.
put
(
'H'
|
(
'2'
<<
8
)
|
(
'6'
<<
16
)
|
(
'4'
<<
24
),
MimeTypes
.
VIDEO_H264
);
STREAM_MAP
.
put
(
'a'
|
(
'v'
<<
8
)
|
(
'c'
<<
16
)
|
(
'1'
<<
24
),
MimeTypes
.
VIDEO_H264
);
STREAM_MAP
.
put
(
'A'
|
(
'V'
<<
8
)
|
(
'C'
<<
16
)
|
(
'1'
<<
24
),
MimeTypes
.
VIDEO_H264
);
STREAM_MAP
.
put
(
'3'
|
(
'V'
<<
8
)
|
(
'I'
<<
16
)
|
(
'D'
<<
24
),
mimeType
);
STREAM_MAP
.
put
(
'x'
|
(
'v'
<<
8
)
|
(
'i'
<<
16
)
|
(
'd'
<<
24
),
mimeType
);
STREAM_MAP
.
put
(
XVID
,
mimeType
);
STREAM_MAP
.
put
(
'D'
|
(
'X'
<<
8
)
|
(
'5'
<<
16
)
|
(
'0'
<<
24
),
mimeType
);
STREAM_MAP
.
put
(
'd'
|
(
'i'
<<
8
)
|
(
'v'
<<
16
)
|
(
'x'
<<
24
),
mimeType
);
STREAM_MAP
.
put
(
'm'
|
(
'j'
<<
8
)
|
(
'p'
<<
16
)
|
(
'g'
<<
24
),
MimeTypes
.
VIDEO_MJPEG
);
}
StreamHeaderBox
(
int
type
,
int
size
,
ByteBuffer
byteBuffer
)
{
StreamHeaderBox
(
int
type
,
int
size
,
ByteBuffer
byteBuffer
)
{
super
(
type
,
size
,
byteBuffer
);
super
(
type
,
size
,
byteBuffer
);
}
}
...
@@ -64,11 +37,6 @@ public class StreamHeaderBox extends ResidentBox {
...
@@ -64,11 +37,6 @@ public class StreamHeaderBox extends ResidentBox {
return
getScale
()
*
1_000_000L
/
getRate
();
return
getScale
()
*
1_000_000L
/
getRate
();
}
}
public
String
getMimeType
()
{
return
STREAM_MAP
.
get
(
getFourCC
());
}
public
int
getSteamType
()
{
public
int
getSteamType
()
{
return
byteBuffer
.
getInt
(
0
);
return
byteBuffer
.
getInt
(
0
);
}
}
...
...
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/VideoFormat.java
View file @
f1d007e6
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
avi
;
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
avi
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.util.MimeTypes
;
import
java.nio.ByteBuffer
;
import
java.nio.ByteBuffer
;
import
java.util.HashMap
;
public
class
VideoFormat
implements
IStreamFormat
{
static
final
int
XVID
=
'X'
|
(
'V'
<<
8
)
|
(
'I'
<<
16
)
|
(
'D'
<<
24
);
private
static
final
HashMap
<
Integer
,
String
>
STREAM_MAP
=
new
HashMap
<>();
static
{
//Although other types are technically supported, AVI is almost exclusively MP4V and MJPEG
final
String
mimeType
=
MimeTypes
.
VIDEO_MP4V
;
//final String mimeType = MimeTypes.VIDEO_H263;
//I've never seen an Android devices that actually supports MP42
STREAM_MAP
.
put
(
'M'
|
(
'P'
<<
8
)
|
(
'4'
<<
16
)
|
(
'2'
<<
24
),
MimeTypes
.
BASE_TYPE_VIDEO
+
"/mp42"
);
//Samsung seems to support the rare MP43.
STREAM_MAP
.
put
(
'M'
|
(
'P'
<<
8
)
|
(
'4'
<<
16
)
|
(
'3'
<<
24
),
MimeTypes
.
BASE_TYPE_VIDEO
+
"/mp43"
);
STREAM_MAP
.
put
(
'H'
|
(
'2'
<<
8
)
|
(
'6'
<<
16
)
|
(
'4'
<<
24
),
MimeTypes
.
VIDEO_H264
);
STREAM_MAP
.
put
(
'a'
|
(
'v'
<<
8
)
|
(
'c'
<<
16
)
|
(
'1'
<<
24
),
MimeTypes
.
VIDEO_H264
);
STREAM_MAP
.
put
(
'A'
|
(
'V'
<<
8
)
|
(
'C'
<<
16
)
|
(
'1'
<<
24
),
MimeTypes
.
VIDEO_H264
);
STREAM_MAP
.
put
(
'3'
|
(
'V'
<<
8
)
|
(
'I'
<<
16
)
|
(
'D'
<<
24
),
mimeType
);
STREAM_MAP
.
put
(
'x'
|
(
'v'
<<
8
)
|
(
'i'
<<
16
)
|
(
'd'
<<
24
),
mimeType
);
STREAM_MAP
.
put
(
XVID
,
mimeType
);
STREAM_MAP
.
put
(
'D'
|
(
'X'
<<
8
)
|
(
'5'
<<
16
)
|
(
'0'
<<
24
),
mimeType
);
STREAM_MAP
.
put
(
'd'
|
(
'i'
<<
8
)
|
(
'v'
<<
16
)
|
(
'x'
<<
24
),
mimeType
);
STREAM_MAP
.
put
(
'M'
|
(
'J'
<<
8
)
|
(
'P'
<<
16
)
|
(
'G'
<<
24
),
MimeTypes
.
VIDEO_MJPEG
);
STREAM_MAP
.
put
(
'm'
|
(
'j'
<<
8
)
|
(
'p'
<<
16
)
|
(
'g'
<<
24
),
MimeTypes
.
VIDEO_MJPEG
);
}
public
class
VideoFormat
{
private
final
ByteBuffer
byteBuffer
;
private
final
ByteBuffer
byteBuffer
;
public
VideoFormat
(
final
ByteBuffer
byteBuffer
)
{
public
VideoFormat
(
final
ByteBuffer
byteBuffer
)
{
...
@@ -17,5 +47,23 @@ public class VideoFormat {
...
@@ -17,5 +47,23 @@ public class VideoFormat {
public
int
getHeight
()
{
public
int
getHeight
()
{
return
byteBuffer
.
getInt
(
8
);
return
byteBuffer
.
getInt
(
8
);
}
}
// 12 - biPlanes
// 14 - biBitCount
public
int
getCompression
()
{
return
byteBuffer
.
getInt
(
16
);
}
public
String
getMimeType
()
{
return
STREAM_MAP
.
get
(
getCompression
());
}
@Override
public
boolean
isAllKeyFrames
()
{
return
MimeTypes
.
VIDEO_MJPEG
.
equals
(
getMimeType
());
}
@Override
public
int
getTrackType
()
{
return
C
.
TRACK_TYPE_VIDEO
;
}
}
}
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/AudioFormatTest.java
View file @
f1d007e6
...
@@ -13,7 +13,7 @@ public class AudioFormatTest {
...
@@ -13,7 +13,7 @@ public class AudioFormatTest {
@Test
@Test
public
void
getters_givenAacStreamFormat
()
throws
IOException
{
public
void
getters_givenAacStreamFormat
()
throws
IOException
{
final
StreamFormatBox
streamFormatBox
=
DataHelper
.
getA
udio
StreamFormat
();
final
StreamFormatBox
streamFormatBox
=
DataHelper
.
getA
ac
StreamFormat
();
final
AudioFormat
audioFormat
=
streamFormatBox
.
getAudioFormat
();
final
AudioFormat
audioFormat
=
streamFormatBox
.
getAudioFormat
();
Assert
.
assertEquals
(
MimeTypes
.
AUDIO_AAC
,
audioFormat
.
getMimeType
());
Assert
.
assertEquals
(
MimeTypes
.
AUDIO_AAC
,
audioFormat
.
getMimeType
());
Assert
.
assertEquals
(
2
,
audioFormat
.
getChannels
());
Assert
.
assertEquals
(
2
,
audioFormat
.
getChannels
());
...
@@ -21,5 +21,6 @@ public class AudioFormatTest {
...
@@ -21,5 +21,6 @@ public class AudioFormatTest {
Assert
.
assertEquals
(
48000
,
audioFormat
.
getSamplesPerSecond
());
Assert
.
assertEquals
(
48000
,
audioFormat
.
getSamplesPerSecond
());
Assert
.
assertEquals
(
0
,
audioFormat
.
getBitsPerSample
());
//Not meaningful for AAC
Assert
.
assertEquals
(
0
,
audioFormat
.
getBitsPerSample
());
//Not meaningful for AAC
Assert
.
assertArrayEquals
(
CODEC_PRIVATE
,
audioFormat
.
getCodecData
());
Assert
.
assertArrayEquals
(
CODEC_PRIVATE
,
audioFormat
.
getCodecData
());
Assert
.
assertEquals
(
MimeTypes
.
AUDIO_AAC
,
audioFormat
.
getMimeType
());
}
}
}
}
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/AviExtractorRoboTest.java
0 → 100644
View file @
f1d007e6
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
avi
;
import
androidx.test.ext.junit.runners.AndroidJUnit4
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.testutil.FakeExtractorOutput
;
import
com.google.android.exoplayer2.testutil.FakeTrackOutput
;
import
com.google.android.exoplayer2.util.MimeTypes
;
import
java.io.IOException
;
import
org.junit.Assert
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
@RunWith
(
AndroidJUnit4
.
class
)
public
class
AviExtractorRoboTest
{
@Test
public
void
parseStream_givenH264StreamList
()
throws
IOException
{
final
AviExtractor
aviExtractor
=
new
AviExtractor
();
final
FakeExtractorOutput
fakeExtractorOutput
=
new
FakeExtractorOutput
();
aviExtractor
.
init
(
fakeExtractorOutput
);
final
ListBox
streamList
=
DataHelper
.
getVideoStreamList
();
aviExtractor
.
parseStream
(
streamList
,
0
);
FakeTrackOutput
trackOutput
=
fakeExtractorOutput
.
track
(
0
,
C
.
TRACK_TYPE_VIDEO
);
Assert
.
assertEquals
(
MimeTypes
.
VIDEO_H264
,
trackOutput
.
lastFormat
.
sampleMimeType
);
}
@Test
public
void
parseStream_givenAacStreamList
()
throws
IOException
{
final
AviExtractor
aviExtractor
=
new
AviExtractor
();
final
FakeExtractorOutput
fakeExtractorOutput
=
new
FakeExtractorOutput
();
aviExtractor
.
init
(
fakeExtractorOutput
);
final
ListBox
streamList
=
DataHelper
.
getAacStreamList
();
aviExtractor
.
parseStream
(
streamList
,
0
);
FakeTrackOutput
trackOutput
=
fakeExtractorOutput
.
track
(
0
,
C
.
TRACK_TYPE_VIDEO
);
Assert
.
assertEquals
(
MimeTypes
.
AUDIO_AAC
,
trackOutput
.
lastFormat
.
sampleMimeType
);
}
}
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/AviExtractorTest.java
View file @
f1d007e6
...
@@ -98,4 +98,54 @@ public class AviExtractorTest {
...
@@ -98,4 +98,54 @@ public class AviExtractorTest {
final
int
riff
=
'R'
|
(
'I'
<<
8
)
|
(
'F'
<<
16
)
|
(
'F'
<<
24
);
final
int
riff
=
'R'
|
(
'I'
<<
8
)
|
(
'F'
<<
16
)
|
(
'F'
<<
24
);
Assert
.
assertEquals
(
"RIFF"
,
AviExtractor
.
toString
(
riff
));
Assert
.
assertEquals
(
"RIFF"
,
AviExtractor
.
toString
(
riff
));
}
}
@Test
public
void
alignPosition_givenOddPosition
()
{
Assert
.
assertEquals
(
2
,
AviExtractor
.
alignPosition
(
1
));
}
@Test
public
void
alignPosition_givenEvenPosition
()
{
Assert
.
assertEquals
(
2
,
AviExtractor
.
alignPosition
(
2
));
}
@Test
public
void
alignInput_givenOddPosition
()
throws
IOException
{
final
FakeExtractorInput
fakeExtractorInput
=
new
FakeExtractorInput
.
Builder
().
setData
(
new
byte
[
16
]).
build
();
fakeExtractorInput
.
setPosition
(
1
);
AviExtractor
.
alignInput
(
fakeExtractorInput
);
Assert
.
assertEquals
(
2
,
fakeExtractorInput
.
getPosition
());
}
@Test
public
void
alignInput_givenEvenPosition
()
throws
IOException
{
final
FakeExtractorInput
fakeExtractorInput
=
new
FakeExtractorInput
.
Builder
().
setData
(
new
byte
[
16
]).
build
();
fakeExtractorInput
.
setPosition
(
4
);
AviExtractor
.
alignInput
(
fakeExtractorInput
);
Assert
.
assertEquals
(
4
,
fakeExtractorInput
.
getPosition
());
}
@Test
public
void
setSeekMap_givenStubbedSeekMap
()
throws
IOException
{
final
AviSeekMap
aviSeekMap
=
DataHelper
.
getAviSeekMap
();
final
AviExtractor
aviExtractor
=
new
AviExtractor
();
final
FakeExtractorOutput
fakeExtractorOutput
=
new
FakeExtractorOutput
();
aviExtractor
.
init
(
fakeExtractorOutput
);
aviExtractor
.
setSeekMap
(
aviSeekMap
);
Assert
.
assertEquals
(
aviSeekMap
,
fakeExtractorOutput
.
seekMap
);
Assert
.
assertEquals
(
aviSeekMap
,
aviExtractor
.
aviSeekMap
);
}
@Test
public
void
getStreamId_givenInvalidStreamId
()
{
Assert
.
assertEquals
(-
1
,
AviExtractor
.
getStreamId
(
AviExtractor
.
JUNK
));
}
@Test
public
void
getStreamId_givenValidStreamId
()
{
Assert
.
assertEquals
(
1
,
AviExtractor
.
getStreamId
(
'0'
|
(
'1'
<<
8
)
|
(
'd'
<<
16
)
|
(
'c'
<<
24
)));
}
}
}
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/DataHelper.java
View file @
f1d007e6
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
avi
;
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
avi
;
import
com.google.android.exoplayer2.testutil.FakeExtractorInput
;
import
com.google.android.exoplayer2.testutil.FakeExtractorInput
;
import
com.google.android.exoplayer2.testutil.FakeTrackOutput
;
import
java.io.File
;
import
java.io.File
;
import
java.io.FileInputStream
;
import
java.io.FileInputStream
;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.nio.ByteBuffer
;
import
java.nio.ByteBuffer
;
import
java.nio.ByteOrder
;
import
java.nio.ByteOrder
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.Arrays
;
public
class
DataHelper
{
public
class
DataHelper
{
...
@@ -31,7 +33,14 @@ public class DataHelper {
...
@@ -31,7 +33,14 @@ public class DataHelper {
return
new
StreamHeaderBox
(
StreamHeaderBox
.
STRH
,
buffer
.
length
,
byteBuffer
);
return
new
StreamHeaderBox
(
StreamHeaderBox
.
STRH
,
buffer
.
length
,
byteBuffer
);
}
}
public
static
StreamFormatBox
getAudioStreamFormat
()
throws
IOException
{
public
static
StreamHeaderBox
getAudioStreamHeader
()
throws
IOException
{
final
byte
[]
buffer
=
getBytes
(
"auds_stream_header.dump"
);
final
ByteBuffer
byteBuffer
=
ByteBuffer
.
wrap
(
buffer
);
byteBuffer
.
order
(
ByteOrder
.
LITTLE_ENDIAN
);
return
new
StreamHeaderBox
(
StreamHeaderBox
.
STRH
,
buffer
.
length
,
byteBuffer
);
}
public
static
StreamFormatBox
getAacStreamFormat
()
throws
IOException
{
final
byte
[]
buffer
=
getBytes
(
"aac_stream_format.dump"
);
final
byte
[]
buffer
=
getBytes
(
"aac_stream_format.dump"
);
final
ByteBuffer
byteBuffer
=
ByteBuffer
.
wrap
(
buffer
);
final
ByteBuffer
byteBuffer
=
ByteBuffer
.
wrap
(
buffer
);
byteBuffer
.
order
(
ByteOrder
.
LITTLE_ENDIAN
);
byteBuffer
.
order
(
ByteOrder
.
LITTLE_ENDIAN
);
...
@@ -45,6 +54,26 @@ public class DataHelper {
...
@@ -45,6 +54,26 @@ public class DataHelper {
return
new
StreamFormatBox
(
StreamFormatBox
.
STRF
,
buffer
.
length
,
byteBuffer
);
return
new
StreamFormatBox
(
StreamFormatBox
.
STRF
,
buffer
.
length
,
byteBuffer
);
}
}
public
static
ListBox
getVideoStreamList
()
throws
IOException
{
final
StreamHeaderBox
streamHeaderBox
=
getVidsStreamHeader
();
final
StreamFormatBox
streamFormatBox
=
getVideoStreamFormat
();
final
ArrayList
<
Box
>
list
=
new
ArrayList
<>(
2
);
list
.
add
(
streamHeaderBox
);
list
.
add
(
streamFormatBox
);
return
new
ListBox
((
int
)(
streamHeaderBox
.
getSize
()
+
streamFormatBox
.
getSize
()),
AviExtractor
.
STRL
,
list
);
}
public
static
ListBox
getAacStreamList
()
throws
IOException
{
final
StreamHeaderBox
streamHeaderBox
=
getAudioStreamHeader
();
final
StreamFormatBox
streamFormatBox
=
getAacStreamFormat
();
final
ArrayList
<
Box
>
list
=
new
ArrayList
<>(
2
);
list
.
add
(
streamHeaderBox
);
list
.
add
(
streamFormatBox
);
return
new
ListBox
((
int
)(
streamHeaderBox
.
getSize
()
+
streamFormatBox
.
getSize
()),
AviExtractor
.
STRL
,
list
);
}
public
static
StreamNameBox
getStreamNameBox
(
final
String
name
)
{
public
static
StreamNameBox
getStreamNameBox
(
final
String
name
)
{
byte
[]
bytes
=
name
.
getBytes
();
byte
[]
bytes
=
name
.
getBytes
();
bytes
=
Arrays
.
copyOf
(
bytes
,
bytes
.
length
+
1
);
bytes
=
Arrays
.
copyOf
(
bytes
,
bytes
.
length
+
1
);
...
@@ -58,4 +87,18 @@ public class DataHelper {
...
@@ -58,4 +87,18 @@ public class DataHelper {
byteBuffer
.
put
(
nalType
);
byteBuffer
.
put
(
nalType
);
return
byteBuffer
;
return
byteBuffer
;
}
}
public
static
AviSeekMap
getAviSeekMap
()
throws
IOException
{
final
FakeTrackOutput
output
=
new
FakeTrackOutput
(
false
);
final
AviTrack
videoTrack
=
new
AviTrack
(
0
,
DataHelper
.
getVideoStreamFormat
().
getVideoFormat
(),
new
LinearClock
(
100
),
output
);
final
UnboundedIntArray
videoArray
=
new
UnboundedIntArray
();
videoArray
.
add
(
0
);
videoArray
.
add
(
1024
);
final
UnboundedIntArray
audioArray
=
new
UnboundedIntArray
();
audioArray
.
add
(
0
);
audioArray
.
add
(
128
);
return
new
AviSeekMap
(
videoTrack
,
new
UnboundedIntArray
[]{
videoArray
,
audioArray
},
24
,
0L
,
0L
);
}
}
}
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/LinearClockTest.java
0 → 100644
View file @
f1d007e6
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
avi
;
import
org.junit.Assert
;
import
org.junit.Test
;
/**
* Most of this is covered by the PicOrderClockTest
*/
public
class
LinearClockTest
{
@Test
public
void
advance
()
{
final
LinearClock
linearClock
=
new
LinearClock
(
100L
);
linearClock
.
setIndex
(
2
);
Assert
.
assertEquals
(
200
,
linearClock
.
getUs
());
linearClock
.
advance
();
Assert
.
assertEquals
(
300
,
linearClock
.
getUs
());
}
}
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/PicCountClockTest.java
0 → 100644
View file @
f1d007e6
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
avi
;
import
org.junit.Assert
;
import
org.junit.Test
;
public
class
PicCountClockTest
{
@Test
public
void
us_givenTwoStepsForward
()
{
final
PicCountClock
picCountClock
=
new
PicCountClock
(
100
);
picCountClock
.
setMaxPicCount
(
16
*
2
);
picCountClock
.
setPicCount
(
2
*
2
);
Assert
.
assertEquals
(
2
*
100
,
picCountClock
.
getUs
());
}
@Test
public
void
us_givenThreeStepsBackwards
()
{
final
PicCountClock
picCountClock
=
new
PicCountClock
(
100
);
picCountClock
.
setMaxPicCount
(
16
*
2
);
picCountClock
.
setPicCount
(
4
*
2
);
// 400ms
Assert
.
assertEquals
(
400
,
picCountClock
.
getUs
());
picCountClock
.
setPicCount
(
1
*
2
);
Assert
.
assertEquals
(
1
*
100
,
picCountClock
.
getUs
());
}
@Test
public
void
setIndex_given3Chunks
()
{
final
PicCountClock
picCountClock
=
new
PicCountClock
(
100
);
picCountClock
.
setIndex
(
3
);
Assert
.
assertEquals
(
3
*
100
,
picCountClock
.
getUs
());
}
@Test
public
void
us_giveWrapBackwards
()
{
final
PicCountClock
picCountClock
=
new
PicCountClock
(
100
);
picCountClock
.
setMaxPicCount
(
16
*
2
);
//Need to walk up no faster than maxPicCount / 2
picCountClock
.
setPicCount
(
7
*
2
);
picCountClock
.
setPicCount
(
11
*
2
);
picCountClock
.
setPicCount
(
15
*
2
);
picCountClock
.
setPicCount
(
1
*
2
);
Assert
.
assertEquals
(
17
*
100
,
picCountClock
.
getUs
());
picCountClock
.
setPicCount
(
14
*
2
);
Assert
.
assertEquals
(
14
*
100
,
picCountClock
.
getUs
());
}
}
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/StreamHeaderBoxTest.java
View file @
f1d007e6
...
@@ -19,11 +19,10 @@ public class StreamHeaderBoxTest {
...
@@ -19,11 +19,10 @@ public class StreamHeaderBoxTest {
Assert
.
assertTrue
(
streamHeaderBox
.
isVideo
());
Assert
.
assertTrue
(
streamHeaderBox
.
isVideo
());
Assert
.
assertFalse
(
streamHeaderBox
.
isAudio
());
Assert
.
assertFalse
(
streamHeaderBox
.
isAudio
());
Assert
.
assertEquals
(
StreamHeaderBox
.
VIDS
,
streamHeaderBox
.
getSteamType
());
Assert
.
assertEquals
(
StreamHeaderBox
.
VIDS
,
streamHeaderBox
.
getSteamType
());
Assert
.
assertEquals
(
StreamHeaderBox
.
XVID
,
streamHeaderBox
.
getFourCC
());
Assert
.
assertEquals
(
VideoFormat
.
XVID
,
streamHeaderBox
.
getFourCC
());
Assert
.
assertEquals
(
0
,
streamHeaderBox
.
getInitialFrames
());
Assert
.
assertEquals
(
0
,
streamHeaderBox
.
getInitialFrames
());
Assert
.
assertEquals
(
FPS24
,
streamHeaderBox
.
getFrameRate
(),
0.1
);
Assert
.
assertEquals
(
FPS24
,
streamHeaderBox
.
getFrameRate
(),
0.1
);
Assert
.
assertEquals
(
US_SAMPLE24FPS
,
streamHeaderBox
.
getUsPerSample
());
Assert
.
assertEquals
(
US_SAMPLE24FPS
,
streamHeaderBox
.
getUsPerSample
());
Assert
.
assertEquals
(
MimeTypes
.
VIDEO_MP4V
,
streamHeaderBox
.
getMimeType
());
Assert
.
assertEquals
(
11805L
,
streamHeaderBox
.
getLength
());
Assert
.
assertEquals
(
11805L
,
streamHeaderBox
.
getLength
());
Assert
.
assertEquals
(
0
,
streamHeaderBox
.
getSuggestedBufferSize
());
Assert
.
assertEquals
(
0
,
streamHeaderBox
.
getSuggestedBufferSize
());
}
}
...
...
testdata/src/test/assets/extractordumps/avi/auds_stream_header.dump
0 → 100644
View file @
f1d007e6
No preview for this file type
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