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
1a1dc44b
authored
Jan 18, 2022
by
Dustin
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
More efficient header parsing
parent
a9c94185
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
141 additions
and
63 deletions
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/AviExtractor.java
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/Box.java
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/BoxFactory.java
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/ListBox.java
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/ResidentBox.java
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/StreamDataBox.java
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/AviExtractor.java
View file @
1a1dc44b
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
avi
;
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
avi
;
import
android.util.SparseArray
;
import
android.util.SparseArray
;
import
android.util.SparseIntArray
;
import
androidx.annotation.NonNull
;
import
androidx.annotation.NonNull
;
import
androidx.annotation.Nullable
;
import
androidx.annotation.Nullable
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.C
;
...
@@ -17,12 +16,10 @@ import com.google.android.exoplayer2.util.MimeTypes;
...
@@ -17,12 +16,10 @@ import com.google.android.exoplayer2.util.MimeTypes;
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.Collections
;
import
java.util.Collections
;
import
java.util.HashMap
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Map
;
import
java.util.TreeMap
;
/**
/**
* Based on the official MicroSoft spec
* Based on the official MicroSoft spec
...
@@ -46,8 +43,6 @@ public class AviExtractor implements Extractor {
...
@@ -46,8 +43,6 @@ public class AviExtractor implements Extractor {
static
final
int
AVI_
=
AviUtil
.
toInt
(
new
byte
[]{
'A'
,
'V'
,
'I'
,
' '
});
static
final
int
AVI_
=
AviUtil
.
toInt
(
new
byte
[]{
'A'
,
'V'
,
'I'
,
' '
});
//Stream List
//Stream List
static
final
int
STRL
=
's'
|
(
't'
<<
8
)
|
(
'r'
<<
16
)
|
(
'l'
<<
24
);
static
final
int
STRL
=
's'
|
(
't'
<<
8
)
|
(
'r'
<<
16
)
|
(
'l'
<<
24
);
//Stream CODEC data
static
final
int
STRD
=
's'
|
(
't'
<<
8
)
|
(
'r'
<<
16
)
|
(
'd'
<<
24
);
//movie data box
//movie data box
static
final
int
MOVI
=
'm'
|
(
'o'
<<
8
)
|
(
'v'
<<
16
)
|
(
'i'
<<
24
);
static
final
int
MOVI
=
'm'
|
(
'o'
<<
8
)
|
(
'v'
<<
16
)
|
(
'i'
<<
24
);
//Index
//Index
...
@@ -144,20 +139,20 @@ public class AviExtractor implements Extractor {
...
@@ -144,20 +139,20 @@ public class AviExtractor implements Extractor {
if
(
inputLen
!=
C
.
LENGTH_UNSET
&&
inputLen
!=
reportedLen
)
{
if
(
inputLen
!=
C
.
LENGTH_UNSET
&&
inputLen
!=
reportedLen
)
{
Log
.
w
(
TAG
,
"Header length doesn't match stream length"
);
Log
.
w
(
TAG
,
"Header length doesn't match stream length"
);
}
}
int
avi
=
byteBuffer
.
getInt
();
final
int
avi
=
byteBuffer
.
getInt
();
if
(
avi
!=
AviExtractor
.
AVI_
)
{
if
(
avi
!=
AviExtractor
.
AVI_
)
{
return
null
;
return
null
;
}
}
final
ListBox
header
=
ListBox
.
getInstance
(
byteBuffer
,
input
,
ListBox
.
class
);
final
int
list
=
byteBuffer
.
getInt
(
);
if
(
header
==
null
)
{
if
(
list
!=
ListBox
.
LIST
)
{
return
null
;
return
null
;
}
}
if
(
header
.
getListType
()
!=
ListBox
.
TYPE_HDRL
)
{
final
int
listSize
=
byteBuffer
.
getInt
();
Log
.
e
(
TAG
,
"Expected "
+
AviUtil
.
toString
(
ListBox
.
TYPE_HDRL
)
+
", got: "
+
final
ListBox
listBox
=
ListBox
.
newInstance
(
listSize
,
new
BoxFactory
(),
input
);
AviUtil
.
toString
(
header
.
getType
()));
if
(
listBox
.
getListType
()
!=
ListBox
.
TYPE_HDRL
)
{
return
null
;
return
null
;
}
}
return
header
;
return
listBox
;
}
}
long
getDuration
()
{
long
getDuration
()
{
...
@@ -173,7 +168,7 @@ public class AviExtractor implements Extractor {
...
@@ -173,7 +168,7 @@ public class AviExtractor implements Extractor {
this
.
output
=
output
;
this
.
output
=
output
;
}
}
private
static
ResidentBox
peekNext
(
final
List
<
Resident
Box
>
streams
,
int
i
,
int
type
)
{
private
static
Box
peekNext
(
final
List
<
Box
>
streams
,
int
i
,
int
type
)
{
if
(
i
+
1
<
streams
.
size
()
&&
streams
.
get
(
i
+
1
).
getType
()
==
type
)
{
if
(
i
+
1
<
streams
.
size
()
&&
streams
.
get
(
i
+
1
).
getType
()
==
type
)
{
return
streams
.
get
(
i
+
1
);
return
streams
.
get
(
i
+
1
);
}
}
...
@@ -185,8 +180,7 @@ public class AviExtractor implements Extractor {
...
@@ -185,8 +180,7 @@ public class AviExtractor implements Extractor {
if
(
headerList
==
null
)
{
if
(
headerList
==
null
)
{
throw
new
IOException
(
"AVI Header List not found"
);
throw
new
IOException
(
"AVI Header List not found"
);
}
}
final
BoxFactory
boxFactory
=
new
BoxFactory
();
final
List
<
Box
>
headerChildren
=
headerList
.
getChildren
();
final
List
<
ResidentBox
>
headerChildren
=
headerList
.
getBoxList
(
boxFactory
);
aviHeader
=
AviUtil
.
getBox
(
headerChildren
,
AviHeaderBox
.
class
);
aviHeader
=
AviUtil
.
getBox
(
headerChildren
,
AviHeaderBox
.
class
);
if
(
aviHeader
==
null
)
{
if
(
aviHeader
==
null
)
{
throw
new
IOException
(
"AviHeader not found"
);
throw
new
IOException
(
"AviHeader not found"
);
...
@@ -198,9 +192,9 @@ public class AviExtractor implements Extractor {
...
@@ -198,9 +192,9 @@ public class AviExtractor implements Extractor {
for
(
Box
box
:
headerChildren
)
{
for
(
Box
box
:
headerChildren
)
{
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
;
final
List
<
ResidentBox
>
streamChildren
=
streamList
.
getBoxList
(
boxFactory
);
final
List
<
Box
>
streamChildren
=
streamList
.
getChildren
(
);
for
(
int
i
=
0
;
i
<
streamChildren
.
size
();
i
++)
{
for
(
int
i
=
0
;
i
<
streamChildren
.
size
();
i
++)
{
final
Resident
Box
residentBox
=
streamChildren
.
get
(
i
);
final
Box
residentBox
=
streamChildren
.
get
(
i
);
if
(
residentBox
instanceof
StreamHeaderBox
)
{
if
(
residentBox
instanceof
StreamHeaderBox
)
{
final
StreamHeaderBox
streamHeader
=
(
StreamHeaderBox
)
residentBox
;
final
StreamHeaderBox
streamHeader
=
(
StreamHeaderBox
)
residentBox
;
final
StreamFormatBox
streamFormat
=
(
StreamFormatBox
)
peekNext
(
streamChildren
,
i
,
StreamFormatBox
.
STRF
);
final
StreamFormatBox
streamFormat
=
(
StreamFormatBox
)
peekNext
(
streamChildren
,
i
,
StreamFormatBox
.
STRF
);
...
@@ -208,10 +202,10 @@ public class AviExtractor implements Extractor {
...
@@ -208,10 +202,10 @@ public class AviExtractor implements Extractor {
i
++;
i
++;
if
(
streamHeader
.
isVideo
())
{
if
(
streamHeader
.
isVideo
())
{
final
VideoFormat
videoFormat
=
streamFormat
.
getVideoFormat
();
final
VideoFormat
videoFormat
=
streamFormat
.
getVideoFormat
();
final
ResidentBox
codecBox
=
(
ResidentBox
)
peekNext
(
streamChildren
,
i
,
STRD
);
final
StreamDataBox
codecBox
=
(
StreamDataBox
)
peekNext
(
streamChildren
,
i
,
StreamDataBox
.
STRD
);
final
List
<
byte
[]>
codecData
;
final
List
<
byte
[]>
codecData
;
if
(
codecBox
!=
null
)
{
if
(
codecBox
!=
null
)
{
codecData
=
Collections
.
singletonList
(
codecBox
.
byteBuffer
.
array
());
codecData
=
Collections
.
singletonList
(
codecBox
.
getData
());
i
++;
i
++;
}
else
{
}
else
{
codecData
=
null
;
codecData
=
null
;
...
...
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/Box.java
View file @
1a1dc44b
...
@@ -4,15 +4,19 @@ package com.google.android.exoplayer2.extractor.avi;
...
@@ -4,15 +4,19 @@ package com.google.android.exoplayer2.extractor.avi;
* This is referred to as a Chunk in the MS spec, but that gets confusing with AV chunks
* This is referred to as a Chunk in the MS spec, but that gets confusing with AV chunks
*/
*/
public
class
Box
{
public
class
Box
{
private
final
long
size
;
private
final
int
size
;
private
final
int
type
;
private
final
int
type
;
Box
(
int
type
,
long
size
)
{
Box
(
int
type
,
int
size
)
{
this
.
type
=
type
;
this
.
type
=
type
;
this
.
size
=
size
;
this
.
size
=
size
;
}
}
public
long
getSize
()
{
public
long
getSize
()
{
return
size
&
AviUtil
.
UINT_MASK
;
}
public
int
getSizeInt
()
{
return
size
;
return
size
;
}
}
...
...
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/BoxFactory.java
View file @
1a1dc44b
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
avi
;
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
avi
;
import
androidx.annotation.NonNull
;
import
androidx.annotation.Nullable
;
import
com.google.android.exoplayer2.extractor.ExtractorInput
;
import
java.io.IOException
;
import
java.nio.ByteBuffer
;
import
java.nio.ByteBuffer
;
import
java.util.Arrays
;
public
class
BoxFactory
{
public
class
BoxFactory
{
@NonNull
static
int
[]
types
=
{
AviHeaderBox
.
AVIH
,
StreamHeaderBox
.
STRH
,
StreamFormatBox
.
STRF
,
StreamDataBox
.
STRD
};
static
{
Arrays
.
sort
(
types
);
}
public
boolean
isUnknown
(
final
int
type
)
{
return
Arrays
.
binarySearch
(
types
,
type
)
<
0
;
}
@Nullable
public
ResidentBox
createBox
(
final
int
type
,
final
int
size
,
final
ByteBuffer
byteBuffer
)
{
public
ResidentBox
createBox
(
final
int
type
,
final
int
size
,
final
ByteBuffer
byteBuffer
)
{
final
ByteBuffer
boxBuffer
=
AviExtractor
.
allocate
(
size
);
final
ByteBuffer
boxBuffer
=
AviExtractor
.
allocate
(
size
);
AviUtil
.
copy
(
byteBuffer
,
boxBuffer
,
size
);
AviUtil
.
copy
(
byteBuffer
,
boxBuffer
,
size
);
//TODO: Deal with list
switch
(
type
)
{
case
AviHeaderBox
.
AVIH
:
return
new
AviHeaderBox
(
type
,
size
,
boxBuffer
);
case
StreamHeaderBox
.
STRH
:
return
new
StreamHeaderBox
(
type
,
size
,
boxBuffer
);
case
StreamFormatBox
.
STRF
:
return
new
StreamFormatBox
(
type
,
size
,
boxBuffer
);
case
StreamDataBox
.
STRD
:
return
new
StreamDataBox
(
type
,
size
,
boxBuffer
);
default
:
return
null
;
}
}
private
ResidentBox
createBoxImpl
(
final
int
type
,
final
int
size
,
final
ByteBuffer
boxBuffer
)
{
switch
(
type
)
{
switch
(
type
)
{
case
AviHeaderBox
.
AVIH
:
case
AviHeaderBox
.
AVIH
:
return
new
AviHeaderBox
(
type
,
size
,
boxBuffer
);
return
new
AviHeaderBox
(
type
,
size
,
boxBuffer
);
case
ListBox
.
LIST
:
return
new
ListBox
(
type
,
size
,
boxBuffer
);
case
StreamHeaderBox
.
STRH
:
case
StreamHeaderBox
.
STRH
:
return
new
StreamHeaderBox
(
type
,
size
,
boxBuffer
);
return
new
StreamHeaderBox
(
type
,
size
,
boxBuffer
);
case
StreamFormatBox
.
STRF
:
case
StreamFormatBox
.
STRF
:
return
new
StreamFormatBox
(
type
,
size
,
boxBuffer
);
return
new
StreamFormatBox
(
type
,
size
,
boxBuffer
);
default
:
default
:
return
n
ew
ResidentBox
(
type
,
size
,
boxBuffer
)
;
return
n
ull
;
}
}
}
}
public
ResidentBox
createBox
(
final
int
type
,
final
int
size
,
ExtractorInput
input
)
throws
IOException
{
if
(
isUnknown
(
type
))
{
input
.
skipFully
(
size
);
return
null
;
}
final
ByteBuffer
boxBuffer
=
AviExtractor
.
allocate
(
size
);
input
.
readFully
(
boxBuffer
.
array
(),
0
,
size
);
return
createBoxImpl
(
type
,
size
,
boxBuffer
);
}
}
}
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/ListBox.java
View file @
1a1dc44b
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
java.io.IOException
;
import
java.nio.ByteBuffer
;
import
java.nio.ByteBuffer
;
import
java.util.ArrayList
;
import
java.util.List
;
/**
/**
* An AVI LIST box, memory resident
* An AVI LIST box, memory resident
*/
*/
public
class
ListBox
extends
Resident
Box
{
public
class
ListBox
extends
Box
{
public
static
final
int
LIST
=
'L'
|
(
'I'
<<
8
)
|
(
'S'
<<
16
)
|
(
'T'
<<
24
);
public
static
final
int
LIST
=
'L'
|
(
'I'
<<
8
)
|
(
'S'
<<
16
)
|
(
'T'
<<
24
);
//Header List
//Header List
public
static
final
int
TYPE_HDRL
=
'h'
|
(
'd'
<<
8
)
|
(
'r'
<<
16
)
|
(
'l'
<<
24
);
public
static
final
int
TYPE_HDRL
=
'h'
|
(
'd'
<<
8
)
|
(
'r'
<<
16
)
|
(
'l'
<<
24
);
private
final
int
listType
;
private
final
int
listType
;
ListBox
(
int
type
,
int
size
,
ByteBuffer
byteBuffer
)
{
final
List
<
Box
>
children
;
super
(
type
,
size
,
byteBuffer
);
listType
=
byteBuffer
.
getInt
(
0
);
ListBox
(
int
size
,
int
listType
,
List
<
Box
>
children
)
{
super
(
LIST
,
size
);
this
.
listType
=
listType
;
this
.
children
=
children
;
}
}
public
int
getListType
()
{
public
int
getListType
()
{
...
@@ -25,4 +33,56 @@ public class ListBox extends ResidentBox {
...
@@ -25,4 +33,56 @@ public class ListBox extends ResidentBox {
boolean
assertType
()
{
boolean
assertType
()
{
return
simpleAssert
(
LIST
);
return
simpleAssert
(
LIST
);
}
}
@NonNull
public
List
<
Box
>
getChildren
()
{
return
new
ArrayList
<>(
children
);
}
// static List<ResidentBox> realizeChildren(final ByteBuffer byteBuffer, final BoxFactory boxFactory) {
// final List<ResidentBox> list = new ArrayList<>();
// while (byteBuffer.hasRemaining()) {
// final int type = byteBuffer.getInt();
// final int size = byteBuffer.getInt();
// final ResidentBox residentBox = boxFactory.createBox(type, size, byteBuffer);
// list.add(residentBox);
// }
// return list;
// }
/**
* Assume the input is pointing to the list type
* @param boxFactory
* @param input
* @return
* @throws IOException
*/
public
static
ListBox
newInstance
(
final
int
listSize
,
BoxFactory
boxFactory
,
ExtractorInput
input
)
throws
IOException
{
final
List
<
Box
>
list
=
new
ArrayList
<>();
final
ByteBuffer
headerBuffer
=
AviExtractor
.
allocate
(
8
);
byte
[]
bytes
=
headerBuffer
.
array
();
input
.
readFully
(
bytes
,
0
,
4
);
final
int
listType
=
headerBuffer
.
getInt
();
long
endPos
=
input
.
getPosition
()
+
listSize
-
4
;
while
(
input
.
getPosition
()
+
8
<
endPos
)
{
headerBuffer
.
clear
();
input
.
readFully
(
bytes
,
0
,
8
);
final
int
type
=
headerBuffer
.
getInt
();
final
int
size
=
headerBuffer
.
getInt
();
final
Box
box
;
if
(
type
==
LIST
)
{
box
=
newInstance
(
size
,
boxFactory
,
input
);
}
else
{
box
=
boxFactory
.
createBox
(
type
,
size
,
input
);
}
if
(
box
!=
null
)
{
list
.
add
(
box
);
}
}
return
new
ListBox
(
listSize
,
listType
,
list
);
}
}
}
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/ResidentBox.java
View file @
1a1dc44b
...
@@ -10,32 +10,15 @@ import java.nio.BufferOverflowException;
...
@@ -10,32 +10,15 @@ import java.nio.BufferOverflowException;
import
java.nio.BufferUnderflowException
;
import
java.nio.BufferUnderflowException
;
import
java.nio.ByteBuffer
;
import
java.nio.ByteBuffer
;
import
java.nio.ByteOrder
;
import
java.nio.ByteOrder
;
import
java.util.ArrayList
;
import
java.util.List
;
/**
/**
* A box that is resident in memory
* A box that is resident in memory
*/
*/
public
class
ResidentBox
extends
Box
{
public
class
ResidentBox
extends
Box
{
private
static
final
String
TAG
=
AviExtractor
.
TAG
;
private
static
final
String
TAG
=
AviExtractor
.
TAG
;
final
private
static
int
MAX_RESIDENT
=
64
*
1024
;
final
private
static
int
MAX_RESIDENT
=
1024
;
final
ByteBuffer
byteBuffer
;
final
ByteBuffer
byteBuffer
;
// private Class<? extends ResidentBox> getClass(final int type) {
// switch (type) {
// case AviHeaderBox.AVIH:
// return AviHeaderBox.class;
// case ListBox.LIST:
// return ListBox.class;
// case StreamHeaderBox.STRH:
// return StreamHeaderBox.class;
// case StreamFormatBox.STRF:
// return StreamFormatBox.class;
// default:
// return ResidentBox.class;
// }
// }
ResidentBox
(
int
type
,
int
size
,
ByteBuffer
byteBuffer
)
{
ResidentBox
(
int
type
,
int
size
,
ByteBuffer
byteBuffer
)
{
super
(
type
,
size
);
super
(
type
,
size
);
this
.
byteBuffer
=
byteBuffer
;
this
.
byteBuffer
=
byteBuffer
;
...
@@ -81,7 +64,6 @@ public class ResidentBox extends Box {
...
@@ -81,7 +64,6 @@ public class ResidentBox extends Box {
}
}
}
}
/**
/**
* Returns shallow copy of this ByteBuffer with the position at 0
* Returns shallow copy of this ByteBuffer with the position at 0
* @return
* @return
...
@@ -93,18 +75,4 @@ public class ResidentBox extends Box {
...
@@ -93,18 +75,4 @@ public class ResidentBox extends Box {
clone
.
clear
();
clone
.
clear
();
return
clone
;
return
clone
;
}
}
@NonNull
public
List
<
ResidentBox
>
getBoxList
(
final
BoxFactory
boxFactory
)
{
final
ByteBuffer
temp
=
getByteBuffer
();
temp
.
position
(
4
);
final
List
<
ResidentBox
>
list
=
new
ArrayList
<>();
while
(
temp
.
hasRemaining
())
{
final
int
type
=
temp
.
getInt
();
final
int
size
=
temp
.
getInt
();
final
ResidentBox
residentBox
=
boxFactory
.
createBox
(
type
,
size
,
temp
);
list
.
add
(
residentBox
);
}
return
list
;
}
}
}
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/StreamDataBox.java
0 → 100644
View file @
1a1dc44b
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
avi
;
import
java.nio.ByteBuffer
;
public
class
StreamDataBox
extends
ResidentBox
{
//Stream CODEC data
static
final
int
STRD
=
's'
|
(
't'
<<
8
)
|
(
'r'
<<
16
)
|
(
'd'
<<
24
);
StreamDataBox
(
int
type
,
int
size
,
ByteBuffer
byteBuffer
)
{
super
(
type
,
size
,
byteBuffer
);
}
byte
[]
getData
()
{
byte
[]
data
=
new
byte
[
byteBuffer
.
capacity
()];
System
.
arraycopy
(
byteBuffer
.
array
(),
0
,
data
,
0
,
data
.
length
);
return
data
;
}
}
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