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
f5025bfc
authored
Feb 13, 2020
by
kimvde
Committed by
Oliver Woodman
Feb 13, 2020
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Share seek tests between FLAC extractors
PiperOrigin-RevId: 294893303
parent
ebce903a
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
184 additions
and
286 deletions
extensions/flac/src/androidTest/java/com/google/android/exoplayer2/ext/flac/FlacBinarySearchSeekerTest.java
extensions/flac/src/androidTest/java/com/google/android/exoplayer2/ext/flac/FlacExtractorSeekTest.java
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/flac/FlacExtractorSeekTest.java
extensions/flac/src/androidTest/java/com/google/android/exoplayer2/ext/flac/FlacBinarySearchSeekerTest.java
deleted
100644 → 0
View file @
ebce903a
/*
* Copyright (C) 2018 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
.
ext
.
flac
;
import
static
com
.
google
.
common
.
truth
.
Truth
.
assertThat
;
import
static
org
.
junit
.
Assert
.
fail
;
import
androidx.test.core.app.ApplicationProvider
;
import
androidx.test.ext.junit.runners.AndroidJUnit4
;
import
com.google.android.exoplayer2.ext.flac.FlacBinarySearchSeeker.OutputFrameHolder
;
import
com.google.android.exoplayer2.extractor.SeekMap
;
import
com.google.android.exoplayer2.testutil.FakeExtractorInput
;
import
com.google.android.exoplayer2.testutil.TestUtil
;
import
java.io.IOException
;
import
java.nio.ByteBuffer
;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
/** Unit test for {@link FlacBinarySearchSeeker}. */
@RunWith
(
AndroidJUnit4
.
class
)
public
final
class
FlacBinarySearchSeekerTest
{
private
static
final
String
NOSEEKTABLE_FLAC
=
"flac/bear_one_metadata_block.flac"
;
private
static
final
int
DURATION_US
=
2_741_000
;
@Before
public
void
setUp
()
{
if
(!
FlacLibrary
.
isAvailable
())
{
fail
(
"Flac library not available."
);
}
}
@Test
public
void
testGetSeekMap_returnsSeekMapWithCorrectDuration
()
throws
IOException
,
FlacDecoderException
,
InterruptedException
{
byte
[]
data
=
TestUtil
.
getByteArray
(
ApplicationProvider
.
getApplicationContext
(),
NOSEEKTABLE_FLAC
);
FakeExtractorInput
input
=
new
FakeExtractorInput
.
Builder
().
setData
(
data
).
build
();
FlacDecoderJni
decoderJni
=
new
FlacDecoderJni
();
decoderJni
.
setData
(
input
);
OutputFrameHolder
outputFrameHolder
=
new
OutputFrameHolder
(
ByteBuffer
.
allocateDirect
(
0
));
FlacBinarySearchSeeker
seeker
=
new
FlacBinarySearchSeeker
(
decoderJni
.
decodeStreamMetadata
(),
/* firstFramePosition= */
0
,
data
.
length
,
decoderJni
,
outputFrameHolder
);
SeekMap
seekMap
=
seeker
.
getSeekMap
();
assertThat
(
seekMap
).
isNotNull
();
assertThat
(
seekMap
.
getDurationUs
()).
isEqualTo
(
DURATION_US
);
assertThat
(
seekMap
.
isSeekable
()).
isTrue
();
}
@Test
public
void
testSetSeekTargetUs_returnsSeekPending
()
throws
IOException
,
FlacDecoderException
,
InterruptedException
{
byte
[]
data
=
TestUtil
.
getByteArray
(
ApplicationProvider
.
getApplicationContext
(),
NOSEEKTABLE_FLAC
);
FakeExtractorInput
input
=
new
FakeExtractorInput
.
Builder
().
setData
(
data
).
build
();
FlacDecoderJni
decoderJni
=
new
FlacDecoderJni
();
decoderJni
.
setData
(
input
);
OutputFrameHolder
outputFrameHolder
=
new
OutputFrameHolder
(
ByteBuffer
.
allocateDirect
(
0
));
FlacBinarySearchSeeker
seeker
=
new
FlacBinarySearchSeeker
(
decoderJni
.
decodeStreamMetadata
(),
/* firstFramePosition= */
0
,
data
.
length
,
decoderJni
,
outputFrameHolder
);
seeker
.
setSeekTargetUs
(
/* timeUs= */
1000
);
assertThat
(
seeker
.
isSeeking
()).
isTrue
();
}
}
extensions/flac/src/androidTest/java/com/google/android/exoplayer2/ext/flac/FlacExtractorSeekTest.java
View file @
f5025bfc
...
@@ -16,73 +16,44 @@
...
@@ -16,73 +16,44 @@
package
com
.
google
.
android
.
exoplayer2
.
ext
.
flac
;
package
com
.
google
.
android
.
exoplayer2
.
ext
.
flac
;
import
static
com
.
google
.
common
.
truth
.
Truth
.
assertThat
;
import
static
com
.
google
.
common
.
truth
.
Truth
.
assertThat
;
import
static
org
.
junit
.
Assert
.
fail
;
import
android.content.Context
;
import
android.net.Uri
;
import
android.net.Uri
;
import
androidx.annotation.Nullable
;
import
androidx.test.core.app.ApplicationProvider
;
import
androidx.test.core.app.ApplicationProvider
;
import
androidx.test.ext.junit.runners.AndroidJUnit4
;
import
androidx.test.ext.junit.runners.AndroidJUnit4
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.extractor.DefaultExtractorInput
;
import
com.google.android.exoplayer2.extractor.Extractor
;
import
com.google.android.exoplayer2.extractor.ExtractorInput
;
import
com.google.android.exoplayer2.extractor.PositionHolder
;
import
com.google.android.exoplayer2.extractor.SeekMap
;
import
com.google.android.exoplayer2.extractor.SeekMap
;
import
com.google.android.exoplayer2.testutil.FakeExtractorInput
;
import
com.google.android.exoplayer2.testutil.FakeExtractorOutput
;
import
com.google.android.exoplayer2.testutil.FakeExtractorOutput
;
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
com.google.android.exoplayer2.upstream.DataSpec
;
import
com.google.android.exoplayer2.upstream.DefaultDataSource
;
import
com.google.android.exoplayer2.upstream.DefaultDataSource
;
import
com.google.android.exoplayer2.upstream.DefaultDataSourceFactory
;
import
com.google.android.exoplayer2.upstream.DefaultDataSourceFactory
;
import
com.google.android.exoplayer2.util.Util
;
import
com.google.android.exoplayer2.util.Util
;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.util.List
;
import
java.util.List
;
import
java.util.Random
;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.junit.runner.RunWith
;
/** Seeking tests for {@link FlacExtractor}
when the FLAC stream does not have a SEEKTABLE
. */
/** Seeking tests for {@link FlacExtractor}. */
@RunWith
(
AndroidJUnit4
.
class
)
@RunWith
(
AndroidJUnit4
.
class
)
public
final
class
FlacExtractorSeekTest
{
public
final
class
FlacExtractorSeekTest
{
private
static
final
String
NO_SEEKTABLE_FLAC
=
"flac/bear_one_metadata_block.flac"
;
private
static
final
String
TEST_FILE_SEEK_TABLE
=
"flac/bear.flac"
;
private
static
final
String
TEST_FILE_BINARY_SEARCH
=
"flac/bear_one_metadata_block.flac"
;
private
static
final
String
TEST_FILE_UNSEEKABLE
=
"flac/bear_no_seek_table_no_num_samples.flac"
;
private
static
final
int
DURATION_US
=
2_741_000
;
private
static
final
int
DURATION_US
=
2_741_000
;
private
static
final
Uri
FILE_URI
=
Uri
.
parse
(
"file:///android_asset/"
+
NO_SEEKTABLE_FLAC
);
private
static
final
Random
RANDOM
=
new
Random
(
1234L
);
private
FakeExtractorOutput
expectedOutput
;
private
FlacExtractor
extractor
=
new
FlacExtractor
();
private
FakeTrackOutput
expectedTrackOutput
;
private
FakeExtractorOutput
extractorOutput
=
new
FakeExtractorOutput
();
private
DefaultDataSource
dataSource
=
private
DefaultDataSource
dataSource
;
private
PositionHolder
positionHolder
;
private
long
totalInputLength
;
@Before
public
void
setUp
()
throws
Exception
{
if
(!
FlacLibrary
.
isAvailable
())
{
fail
(
"Flac library not available."
);
}
expectedOutput
=
new
FakeExtractorOutput
();
extractAllSamplesFromFileToExpectedOutput
(
ApplicationProvider
.
getApplicationContext
(),
NO_SEEKTABLE_FLAC
);
expectedTrackOutput
=
expectedOutput
.
trackOutputs
.
get
(
0
);
dataSource
=
new
DefaultDataSourceFactory
(
ApplicationProvider
.
getApplicationContext
(),
"UserAgent"
)
new
DefaultDataSourceFactory
(
ApplicationProvider
.
getApplicationContext
(),
"UserAgent"
)
.
createDataSource
();
.
createDataSource
();
totalInputLength
=
readInputLength
();
positionHolder
=
new
PositionHolder
();
}
@Test
@Test
public
void
testFlacExtractorReads_nonSeekTableFi
le_returnSeekableSeekMap
()
public
void
flacExtractorReads_seekTab
le_returnSeekableSeekMap
()
throws
IOException
,
InterruptedException
{
throws
IOException
,
InterruptedException
{
FlacExtractor
extractor
=
new
FlacExtractor
(
);
Uri
fileUri
=
TestUtil
.
buildAssetUri
(
TEST_FILE_SEEK_TABLE
);
SeekMap
seekMap
=
extractSeekMap
(
extractor
,
new
FakeExtractorOutput
()
);
SeekMap
seekMap
=
TestUtil
.
extractSeekMap
(
extractor
,
extractorOutput
,
dataSource
,
fileUri
);
assertThat
(
seekMap
).
isNotNull
();
assertThat
(
seekMap
).
isNotNull
();
assertThat
(
seekMap
.
getDurationUs
()).
isEqualTo
(
DURATION_US
);
assertThat
(
seekMap
.
getDurationUs
()).
isEqualTo
(
DURATION_US
);
...
@@ -90,205 +61,232 @@ public final class FlacExtractorSeekTest {
...
@@ -90,205 +61,232 @@ public final class FlacExtractorSeekTest {
}
}
@Test
@Test
public
void
testHandlePendingSeek_handlesSeekingToPositionInFile_extractsCorrectFrame
()
public
void
seeking_seekTable_handlesSeekToZero
()
throws
IOException
,
InterruptedException
{
throws
IOException
,
InterruptedException
{
String
fileName
=
TEST_FILE_SEEK_TABLE
;
FlacExtractor
extractor
=
new
FlacExtractor
();
Uri
fileUri
=
TestUtil
.
buildAssetUri
(
fileName
);
SeekMap
seekMap
=
TestUtil
.
extractSeekMap
(
extractor
,
extractorOutput
,
dataSource
,
fileUri
);
FakeExtractorOutput
extractorOutput
=
new
FakeExtractorOutput
();
SeekMap
seekMap
=
extractSeekMap
(
extractor
,
extractorOutput
);
FakeTrackOutput
trackOutput
=
extractorOutput
.
trackOutputs
.
get
(
0
);
FakeTrackOutput
trackOutput
=
extractorOutput
.
trackOutputs
.
get
(
0
);
long
targetSeekTimeUs
=
987_000
;
long
targetSeekTimeUs
=
0
;
int
extractedFrameIndex
=
seekToTimeUs
(
extractor
,
seekMap
,
targetSeekTimeUs
,
trackOutput
);
int
extractedFrameIndex
=
TestUtil
.
seekToTimeUs
(
extractor
,
seekMap
,
targetSeekTimeUs
,
dataSource
,
trackOutput
,
fileUri
);
assertThat
(
extractedFrameIndex
).
isNotEqualTo
(
-
1
);
assertThat
(
extractedFrameIndex
).
isNotEqualTo
(
C
.
INDEX_UNSET
);
assertFirstFrameAfterSeek
Contain
TargetSeekTime
(
assertFirstFrameAfterSeek
Precedes
TargetSeekTime
(
trackOutput
,
targetSeekTimeUs
,
extractedFrameIndex
);
fileName
,
trackOutput
,
targetSeekTimeUs
,
extractedFrameIndex
);
}
}
@Test
@Test
public
void
testHandlePendingSeek_handlesSeekToEoF_extractsLastFrame
()
public
void
seeking_seekTable_handlesSeekToEoF
()
throws
IOException
,
InterruptedException
{
throws
IOException
,
InterruptedException
{
String
fileName
=
TEST_FILE_SEEK_TABLE
;
FlacExtractor
extractor
=
new
FlacExtractor
();
Uri
fileUri
=
TestUtil
.
buildAssetUri
(
fileName
);
SeekMap
seekMap
=
TestUtil
.
extractSeekMap
(
extractor
,
extractorOutput
,
dataSource
,
fileUri
);
FakeExtractorOutput
extractorOutput
=
new
FakeExtractorOutput
();
SeekMap
seekMap
=
extractSeekMap
(
extractor
,
extractorOutput
);
FakeTrackOutput
trackOutput
=
extractorOutput
.
trackOutputs
.
get
(
0
);
FakeTrackOutput
trackOutput
=
extractorOutput
.
trackOutputs
.
get
(
0
);
long
targetSeekTimeUs
=
seekMap
.
getDurationUs
();
long
targetSeekTimeUs
=
seekMap
.
getDurationUs
();
int
extractedFrameIndex
=
TestUtil
.
seekToTimeUs
(
extractor
,
seekMap
,
targetSeekTimeUs
,
dataSource
,
trackOutput
,
fileUri
);
int
extractedFrameIndex
=
seekToTimeUs
(
extractor
,
seekMap
,
targetSeekTimeUs
,
trackOutput
);
assertThat
(
extractedFrameIndex
).
isNotEqualTo
(
C
.
INDEX_UNSET
);
assertFirstFrameAfterSeekPrecedesTargetSeekTime
(
assertThat
(
extractedFrameIndex
).
isNotEqualTo
(-
1
);
fileName
,
trackOutput
,
targetSeekTimeUs
,
extractedFrameIndex
);
assertFirstFrameAfterSeekContainTargetSeekTime
(
trackOutput
,
targetSeekTimeUs
,
extractedFrameIndex
);
}
}
@Test
@Test
public
void
testHandlePendingSeek_handlesSeekingBackward_extractsCorrectFrame
()
public
void
seeking_seekTable_handlesSeekingBackward
()
throws
IOException
,
InterruptedException
{
throws
IOException
,
InterruptedException
{
String
fileName
=
TEST_FILE_SEEK_TABLE
;
FlacExtractor
extractor
=
new
FlacExtractor
();
Uri
fileUri
=
TestUtil
.
buildAssetUri
(
fileName
);
SeekMap
seekMap
=
TestUtil
.
extractSeekMap
(
extractor
,
extractorOutput
,
dataSource
,
fileUri
);
FakeExtractorOutput
extractorOutput
=
new
FakeExtractorOutput
();
SeekMap
seekMap
=
extractSeekMap
(
extractor
,
extractorOutput
);
FakeTrackOutput
trackOutput
=
extractorOutput
.
trackOutputs
.
get
(
0
);
FakeTrackOutput
trackOutput
=
extractorOutput
.
trackOutputs
.
get
(
0
);
long
firstSeekTimeUs
=
987_000
;
long
firstSeekTimeUs
=
1_234_000
;
seekToTimeUs
(
extractor
,
seekMap
,
firstSeekTimeUs
,
trackOutput
);
TestUtil
.
seekToTimeUs
(
extractor
,
seekMap
,
firstSeekTimeUs
,
dataSource
,
trackOutput
,
fileUri
);
long
targetSeekTimeUs
=
987_000
;
long
targetSeekTimeUs
=
0
;
int
extractedFrameIndex
=
int
extractedFrameIndex
=
seekToTimeUs
(
extractor
,
seekMap
,
targetSeekTimeUs
,
trackOutput
);
TestUtil
.
seekToTimeUs
(
extractor
,
seekMap
,
targetSeekTimeUs
,
dataSource
,
trackOutput
,
fileUri
);
assertThat
(
extractedFrameIndex
).
isNotEqualTo
(
-
1
);
assertThat
(
extractedFrameIndex
).
isNotEqualTo
(
C
.
INDEX_UNSET
);
assertFirstFrameAfterSeek
Contain
TargetSeekTime
(
assertFirstFrameAfterSeek
Precedes
TargetSeekTime
(
trackOutput
,
targetSeekTimeUs
,
extractedFrameIndex
);
fileName
,
trackOutput
,
targetSeekTimeUs
,
extractedFrameIndex
);
}
}
@Test
@Test
public
void
testHandlePendingSeek_handlesSeekingForward_extractsCorrectFrame
()
public
void
seeking_seekTable_handlesSeekingForward
()
throws
IOException
,
InterruptedException
{
throws
IOException
,
InterruptedException
{
String
fileName
=
TEST_FILE_SEEK_TABLE
;
FlacExtractor
extractor
=
new
FlacExtractor
();
Uri
fileUri
=
TestUtil
.
buildAssetUri
(
fileName
);
SeekMap
seekMap
=
TestUtil
.
extractSeekMap
(
extractor
,
extractorOutput
,
dataSource
,
fileUri
);
FakeExtractorOutput
extractorOutput
=
new
FakeExtractorOutput
();
SeekMap
seekMap
=
extractSeekMap
(
extractor
,
extractorOutput
);
FakeTrackOutput
trackOutput
=
extractorOutput
.
trackOutputs
.
get
(
0
);
FakeTrackOutput
trackOutput
=
extractorOutput
.
trackOutputs
.
get
(
0
);
long
firstSeekTimeUs
=
987_000
;
long
firstSeekTimeUs
=
987_000
;
seekToTimeUs
(
extractor
,
seekMap
,
firstSeekTimeUs
,
trackOutput
);
TestUtil
.
seekToTimeUs
(
extractor
,
seekMap
,
firstSeekTimeUs
,
dataSource
,
trackOutput
,
fileUri
);
long
targetSeekTimeUs
=
1_234_000
;
long
targetSeekTimeUs
=
1_234_000
;
int
extractedFrameIndex
=
seekToTimeUs
(
extractor
,
seekMap
,
targetSeekTimeUs
,
trackOutput
);
int
extractedFrameIndex
=
TestUtil
.
seekToTimeUs
(
extractor
,
seekMap
,
targetSeekTimeUs
,
dataSource
,
trackOutput
,
fileUri
);
assertThat
(
extractedFrameIndex
).
isNotEqualTo
(
-
1
);
assertThat
(
extractedFrameIndex
).
isNotEqualTo
(
C
.
INDEX_UNSET
);
assertFirstFrameAfterSeek
Contain
TargetSeekTime
(
assertFirstFrameAfterSeek
Precedes
TargetSeekTime
(
trackOutput
,
targetSeekTimeUs
,
extractedFrameIndex
);
fileName
,
trackOutput
,
targetSeekTimeUs
,
extractedFrameIndex
);
}
}
@Test
@Test
public
void
testHandlePendingSeek_handlesRandomSeeks_extractsCorrectFrame
()
public
void
flacExtractorReads_binarySearch_returnSeekableSeekMap
()
throws
IOException
,
InterruptedException
{
throws
IOException
,
InterruptedException
{
FlacExtractor
extractor
=
new
FlacExtractor
();
Uri
fileUri
=
TestUtil
.
buildAssetUri
(
TEST_FILE_BINARY_SEARCH
);
SeekMap
seekMap
=
TestUtil
.
extractSeekMap
(
extractor
,
extractorOutput
,
dataSource
,
fileUri
);
assertThat
(
seekMap
).
isNotNull
();
assertThat
(
seekMap
.
getDurationUs
()).
isEqualTo
(
DURATION_US
);
assertThat
(
seekMap
.
isSeekable
()).
isTrue
();
}
FakeExtractorOutput
extractorOutput
=
new
FakeExtractorOutput
();
@Test
SeekMap
seekMap
=
extractSeekMap
(
extractor
,
extractorOutput
);
public
void
seeking_binarySearch_handlesSeekToZero
()
throws
IOException
,
InterruptedException
{
String
fileName
=
TEST_FILE_BINARY_SEARCH
;
Uri
fileUri
=
TestUtil
.
buildAssetUri
(
fileName
);
SeekMap
seekMap
=
TestUtil
.
extractSeekMap
(
extractor
,
extractorOutput
,
dataSource
,
fileUri
);
FakeTrackOutput
trackOutput
=
extractorOutput
.
trackOutputs
.
get
(
0
);
FakeTrackOutput
trackOutput
=
extractorOutput
.
trackOutputs
.
get
(
0
);
long
numSeek
=
10
0
;
long
targetSeekTimeUs
=
0
;
for
(
long
i
=
0
;
i
<
numSeek
;
i
++)
{
int
extractedFrameIndex
=
long
targetSeekTimeUs
=
RANDOM
.
nextInt
(
DURATION_US
+
1
);
TestUtil
.
seekToTimeUs
(
int
extractedFrameIndex
=
seekToTimeUs
(
extractor
,
seekMap
,
targetSeekTimeUs
,
trackOutput
);
extractor
,
seekMap
,
targetSeekTimeUs
,
dataSource
,
trackOutput
,
fileUri
);
assertThat
(
extractedFrameIndex
).
isNotEqualTo
(-
1
);
assertThat
(
extractedFrameIndex
).
isNotEqualTo
(
C
.
INDEX_UNSET
);
assertFirstFrameAfterSeekContainTargetSeekTime
(
assertFirstFrameAfterSeekContainsTargetSeekTime
(
trackOutput
,
targetSeekTimeUs
,
extractedFrameIndex
);
fileName
,
trackOutput
,
targetSeekTimeUs
,
extractedFrameIndex
);
}
}
}
// Internal methods
@Test
public
void
seeking_binarySearch_handlesSeekToEoF
()
throws
IOException
,
InterruptedException
{
String
fileName
=
TEST_FILE_BINARY_SEARCH
;
Uri
fileUri
=
TestUtil
.
buildAssetUri
(
fileName
);
SeekMap
seekMap
=
TestUtil
.
extractSeekMap
(
extractor
,
extractorOutput
,
dataSource
,
fileUri
);
FakeTrackOutput
trackOutput
=
extractorOutput
.
trackOutputs
.
get
(
0
);
long
targetSeekTimeUs
=
seekMap
.
getDurationUs
();
int
extractedFrameIndex
=
TestUtil
.
seekToTimeUs
(
extractor
,
seekMap
,
targetSeekTimeUs
,
dataSource
,
trackOutput
,
fileUri
);
private
long
readInputLength
()
throws
IOException
{
assertThat
(
extractedFrameIndex
).
isNotEqualTo
(
C
.
INDEX_UNSET
);
DataSpec
dataSpec
=
new
DataSpec
(
FILE_URI
,
/* position= */
0
,
C
.
LENGTH_UNSET
);
assertFirstFrameAfterSeekContainsTargetSeekTime
(
long
totalInputLength
=
dataSource
.
open
(
dataSpec
);
fileName
,
trackOutput
,
targetSeekTimeUs
,
extractedFrameIndex
);
Util
.
closeQuietly
(
dataSource
);
return
totalInputLength
;
}
}
/**
@Test
* Seeks to the given seek time and keeps reading from input until we can extract at least one
public
void
seeking_binarySearch_handlesSeekingBackward
()
* frame from the seek position, or until end-of-input is reached.
*
* @return The index of the first extracted frame written to the given {@code trackOutput} after
* the seek is completed, or -1 if the seek is completed without any extracted frame.
*/
private
int
seekToTimeUs
(
FlacExtractor
flacExtractor
,
SeekMap
seekMap
,
long
seekTimeUs
,
FakeTrackOutput
trackOutput
)
throws
IOException
,
InterruptedException
{
throws
IOException
,
InterruptedException
{
int
numSampleBeforeSeek
=
trackOutput
.
getSampleCount
();
String
fileName
=
TEST_FILE_BINARY_SEARCH
;
SeekMap
.
SeekPoints
seekPoints
=
seekMap
.
getSeekPoints
(
seekTimeUs
);
Uri
fileUri
=
TestUtil
.
buildAssetUri
(
fileName
);
SeekMap
seekMap
=
TestUtil
.
extractSeekMap
(
extractor
,
extractorOutput
,
dataSource
,
fileUri
);
long
initialSeekLoadPosition
=
seekPoints
.
first
.
position
;
FakeTrackOutput
trackOutput
=
extractorOutput
.
trackOutputs
.
get
(
0
);
flacExtractor
.
seek
(
initialSeekLoadPosition
,
seekTimeUs
);
positionHolder
.
position
=
C
.
POSITION_UNSET
;
ExtractorInput
extractorInput
=
getExtractorInputFromPosition
(
initialSeekLoadPosition
);
int
extractorReadResult
=
Extractor
.
RESULT_CONTINUE
;
while
(
true
)
{
try
{
// Keep reading until we can read at least one frame after seek
while
(
extractorReadResult
==
Extractor
.
RESULT_CONTINUE
&&
trackOutput
.
getSampleCount
()
==
numSampleBeforeSeek
)
{
extractorReadResult
=
flacExtractor
.
read
(
extractorInput
,
positionHolder
);
}
}
finally
{
Util
.
closeQuietly
(
dataSource
);
}
if
(
extractorReadResult
==
Extractor
.
RESULT_SEEK
)
{
long
firstSeekTimeUs
=
1_234_000
;
extractorInput
=
getExtractorInputFromPosition
(
positionHolder
.
position
);
TestUtil
.
seekToTimeUs
(
extractor
,
seekMap
,
firstSeekTimeUs
,
dataSource
,
trackOutput
,
fileUri
);
extractorReadResult
=
Extractor
.
RESULT_CONTINUE
;
long
targetSeekTimeUs
=
987_00
;
}
else
if
(
extractorReadResult
==
Extractor
.
RESULT_END_OF_INPUT
)
{
int
extractedFrameIndex
=
return
-
1
;
TestUtil
.
seekToTimeUs
(
}
else
if
(
trackOutput
.
getSampleCount
()
>
numSampleBeforeSeek
)
{
extractor
,
seekMap
,
targetSeekTimeUs
,
dataSource
,
trackOutput
,
fileUri
);
// First index after seek = num sample before seek.
return
numSampleBeforeSeek
;
assertThat
(
extractedFrameIndex
).
isNotEqualTo
(
C
.
INDEX_UNSET
)
;
}
assertFirstFrameAfterSeekContainsTargetSeekTime
(
}
fileName
,
trackOutput
,
targetSeekTimeUs
,
extractedFrameIndex
);
}
}
@
Nullable
@
Test
p
rivate
SeekMap
extractSeekMap
(
FlacExtractor
extractor
,
FakeExtractorOutput
output
)
p
ublic
void
seeking_binarySearch_handlesSeekingForward
(
)
throws
IOException
,
InterruptedException
{
throws
IOException
,
InterruptedException
{
try
{
String
fileName
=
TEST_FILE_BINARY_SEARCH
;
ExtractorInput
input
=
getExtractorInputFromPosition
(
0
);
Uri
fileUri
=
TestUtil
.
buildAssetUri
(
fileName
);
extractor
.
init
(
output
);
SeekMap
seekMap
=
TestUtil
.
extractSeekMap
(
extractor
,
extractorOutput
,
dataSource
,
fileUri
);
while
(
output
.
seekMap
==
null
)
{
FakeTrackOutput
trackOutput
=
extractorOutput
.
trackOutputs
.
get
(
0
);
extractor
.
read
(
input
,
positionHolder
);
}
long
firstSeekTimeUs
=
987_000
;
}
finally
{
TestUtil
.
seekToTimeUs
(
extractor
,
seekMap
,
firstSeekTimeUs
,
dataSource
,
trackOutput
,
fileUri
);
Util
.
closeQuietly
(
dataSource
);
long
targetSeekTimeUs
=
1_234_000
;
int
extractedFrameIndex
=
TestUtil
.
seekToTimeUs
(
extractor
,
seekMap
,
targetSeekTimeUs
,
dataSource
,
trackOutput
,
fileUri
);
assertThat
(
extractedFrameIndex
).
isNotEqualTo
(
C
.
INDEX_UNSET
);
assertFirstFrameAfterSeekContainsTargetSeekTime
(
fileName
,
trackOutput
,
targetSeekTimeUs
,
extractedFrameIndex
);
}
}
return
output
.
seekMap
;
@Test
public
void
flacExtractorReads_unseekable_returnUnseekableSeekMap
()
throws
IOException
,
InterruptedException
{
Uri
fileUri
=
TestUtil
.
buildAssetUri
(
TEST_FILE_UNSEEKABLE
);
SeekMap
seekMap
=
TestUtil
.
extractSeekMap
(
extractor
,
extractorOutput
,
dataSource
,
fileUri
);
assertThat
(
seekMap
).
isNotNull
();
assertThat
(
seekMap
.
getDurationUs
()).
isEqualTo
(
C
.
TIME_UNSET
);
assertThat
(
seekMap
.
isSeekable
()).
isFalse
();
}
}
private
void
assertFirstFrameAfterSeekContainTargetSeekTime
(
private
static
void
assertFirstFrameAfterSeekContainsTargetSeekTime
(
FakeTrackOutput
trackOutput
,
long
seekTimeUs
,
int
firstFrameIndexAfterSeek
)
{
String
fileName
,
int
expectedSampleIndex
=
findTargetFrameInExpectedOutput
(
seekTimeUs
);
FakeTrackOutput
trackOutput
,
// Assert that after seeking, the first sample frame written to output contains the sample
long
targetSeekTimeUs
,
// at seek time.
int
firstFrameIndexAfterSeek
)
throws
IOException
,
InterruptedException
{
FakeTrackOutput
expectedTrackOutput
=
getExpectedTrackOutput
(
fileName
);
int
expectedFrameIndex
=
getFrameIndex
(
expectedTrackOutput
,
targetSeekTimeUs
);
trackOutput
.
assertSample
(
trackOutput
.
assertSample
(
firstFrameIndexAfterSeek
,
firstFrameIndexAfterSeek
,
expectedTrackOutput
.
getSampleData
(
expected
Sampl
eIndex
),
expectedTrackOutput
.
getSampleData
(
expected
Fram
eIndex
),
expectedTrackOutput
.
getSampleTimeUs
(
expected
Sampl
eIndex
),
expectedTrackOutput
.
getSampleTimeUs
(
expected
Fram
eIndex
),
expectedTrackOutput
.
getSampleFlags
(
expected
Sampl
eIndex
),
expectedTrackOutput
.
getSampleFlags
(
expected
Fram
eIndex
),
expectedTrackOutput
.
getSampleCryptoData
(
expected
Sampl
eIndex
));
expectedTrackOutput
.
getSampleCryptoData
(
expected
Fram
eIndex
));
}
}
private
int
findTargetFrameInExpectedOutput
(
long
seekTimeUs
)
{
private
static
void
assertFirstFrameAfterSeekPrecedesTargetSeekTime
(
List
<
Long
>
sampleTimes
=
expectedTrackOutput
.
getSampleTimesUs
();
String
fileName
,
for
(
int
i
=
0
;
i
<
sampleTimes
.
size
()
-
1
;
i
++)
{
FakeTrackOutput
trackOutput
,
long
currentSampleTime
=
sampleTimes
.
get
(
i
);
long
targetSeekTimeUs
,
long
nextSampleTime
=
sampleTimes
.
get
(
i
+
1
);
int
firstFrameIndexAfterSeek
)
if
(
currentSampleTime
<=
seekTimeUs
&&
nextSampleTime
>
seekTimeUs
)
{
throws
IOException
,
InterruptedException
{
return
i
;
FakeTrackOutput
expectedTrackOutput
=
getExpectedTrackOutput
(
fileName
);
}
int
maxFrameIndex
=
getFrameIndex
(
expectedTrackOutput
,
targetSeekTimeUs
);
long
firstFrameAfterSeekTimeUs
=
trackOutput
.
getSampleTimeUs
(
firstFrameIndexAfterSeek
);
assertThat
(
firstFrameAfterSeekTimeUs
).
isAtMost
(
targetSeekTimeUs
);
boolean
frameFound
=
false
;
for
(
int
i
=
maxFrameIndex
;
i
>=
0
;
i
--)
{
if
(
firstFrameAfterSeekTimeUs
==
expectedTrackOutput
.
getSampleTimeUs
(
i
))
{
trackOutput
.
assertSample
(
firstFrameIndexAfterSeek
,
expectedTrackOutput
.
getSampleData
(
i
),
expectedTrackOutput
.
getSampleTimeUs
(
i
),
expectedTrackOutput
.
getSampleFlags
(
i
),
expectedTrackOutput
.
getSampleCryptoData
(
i
));
frameFound
=
true
;
break
;
}
}
return
sampleTimes
.
size
()
-
1
;
}
}
private
ExtractorInput
getExtractorInputFromPosition
(
long
position
)
throws
IOException
{
assertThat
(
frameFound
).
isTrue
();
DataSpec
dataSpec
=
new
DataSpec
(
FILE_URI
,
position
,
totalInputLength
);
dataSource
.
open
(
dataSpec
);
return
new
DefaultExtractorInput
(
dataSource
,
position
,
totalInputLength
);
}
}
private
void
extractAllSamplesFromFileToExpectedOutput
(
Context
context
,
String
fileName
)
private
static
FakeTrackOutput
getExpectedTrackOutput
(
String
fileName
)
throws
IOException
,
InterruptedException
{
throws
IOException
,
InterruptedException
{
byte
[]
data
=
TestUtil
.
getByteArray
(
context
,
fileName
);
return
TestUtil
.
extractAllSamplesFromFile
(
new
FlacExtractor
(),
ApplicationProvider
.
getApplicationContext
(),
fileName
)
FlacExtractor
extractor
=
new
FlacExtractor
();
.
trackOutputs
extractor
.
init
(
expectedOutput
);
.
get
(
0
);
FakeExtractorInput
input
=
new
FakeExtractorInput
.
Builder
().
setData
(
data
).
build
();
}
while
(
extractor
.
read
(
input
,
new
PositionHolder
())
!=
Extractor
.
RESULT_END_OF_INPUT
)
{}
private
static
int
getFrameIndex
(
FakeTrackOutput
expectedTrackOutput
,
long
targetSeekTimeUs
)
{
List
<
Long
>
frameTimes
=
expectedTrackOutput
.
getSampleTimesUs
();
return
Util
.
binarySearchFloor
(
frameTimes
,
targetSeekTimeUs
,
/* inclusive= */
true
,
/* stayInBounds= */
false
);
}
}
}
}
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/flac/FlacExtractorSeekTest.java
View file @
f5025bfc
...
@@ -30,7 +30,6 @@ import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
...
@@ -30,7 +30,6 @@ import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
import
com.google.android.exoplayer2.util.Util
;
import
com.google.android.exoplayer2.util.Util
;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.util.List
;
import
java.util.List
;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.junit.runner.RunWith
;
...
@@ -43,18 +42,11 @@ public class FlacExtractorSeekTest {
...
@@ -43,18 +42,11 @@ public class FlacExtractorSeekTest {
private
static
final
String
TEST_FILE_UNSEEKABLE
=
"flac/bear_no_seek_table_no_num_samples.flac"
;
private
static
final
String
TEST_FILE_UNSEEKABLE
=
"flac/bear_no_seek_table_no_num_samples.flac"
;
private
static
final
int
DURATION_US
=
2_741_000
;
private
static
final
int
DURATION_US
=
2_741_000
;
private
FlacExtractor
extractor
;
private
FlacExtractor
extractor
=
new
FlacExtractor
();
private
FakeExtractorOutput
extractorOutput
;
private
FakeExtractorOutput
extractorOutput
=
new
FakeExtractorOutput
();
private
DefaultDataSource
dataSource
;
private
DefaultDataSource
dataSource
=
@Before
public
void
setUp
()
throws
Exception
{
extractor
=
new
FlacExtractor
();
extractorOutput
=
new
FakeExtractorOutput
();
dataSource
=
new
DefaultDataSourceFactory
(
ApplicationProvider
.
getApplicationContext
(),
"UserAgent"
)
new
DefaultDataSourceFactory
(
ApplicationProvider
.
getApplicationContext
(),
"UserAgent"
)
.
createDataSource
();
.
createDataSource
();
}
@Test
@Test
public
void
flacExtractorReads_seekTable_returnSeekableSeekMap
()
public
void
flacExtractorReads_seekTable_returnSeekableSeekMap
()
...
...
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