Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
Valentin Popov committed Jun 11, 2020
1 parent 22b4d64 commit 80125a8
Show file tree
Hide file tree
Showing 9 changed files with 364 additions and 210 deletions.
8 changes: 8 additions & 0 deletions core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
15 changes: 13 additions & 2 deletions core/src/main/java/org/gagravarr/flac/FlacFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,17 @@
package org.gagravarr.flac;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.SequenceInputStream;
import java.util.Enumeration;
import java.util.List;
import java.util.Vector;

import org.gagravarr.ogg.IOUtils;
import org.gagravarr.ogg.OggFile;
Expand Down Expand Up @@ -52,7 +56,7 @@ public static FlacFile open(InputStream inp) throws IOException, FileNotFoundExc
byte[] header = new byte[4];
IOUtils.readFully(inp, header);
inp.reset();

if(header[0] == (byte)'O' && header[1] == (byte)'g' &&
header[2] == (byte)'g' && header[3] == (byte)'S') {
return new FlacOggFile(new OggFile(inp));
Expand Down Expand Up @@ -89,8 +93,15 @@ public FlacTags getTags() {
/**
* In Reading mode, will close the underlying ogg/flac
* file and free its resources.
* In Writing mode, will write out the Info and
* In Writing mode, will write out the Info and
* Comments objects, and then the audio data.
*/
public abstract void close() throws IOException;

/**
* <p>Return {@link InputStream} of {@link FlacFile}. If tags modified, then return modified.</p>
* @return
*/
public abstract InputStream getInputStream();

}
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public byte[] getData() {

// Fix the length
byte[] data = baos.toByteArray();
IOUtils.putInt3BE(data, 1, data.length);
IOUtils.putInt3BE(data, 1, data.length - 4);

// All done
return data;
Expand Down
234 changes: 146 additions & 88 deletions core/src/main/java/org/gagravarr/flac/FlacNativeFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,106 +13,164 @@
*/
package org.gagravarr.flac;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.SequenceInputStream;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.Vector;

import org.gagravarr.flac.FlacTags.FlacTagsAsMetadata;
import org.gagravarr.ogg.IOUtils;
import org.gagravarr.ogg.OggPacket;
import org.gagravarr.ogg.OggStreamPacket;

/**
* This lets you work with FLAC files that
* are contained in a native FLAC Stream
* are contained in a native FLAC Stream
*/
public class FlacNativeFile extends FlacFile {
private InputStream input;

/**
* Opens the given file for reading
*/
public FlacNativeFile(File f) throws IOException, FileNotFoundException {
this(new FileInputStream(f));
}

/**
* Opens the given FLAC file
*/
public FlacNativeFile(InputStream inp) throws IOException {
// Check the header
byte[] header = new byte[4];
IOUtils.readFully(inp, header);
if(header[0] == (byte)'f' && header[1] == (byte)'L' &&
header[2] == (byte)'a' && header[3] == (byte)'C') {
// Good
} else {
throw new IllegalArgumentException("Not a FLAC file");
}

// First must be the FLAC info
info = (FlacInfo)FlacMetadataBlock.create(inp);

// Read the rest of the Metadata blocks
otherMetadata = new ArrayList<FlacMetadataBlock>();
while(true) {
FlacMetadataBlock m = FlacMetadataBlock.create(inp);
if(m instanceof FlacTagsAsMetadata) {
tags = ((FlacTagsAsMetadata)m).getTags();
} else {
otherMetadata.add(m);
}

if(m.isLastMetadataBlock()) {
break;
}
}

// Rest is audio
this.input = inp;
}


public FlacAudioFrame getNextAudioPacket() throws IOException {
int skipped = 0;
int b1 = 0;
int b2 = input.read();
while (b1 != -1 && b2 != -1) {
b1 = b2;
b2 = input.read();
if (FlacAudioFrame.isFrameHeaderStart(b1, b2)) {
if (skipped > 0)
System.err.println("Warning - had to skip " + skipped +
" bytes of junk data before finding the next packet header");
return new FlacAudioFrame(b1, b2, input, info);
}
skipped++;
}
return null;
}

/**
* Skips the audio data to the next packet with a granule
* of at least the given granule position.
* Note that skipping backwards is not currently supported!
*/
public void skipToGranule(long granulePosition) throws IOException {
throw new RuntimeException("Not supported");
}

/**
* In Reading mode, will close the underlying ogg/flac
* file and free its resources.
* In Writing mode, will write out the Info and
* Comments objects, and then the audio data.
*/
public void close() throws IOException {
if(input != null) {
input.close();
input = null;
} else {
throw new RuntimeException("Not supported");
}
}
private InputStream input;
private final LinkedList<FlacFrame> blocksInOrder = new LinkedList<>();

/**
* Opens the given file for reading
*/
public FlacNativeFile(File f) throws IOException, FileNotFoundException {
this(new FileInputStream(f));
}

/**
* Opens the given FLAC file
*/
public FlacNativeFile(InputStream inp) throws IOException {
// Check the header
byte[] header = new byte[4];
IOUtils.readFully(inp, header);
if (header[0] == (byte) 'f' && header[1] == (byte) 'L' &&
header[2] == (byte) 'a' && header[3] == (byte) 'C') {
// Good
} else {
throw new IllegalArgumentException("Not a FLAC file");
}

// First must be the FLAC info
info = (FlacInfo) FlacMetadataBlock.create(inp);
blocksInOrder.addLast(info);

// Read the rest of the Metadata blocks
otherMetadata = new ArrayList<>();
while (true) {
FlacMetadataBlock m = FlacMetadataBlock.create(inp);
if (m instanceof FlacTagsAsMetadata) {
tags = ((FlacTagsAsMetadata) m).getTags();
blocksInOrder.addLast(new OggStreamPacketDecorator(tags));
} else {
otherMetadata.add(m);
blocksInOrder.addLast(m);
}

if (m.isLastMetadataBlock()) {
break;
}
}

// Rest is audio
this.input = inp;
}

public FlacAudioFrame getNextAudioPacket() throws IOException {
int skipped = 0;
int b1 = 0;
int b2 = input.read();
while (b1 != -1 && b2 != -1) {
b1 = b2;
b2 = input.read();
if (FlacAudioFrame.isFrameHeaderStart(b1, b2)) {
if (skipped > 0)
System.err.println("Warning - had to skip " + skipped +
" bytes of junk data before finding the next packet header");
return new FlacAudioFrame(b1, b2, input, info);
}
skipped++;
}
return null;
}

/**
* Skips the audio data to the next packet with a granule
* of at least the given granule position.
* Note that skipping backwards is not currently supported!
*/
public void skipToGranule(long granulePosition) throws IOException {
throw new RuntimeException("Not supported");
}

/**
* In Reading mode, will close the underlying ogg/flac
* file and free its resources.
* In Writing mode, will write out the Info and
* Comments objects, and then the audio data.
*/
public void close() throws IOException {
if (input != null) {
input.close();
input = null;
} else {
throw new RuntimeException("Not supported");
}
}

@Override
public InputStream getInputStream() {
Vector<InputStream> streams = new Vector<>();
byte[] header = {'f', 'L', 'a', 'C'};
streams.add(new ByteArrayInputStream(header));
blocksInOrder.stream().forEach(block -> this.addStream(streams, block.getData()));
streams.add(input);

return new SequenceInputStream(streams.elements());
}

private void addStream(Vector<InputStream> streams, byte[] data) {
if (Objects.nonNull(data) && data.length > 0)
streams.add(new ByteArrayInputStream(data));
}

private static final class OggStreamPacketDecorator extends FlacFrame implements OggStreamPacket {

private OggStreamPacket decorated;

public OggStreamPacketDecorator(OggStreamPacket decorated) {
this.decorated = decorated;
}

public byte[] getData() {
return decorated.getData();
}

@Override
public void setData(byte[] data) {

}

@Override
public int getOggOverheadSize() {
return 0;
}

@Override
public OggPacket write() {
return null;
}

}
}
6 changes: 6 additions & 0 deletions core/src/main/java/org/gagravarr/flac/FlacOggFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -223,6 +224,11 @@ public void close() throws IOException {
}
}

@Override
public InputStream getInputStream() {
return null;
}

/**
* Return the Ogg-specific version of the Flac Info
*/
Expand Down
Loading

0 comments on commit 80125a8

Please sign in to comment.