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
bba0a27c
authored
Jul 14, 2019
by
Oliver Woodman
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Merge pull request #6151 from ittiam-systems:bug-5527
PiperOrigin-RevId: 257668797
parent
b6777e03
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
424 additions
and
88 deletions
RELEASENOTES.md
extensions/flac/proguard-rules.txt
extensions/flac/src/androidTest/java/com/google/android/exoplayer2/ext/flac/FlacBinarySearchSeekerTest.java
extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/FlacBinarySearchSeeker.java
extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/FlacDecoder.java
extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/FlacDecoderJni.java
extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/FlacExtractor.java
extensions/flac/src/main/jni/flac_jni.cc
extensions/flac/src/main/jni/flac_parser.cc
extensions/flac/src/main/jni/include/flac_parser.h
library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/FlacReader.java
library/core/src/main/java/com/google/android/exoplayer2/metadata/vorbis/VorbisComment.java
library/core/src/main/java/com/google/android/exoplayer2/util/FlacStreamInfo.java → library/core/src/main/java/com/google/android/exoplayer2/util/FlacStreamMetadata.java
library/core/src/test/java/com/google/android/exoplayer2/metadata/vorbis/VorbisCommentTest.java
library/core/src/test/java/com/google/android/exoplayer2/util/ColorParserTest.java
library/core/src/test/java/com/google/android/exoplayer2/util/FlacStreamMetadataTest.java
RELEASENOTES.md
View file @
bba0a27c
...
@@ -3,6 +3,8 @@
...
@@ -3,6 +3,8 @@
### 2.10.4 ###
### 2.10.4 ###
*
Offline: Add Scheduler implementation which uses WorkManager.
*
Offline: Add Scheduler implementation which uses WorkManager.
*
Flac extension: Parse
`VORBIS_COMMENT`
metadata
(
[
#5527
](
https://github.com/google/ExoPlayer/issues/5527
)
).
### 2.10.3 ###
### 2.10.3 ###
...
...
extensions/flac/proguard-rules.txt
View file @
bba0a27c
...
@@ -9,6 +9,6 @@
...
@@ -9,6 +9,6 @@
-keep class com.google.android.exoplayer2.ext.flac.FlacDecoderJni {
-keep class com.google.android.exoplayer2.ext.flac.FlacDecoderJni {
*;
*;
}
}
-keep class com.google.android.exoplayer2.util.FlacStream
Info
{
-keep class com.google.android.exoplayer2.util.FlacStream
Metadata
{
*;
*;
}
}
extensions/flac/src/androidTest/java/com/google/android/exoplayer2/ext/flac/FlacBinarySearchSeekerTest.java
View file @
bba0a27c
...
@@ -52,7 +52,10 @@ public final class FlacBinarySearchSeekerTest {
...
@@ -52,7 +52,10 @@ public final class FlacBinarySearchSeekerTest {
FlacBinarySearchSeeker
seeker
=
FlacBinarySearchSeeker
seeker
=
new
FlacBinarySearchSeeker
(
new
FlacBinarySearchSeeker
(
decoderJni
.
decodeStreamInfo
(),
/* firstFramePosition= */
0
,
data
.
length
,
decoderJni
);
decoderJni
.
decodeStreamMetadata
(),
/* firstFramePosition= */
0
,
data
.
length
,
decoderJni
);
SeekMap
seekMap
=
seeker
.
getSeekMap
();
SeekMap
seekMap
=
seeker
.
getSeekMap
();
assertThat
(
seekMap
).
isNotNull
();
assertThat
(
seekMap
).
isNotNull
();
...
@@ -70,7 +73,10 @@ public final class FlacBinarySearchSeekerTest {
...
@@ -70,7 +73,10 @@ public final class FlacBinarySearchSeekerTest {
decoderJni
.
setData
(
input
);
decoderJni
.
setData
(
input
);
FlacBinarySearchSeeker
seeker
=
FlacBinarySearchSeeker
seeker
=
new
FlacBinarySearchSeeker
(
new
FlacBinarySearchSeeker
(
decoderJni
.
decodeStreamInfo
(),
/* firstFramePosition= */
0
,
data
.
length
,
decoderJni
);
decoderJni
.
decodeStreamMetadata
(),
/* firstFramePosition= */
0
,
data
.
length
,
decoderJni
);
seeker
.
setSeekTargetUs
(
/* timeUs= */
1000
);
seeker
.
setSeekTargetUs
(
/* timeUs= */
1000
);
assertThat
(
seeker
.
isSeeking
()).
isTrue
();
assertThat
(
seeker
.
isSeeking
()).
isTrue
();
...
...
extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/FlacBinarySearchSeeker.java
View file @
bba0a27c
...
@@ -19,7 +19,7 @@ import com.google.android.exoplayer2.extractor.BinarySearchSeeker;
...
@@ -19,7 +19,7 @@ import com.google.android.exoplayer2.extractor.BinarySearchSeeker;
import
com.google.android.exoplayer2.extractor.ExtractorInput
;
import
com.google.android.exoplayer2.extractor.ExtractorInput
;
import
com.google.android.exoplayer2.extractor.SeekMap
;
import
com.google.android.exoplayer2.extractor.SeekMap
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.FlacStream
Info
;
import
com.google.android.exoplayer2.util.FlacStream
Metadata
;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.nio.ByteBuffer
;
import
java.nio.ByteBuffer
;
...
@@ -34,20 +34,20 @@ import java.nio.ByteBuffer;
...
@@ -34,20 +34,20 @@ import java.nio.ByteBuffer;
private
final
FlacDecoderJni
decoderJni
;
private
final
FlacDecoderJni
decoderJni
;
public
FlacBinarySearchSeeker
(
public
FlacBinarySearchSeeker
(
FlacStream
Info
streamInfo
,
FlacStream
Metadata
streamMetadata
,
long
firstFramePosition
,
long
firstFramePosition
,
long
inputLength
,
long
inputLength
,
FlacDecoderJni
decoderJni
)
{
FlacDecoderJni
decoderJni
)
{
super
(
super
(
new
FlacSeekTimestampConverter
(
stream
Info
),
new
FlacSeekTimestampConverter
(
stream
Metadata
),
new
FlacTimestampSeeker
(
decoderJni
),
new
FlacTimestampSeeker
(
decoderJni
),
stream
Info
.
durationUs
(),
stream
Metadata
.
durationUs
(),
/* floorTimePosition= */
0
,
/* floorTimePosition= */
0
,
/* ceilingTimePosition= */
stream
Info
.
totalSamples
,
/* ceilingTimePosition= */
stream
Metadata
.
totalSamples
,
/* floorBytePosition= */
firstFramePosition
,
/* floorBytePosition= */
firstFramePosition
,
/* ceilingBytePosition= */
inputLength
,
/* ceilingBytePosition= */
inputLength
,
/* approxBytesPerFrame= */
stream
Info
.
getApproxBytesPerFrame
(),
/* approxBytesPerFrame= */
stream
Metadata
.
getApproxBytesPerFrame
(),
/* minimumSearchRange= */
Math
.
max
(
1
,
stream
Info
.
minFrameSize
));
/* minimumSearchRange= */
Math
.
max
(
1
,
stream
Metadata
.
minFrameSize
));
this
.
decoderJni
=
Assertions
.
checkNotNull
(
decoderJni
);
this
.
decoderJni
=
Assertions
.
checkNotNull
(
decoderJni
);
}
}
...
@@ -112,15 +112,15 @@ import java.nio.ByteBuffer;
...
@@ -112,15 +112,15 @@ import java.nio.ByteBuffer;
* the timestamp for a stream seek time position.
* the timestamp for a stream seek time position.
*/
*/
private
static
final
class
FlacSeekTimestampConverter
implements
SeekTimestampConverter
{
private
static
final
class
FlacSeekTimestampConverter
implements
SeekTimestampConverter
{
private
final
FlacStream
Info
streamInfo
;
private
final
FlacStream
Metadata
streamMetadata
;
public
FlacSeekTimestampConverter
(
FlacStream
Info
streamInfo
)
{
public
FlacSeekTimestampConverter
(
FlacStream
Metadata
streamMetadata
)
{
this
.
stream
Info
=
streamInfo
;
this
.
stream
Metadata
=
streamMetadata
;
}
}
@Override
@Override
public
long
timeUsToTargetTime
(
long
timeUs
)
{
public
long
timeUsToTargetTime
(
long
timeUs
)
{
return
Assertions
.
checkNotNull
(
stream
Info
).
getSampleIndex
(
timeUs
);
return
Assertions
.
checkNotNull
(
stream
Metadata
).
getSampleIndex
(
timeUs
);
}
}
}
}
}
}
extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/FlacDecoder.java
View file @
bba0a27c
...
@@ -21,7 +21,7 @@ import com.google.android.exoplayer2.ParserException;
...
@@ -21,7 +21,7 @@ import com.google.android.exoplayer2.ParserException;
import
com.google.android.exoplayer2.decoder.DecoderInputBuffer
;
import
com.google.android.exoplayer2.decoder.DecoderInputBuffer
;
import
com.google.android.exoplayer2.decoder.SimpleDecoder
;
import
com.google.android.exoplayer2.decoder.SimpleDecoder
;
import
com.google.android.exoplayer2.decoder.SimpleOutputBuffer
;
import
com.google.android.exoplayer2.decoder.SimpleOutputBuffer
;
import
com.google.android.exoplayer2.util.FlacStream
Info
;
import
com.google.android.exoplayer2.util.FlacStream
Metadata
;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.nio.ByteBuffer
;
import
java.nio.ByteBuffer
;
import
java.util.List
;
import
java.util.List
;
...
@@ -58,9 +58,9 @@ import java.util.List;
...
@@ -58,9 +58,9 @@ import java.util.List;
}
}
decoderJni
=
new
FlacDecoderJni
();
decoderJni
=
new
FlacDecoderJni
();
decoderJni
.
setData
(
ByteBuffer
.
wrap
(
initializationData
.
get
(
0
)));
decoderJni
.
setData
(
ByteBuffer
.
wrap
(
initializationData
.
get
(
0
)));
FlacStream
Info
streamInfo
;
FlacStream
Metadata
streamMetadata
;
try
{
try
{
stream
Info
=
decoderJni
.
decodeStreamInfo
();
stream
Metadata
=
decoderJni
.
decodeStreamMetadata
();
}
catch
(
ParserException
e
)
{
}
catch
(
ParserException
e
)
{
throw
new
FlacDecoderException
(
"Failed to decode StreamInfo"
,
e
);
throw
new
FlacDecoderException
(
"Failed to decode StreamInfo"
,
e
);
}
catch
(
IOException
|
InterruptedException
e
)
{
}
catch
(
IOException
|
InterruptedException
e
)
{
...
@@ -69,9 +69,9 @@ import java.util.List;
...
@@ -69,9 +69,9 @@ import java.util.List;
}
}
int
initialInputBufferSize
=
int
initialInputBufferSize
=
maxInputBufferSize
!=
Format
.
NO_VALUE
?
maxInputBufferSize
:
stream
Info
.
maxFrameSize
;
maxInputBufferSize
!=
Format
.
NO_VALUE
?
maxInputBufferSize
:
stream
Metadata
.
maxFrameSize
;
setInitialInputBufferSize
(
initialInputBufferSize
);
setInitialInputBufferSize
(
initialInputBufferSize
);
maxOutputBufferSize
=
stream
Info
.
maxDecodedFrameSize
();
maxOutputBufferSize
=
stream
Metadata
.
maxDecodedFrameSize
();
}
}
@Override
@Override
...
...
extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/FlacDecoderJni.java
View file @
bba0a27c
...
@@ -19,7 +19,7 @@ import androidx.annotation.Nullable;
...
@@ -19,7 +19,7 @@ import androidx.annotation.Nullable;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.ParserException
;
import
com.google.android.exoplayer2.ParserException
;
import
com.google.android.exoplayer2.extractor.ExtractorInput
;
import
com.google.android.exoplayer2.extractor.ExtractorInput
;
import
com.google.android.exoplayer2.util.FlacStream
Info
;
import
com.google.android.exoplayer2.util.FlacStream
Metadata
;
import
com.google.android.exoplayer2.util.Util
;
import
com.google.android.exoplayer2.util.Util
;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.nio.ByteBuffer
;
import
java.nio.ByteBuffer
;
...
@@ -142,13 +142,13 @@ import java.nio.ByteBuffer;
...
@@ -142,13 +142,13 @@ import java.nio.ByteBuffer;
return
byteCount
;
return
byteCount
;
}
}
/** Decodes and consumes the
StreamInfo section
from the FLAC stream. */
/** Decodes and consumes the
metadata
from the FLAC stream. */
public
FlacStream
Info
decodeStreamInfo
()
throws
IOException
,
InterruptedException
{
public
FlacStream
Metadata
decodeStreamMetadata
()
throws
IOException
,
InterruptedException
{
FlacStream
Info
streamInfo
=
flacDecodeMetadata
(
nativeDecoderContext
);
FlacStream
Metadata
streamMetadata
=
flacDecodeMetadata
(
nativeDecoderContext
);
if
(
stream
Info
==
null
)
{
if
(
stream
Metadata
==
null
)
{
throw
new
ParserException
(
"Failed to decode
StreamInfo
"
);
throw
new
ParserException
(
"Failed to decode
stream metadata
"
);
}
}
return
stream
Info
;
return
stream
Metadata
;
}
}
/**
/**
...
@@ -266,7 +266,7 @@ import java.nio.ByteBuffer;
...
@@ -266,7 +266,7 @@ import java.nio.ByteBuffer;
private
native
long
flacInit
();
private
native
long
flacInit
();
private
native
FlacStream
Info
flacDecodeMetadata
(
long
context
)
private
native
FlacStream
Metadata
flacDecodeMetadata
(
long
context
)
throws
IOException
,
InterruptedException
;
throws
IOException
,
InterruptedException
;
private
native
int
flacDecodeToBuffer
(
long
context
,
ByteBuffer
outputBuffer
)
private
native
int
flacDecodeToBuffer
(
long
context
,
ByteBuffer
outputBuffer
)
...
...
extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/FlacExtractor.java
View file @
bba0a27c
...
@@ -34,7 +34,7 @@ import com.google.android.exoplayer2.extractor.TrackOutput;
...
@@ -34,7 +34,7 @@ import com.google.android.exoplayer2.extractor.TrackOutput;
import
com.google.android.exoplayer2.metadata.Metadata
;
import
com.google.android.exoplayer2.metadata.Metadata
;
import
com.google.android.exoplayer2.metadata.id3.Id3Decoder
;
import
com.google.android.exoplayer2.metadata.id3.Id3Decoder
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.FlacStream
Info
;
import
com.google.android.exoplayer2.util.FlacStream
Metadata
;
import
com.google.android.exoplayer2.util.MimeTypes
;
import
com.google.android.exoplayer2.util.MimeTypes
;
import
com.google.android.exoplayer2.util.ParsableByteArray
;
import
com.google.android.exoplayer2.util.ParsableByteArray
;
import
java.io.IOException
;
import
java.io.IOException
;
...
@@ -86,8 +86,8 @@ public final class FlacExtractor implements Extractor {
...
@@ -86,8 +86,8 @@ public final class FlacExtractor implements Extractor {
private
@MonotonicNonNull
ExtractorOutput
extractorOutput
;
private
@MonotonicNonNull
ExtractorOutput
extractorOutput
;
private
@MonotonicNonNull
TrackOutput
trackOutput
;
private
@MonotonicNonNull
TrackOutput
trackOutput
;
private
boolean
stream
Info
Decoded
;
private
boolean
stream
Metadata
Decoded
;
private
@MonotonicNonNull
FlacStream
Info
streamInfo
;
private
@MonotonicNonNull
FlacStream
Metadata
streamMetadata
;
private
@MonotonicNonNull
OutputFrameHolder
outputFrameHolder
;
private
@MonotonicNonNull
OutputFrameHolder
outputFrameHolder
;
@Nullable
private
Metadata
id3Metadata
;
@Nullable
private
Metadata
id3Metadata
;
...
@@ -138,7 +138,7 @@ public final class FlacExtractor implements Extractor {
...
@@ -138,7 +138,7 @@ public final class FlacExtractor implements Extractor {
FlacDecoderJni
decoderJni
=
initDecoderJni
(
input
);
FlacDecoderJni
decoderJni
=
initDecoderJni
(
input
);
try
{
try
{
decodeStream
Info
(
input
);
decodeStream
Metadata
(
input
);
if
(
binarySearchSeeker
!=
null
&&
binarySearchSeeker
.
isSeeking
())
{
if
(
binarySearchSeeker
!=
null
&&
binarySearchSeeker
.
isSeeking
())
{
return
handlePendingSeek
(
input
,
seekPosition
,
outputBuffer
,
outputFrameHolder
,
trackOutput
);
return
handlePendingSeek
(
input
,
seekPosition
,
outputBuffer
,
outputFrameHolder
,
trackOutput
);
...
@@ -166,7 +166,7 @@ public final class FlacExtractor implements Extractor {
...
@@ -166,7 +166,7 @@ public final class FlacExtractor implements Extractor {
@Override
@Override
public
void
seek
(
long
position
,
long
timeUs
)
{
public
void
seek
(
long
position
,
long
timeUs
)
{
if
(
position
==
0
)
{
if
(
position
==
0
)
{
stream
Info
Decoded
=
false
;
stream
Metadata
Decoded
=
false
;
}
}
if
(
decoderJni
!=
null
)
{
if
(
decoderJni
!=
null
)
{
decoderJni
.
reset
(
position
);
decoderJni
.
reset
(
position
);
...
@@ -207,29 +207,33 @@ public final class FlacExtractor implements Extractor {
...
@@ -207,29 +207,33 @@ public final class FlacExtractor implements Extractor {
}
}
@RequiresNonNull
({
"decoderJni"
,
"extractorOutput"
,
"trackOutput"
})
// Requires initialized.
@RequiresNonNull
({
"decoderJni"
,
"extractorOutput"
,
"trackOutput"
})
// Requires initialized.
@EnsuresNonNull
({
"stream
Info"
,
"outputFrameHolder"
})
// Ensures StreamInfo
decoded.
@EnsuresNonNull
({
"stream
Metadata"
,
"outputFrameHolder"
})
// Ensures stream metadata
decoded.
@SuppressWarnings
({
"contracts.postcondition.not.satisfied"
})
@SuppressWarnings
({
"contracts.postcondition.not.satisfied"
})
private
void
decodeStream
Info
(
ExtractorInput
input
)
throws
InterruptedException
,
IOException
{
private
void
decodeStream
Metadata
(
ExtractorInput
input
)
throws
InterruptedException
,
IOException
{
if
(
stream
Info
Decoded
)
{
if
(
stream
Metadata
Decoded
)
{
return
;
return
;
}
}
FlacStream
Info
streamInfo
;
FlacStream
Metadata
streamMetadata
;
try
{
try
{
stream
Info
=
decoderJni
.
decodeStreamInfo
();
stream
Metadata
=
decoderJni
.
decodeStreamMetadata
();
}
catch
(
IOException
e
)
{
}
catch
(
IOException
e
)
{
decoderJni
.
reset
(
/* newPosition= */
0
);
decoderJni
.
reset
(
/* newPosition= */
0
);
input
.
setRetryPosition
(
/* position= */
0
,
e
);
input
.
setRetryPosition
(
/* position= */
0
,
e
);
throw
e
;
throw
e
;
}
}
stream
Info
Decoded
=
true
;
stream
Metadata
Decoded
=
true
;
if
(
this
.
stream
Info
==
null
)
{
if
(
this
.
stream
Metadata
==
null
)
{
this
.
stream
Info
=
streamInfo
;
this
.
stream
Metadata
=
streamMetadata
;
binarySearchSeeker
=
binarySearchSeeker
=
outputSeekMap
(
decoderJni
,
streamInfo
,
input
.
getLength
(),
extractorOutput
);
outputSeekMap
(
decoderJni
,
streamMetadata
,
input
.
getLength
(),
extractorOutput
);
outputFormat
(
streamInfo
,
id3MetadataDisabled
?
null
:
id3Metadata
,
trackOutput
);
Metadata
metadata
=
id3MetadataDisabled
?
null
:
id3Metadata
;
outputBuffer
.
reset
(
streamInfo
.
maxDecodedFrameSize
());
if
(
streamMetadata
.
vorbisComments
!=
null
)
{
metadata
=
streamMetadata
.
vorbisComments
.
copyWithAppendedEntriesFrom
(
metadata
);
}
outputFormat
(
streamMetadata
,
metadata
,
trackOutput
);
outputBuffer
.
reset
(
streamMetadata
.
maxDecodedFrameSize
());
outputFrameHolder
=
new
OutputFrameHolder
(
ByteBuffer
.
wrap
(
outputBuffer
.
data
));
outputFrameHolder
=
new
OutputFrameHolder
(
ByteBuffer
.
wrap
(
outputBuffer
.
data
));
}
}
}
}
...
@@ -269,38 +273,38 @@ public final class FlacExtractor implements Extractor {
...
@@ -269,38 +273,38 @@ public final class FlacExtractor implements Extractor {
@Nullable
@Nullable
private
static
FlacBinarySearchSeeker
outputSeekMap
(
private
static
FlacBinarySearchSeeker
outputSeekMap
(
FlacDecoderJni
decoderJni
,
FlacDecoderJni
decoderJni
,
FlacStream
Info
streamInfo
,
FlacStream
Metadata
streamMetadata
,
long
streamLength
,
long
streamLength
,
ExtractorOutput
output
)
{
ExtractorOutput
output
)
{
boolean
hasSeekTable
=
decoderJni
.
getSeekPosition
(
/* timeUs= */
0
)
!=
-
1
;
boolean
hasSeekTable
=
decoderJni
.
getSeekPosition
(
/* timeUs= */
0
)
!=
-
1
;
FlacBinarySearchSeeker
binarySearchSeeker
=
null
;
FlacBinarySearchSeeker
binarySearchSeeker
=
null
;
SeekMap
seekMap
;
SeekMap
seekMap
;
if
(
hasSeekTable
)
{
if
(
hasSeekTable
)
{
seekMap
=
new
FlacSeekMap
(
stream
Info
.
durationUs
(),
decoderJni
);
seekMap
=
new
FlacSeekMap
(
stream
Metadata
.
durationUs
(),
decoderJni
);
}
else
if
(
streamLength
!=
C
.
LENGTH_UNSET
)
{
}
else
if
(
streamLength
!=
C
.
LENGTH_UNSET
)
{
long
firstFramePosition
=
decoderJni
.
getDecodePosition
();
long
firstFramePosition
=
decoderJni
.
getDecodePosition
();
binarySearchSeeker
=
binarySearchSeeker
=
new
FlacBinarySearchSeeker
(
stream
Info
,
firstFramePosition
,
streamLength
,
decoderJni
);
new
FlacBinarySearchSeeker
(
stream
Metadata
,
firstFramePosition
,
streamLength
,
decoderJni
);
seekMap
=
binarySearchSeeker
.
getSeekMap
();
seekMap
=
binarySearchSeeker
.
getSeekMap
();
}
else
{
}
else
{
seekMap
=
new
SeekMap
.
Unseekable
(
stream
Info
.
durationUs
());
seekMap
=
new
SeekMap
.
Unseekable
(
stream
Metadata
.
durationUs
());
}
}
output
.
seekMap
(
seekMap
);
output
.
seekMap
(
seekMap
);
return
binarySearchSeeker
;
return
binarySearchSeeker
;
}
}
private
static
void
outputFormat
(
private
static
void
outputFormat
(
FlacStream
Info
streamInfo
,
@Nullable
Metadata
metadata
,
TrackOutput
output
)
{
FlacStream
Metadata
streamMetadata
,
@Nullable
Metadata
metadata
,
TrackOutput
output
)
{
Format
mediaFormat
=
Format
mediaFormat
=
Format
.
createAudioSampleFormat
(
Format
.
createAudioSampleFormat
(
/* id= */
null
,
/* id= */
null
,
MimeTypes
.
AUDIO_RAW
,
MimeTypes
.
AUDIO_RAW
,
/* codecs= */
null
,
/* codecs= */
null
,
stream
Info
.
bitRate
(),
stream
Metadata
.
bitRate
(),
stream
Info
.
maxDecodedFrameSize
(),
stream
Metadata
.
maxDecodedFrameSize
(),
stream
Info
.
channels
,
stream
Metadata
.
channels
,
stream
Info
.
sampleRate
,
stream
Metadata
.
sampleRate
,
getPcmEncoding
(
stream
Info
.
bitsPerSample
),
getPcmEncoding
(
stream
Metadata
.
bitsPerSample
),
/* encoderDelay= */
0
,
/* encoderDelay= */
0
,
/* encoderPadding= */
0
,
/* encoderPadding= */
0
,
/* initializationData= */
null
,
/* initializationData= */
null
,
...
...
extensions/flac/src/main/jni/flac_jni.cc
View file @
bba0a27c
...
@@ -14,9 +14,12 @@
...
@@ -14,9 +14,12 @@
* limitations under the License.
* limitations under the License.
*/
*/
#include <jni.h>
#include <android/log.h>
#include <android/log.h>
#include <jni.h>
#include <cstdlib>
#include <cstdlib>
#include <cstring>
#include "include/flac_parser.h"
#include "include/flac_parser.h"
#define LOG_TAG "flac_jni"
#define LOG_TAG "flac_jni"
...
@@ -95,19 +98,40 @@ DECODER_FUNC(jobject, flacDecodeMetadata, jlong jContext) {
...
@@ -95,19 +98,40 @@ DECODER_FUNC(jobject, flacDecodeMetadata, jlong jContext) {
return
NULL
;
return
NULL
;
}
}
jclass
arrayListClass
=
env
->
FindClass
(
"java/util/ArrayList"
);
jmethodID
arrayListConstructor
=
env
->
GetMethodID
(
arrayListClass
,
"<init>"
,
"()V"
);
jobject
commentList
=
env
->
NewObject
(
arrayListClass
,
arrayListConstructor
);
if
(
context
->
parser
->
isVorbisCommentsValid
())
{
jmethodID
arrayListAddMethod
=
env
->
GetMethodID
(
arrayListClass
,
"add"
,
"(Ljava/lang/Object;)Z"
);
std
::
vector
<
std
::
string
>
vorbisComments
=
context
->
parser
->
getVorbisComments
();
for
(
std
::
vector
<
std
::
string
>::
const_iterator
vorbisComment
=
vorbisComments
.
begin
();
vorbisComment
!=
vorbisComments
.
end
();
++
vorbisComment
)
{
jstring
commentString
=
env
->
NewStringUTF
((
*
vorbisComment
).
c_str
());
env
->
CallBooleanMethod
(
commentList
,
arrayListAddMethod
,
commentString
);
env
->
DeleteLocalRef
(
commentString
);
}
}
const
FLAC__StreamMetadata_StreamInfo
&
streamInfo
=
const
FLAC__StreamMetadata_StreamInfo
&
streamInfo
=
context
->
parser
->
getStreamInfo
();
context
->
parser
->
getStreamInfo
();
jclass
cl
s
=
env
->
FindClass
(
jclass
flacStreamMetadataClas
s
=
env
->
FindClass
(
"com/google/android/exoplayer2/util/"
"com/google/android/exoplayer2/util/"
"FlacStreamInfo"
);
"FlacStreamMetadata"
);
jmethodID
constructor
=
env
->
GetMethodID
(
cls
,
"<init>"
,
"(IIIIIIIJ)V"
);
jmethodID
flacStreamMetadataConstructor
=
env
->
GetMethodID
(
flacStreamMetadataClass
,
"<init>"
,
"(IIIIIIIJLjava/util/List;)V"
);
return
env
->
NewObject
(
cls
,
constructor
,
streamInfo
.
min_blocksize
,
streamInfo
.
max_blocksize
,
streamInfo
.
min_framesize
,
return
env
->
NewObject
(
flacStreamMetadataClass
,
flacStreamMetadataConstructor
,
streamInfo
.
max_framesize
,
streamInfo
.
sample_rate
,
streamInfo
.
min_blocksize
,
streamInfo
.
max_blocksize
,
streamInfo
.
channels
,
streamInfo
.
bits_per_sample
,
streamInfo
.
min_framesize
,
streamInfo
.
max_framesize
,
streamInfo
.
total_samples
);
streamInfo
.
sample_rate
,
streamInfo
.
channels
,
streamInfo
.
bits_per_sample
,
streamInfo
.
total_samples
,
commentList
);
}
}
DECODER_FUNC
(
jint
,
flacDecodeToBuffer
,
jlong
jContext
,
jobject
jOutputBuffer
)
{
DECODER_FUNC
(
jint
,
flacDecodeToBuffer
,
jlong
jContext
,
jobject
jOutputBuffer
)
{
...
...
extensions/flac/src/main/jni/flac_parser.cc
View file @
bba0a27c
...
@@ -172,6 +172,25 @@ void FLACParser::metadataCallback(const FLAC__StreamMetadata *metadata) {
...
@@ -172,6 +172,25 @@ void FLACParser::metadataCallback(const FLAC__StreamMetadata *metadata) {
case
FLAC__METADATA_TYPE_SEEKTABLE
:
case
FLAC__METADATA_TYPE_SEEKTABLE
:
mSeekTable
=
&
metadata
->
data
.
seek_table
;
mSeekTable
=
&
metadata
->
data
.
seek_table
;
break
;
break
;
case
FLAC__METADATA_TYPE_VORBIS_COMMENT
:
if
(
!
mVorbisCommentsValid
)
{
FLAC__StreamMetadata_VorbisComment
vorbisComment
=
metadata
->
data
.
vorbis_comment
;
for
(
FLAC__uint32
i
=
0
;
i
<
vorbisComment
.
num_comments
;
++
i
)
{
FLAC__StreamMetadata_VorbisComment_Entry
vorbisCommentEntry
=
vorbisComment
.
comments
[
i
];
if
(
vorbisCommentEntry
.
entry
!=
NULL
)
{
std
::
string
comment
(
reinterpret_cast
<
char
*>
(
vorbisCommentEntry
.
entry
),
vorbisCommentEntry
.
length
);
mVorbisComments
.
push_back
(
comment
);
}
}
mVorbisCommentsValid
=
true
;
}
else
{
ALOGE
(
"FLACParser::metadataCallback unexpected VORBISCOMMENT"
);
}
break
;
default
:
default
:
ALOGE
(
"FLACParser::metadataCallback unexpected type %u"
,
metadata
->
type
);
ALOGE
(
"FLACParser::metadataCallback unexpected type %u"
,
metadata
->
type
);
break
;
break
;
...
@@ -233,6 +252,7 @@ FLACParser::FLACParser(DataSource *source)
...
@@ -233,6 +252,7 @@ FLACParser::FLACParser(DataSource *source)
mCurrentPos
(
0LL
),
mCurrentPos
(
0LL
),
mEOF
(
false
),
mEOF
(
false
),
mStreamInfoValid
(
false
),
mStreamInfoValid
(
false
),
mVorbisCommentsValid
(
false
),
mWriteRequested
(
false
),
mWriteRequested
(
false
),
mWriteCompleted
(
false
),
mWriteCompleted
(
false
),
mWriteBuffer
(
NULL
),
mWriteBuffer
(
NULL
),
...
@@ -266,6 +286,8 @@ bool FLACParser::init() {
...
@@ -266,6 +286,8 @@ bool FLACParser::init() {
FLAC__METADATA_TYPE_STREAMINFO
);
FLAC__METADATA_TYPE_STREAMINFO
);
FLAC__stream_decoder_set_metadata_respond
(
mDecoder
,
FLAC__stream_decoder_set_metadata_respond
(
mDecoder
,
FLAC__METADATA_TYPE_SEEKTABLE
);
FLAC__METADATA_TYPE_SEEKTABLE
);
FLAC__stream_decoder_set_metadata_respond
(
mDecoder
,
FLAC__METADATA_TYPE_VORBIS_COMMENT
);
FLAC__StreamDecoderInitStatus
initStatus
;
FLAC__StreamDecoderInitStatus
initStatus
;
initStatus
=
FLAC__stream_decoder_init_stream
(
initStatus
=
FLAC__stream_decoder_init_stream
(
mDecoder
,
read_callback
,
seek_callback
,
tell_callback
,
length_callback
,
mDecoder
,
read_callback
,
seek_callback
,
tell_callback
,
length_callback
,
...
...
extensions/flac/src/main/jni/include/flac_parser.h
View file @
bba0a27c
...
@@ -19,6 +19,10 @@
...
@@ -19,6 +19,10 @@
#include <stdint.h>
#include <stdint.h>
#include <cstdlib>
#include <string>
#include <vector>
// libFLAC parser
// libFLAC parser
#include "FLAC/stream_decoder.h"
#include "FLAC/stream_decoder.h"
...
@@ -44,6 +48,10 @@ class FLACParser {
...
@@ -44,6 +48,10 @@ class FLACParser {
return
mStreamInfo
;
return
mStreamInfo
;
}
}
bool
isVorbisCommentsValid
()
{
return
mVorbisCommentsValid
;
}
std
::
vector
<
std
::
string
>
getVorbisComments
()
{
return
mVorbisComments
;
}
int64_t
getLastFrameTimestamp
()
const
{
int64_t
getLastFrameTimestamp
()
const
{
return
(
1000000LL
*
mWriteHeader
.
number
.
sample_number
)
/
getSampleRate
();
return
(
1000000LL
*
mWriteHeader
.
number
.
sample_number
)
/
getSampleRate
();
}
}
...
@@ -71,6 +79,8 @@ class FLACParser {
...
@@ -71,6 +79,8 @@ class FLACParser {
mEOF
=
false
;
mEOF
=
false
;
if
(
newPosition
==
0
)
{
if
(
newPosition
==
0
)
{
mStreamInfoValid
=
false
;
mStreamInfoValid
=
false
;
mVorbisCommentsValid
=
false
;
mVorbisComments
.
clear
();
FLAC__stream_decoder_reset
(
mDecoder
);
FLAC__stream_decoder_reset
(
mDecoder
);
}
else
{
}
else
{
FLAC__stream_decoder_flush
(
mDecoder
);
FLAC__stream_decoder_flush
(
mDecoder
);
...
@@ -116,6 +126,10 @@ class FLACParser {
...
@@ -116,6 +126,10 @@ class FLACParser {
const
FLAC__StreamMetadata_SeekTable
*
mSeekTable
;
const
FLAC__StreamMetadata_SeekTable
*
mSeekTable
;
uint64_t
firstFrameOffset
;
uint64_t
firstFrameOffset
;
// cached when the VORBIS_COMMENT metadata is parsed by libFLAC
std
::
vector
<
std
::
string
>
mVorbisComments
;
bool
mVorbisCommentsValid
;
// cached when a decoded PCM block is "written" by libFLAC parser
// cached when a decoded PCM block is "written" by libFLAC parser
bool
mWriteRequested
;
bool
mWriteRequested
;
bool
mWriteCompleted
;
bool
mWriteCompleted
;
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/FlacReader.java
View file @
bba0a27c
...
@@ -19,7 +19,7 @@ import com.google.android.exoplayer2.Format;
...
@@ -19,7 +19,7 @@ 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.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.FlacStream
Info
;
import
com.google.android.exoplayer2.util.FlacStream
Metadata
;
import
com.google.android.exoplayer2.util.MimeTypes
;
import
com.google.android.exoplayer2.util.MimeTypes
;
import
com.google.android.exoplayer2.util.ParsableByteArray
;
import
com.google.android.exoplayer2.util.ParsableByteArray
;
import
com.google.android.exoplayer2.util.Util
;
import
com.google.android.exoplayer2.util.Util
;
...
@@ -38,7 +38,7 @@ import java.util.List;
...
@@ -38,7 +38,7 @@ import java.util.List;
private
static
final
int
FRAME_HEADER_SAMPLE_NUMBER_OFFSET
=
4
;
private
static
final
int
FRAME_HEADER_SAMPLE_NUMBER_OFFSET
=
4
;
private
FlacStream
Info
streamInfo
;
private
FlacStream
Metadata
streamMetadata
;
private
FlacOggSeeker
flacOggSeeker
;
private
FlacOggSeeker
flacOggSeeker
;
public
static
boolean
verifyBitstreamType
(
ParsableByteArray
data
)
{
public
static
boolean
verifyBitstreamType
(
ParsableByteArray
data
)
{
...
@@ -50,7 +50,7 @@ import java.util.List;
...
@@ -50,7 +50,7 @@ import java.util.List;
protected
void
reset
(
boolean
headerData
)
{
protected
void
reset
(
boolean
headerData
)
{
super
.
reset
(
headerData
);
super
.
reset
(
headerData
);
if
(
headerData
)
{
if
(
headerData
)
{
stream
Info
=
null
;
stream
Metadata
=
null
;
flacOggSeeker
=
null
;
flacOggSeeker
=
null
;
}
}
}
}
...
@@ -71,14 +71,24 @@ import java.util.List;
...
@@ -71,14 +71,24 @@ import java.util.List;
protected
boolean
readHeaders
(
ParsableByteArray
packet
,
long
position
,
SetupData
setupData
)
protected
boolean
readHeaders
(
ParsableByteArray
packet
,
long
position
,
SetupData
setupData
)
throws
IOException
,
InterruptedException
{
throws
IOException
,
InterruptedException
{
byte
[]
data
=
packet
.
data
;
byte
[]
data
=
packet
.
data
;
if
(
stream
Info
==
null
)
{
if
(
stream
Metadata
==
null
)
{
stream
Info
=
new
FlacStreamInfo
(
data
,
17
);
stream
Metadata
=
new
FlacStreamMetadata
(
data
,
17
);
byte
[]
metadata
=
Arrays
.
copyOfRange
(
data
,
9
,
packet
.
limit
());
byte
[]
metadata
=
Arrays
.
copyOfRange
(
data
,
9
,
packet
.
limit
());
metadata
[
4
]
=
(
byte
)
0x80
;
// Set the last metadata block flag, ignore the other blocks
metadata
[
4
]
=
(
byte
)
0x80
;
// Set the last metadata block flag, ignore the other blocks
List
<
byte
[]>
initializationData
=
Collections
.
singletonList
(
metadata
);
List
<
byte
[]>
initializationData
=
Collections
.
singletonList
(
metadata
);
setupData
.
format
=
Format
.
createAudioSampleFormat
(
null
,
MimeTypes
.
AUDIO_FLAC
,
null
,
setupData
.
format
=
Format
.
NO_VALUE
,
streamInfo
.
bitRate
(),
streamInfo
.
channels
,
streamInfo
.
sampleRate
,
Format
.
createAudioSampleFormat
(
initializationData
,
null
,
0
,
null
);
null
,
MimeTypes
.
AUDIO_FLAC
,
null
,
Format
.
NO_VALUE
,
streamMetadata
.
bitRate
(),
streamMetadata
.
channels
,
streamMetadata
.
sampleRate
,
initializationData
,
null
,
0
,
null
);
}
else
if
((
data
[
0
]
&
0x7F
)
==
SEEKTABLE_PACKET_TYPE
)
{
}
else
if
((
data
[
0
]
&
0x7F
)
==
SEEKTABLE_PACKET_TYPE
)
{
flacOggSeeker
=
new
FlacOggSeeker
();
flacOggSeeker
=
new
FlacOggSeeker
();
flacOggSeeker
.
parseSeekTable
(
packet
);
flacOggSeeker
.
parseSeekTable
(
packet
);
...
@@ -211,7 +221,7 @@ import java.util.List;
...
@@ -211,7 +221,7 @@ import java.util.List;
@Override
@Override
public
long
getDurationUs
()
{
public
long
getDurationUs
()
{
return
stream
Info
.
durationUs
();
return
stream
Metadata
.
durationUs
();
}
}
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/metadata/vorbis/VorbisComment.java
0 → 100644
View file @
bba0a27c
/*
* Copyright (C) 2019 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
.
metadata
.
vorbis
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Util
.
castNonNull
;
import
android.os.Parcel
;
import
android.os.Parcelable
;
import
androidx.annotation.Nullable
;
import
com.google.android.exoplayer2.metadata.Metadata
;
/** A vorbis comment. */
public
final
class
VorbisComment
implements
Metadata
.
Entry
{
/** The key. */
public
final
String
key
;
/** The value. */
public
final
String
value
;
/**
* @param key The key.
* @param value The value.
*/
public
VorbisComment
(
String
key
,
String
value
)
{
this
.
key
=
key
;
this
.
value
=
value
;
}
/* package */
VorbisComment
(
Parcel
in
)
{
this
.
key
=
castNonNull
(
in
.
readString
());
this
.
value
=
castNonNull
(
in
.
readString
());
}
@Override
public
String
toString
()
{
return
"VC: "
+
key
+
"="
+
value
;
}
@Override
public
boolean
equals
(
@Nullable
Object
obj
)
{
if
(
this
==
obj
)
{
return
true
;
}
if
(
obj
==
null
||
getClass
()
!=
obj
.
getClass
())
{
return
false
;
}
VorbisComment
other
=
(
VorbisComment
)
obj
;
return
key
.
equals
(
other
.
key
)
&&
value
.
equals
(
other
.
value
);
}
@Override
public
int
hashCode
()
{
int
result
=
17
;
result
=
31
*
result
+
key
.
hashCode
();
result
=
31
*
result
+
value
.
hashCode
();
return
result
;
}
// Parcelable implementation.
@Override
public
void
writeToParcel
(
Parcel
dest
,
int
flags
)
{
dest
.
writeString
(
key
);
dest
.
writeString
(
value
);
}
@Override
public
int
describeContents
()
{
return
0
;
}
public
static
final
Parcelable
.
Creator
<
VorbisComment
>
CREATOR
=
new
Parcelable
.
Creator
<
VorbisComment
>()
{
@Override
public
VorbisComment
createFromParcel
(
Parcel
in
)
{
return
new
VorbisComment
(
in
);
}
@Override
public
VorbisComment
[]
newArray
(
int
size
)
{
return
new
VorbisComment
[
size
];
}
};
}
library/core/src/main/java/com/google/android/exoplayer2/util/FlacStream
Info
.java
→
library/core/src/main/java/com/google/android/exoplayer2/util/FlacStream
Metadata
.java
View file @
bba0a27c
...
@@ -15,12 +15,17 @@
...
@@ -15,12 +15,17 @@
*/
*/
package
com
.
google
.
android
.
exoplayer2
.
util
;
package
com
.
google
.
android
.
exoplayer2
.
util
;
import
androidx.annotation.Nullable
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.metadata.Metadata
;
import
com.google.android.exoplayer2.metadata.vorbis.VorbisComment
;
import
java.util.ArrayList
;
import
java.util.List
;
/**
/**
Holder for FLAC metadata. */
* Holder for FLAC stream info.
public
final
class
FlacStreamMetadata
{
*/
public
final
class
FlacStreamInfo
{
private
static
final
String
TAG
=
"FlacStreamMetadata"
;
public
final
int
minBlockSize
;
public
final
int
minBlockSize
;
public
final
int
maxBlockSize
;
public
final
int
maxBlockSize
;
...
@@ -30,16 +35,19 @@ public final class FlacStreamInfo {
...
@@ -30,16 +35,19 @@ public final class FlacStreamInfo {
public
final
int
channels
;
public
final
int
channels
;
public
final
int
bitsPerSample
;
public
final
int
bitsPerSample
;
public
final
long
totalSamples
;
public
final
long
totalSamples
;
@Nullable
public
final
Metadata
vorbisComments
;
private
static
final
String
SEPARATOR
=
"="
;
/**
/**
*
Constructs a FlacStreamInfo parsing the given binary FLAC stream info metadata structure
.
*
Parses binary FLAC stream info metadata
.
*
*
* @param data An array
holding FLAC stream info metadata structure
* @param data An array
containing binary FLAC stream info metadata.
* @param offset
Offset of the structure in the array
* @param offset
The offset of the stream info metadata in {@code data}.
* @see <a href="https://xiph.org/flac/format.html#metadata_block_streaminfo">FLAC format
* @see <a href="https://xiph.org/flac/format.html#metadata_block_streaminfo">FLAC format
* METADATA_BLOCK_STREAMINFO</a>
* METADATA_BLOCK_STREAMINFO</a>
*/
*/
public
FlacStream
Info
(
byte
[]
data
,
int
offset
)
{
public
FlacStream
Metadata
(
byte
[]
data
,
int
offset
)
{
ParsableBitArray
scratch
=
new
ParsableBitArray
(
data
);
ParsableBitArray
scratch
=
new
ParsableBitArray
(
data
);
scratch
.
setPosition
(
offset
*
8
);
scratch
.
setPosition
(
offset
*
8
);
this
.
minBlockSize
=
scratch
.
readBits
(
16
);
this
.
minBlockSize
=
scratch
.
readBits
(
16
);
...
@@ -49,14 +57,11 @@ public final class FlacStreamInfo {
...
@@ -49,14 +57,11 @@ public final class FlacStreamInfo {
this
.
sampleRate
=
scratch
.
readBits
(
20
);
this
.
sampleRate
=
scratch
.
readBits
(
20
);
this
.
channels
=
scratch
.
readBits
(
3
)
+
1
;
this
.
channels
=
scratch
.
readBits
(
3
)
+
1
;
this
.
bitsPerSample
=
scratch
.
readBits
(
5
)
+
1
;
this
.
bitsPerSample
=
scratch
.
readBits
(
5
)
+
1
;
this
.
totalSamples
=
((
scratch
.
readBits
(
4
)
&
0xF
L
)
<<
32
)
this
.
totalSamples
=
((
scratch
.
readBits
(
4
)
&
0xF
L
)
<<
32
)
|
(
scratch
.
readBits
(
32
)
&
0xFFFFFFFF
L
);
|
(
scratch
.
readBits
(
32
)
&
0xFFFFFFFF
L
);
this
.
vorbisComments
=
null
;
// Remaining 16 bytes is md5 value
}
}
/**
/**
* Constructs a FlacStreamInfo given the parameters.
*
* @param minBlockSize Minimum block size of the FLAC stream.
* @param minBlockSize Minimum block size of the FLAC stream.
* @param maxBlockSize Maximum block size of the FLAC stream.
* @param maxBlockSize Maximum block size of the FLAC stream.
* @param minFrameSize Minimum frame size of the FLAC stream.
* @param minFrameSize Minimum frame size of the FLAC stream.
...
@@ -65,10 +70,13 @@ public final class FlacStreamInfo {
...
@@ -65,10 +70,13 @@ public final class FlacStreamInfo {
* @param channels Number of channels of the FLAC stream.
* @param channels Number of channels of the FLAC stream.
* @param bitsPerSample Number of bits per sample of the FLAC stream.
* @param bitsPerSample Number of bits per sample of the FLAC stream.
* @param totalSamples Total samples of the FLAC stream.
* @param totalSamples Total samples of the FLAC stream.
* @param vorbisComments Vorbis comments. Each entry must be in key=value form.
* @see <a href="https://xiph.org/flac/format.html#metadata_block_streaminfo">FLAC format
* @see <a href="https://xiph.org/flac/format.html#metadata_block_streaminfo">FLAC format
* METADATA_BLOCK_STREAMINFO</a>
* METADATA_BLOCK_STREAMINFO</a>
* @see <a href="https://xiph.org/flac/format.html#metadata_block_vorbis_comment">FLAC format
* METADATA_BLOCK_VORBIS_COMMENT</a>
*/
*/
public
FlacStream
Info
(
public
FlacStream
Metadata
(
int
minBlockSize
,
int
minBlockSize
,
int
maxBlockSize
,
int
maxBlockSize
,
int
minFrameSize
,
int
minFrameSize
,
...
@@ -76,7 +84,8 @@ public final class FlacStreamInfo {
...
@@ -76,7 +84,8 @@ public final class FlacStreamInfo {
int
sampleRate
,
int
sampleRate
,
int
channels
,
int
channels
,
int
bitsPerSample
,
int
bitsPerSample
,
long
totalSamples
)
{
long
totalSamples
,
List
<
String
>
vorbisComments
)
{
this
.
minBlockSize
=
minBlockSize
;
this
.
minBlockSize
=
minBlockSize
;
this
.
maxBlockSize
=
maxBlockSize
;
this
.
maxBlockSize
=
maxBlockSize
;
this
.
minFrameSize
=
minFrameSize
;
this
.
minFrameSize
=
minFrameSize
;
...
@@ -85,6 +94,7 @@ public final class FlacStreamInfo {
...
@@ -85,6 +94,7 @@ public final class FlacStreamInfo {
this
.
channels
=
channels
;
this
.
channels
=
channels
;
this
.
bitsPerSample
=
bitsPerSample
;
this
.
bitsPerSample
=
bitsPerSample
;
this
.
totalSamples
=
totalSamples
;
this
.
totalSamples
=
totalSamples
;
this
.
vorbisComments
=
parseVorbisComments
(
vorbisComments
);
}
}
/** Returns the maximum size for a decoded frame from the FLAC stream. */
/** Returns the maximum size for a decoded frame from the FLAC stream. */
...
@@ -126,4 +136,24 @@ public final class FlacStreamInfo {
...
@@ -126,4 +136,24 @@ public final class FlacStreamInfo {
}
}
return
approxBytesPerFrame
;
return
approxBytesPerFrame
;
}
}
@Nullable
private
static
Metadata
parseVorbisComments
(
@Nullable
List
<
String
>
vorbisComments
)
{
if
(
vorbisComments
==
null
||
vorbisComments
.
isEmpty
())
{
return
null
;
}
ArrayList
<
VorbisComment
>
commentFrames
=
new
ArrayList
<>();
for
(
String
vorbisComment
:
vorbisComments
)
{
String
[]
keyAndValue
=
Util
.
splitAtFirst
(
vorbisComment
,
SEPARATOR
);
if
(
keyAndValue
.
length
!=
2
)
{
Log
.
w
(
TAG
,
"Failed to parse vorbis comment: "
+
vorbisComment
);
}
else
{
VorbisComment
commentFrame
=
new
VorbisComment
(
keyAndValue
[
0
],
keyAndValue
[
1
]);
commentFrames
.
add
(
commentFrame
);
}
}
return
commentFrames
.
isEmpty
()
?
null
:
new
Metadata
(
commentFrames
);
}
}
}
library/core/src/test/java/com/google/android/exoplayer2/metadata/vorbis/VorbisCommentTest.java
0 → 100644
View file @
bba0a27c
/*
* Copyright (C) 2019 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
.
metadata
.
vorbis
;
import
static
com
.
google
.
common
.
truth
.
Truth
.
assertThat
;
import
android.os.Parcel
;
import
androidx.test.ext.junit.runners.AndroidJUnit4
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
/** Test for {@link VorbisComment}. */
@RunWith
(
AndroidJUnit4
.
class
)
public
final
class
VorbisCommentTest
{
@Test
public
void
testParcelable
()
{
VorbisComment
vorbisCommentFrameToParcel
=
new
VorbisComment
(
"key"
,
"value"
);
Parcel
parcel
=
Parcel
.
obtain
();
vorbisCommentFrameToParcel
.
writeToParcel
(
parcel
,
0
);
parcel
.
setDataPosition
(
0
);
VorbisComment
vorbisCommentFrameFromParcel
=
VorbisComment
.
CREATOR
.
createFromParcel
(
parcel
);
assertThat
(
vorbisCommentFrameFromParcel
).
isEqualTo
(
vorbisCommentFrameToParcel
);
parcel
.
recycle
();
}
}
library/core/src/test/java/com/google/android/exoplayer2/util/ColorParserTest.java
View file @
bba0a27c
...
@@ -28,7 +28,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
...
@@ -28,7 +28,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
import
org.junit.Test
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.junit.runner.RunWith
;
/** Unit test for
<code>ColorParser</code>
. */
/** Unit test for
{@link ColorParser}
. */
@RunWith
(
AndroidJUnit4
.
class
)
@RunWith
(
AndroidJUnit4
.
class
)
public
final
class
ColorParserTest
{
public
final
class
ColorParserTest
{
...
...
library/core/src/test/java/com/google/android/exoplayer2/util/FlacStreamMetadataTest.java
0 → 100644
View file @
bba0a27c
/*
* Copyright (C) 2019 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
.
util
;
import
static
com
.
google
.
common
.
truth
.
Truth
.
assertThat
;
import
androidx.test.ext.junit.runners.AndroidJUnit4
;
import
com.google.android.exoplayer2.metadata.Metadata
;
import
com.google.android.exoplayer2.metadata.vorbis.VorbisComment
;
import
java.util.ArrayList
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
/** Unit test for {@link FlacStreamMetadata}. */
@RunWith
(
AndroidJUnit4
.
class
)
public
final
class
FlacStreamMetadataTest
{
@Test
public
void
parseVorbisComments
()
{
ArrayList
<
String
>
commentsList
=
new
ArrayList
<>();
commentsList
.
add
(
"Title=Song"
);
commentsList
.
add
(
"Artist=Singer"
);
Metadata
metadata
=
new
FlacStreamMetadata
(
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
commentsList
).
vorbisComments
;
assertThat
(
metadata
.
length
()).
isEqualTo
(
2
);
VorbisComment
commentFrame
=
(
VorbisComment
)
metadata
.
get
(
0
);
assertThat
(
commentFrame
.
key
).
isEqualTo
(
"Title"
);
assertThat
(
commentFrame
.
value
).
isEqualTo
(
"Song"
);
commentFrame
=
(
VorbisComment
)
metadata
.
get
(
1
);
assertThat
(
commentFrame
.
key
).
isEqualTo
(
"Artist"
);
assertThat
(
commentFrame
.
value
).
isEqualTo
(
"Singer"
);
}
@Test
public
void
parseEmptyVorbisComments
()
{
ArrayList
<
String
>
commentsList
=
new
ArrayList
<>();
Metadata
metadata
=
new
FlacStreamMetadata
(
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
commentsList
).
vorbisComments
;
assertThat
(
metadata
).
isNull
();
}
@Test
public
void
parseVorbisCommentWithEqualsInValue
()
{
ArrayList
<
String
>
commentsList
=
new
ArrayList
<>();
commentsList
.
add
(
"Title=So=ng"
);
Metadata
metadata
=
new
FlacStreamMetadata
(
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
commentsList
).
vorbisComments
;
assertThat
(
metadata
.
length
()).
isEqualTo
(
1
);
VorbisComment
commentFrame
=
(
VorbisComment
)
metadata
.
get
(
0
);
assertThat
(
commentFrame
.
key
).
isEqualTo
(
"Title"
);
assertThat
(
commentFrame
.
value
).
isEqualTo
(
"So=ng"
);
}
@Test
public
void
parseInvalidVorbisComment
()
{
ArrayList
<
String
>
commentsList
=
new
ArrayList
<>();
commentsList
.
add
(
"TitleSong"
);
commentsList
.
add
(
"Artist=Singer"
);
Metadata
metadata
=
new
FlacStreamMetadata
(
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
commentsList
).
vorbisComments
;
assertThat
(
metadata
.
length
()).
isEqualTo
(
1
);
VorbisComment
commentFrame
=
(
VorbisComment
)
metadata
.
get
(
0
);
assertThat
(
commentFrame
.
key
).
isEqualTo
(
"Artist"
);
assertThat
(
commentFrame
.
value
).
isEqualTo
(
"Singer"
);
}
}
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