nayuki / Nayuki-web-published-code

Complete collection of code files (*.java/js/py/cpp/etc.) published on Project Nayuki website.

Home Page:https://www.nayuki.io/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

simple-flac-implementation/SimpleEncodeWavToFlac: Incorrect block size?

opened this issue · comments

SUMMARY

It appears that SimpleEncodeWavToFlac.java produces a bad FLAC file, possibly because of the block size.

STEPS TO REPRODUCE
  1. Prepare a test audio file in WAV format
  2. Compile SimpleEncodeWavToFlac.java
  3. Convert the file: java SimpleEncodeWavToFlac orig.wav out.flac
  4. Use ffmpeg to convert the resulting FLAC file to WAV: ffmpeg -i out.flac out.wav
OBSERVED RESULT

In Step 4, the conversion will fail because the FLAC file produced by SimpleEncodeWavToFlac.java cannot be decoded:

Press [q] to stop, [?] for help
[flac @ 0x564ee0f5c380] blocksize 4096 > 4095
[flac @ 0x564ee0f5c380] decode_frame() failed
[flac @ 0x564ee0f52f80] blocksize 4096 > 4095
[flac @ 0x564ee0f52f80] decode_frame() failed
[flac @ 0x564ee0f49ec0] blocksize 4096 > 4095
[flac @ 0x564ee0f49ec0] decode_frame() failed
Error while decoding stream #0:0: Invalid data found when processing input
    Last message repeated 2 times
[flac @ 0x564ee0f5c380] blocksize 4096 > 4095
[flac @ 0x564ee0f5c380] decode_frame() failed
[flac @ 0x564ee0f52f80] blocksize 4096 > 4095
[flac @ 0x564ee0f52f80] decode_frame() failed
[flac @ 0x564ee0f49ec0] blocksize 4096 > 4095
[flac @ 0x564ee0f49ec0] decode_frame() failed
Error while decoding stream #0:0: Invalid data found when processing input
    Last message repeated 2 times
ADDITIONAL INFORMATION

If I change Line 96 as follows, then it appears that the FLAC file produced is correct:

@@ -93,7 +93,7 @@
 		
 		// Read raw samples and encode FLAC audio frames
 		for (int i = 0; numSamples > 0; i++) {
-			int blockSize = Math.min(numSamples, BLOCK_SIZE);
+			int blockSize = Math.min(numSamples, BLOCK_SIZE - 1);
 			encodeFrame(in, i, numChannels, sampleDepth, sampleRate, blockSize, out);
 			numSamples -= blockSize;
 		}

Regarding code on the page https://www.nayuki.io/page/simple-flac-implementation

Hello 8642..., thank you for bringing this issue to my attention. I have now fixed the code published on the live web page (though not in this repository yet). I will explain the technical details now.

Let's refer to the FLAC specification: https://xiph.org/flac/format.html

In METADATA_BLOCK_STREAMINFO, there are the two fields "The minimum block size (in samples) used in the stream" and "The maximum block size (in samples) used in the stream". By mistake, I wrote out the value BLOCKSIZE-1 instead of BLOCKSIZE.

This is because in the other section FRAME_HEADER, there is a field "Block size in inter-channel samples", where I write out "0111 : get 16 bit (blocksize-1) from end of header". I handled this field correctly, but I got confused and mistakenly applied the arithmetic to the metadata field. In other words, in the very beginning of the file I said that the minimum block size is 4095 and the maximum block size among the whole file is 4095, but in actuality I wrote out blocks that had 4096 samples per channel.

The metadata block seems to be largely ignored by FLAC decoders. For example, foobar2000 and even the official Xiph.org tools (e.g. flac -t to test for validity) reported no errors at all. On the other hand, I tried ffmpeg as you suggested, and it printed tons of errors and skipped all the frames because they were too big; furthermore, the media player application MPC-HC played silence for my whole FLAC file.

Your fix would work, but it violates my design intent. You artificially restrict the block size during the computation instead of changing the constant or writing the correct metadata field value. Anyhow, I am disappointed in myself and in other people's tools that this silly mistake wasn't caught earlier by a stricter FLAC file checker tool.

Thank you for the fix and the detailed explanation.