summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSenventise <2375741859@qq.com>2024-06-09 16:04:59 +0800
committerGitHub <noreply@github.com>2024-06-09 10:04:59 +0200
commit91f8ed055f552cdf32fd8bbcdd632534542257f8 (patch)
treedeba8bbdc381a20cd99217e341ae4481daed96f7
parente2ff09bd344e4c53ef40381f533fe26914604492 (diff)
downloadAntennaPod-91f8ed055f552cdf32fd8bbcdd632534542257f8.zip
Support parsing vorbis comments spanning across pages (#7215)
-rw-r--r--parser/media/src/main/java/de/danoeh/antennapod/parser/media/vorbis/VorbisCommentReader.java45
-rw-r--r--parser/media/src/main/java/de/danoeh/antennapod/parser/media/vorbis/VorbisInputStream.java69
-rw-r--r--parser/media/src/test/java/de/danoeh/antennapod/parser/media/vorbis/VorbisCommentMetadataReaderTest.java1
-rw-r--r--parser/media/src/test/resources/opus-comment.opusbin0 -> 178812 bytes
4 files changed, 72 insertions, 43 deletions
diff --git a/parser/media/src/main/java/de/danoeh/antennapod/parser/media/vorbis/VorbisCommentReader.java b/parser/media/src/main/java/de/danoeh/antennapod/parser/media/vorbis/VorbisCommentReader.java
index 7b907b969..607a6b1f1 100644
--- a/parser/media/src/main/java/de/danoeh/antennapod/parser/media/vorbis/VorbisCommentReader.java
+++ b/parser/media/src/main/java/de/danoeh/antennapod/parser/media/vorbis/VorbisCommentReader.java
@@ -20,16 +20,14 @@ public abstract class VorbisCommentReader {
private static final int PACKET_TYPE_IDENTIFICATION = 1;
private static final int PACKET_TYPE_COMMENT = 3;
- private final InputStream input;
+ private final VorbisInputStream input;
VorbisCommentReader(InputStream input) {
- this.input = input;
+ this.input = new VorbisInputStream(input);
}
public void readInputStream() throws VorbisCommentReaderException {
try {
- findIdentificationHeader();
- findOggPage();
findCommentHeader();
VorbisCommentHeader commentHeader = readCommentHeader();
Log.d(TAG, commentHeader.toString());
@@ -41,26 +39,6 @@ public abstract class VorbisCommentReader {
}
}
- private void findOggPage() throws IOException {
- // find OggS
- byte[] buffer = new byte[4];
- final byte[] oggPageHeader = {'O', 'g', 'g', 'S'};
- for (int bytesRead = 0; bytesRead < SECOND_PAGE_MAX_LENGTH; bytesRead++) {
- int data = input.read();
- if (data == -1) {
- throw new IOException("EOF while trying to find vorbis page");
- }
- buffer[bytesRead % buffer.length] = (byte) data;
- if (bufferMatches(buffer, oggPageHeader, bytesRead)) {
- break;
- }
- }
- // read segments
- IOUtils.skipFully(input, 22);
- int numSegments = input.read();
- IOUtils.skipFully(input, numSegments);
- }
-
private void readUserComment() throws VorbisCommentReaderException {
try {
long vectorLength = EndianUtils.readSwappedUnsignedInteger(input);
@@ -90,25 +68,6 @@ public abstract class VorbisCommentReader {
return charset.newDecoder().decode(ByteBuffer.wrap(buffer)).toString();
}
- /**
- * Looks for an identification header in the first page of the file. If an
- * identification header is found, it will be skipped completely
- */
- private void findIdentificationHeader() throws IOException {
- byte[] buffer = new byte[FIRST_OPUS_PAGE_LENGTH];
- IOUtils.readFully(input, buffer);
- final byte[] oggIdentificationHeader = new byte[]{ PACKET_TYPE_IDENTIFICATION, 'v', 'o', 'r', 'b', 'i', 's' };
- for (int i = 6; i < buffer.length; i++) {
- if (bufferMatches(buffer, oggIdentificationHeader, i)) {
- IOUtils.skip(input, FIRST_OGG_PAGE_LENGTH - FIRST_OPUS_PAGE_LENGTH);
- return;
- } else if (bufferMatches(buffer, "OpusHead".getBytes(), i)) {
- return;
- }
- }
- throw new IOException("No vorbis identification header found");
- }
-
private void findCommentHeader() throws IOException {
byte[] buffer = new byte[64]; // Enough space for some bytes. Used circularly.
final byte[] oggCommentHeader = new byte[]{ PACKET_TYPE_COMMENT, 'v', 'o', 'r', 'b', 'i', 's' };
diff --git a/parser/media/src/main/java/de/danoeh/antennapod/parser/media/vorbis/VorbisInputStream.java b/parser/media/src/main/java/de/danoeh/antennapod/parser/media/vorbis/VorbisInputStream.java
new file mode 100644
index 000000000..802813ab9
--- /dev/null
+++ b/parser/media/src/main/java/de/danoeh/antennapod/parser/media/vorbis/VorbisInputStream.java
@@ -0,0 +1,69 @@
+package de.danoeh.antennapod.parser.media.vorbis;
+
+import org.apache.commons.io.IOUtils;
+
+import java.io.BufferedInputStream;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+
+
+public class VorbisInputStream extends FilterInputStream {
+ private static final byte[] CAPTURE_PATTERN = {'O', 'g', 'g', 'S'};
+ private static final int HEADER_SKIP_LENGTH = 1 + 1 + 8 + 4 + 4 + 4;
+
+ private final BufferedInputStream inputStream;
+ private int pageRemainBytes = 0;
+
+ protected VorbisInputStream(InputStream in) {
+ super(in);
+ inputStream = new BufferedInputStream(in);
+ }
+
+ private int parsePageHeader(InputStream in) throws IOException {
+ byte[] capturePattern = new byte[4];
+
+ IOUtils.readFully(in, capturePattern, 0, 4);
+ if (!Arrays.equals(CAPTURE_PATTERN, capturePattern)) {
+ throw new IOException("Invalid page header");
+ }
+
+ IOUtils.skipFully(in, HEADER_SKIP_LENGTH);
+
+ int pageSegments = in.read();
+ byte[] segmentTable = new byte[pageSegments];
+ int pageLength = 0;
+ IOUtils.readFully(in, segmentTable);
+ for (byte segment:segmentTable) {
+ pageLength += (segment & 0xff);
+ }
+
+ return pageLength;
+ }
+
+ /** check and update remaining bytes **/
+ private void updateRemainBytes() throws IOException {
+ if (pageRemainBytes == 0) {
+ pageRemainBytes = parsePageHeader(inputStream);
+ } else if (pageRemainBytes < 0) {
+ throw new IOException("Page remain bytes less than 0");
+ }
+ }
+
+ @Override
+ public int read() throws IOException {
+ updateRemainBytes();
+ pageRemainBytes--;
+ return inputStream.read();
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ updateRemainBytes();
+ int bytesToRead = Math.min(len, pageRemainBytes);
+ IOUtils.readFully(inputStream, b, off, bytesToRead);
+ this.pageRemainBytes -= bytesToRead;
+ return bytesToRead;
+ }
+}
diff --git a/parser/media/src/test/java/de/danoeh/antennapod/parser/media/vorbis/VorbisCommentMetadataReaderTest.java b/parser/media/src/test/java/de/danoeh/antennapod/parser/media/vorbis/VorbisCommentMetadataReaderTest.java
index 7f71c8fa9..6dab507a3 100644
--- a/parser/media/src/test/java/de/danoeh/antennapod/parser/media/vorbis/VorbisCommentMetadataReaderTest.java
+++ b/parser/media/src/test/java/de/danoeh/antennapod/parser/media/vorbis/VorbisCommentMetadataReaderTest.java
@@ -16,6 +16,7 @@ public class VorbisCommentMetadataReaderTest {
public void testRealFilesAuphonic() throws IOException, VorbisCommentReaderException {
testRealFileAuphonic("auphonic.ogg");
testRealFileAuphonic("auphonic.opus");
+ testRealFileAuphonic("opus-comment.opus");
}
public void testRealFileAuphonic(String filename) throws IOException, VorbisCommentReaderException {
diff --git a/parser/media/src/test/resources/opus-comment.opus b/parser/media/src/test/resources/opus-comment.opus
new file mode 100644
index 000000000..d636f2be6
--- /dev/null
+++ b/parser/media/src/test/resources/opus-comment.opus
Binary files differ