package net.pterodactylus.sonitus.io.mp3;
+import java.util.Arrays;
import java.util.Map;
import com.google.common.base.Optional;
/** The decoded emphasis mode. */
private final int emphasis;
+ /** The content of the frame. */
+ private final byte[] content;
+
/**
* Creates a new frame from the given values.
*
* @param emphasis
* The emphasis
*/
- private Frame(int mpegAudioVersionId, int layerDescription, int protectionBit, int bitrateIndex, int samplingRateFrequencyIndex, int paddingBit, int privateBit, int channelMode, int modeExtension, int copyrightBit, int originalBit, int emphasis) {
+ private Frame(int mpegAudioVersionId, int layerDescription, int protectionBit, int bitrateIndex, int samplingRateFrequencyIndex, int paddingBit, int privateBit, int channelMode, int modeExtension, int copyrightBit, int originalBit, int emphasis, byte[] content) {
this.mpegAudioVersionId = mpegAudioVersionId;
this.layerDescription = layerDescription;
this.protectionBit = protectionBit;
this.copyrightBit = copyrightBit;
this.originalBit = originalBit;
this.emphasis = emphasis;
+ this.content = content;
}
//
return Emphasis.values()[emphasis];
}
+ /**
+ * Returns the content of this frame.
+ *
+ * @return The content of this frame
+ */
+ public byte[] content() {
+ return content;
+ }
+
//
// STATIC METHODS
//
}
/**
+ * Calculates the frame length in bytes for the frame starting at the given
+ * offset in the given buffer. This method should only be called for a buffer
+ * and an offset for which {@link #isFrame(byte[], int, int)} returns {@code
+ * true}.
+ *
+ * @param buffer
+ * The buffer storing the frame
+ * @param offset
+ * The offset of the frame
+ * @return The length of the frame in bytes, or {@code -1} if the frame length
+ * can not be calculated
+ */
+ public static int getFrameLength(byte[] buffer, int offset) {
+ MpegAudioVersion mpegAudioVersion = MpegAudioVersion.values()[(buffer[offset + 1] & 0x18) >>> 3];
+ LayerDescription layerDescription = LayerDescription.values()[(buffer[offset + 1] & 0x06) >>> 1];
+ int bitrate = bitrateSupplier.get().get(mpegAudioVersion).get(layerDescription).get((buffer[offset + 2] & 0xf0) >>> 4) * 1000;
+ int samplingRate = samplingRateSupplier.get().get(mpegAudioVersion).get((buffer[offset + 2] & 0x0c) >>> 2);
+ int paddingBit = (buffer[offset + 2] & 0x02) >>> 1;
+ if (layerDescription == LayerDescription.LAYER_1) {
+ return (12 * bitrate / samplingRate + paddingBit) * 4;
+ } else if ((layerDescription == LayerDescription.LAYER_2) || (layerDescription == LayerDescription.LAYER_3)) {
+ return 144 * bitrate / samplingRate + paddingBit;
+ }
+ return -1;
+ }
+
+ /**
* Tries to create an MPEG audio from the given data.
*
* @param buffer
int copyright = (buffer[offset + 3] & 0x08) >> 3;
int original = (buffer[offset + 3] & 0x04) >> 2;
int emphasis = buffer[offset + 3] & 0x03;
- return Optional.of(new Frame(mpegAudioVersionId, layerDescription, protectionBit, bitrateIndex, samplingRateFrequencyIndex, paddingBit, privateBit, channelMode, modeExtension, copyright, original, emphasis));
+ int frameLength = getFrameLength(buffer, offset);
+ return Optional.of(new Frame(mpegAudioVersionId, layerDescription, protectionBit, bitrateIndex, samplingRateFrequencyIndex, paddingBit, privateBit, channelMode, modeExtension, copyright, original, emphasis, Arrays.copyOfRange(buffer, 4, frameLength)));
}
return Optional.absent();
}
}
System.arraycopy(buffer, 1, buffer, 0, 3);
buffer[3] = (byte) r;
- Optional<Frame> frame = Frame.create(buffer, 0, 4);
- if (frame.isPresent()) {
- return frame.get();
+ if (Frame.isFrame(buffer, 0, 4)) {
+ int frameLength = Frame.getFrameLength(buffer, 0);
+ if (frameLength != -1) {
+ byte[] content = new byte[frameLength + 4];
+ readFully(inputStream, content, 4, frameLength);
+ System.arraycopy(buffer, 0, content, 0, 4);
+ Optional<Frame> frame = Frame.create(content, 0, frameLength + 4);
+ if (frame.isPresent()) {
+ return frame.get();
+ }
+ }
}
}
}