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
247b5769
authored
Feb 05, 2022
by
Dustin
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
MpegAudioChunkHandler cleanup and Tests
parent
3a9f1f9a
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
134 additions
and
13 deletions
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/MpegAudioChunkHandler.java
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/MpegAudioChunkHandlerTest.java
testdata/src/test/assets/extractordumps/avi/frame.mp3.dump
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/MpegAudioChunkHandler.java
View file @
247b5769
...
@@ -51,7 +51,12 @@ public class MpegAudioChunkHandler extends ChunkHandler {
...
@@ -51,7 +51,12 @@ public class MpegAudioChunkHandler extends ChunkHandler {
syncTime
();
syncTime
();
return
true
;
return
true
;
}
}
chunkRemaining
=
size
;
this
.
size
=
chunkRemaining
=
size
;
return
resume
(
input
);
}
@Override
boolean
resume
(
@NonNull
ExtractorInput
input
)
throws
IOException
{
if
(
process
(
input
))
{
if
(
process
(
input
))
{
// Fail Over: If the scratch is the entire chunk, we didn't find a MP3 header.
// Fail Over: If the scratch is the entire chunk, we didn't find a MP3 header.
// Dump the chunk as is and hope the decoder can handle it.
// Dump the chunk as is and hope the decoder can handle it.
...
@@ -59,17 +64,8 @@ public class MpegAudioChunkHandler extends ChunkHandler {
...
@@ -59,17 +64,8 @@ public class MpegAudioChunkHandler extends ChunkHandler {
scratch
.
setPosition
(
0
);
scratch
.
setPosition
(
0
);
trackOutput
.
sampleData
(
scratch
,
size
);
trackOutput
.
sampleData
(
scratch
,
size
);
scratch
.
reset
(
0
);
scratch
.
reset
(
0
);
done
(
size
);
}
}
clock
.
advance
();
return
true
;
}
return
false
;
}
@Override
boolean
resume
(
@NonNull
ExtractorInput
input
)
throws
IOException
{
if
(
process
(
input
))
{
clock
.
advance
();
return
true
;
return
true
;
}
}
return
false
;
return
false
;
...
@@ -101,7 +97,6 @@ public class MpegAudioChunkHandler extends ChunkHandler {
...
@@ -101,7 +97,6 @@ public class MpegAudioChunkHandler extends ChunkHandler {
scratch
.
ensureCapacity
(
scratch
.
limit
()
+
chunkRemaining
);
scratch
.
ensureCapacity
(
scratch
.
limit
()
+
chunkRemaining
);
int
toRead
=
4
;
int
toRead
=
4
;
while
(
chunkRemaining
>
0
&&
readScratch
(
input
,
toRead
)
!=
C
.
RESULT_END_OF_INPUT
)
{
while
(
chunkRemaining
>
0
&&
readScratch
(
input
,
toRead
)
!=
C
.
RESULT_END_OF_INPUT
)
{
readScratch
(
input
,
toRead
);
while
(
scratch
.
bytesLeft
()
>=
4
)
{
while
(
scratch
.
bytesLeft
()
>=
4
)
{
if
(
header
.
setForHeaderData
(
scratch
.
readInt
()))
{
if
(
header
.
setForHeaderData
(
scratch
.
readInt
()))
{
scratch
.
skipBytes
(-
4
);
scratch
.
skipBytes
(-
4
);
...
@@ -127,7 +122,7 @@ public class MpegAudioChunkHandler extends ChunkHandler {
...
@@ -127,7 +122,7 @@ public class MpegAudioChunkHandler extends ChunkHandler {
trackOutput
.
sampleData
(
scratch
,
scratchBytes
);
trackOutput
.
sampleData
(
scratch
,
scratchBytes
);
frameRemaining
=
header
.
frameSize
-
scratchBytes
;
frameRemaining
=
header
.
frameSize
-
scratchBytes
;
}
else
{
}
else
{
return
chunkRemaining
==
0
;
return
true
;
}
}
}
}
final
int
bytes
=
trackOutput
.
sampleData
(
input
,
Math
.
min
(
frameRemaining
,
chunkRemaining
),
false
);
final
int
bytes
=
trackOutput
.
sampleData
(
input
,
Math
.
min
(
frameRemaining
,
chunkRemaining
),
false
);
...
@@ -151,4 +146,14 @@ public class MpegAudioChunkHandler extends ChunkHandler {
...
@@ -151,4 +146,14 @@ public class MpegAudioChunkHandler extends ChunkHandler {
timeUs
=
clock
.
getUs
();
timeUs
=
clock
.
getUs
();
frameRemaining
=
0
;
frameRemaining
=
0
;
}
}
@VisibleForTesting
(
otherwise
=
VisibleForTesting
.
NONE
)
long
getTimeUs
()
{
return
timeUs
;
}
@VisibleForTesting
(
otherwise
=
VisibleForTesting
.
NONE
)
int
getFrameRemaining
()
{
return
frameRemaining
;
}
}
}
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/MpegAudioChunkHandlerTest.java
0 → 100644
View file @
247b5769
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
avi
;
import
android.content.Context
;
import
androidx.test.core.app.ApplicationProvider
;
import
androidx.test.ext.junit.runners.AndroidJUnit4
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.audio.MpegAudioUtil
;
import
com.google.android.exoplayer2.testutil.FakeExtractorInput
;
import
com.google.android.exoplayer2.testutil.FakeTrackOutput
;
import
com.google.android.exoplayer2.testutil.TestUtil
;
import
com.google.android.exoplayer2.util.MimeTypes
;
import
java.io.IOException
;
import
java.nio.ByteBuffer
;
import
org.junit.Assert
;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
@RunWith
(
AndroidJUnit4
.
class
)
public
class
MpegAudioChunkHandlerTest
{
private
static
final
int
FPS
=
24
;
private
Format
MP3_FORMAT
=
new
Format
.
Builder
().
setChannelCount
(
2
).
setSampleMimeType
(
MimeTypes
.
AUDIO_MPEG
).
setSampleRate
(
44100
).
build
();
private
static
final
long
CHUNK_MS
=
C
.
MICROS_PER_SECOND
/
FPS
;
private
final
MpegAudioUtil
.
Header
header
=
new
MpegAudioUtil
.
Header
();
private
FakeTrackOutput
fakeTrackOutput
;
private
MpegAudioChunkHandler
mpegAudioChunkHandler
;
private
byte
[]
mp3Frame
;
private
long
frameUs
;
@Before
public
void
before
()
throws
IOException
{
fakeTrackOutput
=
new
FakeTrackOutput
(
false
);
fakeTrackOutput
.
format
(
MP3_FORMAT
);
mpegAudioChunkHandler
=
new
MpegAudioChunkHandler
(
0
,
fakeTrackOutput
,
new
ChunkClock
(
C
.
MICROS_PER_SECOND
,
FPS
),
MP3_FORMAT
.
sampleRate
);
if
(
mp3Frame
==
null
)
{
final
Context
context
=
ApplicationProvider
.
getApplicationContext
();
mp3Frame
=
TestUtil
.
getByteArray
(
context
,
"extractordumps/avi/frame.mp3.dump"
);
header
.
setForHeaderData
(
ByteBuffer
.
wrap
(
mp3Frame
).
getInt
());
//About 26ms
frameUs
=
header
.
samplesPerFrame
*
C
.
MICROS_PER_SECOND
/
header
.
sampleRate
;
}
}
@Test
public
void
newChunk_givenNonMpegData
()
throws
IOException
{
final
FakeExtractorInput
input
=
new
FakeExtractorInput
.
Builder
().
setData
(
new
byte
[
1024
]).
build
();
mpegAudioChunkHandler
.
newChunk
((
int
)
input
.
getLength
(),
input
);
Assert
.
assertEquals
(
1024
,
fakeTrackOutput
.
getSampleData
(
0
).
length
);
Assert
.
assertEquals
(
CHUNK_MS
,
mpegAudioChunkHandler
.
getClock
().
getUs
());
}
@Test
public
void
newChunk_givenEmptyChunk
()
throws
IOException
{
final
FakeExtractorInput
input
=
new
FakeExtractorInput
.
Builder
().
setData
(
new
byte
[
0
]).
build
();
mpegAudioChunkHandler
.
newChunk
((
int
)
input
.
getLength
(),
input
);
Assert
.
assertEquals
(
C
.
MICROS_PER_SECOND
/
24
,
mpegAudioChunkHandler
.
getClock
().
getUs
());
}
@Test
public
void
setIndex_given12frames
()
{
mpegAudioChunkHandler
.
setIndex
(
12
);
Assert
.
assertEquals
(
500_000L
,
mpegAudioChunkHandler
.
getTimeUs
());
}
@Test
public
void
newChunk_givenSingleFrame
()
throws
IOException
{
final
FakeExtractorInput
input
=
new
FakeExtractorInput
.
Builder
().
setData
(
mp3Frame
).
build
();
mpegAudioChunkHandler
.
newChunk
(
mp3Frame
.
length
,
input
);
Assert
.
assertArrayEquals
(
mp3Frame
,
fakeTrackOutput
.
getSampleData
(
0
));
Assert
.
assertEquals
(
frameUs
,
mpegAudioChunkHandler
.
getTimeUs
());
}
@Test
public
void
newChunk_givenSeekAndFragmentedFrames
()
throws
IOException
{
ByteBuffer
byteBuffer
=
ByteBuffer
.
allocate
(
mp3Frame
.
length
*
2
);
byteBuffer
.
put
(
mp3Frame
,
mp3Frame
.
length
/
2
,
mp3Frame
.
length
/
2
);
byteBuffer
.
put
(
mp3Frame
);
final
int
remainder
=
byteBuffer
.
remaining
();
byteBuffer
.
put
(
mp3Frame
,
0
,
remainder
);
final
FakeExtractorInput
input
=
new
FakeExtractorInput
.
Builder
().
setData
(
byteBuffer
.
array
()).
build
();
mpegAudioChunkHandler
.
setIndex
(
1
);
//Seek
Assert
.
assertFalse
(
mpegAudioChunkHandler
.
newChunk
(
byteBuffer
.
capacity
(),
input
));
Assert
.
assertArrayEquals
(
mp3Frame
,
fakeTrackOutput
.
getSampleData
(
0
));
Assert
.
assertEquals
(
frameUs
+
CHUNK_MS
,
mpegAudioChunkHandler
.
getTimeUs
());
Assert
.
assertTrue
(
mpegAudioChunkHandler
.
resume
(
input
));
Assert
.
assertEquals
(
header
.
frameSize
-
remainder
,
mpegAudioChunkHandler
.
getFrameRemaining
());
}
@Test
public
void
newChunk_givenTwoFrames
()
throws
IOException
{
ByteBuffer
byteBuffer
=
ByteBuffer
.
allocate
(
mp3Frame
.
length
*
2
);
byteBuffer
.
put
(
mp3Frame
);
byteBuffer
.
put
(
mp3Frame
);
final
FakeExtractorInput
input
=
new
FakeExtractorInput
.
Builder
().
setData
(
byteBuffer
.
array
()).
build
();
Assert
.
assertFalse
(
mpegAudioChunkHandler
.
newChunk
(
byteBuffer
.
capacity
(),
input
));
Assert
.
assertEquals
(
1
,
fakeTrackOutput
.
getSampleCount
());
Assert
.
assertEquals
(
0L
,
fakeTrackOutput
.
getSampleTimeUs
(
0
));
Assert
.
assertTrue
(
mpegAudioChunkHandler
.
resume
(
input
));
Assert
.
assertEquals
(
2
,
fakeTrackOutput
.
getSampleCount
());
Assert
.
assertEquals
(
frameUs
,
fakeTrackOutput
.
getSampleTimeUs
(
1
));
}
}
testdata/src/test/assets/extractordumps/avi/frame.mp3.dump
0 → 100644
View file @
247b5769
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