Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for RF64 wave files #9543

Merged
merged 4 commits into from
Nov 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
/** Utilities for handling WAVE files. */
public final class WavUtil {

/** Four character code for "RF64". */
public static final int RF64_FOURCC = 0x52463634;
/** Four character code for "ds64". */
public static final int DS64_FOURCC = 0x64733634;
/** Four character code for "RIFF". */
public static final int RIFF_FOURCC = 0x52494646;
/** Four character code for "WAVE". */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ public static WavHeader peek(ExtractorInput input) throws IOException {
// Allocate a scratch buffer large enough to store the format chunk.
ParsableByteArray scratch = new ParsableByteArray(16);

// Attempt to read the RIFF chunk.
// Attempt to read the RIFF or RF64 chunk.
ChunkHeader chunkHeader = ChunkHeader.peek(input, scratch);
if (chunkHeader.id != WavUtil.RIFF_FOURCC) {
if (chunkHeader.id != WavUtil.RIFF_FOURCC && chunkHeader.id != WavUtil.RF64_FOURCC) {
return null;
}

Expand Down Expand Up @@ -117,14 +117,27 @@ public static Pair<Long, Long> skipToData(ExtractorInput input) throws IOExcepti
ParsableByteArray scratch = new ParsableByteArray(ChunkHeader.SIZE_IN_BYTES);
// Skip all chunks until we find the data header.
ChunkHeader chunkHeader = ChunkHeader.peek(input, scratch);

// Data size holder. To be determined from data chunk or ds64 chunk in case of RF64.
long dataSize = -1;

while (chunkHeader.id != WavUtil.DATA_FOURCC) {
if (chunkHeader.id != WavUtil.RIFF_FOURCC && chunkHeader.id != WavUtil.FMT_FOURCC) {
if (chunkHeader.id != WavUtil.RIFF_FOURCC && chunkHeader.id != WavUtil.FMT_FOURCC
&& chunkHeader.id != WavUtil. RF64_FOURCC && chunkHeader.id != WavUtil. DS64_FOURCC) {
Log.w(TAG, "Ignoring unknown WAV chunk: " + chunkHeader.id);
}
long bytesToSkip = ChunkHeader.SIZE_IN_BYTES + chunkHeader.size;
// Override size of RIFF chunk, since it describes its size as the entire file.
if (chunkHeader.id == WavUtil.RIFF_FOURCC) {
// Also, ignore the size of RF64 chunk, since its always going to be 0xFFFFFFFF
if (chunkHeader.id == WavUtil.RIFF_FOURCC || chunkHeader.id == WavUtil.RF64_FOURCC) {
bytesToSkip = ChunkHeader.SIZE_IN_BYTES + 4;
} else if (chunkHeader.id == WavUtil.DS64_FOURCC) {
int ds64Size = (int) chunkHeader.size;
ParsableByteArray ds64Bytes = new ParsableByteArray(ds64Size);
input.peekFully(ds64Bytes.getData(), 0, ds64Size);
// ds64 chunk contains 64bit sizes. From position 8 to 16 is the data size
ds64Bytes.setPosition(8);
dataSize = ds64Bytes.readLittleEndianLong();
}
if (bytesToSkip > Integer.MAX_VALUE) {
throw ParserException.createForUnsupportedContainerFeature(
Expand All @@ -133,11 +146,15 @@ public static Pair<Long, Long> skipToData(ExtractorInput input) throws IOExcepti
input.skipFully((int) bytesToSkip);
chunkHeader = ChunkHeader.peek(input, scratch);
}
// Use size from data chunk if it wasn't determined from ds64 chunk
if (dataSize == -1) {
dataSize = chunkHeader.size;
}
// Skip past the "data" header.
input.skipFully(ChunkHeader.SIZE_IN_BYTES);

long dataStartPosition = input.getPosition();
long dataEndPosition = dataStartPosition + chunkHeader.size;
long dataEndPosition = dataStartPosition + dataSize;
long inputLength = input.getLength();
if (inputLength != C.LENGTH_UNSET && dataEndPosition > inputLength) {
Log.w(TAG, "Data exceeds input length: " + dataEndPosition + ", " + inputLength);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,10 @@ public void sample_imaAdpcm() throws Exception {
ExtractorAsserts.assertBehavior(
WavExtractor::new, "media/wav/sample_ima_adpcm.wav", simulationConfig);
}

@Test
public void sample_RF64() throws Exception {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You also need to generate the dump files that go with the test. To do so, you need to,

  • Set DUMP_FILE_ACTION to WRITE_TO_LOCAL in DumpFileAsserts.java
  • Run the test. This will create dump files that are a summary of the data extracted by the WavExtractor.
  • Set DUMP_FILE_ACTION back to COMPARE_WITH_EXISTING.
  • Run the test. This will compare the extracted data with the files previously generated. This test need to pass.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just added the dump files and the test is passing :)

ExtractorAsserts
.assertBehavior(WavExtractor::new, "media/wav/sample_rf64.wav", simulationConfig);
}
}
36 changes: 36 additions & 0 deletions testdata/src/test/assets/extractordumps/wav/sample_rf64.wav.0.dump
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
seekMap:
isSeekable = true
duration = 348625
getPosition(0) = [[timeUs=0, position=80]]
getPosition(1) = [[timeUs=0, position=80], [timeUs=20, position=84]]
getPosition(174312) = [[timeUs=174291, position=33544], [timeUs=174312, position=33548]]
getPosition(348625) = [[timeUs=348604, position=67012]]
numberOfTracks = 1
track 0:
total output bytes = 66936
sample count = 4
format 0:
averageBitrate = 1536000
peakBitrate = 1536000
sampleMimeType = audio/raw
maxInputSize = 19200
channelCount = 2
sampleRate = 48000
pcmEncoding = 2
sample 0:
time = 0
flags = 1
data = length 19200, hash EF6C7C27
sample 1:
time = 100000
flags = 1
data = length 19200, hash 5AB97AFC
sample 2:
time = 200000
flags = 1
data = length 19200, hash 37920F33
sample 3:
time = 300000
flags = 1
data = length 9336, hash 135F1C30
tracksEnded = true
32 changes: 32 additions & 0 deletions testdata/src/test/assets/extractordumps/wav/sample_rf64.wav.1.dump
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
seekMap:
isSeekable = true
duration = 348625
getPosition(0) = [[timeUs=0, position=80]]
getPosition(1) = [[timeUs=0, position=80], [timeUs=20, position=84]]
getPosition(174312) = [[timeUs=174291, position=33544], [timeUs=174312, position=33548]]
getPosition(348625) = [[timeUs=348604, position=67012]]
numberOfTracks = 1
track 0:
total output bytes = 44628
sample count = 3
format 0:
averageBitrate = 1536000
peakBitrate = 1536000
sampleMimeType = audio/raw
maxInputSize = 19200
channelCount = 2
sampleRate = 48000
pcmEncoding = 2
sample 0:
time = 116208
flags = 1
data = length 19200, hash E4B962ED
sample 1:
time = 216208
flags = 1
data = length 19200, hash 4F13D6CF
sample 2:
time = 316208
flags = 1
data = length 6228, hash 3FB5F446
tracksEnded = true
28 changes: 28 additions & 0 deletions testdata/src/test/assets/extractordumps/wav/sample_rf64.wav.2.dump
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
seekMap:
isSeekable = true
duration = 348625
getPosition(0) = [[timeUs=0, position=80]]
getPosition(1) = [[timeUs=0, position=80], [timeUs=20, position=84]]
getPosition(174312) = [[timeUs=174291, position=33544], [timeUs=174312, position=33548]]
getPosition(348625) = [[timeUs=348604, position=67012]]
numberOfTracks = 1
track 0:
total output bytes = 22316
sample count = 2
format 0:
averageBitrate = 1536000
peakBitrate = 1536000
sampleMimeType = audio/raw
maxInputSize = 19200
channelCount = 2
sampleRate = 48000
pcmEncoding = 2
sample 0:
time = 232416
flags = 1
data = length 19200, hash F82E494B
sample 1:
time = 332416
flags = 1
data = length 3116, hash 93C99CFD
tracksEnded = true
24 changes: 24 additions & 0 deletions testdata/src/test/assets/extractordumps/wav/sample_rf64.wav.3.dump
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
seekMap:
isSeekable = true
duration = 348625
getPosition(0) = [[timeUs=0, position=80]]
getPosition(1) = [[timeUs=0, position=80], [timeUs=20, position=84]]
getPosition(174312) = [[timeUs=174291, position=33544], [timeUs=174312, position=33548]]
getPosition(348625) = [[timeUs=348604, position=67012]]
numberOfTracks = 1
track 0:
total output bytes = 4
sample count = 1
format 0:
averageBitrate = 1536000
peakBitrate = 1536000
sampleMimeType = audio/raw
maxInputSize = 19200
channelCount = 2
sampleRate = 48000
pcmEncoding = 2
sample 0:
time = 348625
flags = 1
data = length 4, hash FFD4C53F
tracksEnded = true
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
seekMap:
isSeekable = true
duration = 348625
getPosition(0) = [[timeUs=0, position=80]]
getPosition(1) = [[timeUs=0, position=80], [timeUs=20, position=84]]
getPosition(174312) = [[timeUs=174291, position=33544], [timeUs=174312, position=33548]]
getPosition(348625) = [[timeUs=348604, position=67012]]
numberOfTracks = 1
track 0:
total output bytes = 66936
sample count = 4
format 0:
averageBitrate = 1536000
peakBitrate = 1536000
sampleMimeType = audio/raw
maxInputSize = 19200
channelCount = 2
sampleRate = 48000
pcmEncoding = 2
sample 0:
time = 0
flags = 1
data = length 19200, hash EF6C7C27
sample 1:
time = 100000
flags = 1
data = length 19200, hash 5AB97AFC
sample 2:
time = 200000
flags = 1
data = length 19200, hash 37920F33
sample 3:
time = 300000
flags = 1
data = length 9336, hash 135F1C30
tracksEnded = true
Binary file not shown.