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
43b8a9b3
authored
Jan 23, 2022
by
Dustin
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Add support for StreamName fixed issues with position alignment
parent
167c2f3f
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
162 additions
and
64 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/BoxFactory.java
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/StreamNameBox.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/ListBuilder.java
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/StreamNameBoxTest.java
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/AviExtractor.java
View file @
43b8a9b3
...
...
@@ -92,6 +92,13 @@ public class AviExtractor implements Extractor {
}
}
static
long
alignPosition
(
long
position
)
{
if
((
position
&
1
)
==
1
)
{
position
++;
}
return
position
;
}
public
AviExtractor
()
{
this
(
0
);
}
...
...
@@ -212,70 +219,73 @@ public class AviExtractor implements Extractor {
for
(
Box
box
:
headerList
.
getChildren
())
{
if
(
box
instanceof
ListBox
&&
((
ListBox
)
box
).
getListType
()
==
STRL
)
{
final
ListBox
streamList
=
(
ListBox
)
box
;
final
List
<
Box
>
streamChildren
=
streamList
.
getChildren
();
for
(
int
i
=
0
;
i
<
streamChildren
.
size
();
i
++)
{
final
Box
residentBox
=
streamChildren
.
get
(
i
);
if
(
residentBox
instanceof
StreamHeaderBox
)
{
final
StreamHeaderBox
streamHeader
=
(
StreamHeaderBox
)
residentBox
;
final
StreamFormatBox
streamFormat
=
(
StreamFormatBox
)
peekNext
(
streamChildren
,
i
,
StreamFormatBox
.
STRF
);
if
(
streamFormat
!=
null
)
{
i
++;
if
(
streamHeader
.
isVideo
())
{
final
String
mimeType
=
streamHeader
.
getMimeType
();
if
(
mimeType
==
null
)
{
Log
.
w
(
TAG
,
"Unknown FourCC: "
+
toString
(
streamHeader
.
getFourCC
()));
continue
;
}
final
VideoFormat
videoFormat
=
streamFormat
.
getVideoFormat
();
final
TrackOutput
trackOutput
=
output
.
track
(
streamId
,
C
.
TRACK_TYPE_VIDEO
);
final
Format
.
Builder
builder
=
new
Format
.
Builder
();
builder
.
setWidth
(
videoFormat
.
getWidth
());
builder
.
setHeight
(
videoFormat
.
getHeight
());
builder
.
setFrameRate
(
streamHeader
.
getFrameRate
());
builder
.
setSampleMimeType
(
mimeType
);
final
AviTrack
aviTrack
;
switch
(
mimeType
)
{
case
MimeTypes
.
VIDEO_MP4V
:
aviTrack
=
new
Mp4vAviTrack
(
streamId
,
streamHeader
,
trackOutput
,
builder
);
break
;
case
MimeTypes
.
VIDEO_H264
:
aviTrack
=
new
AvcAviTrack
(
streamId
,
streamHeader
,
trackOutput
,
builder
);
break
;
default
:
aviTrack
=
new
AviTrack
(
streamId
,
streamHeader
,
trackOutput
);
}
trackOutput
.
format
(
builder
.
build
());
idTrackMap
.
put
(
'0'
|
((
'0'
+
streamId
)
<<
8
)
|
(
'd'
<<
16
)
|
(
'c'
<<
24
),
aviTrack
);
durationUs
=
streamHeader
.
getUsPerSample
()
*
streamHeader
.
getLength
();
}
else
if
(
streamHeader
.
isAudio
())
{
final
AudioFormat
audioFormat
=
streamFormat
.
getAudioFormat
();
final
TrackOutput
trackOutput
=
output
.
track
(
streamId
,
C
.
TRACK_TYPE_AUDIO
);
final
Format
.
Builder
builder
=
new
Format
.
Builder
();
final
String
mimeType
=
audioFormat
.
getMimeType
();
builder
.
setSampleMimeType
(
mimeType
);
//builder.setCodecs(audioFormat.getCodec());
builder
.
setChannelCount
(
audioFormat
.
getChannels
());
builder
.
setSampleRate
(
audioFormat
.
getSamplesPerSecond
());
if
(
audioFormat
.
getFormatTag
()
==
AudioFormat
.
WAVE_FORMAT_PCM
)
{
final
short
bps
=
audioFormat
.
getBitsPerSample
();
if
(
bps
==
8
)
{
builder
.
setPcmEncoding
(
C
.
ENCODING_PCM_8BIT
);
}
else
if
(
bps
==
16
){
builder
.
setPcmEncoding
(
C
.
ENCODING_PCM_16BIT
);
}
}
if
(
MimeTypes
.
AUDIO_AAC
.
equals
(
mimeType
)
&&
audioFormat
.
getCbSize
()
>
0
)
{
builder
.
setInitializationData
(
Collections
.
singletonList
(
audioFormat
.
getCodecData
()));
}
trackOutput
.
format
(
builder
.
build
());
idTrackMap
.
put
(
'0'
|
((
'0'
+
streamId
)
<<
8
)
|
(
'w'
<<
16
)
|
(
'b'
<<
24
),
new
AviTrack
(
streamId
,
streamHeader
,
trackOutput
));
}
final
StreamHeaderBox
streamHeader
=
streamList
.
getChild
(
StreamHeaderBox
.
class
);
final
StreamFormatBox
streamFormat
=
streamList
.
getChild
(
StreamFormatBox
.
class
);
if
(
streamHeader
==
null
)
{
Log
.
w
(
TAG
,
"Missing Stream Header"
);
continue
;
}
if
(
streamFormat
==
null
)
{
Log
.
w
(
TAG
,
"Missing Stream Format"
);
continue
;
}
final
Format
.
Builder
builder
=
new
Format
.
Builder
();
builder
.
setId
(
streamId
);
final
StreamNameBox
streamName
=
streamList
.
getChild
(
StreamNameBox
.
class
);
if
(
streamName
!=
null
)
{
builder
.
setLabel
(
streamName
.
getName
());
}
if
(
streamHeader
.
isVideo
())
{
final
String
mimeType
=
streamHeader
.
getMimeType
();
if
(
mimeType
==
null
)
{
Log
.
w
(
TAG
,
"Unknown FourCC: "
+
toString
(
streamHeader
.
getFourCC
()));
continue
;
}
final
VideoFormat
videoFormat
=
streamFormat
.
getVideoFormat
();
final
TrackOutput
trackOutput
=
output
.
track
(
streamId
,
C
.
TRACK_TYPE_VIDEO
);
builder
.
setWidth
(
videoFormat
.
getWidth
());
builder
.
setHeight
(
videoFormat
.
getHeight
());
builder
.
setFrameRate
(
streamHeader
.
getFrameRate
());
builder
.
setSampleMimeType
(
mimeType
);
final
AviTrack
aviTrack
;
switch
(
mimeType
)
{
case
MimeTypes
.
VIDEO_MP4V
:
aviTrack
=
new
Mp4vAviTrack
(
streamId
,
streamHeader
,
trackOutput
,
builder
);
break
;
case
MimeTypes
.
VIDEO_H264
:
aviTrack
=
new
AvcAviTrack
(
streamId
,
streamHeader
,
trackOutput
,
builder
);
break
;
default
:
aviTrack
=
new
AviTrack
(
streamId
,
streamHeader
,
trackOutput
);
}
trackOutput
.
format
(
builder
.
build
());
idTrackMap
.
put
(
'0'
|
((
'0'
+
streamId
)
<<
8
)
|
(
'd'
<<
16
)
|
(
'c'
<<
24
),
aviTrack
);
durationUs
=
streamHeader
.
getUsPerSample
()
*
streamHeader
.
getLength
();
}
else
if
(
streamHeader
.
isAudio
())
{
final
AudioFormat
audioFormat
=
streamFormat
.
getAudioFormat
();
final
TrackOutput
trackOutput
=
output
.
track
(
streamId
,
C
.
TRACK_TYPE_AUDIO
);
final
String
mimeType
=
audioFormat
.
getMimeType
();
builder
.
setSampleMimeType
(
mimeType
);
//builder.setCodecs(audioFormat.getCodec());
builder
.
setChannelCount
(
audioFormat
.
getChannels
());
builder
.
setSampleRate
(
audioFormat
.
getSamplesPerSecond
());
if
(
audioFormat
.
getFormatTag
()
==
AudioFormat
.
WAVE_FORMAT_PCM
)
{
final
short
bps
=
audioFormat
.
getBitsPerSample
();
if
(
bps
==
8
)
{
builder
.
setPcmEncoding
(
C
.
ENCODING_PCM_8BIT
);
}
else
if
(
bps
==
16
){
builder
.
setPcmEncoding
(
C
.
ENCODING_PCM_16BIT
);
}
streamId
++;
}
if
(
MimeTypes
.
AUDIO_AAC
.
equals
(
mimeType
)
&&
audioFormat
.
getCbSize
()
>
0
)
{
builder
.
setInitializationData
(
Collections
.
singletonList
(
audioFormat
.
getCodecData
()));
}
trackOutput
.
format
(
builder
.
build
());
idTrackMap
.
put
(
'0'
|
((
'0'
+
streamId
)
<<
8
)
|
(
'w'
<<
16
)
|
(
'b'
<<
24
),
new
AviTrack
(
streamId
,
streamHeader
,
trackOutput
));
}
streamId
++;
}
}
output
.
endTracks
();
...
...
@@ -290,7 +300,7 @@ public class AviExtractor implements Extractor {
final
long
size
=
getUInt
(
byteBuffer
);
final
long
position
=
input
.
getPosition
();
//-4 because we over read for the LIST type
long
nextBox
=
position
+
size
-
4
;
long
nextBox
=
alignPosition
(
position
+
size
-
4
)
;
if
(
tag
==
ListBox
.
LIST
)
{
final
int
listType
=
byteBuffer
.
getInt
();
if
(
listType
==
MOVI
)
{
...
...
@@ -430,7 +440,7 @@ public class AviExtractor implements Extractor {
if
(
id
==
ListBox
.
LIST
)
{
seekPosition
.
position
=
input
.
getPosition
()
+
4
;
}
else
{
seekPosition
.
position
=
input
.
getPosition
()
+
size
;
seekPosition
.
position
=
alignPosition
(
input
.
getPosition
()
+
size
)
;
if
(
id
!=
JUNK
)
{
Log
.
w
(
TAG
,
"Unknown tag="
+
toString
(
id
)
+
" pos="
+
(
input
.
getPosition
()
-
8
)
+
" size="
+
size
+
" moviEnd="
+
moviEnd
);
...
...
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/BoxFactory.java
View file @
43b8a9b3
...
...
@@ -6,7 +6,7 @@ import java.nio.ByteBuffer;
import
java.util.Arrays
;
public
class
BoxFactory
{
static
int
[]
types
=
{
AviHeaderBox
.
AVIH
,
StreamHeaderBox
.
STRH
,
StreamFormatBox
.
STRF
};
static
int
[]
types
=
{
AviHeaderBox
.
AVIH
,
StreamHeaderBox
.
STRH
,
StreamFormatBox
.
STRF
,
StreamNameBox
.
STRN
};
static
{
Arrays
.
sort
(
types
);
}
...
...
@@ -23,6 +23,8 @@ public class BoxFactory {
return
new
StreamHeaderBox
(
type
,
size
,
boxBuffer
);
case
StreamFormatBox
.
STRF
:
return
new
StreamFormatBox
(
type
,
size
,
boxBuffer
);
case
StreamNameBox
.
STRN
:
return
new
StreamNameBox
(
type
,
size
,
boxBuffer
);
default
:
return
null
;
}
...
...
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/StreamNameBox.java
0 → 100644
View file @
43b8a9b3
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
avi
;
import
java.nio.ByteBuffer
;
public
class
StreamNameBox
extends
ResidentBox
{
public
static
final
int
STRN
=
's'
|
(
't'
<<
8
)
|
(
'r'
<<
16
)
|
(
'n'
<<
24
);
StreamNameBox
(
int
type
,
int
size
,
ByteBuffer
byteBuffer
)
{
super
(
type
,
size
,
byteBuffer
);
}
public
String
getName
()
{
int
len
=
byteBuffer
.
capacity
();
if
(
byteBuffer
.
get
(
len
-
1
)
==
0
)
{
len
-=
1
;
}
final
byte
[]
bytes
=
new
byte
[
len
];
byteBuffer
.
position
(
0
);
byteBuffer
.
get
(
bytes
);
return
new
String
(
bytes
);
}
}
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/DataHelper.java
View file @
43b8a9b3
...
...
@@ -6,6 +6,7 @@ import java.io.FileInputStream;
import
java.io.IOException
;
import
java.nio.ByteBuffer
;
import
java.nio.ByteOrder
;
import
java.util.Arrays
;
public
class
DataHelper
{
//Base path "\ExoPlayer\library\extractor\."
...
...
@@ -43,4 +44,10 @@ public class DataHelper {
byteBuffer
.
order
(
ByteOrder
.
LITTLE_ENDIAN
);
return
new
StreamFormatBox
(
StreamFormatBox
.
STRF
,
buffer
.
length
,
byteBuffer
);
}
public
static
StreamNameBox
getStreamNameBox
(
final
String
name
)
{
byte
[]
bytes
=
name
.
getBytes
();
bytes
=
Arrays
.
copyOf
(
bytes
,
bytes
.
length
+
1
);
return
new
StreamNameBox
(
StreamNameBox
.
STRN
,
bytes
.
length
,
ByteBuffer
.
wrap
(
bytes
));
}
}
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/ListBuilder.java
0 → 100644
View file @
43b8a9b3
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
avi
;
import
java.nio.ByteBuffer
;
public
class
ListBuilder
{
private
ByteBuffer
byteBuffer
;
public
ListBuilder
(
int
listType
)
{
byteBuffer
=
AviExtractor
.
allocate
(
12
);
byteBuffer
.
putInt
(
ListBox
.
LIST
);
byteBuffer
.
putInt
(
12
);
byteBuffer
.
putInt
(
listType
);
}
public
void
addBox
(
final
ResidentBox
box
)
{
long
boxLen
=
4
+
4
+
box
.
getSize
();
if
((
boxLen
&
1
)
==
1
)
{
boxLen
++;
}
final
ByteBuffer
boxBuffer
=
AviExtractor
.
allocate
(
byteBuffer
.
capacity
()
+
(
int
)
boxLen
);
byteBuffer
.
clear
();
boxBuffer
.
put
(
byteBuffer
);
boxBuffer
.
putInt
(
box
.
getType
());
boxBuffer
.
putInt
((
int
)
box
.
getSize
());
boxBuffer
.
put
(
box
.
getByteBuffer
());
byteBuffer
=
boxBuffer
;
}
public
ByteBuffer
build
()
{
byteBuffer
.
putInt
(
4
,
byteBuffer
.
capacity
()
-
8
);
return
byteBuffer
;
}
}
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/StreamNameBoxTest.java
0 → 100644
View file @
43b8a9b3
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
avi
;
import
com.google.android.exoplayer2.testutil.FakeExtractorInput
;
import
java.io.IOException
;
import
java.nio.ByteBuffer
;
import
org.junit.Assert
;
import
org.junit.Test
;
public
class
StreamNameBoxTest
{
@Test
public
void
createStreamName_givenList
()
throws
IOException
{
final
String
name
=
"Test"
;
final
ListBuilder
listBuilder
=
new
ListBuilder
(
AviExtractor
.
STRL
);
listBuilder
.
addBox
(
DataHelper
.
getStreamNameBox
(
name
));
final
ByteBuffer
listBuffer
=
listBuilder
.
build
();
final
FakeExtractorInput
fakeExtractorInput
=
new
FakeExtractorInput
.
Builder
().
setData
(
listBuffer
.
array
()).
build
();
fakeExtractorInput
.
skipFully
(
8
);
ListBox
listBox
=
ListBox
.
newInstance
(
listBuffer
.
capacity
()
-
8
,
new
BoxFactory
(),
fakeExtractorInput
);
Assert
.
assertEquals
(
1
,
listBox
.
getChildren
().
size
());
final
StreamNameBox
streamNameBox
=
(
StreamNameBox
)
listBox
.
getChildren
().
get
(
0
);
//Test + nullT = 5 bytes, so verify that the input is properly aligned
Assert
.
assertEquals
(
0
,
fakeExtractorInput
.
getPosition
()
&
1
);
Assert
.
assertEquals
(
name
,
streamNameBox
.
getName
());
}
}
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