FLAC: support files which has ID3v2 tag or Last-metadata-block flag is 1
Problem:
1. Some flac audios cannot be played because they have ID3v2 tag
2. flac audio which Last-metadata-block flag is 1 cannot be played
by default
Solution:
1. Skip ID3v2 tag, and make these flac audios can be played
2. Last-metadata-block flag can be 1 according to flac spec.
https://xiph.org/flac/format.html#metadata_block_streaminfo
It is rational that flac files only have one metadata block
(STREAMINFO) before audio frames.
So, we should support files which Last-metadata-block is 1.
Bug: 122939727
Test: 1. manually play flac audio with ID3v2 tag
2. manually play flac audio which Last-metadata-block is 1
Change-Id: Id4928bc3a597176be63130bce9ba25df1978b51d
diff --git a/media/extractors/flac/FLACExtractor.cpp b/media/extractors/flac/FLACExtractor.cpp
index dcda6bf..84fbcee 100644
--- a/media/extractors/flac/FLACExtractor.cpp
+++ b/media/extractors/flac/FLACExtractor.cpp
@@ -806,7 +806,32 @@
bool SniffFLAC(DataSourceHelper *source, float *confidence)
{
- // FLAC header.
+ // Skip ID3 tags
+ off64_t pos = 0;
+ uint8_t header[10];
+ for (;;) {
+ if (source->readAt(pos, header, sizeof(header)) != sizeof(header)) {
+ return false; // no more file to read.
+ }
+
+ // check for ID3 tag
+ if (memcmp("ID3", header, 3) != 0) {
+ break; // not an ID3 tag.
+ }
+
+ // skip the ID3v2 data and check again
+ const unsigned id3Len = 10 +
+ (((header[6] & 0x7f) << 21)
+ | ((header[7] & 0x7f) << 14)
+ | ((header[8] & 0x7f) << 7)
+ | (header[9] & 0x7f));
+ pos += id3Len;
+
+ ALOGV("skipped ID3 tag of len %u new starting offset is %#016llx",
+ id3Len, (long long)pos);
+ }
+
+ // Check FLAC header.
// https://xiph.org/flac/format.html#stream
//
// Note: content stored big endian.
@@ -815,12 +840,8 @@
// 4 8 metadata type STREAMINFO (0) (note: OR with 0x80 if last metadata)
// 5 24 size of metadata, for STREAMINFO (0x22).
- // Android is LE, so express header as little endian int64 constant.
- constexpr int64_t flacHeader = (0x22LL << 56) | 'CaLf';
- constexpr int64_t flacHeader2 = flacHeader | (0x80LL << 32); // alternate form (last metadata)
- int64_t header;
- if (source->readAt(0, &header, sizeof(header)) != sizeof(header)
- || (header != flacHeader && header != flacHeader2)) {
+ if (memcmp("fLaC\x00\x00\x00\x22", header, 8) != 0 &&
+ memcmp("fLaC\x80\x00\x00\x22", header, 8) != 0) {
return false;
}