/*
* Entagged Audio Tag library
* Copyright (c) 2004-2005 Christian Laireiter <liree@web.de>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package org.jaudiotagger.audio.asf.io;
import org.jaudiotagger.audio.asf.data.*;
import org.jaudiotagger.audio.asf.util.Utils;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
/**
* Reads and interprets the data of the audio or video stream information chunk. <br>
*
* @author Christian Laireiter
*/
public class StreamChunkReader implements ChunkReader {
/**
* The GUID this reader {@linkplain #getApplyingIds() applies to}
*/
private final static GUID[] APPLYING = { GUID.GUID_STREAM };
/**
* Shouldn'timer be used for now.
*/
protected StreamChunkReader() {
// Nothing to do
}
/**
* {@inheritDoc}
*/
public boolean canFail() {
return true;
}
/**
* {@inheritDoc}
*/
public GUID[] getApplyingIds() {
return APPLYING.clone();
}
/**
* {@inheritDoc}
*/
public Chunk read(final GUID guid, final InputStream stream,
final long chunkStart) throws IOException {
StreamChunk result = null;
final BigInteger chunkLength = Utils.readBig64(stream);
// Now comes GUID indicating whether stream content type is audio or
// video
final GUID streamTypeGUID = Utils.readGUID(stream);
if (GUID.GUID_AUDIOSTREAM.equals(streamTypeGUID)
|| GUID.GUID_VIDEOSTREAM.equals(streamTypeGUID)) {
// A GUID is indicating whether the stream is error
// concealed
final GUID errorConcealment = Utils.readGUID(stream);
/*
* Read the Time Offset
*/
final long timeOffset = Utils.readUINT64(stream);
final long typeSpecificDataSize = Utils.readUINT32(stream);
final long streamSpecificDataSize = Utils.readUINT32(stream);
/*
* Read a bit field. (Contains stream number, and whether the stream
* content is encrypted.)
*/
final int mask = Utils.readUINT16(stream);
final int streamNumber = mask & 127;
final boolean contentEncrypted = (mask & 0x8000) != 0;
/*
* Skip a reserved field
*/
stream.skip(4);
/*
* very important to set for every stream type. The size of bytes
* read by the specific stream type, in order to skip the remaining
* unread bytes of the stream chunk.
*/
long streamSpecificBytes;
if (GUID.GUID_AUDIOSTREAM.equals(streamTypeGUID)) {
/*
* Reading audio specific information
*/
final AudioStreamChunk audioStreamChunk = new AudioStreamChunk(
chunkLength);
result = audioStreamChunk;
/*
* read WAVEFORMATEX and format extension.
*/
final long compressionFormat = Utils.readUINT16(stream);
final long channelCount = Utils.readUINT16(stream);
final long samplingRate = Utils.readUINT32(stream);
final long avgBytesPerSec = Utils.readUINT32(stream);
final long blockAlignment = Utils.readUINT16(stream);
final int bitsPerSample = Utils.readUINT16(stream);
final int codecSpecificDataSize = Utils.readUINT16(stream);
final byte[] codecSpecificData = new byte[codecSpecificDataSize];
stream.read(codecSpecificData);
audioStreamChunk.setCompressionFormat(compressionFormat);
audioStreamChunk.setChannelCount(channelCount);
audioStreamChunk.setSamplingRate(samplingRate);
audioStreamChunk.setAverageBytesPerSec(avgBytesPerSec);
audioStreamChunk.setErrorConcealment(errorConcealment);
audioStreamChunk.setBlockAlignment(blockAlignment);
audioStreamChunk.setBitsPerSample(bitsPerSample);
audioStreamChunk.setCodecData(codecSpecificData);
streamSpecificBytes = 18 + codecSpecificData.length;
} else {
/*
* Reading video specific information
*/
final VideoStreamChunk videoStreamChunk = new VideoStreamChunk(
chunkLength);
result = videoStreamChunk;
final long pictureWidth = Utils.readUINT32(stream);
final long pictureHeight = Utils.readUINT32(stream);
// Skip unknown field
stream.skip(1);
/*
* Now read the format specific data
*/
// Size of the data section (formatDataSize)
stream.skip(2);
stream.skip(16);
final byte[] fourCC = new byte[4];
stream.read(fourCC);
videoStreamChunk.setPictureWidth(pictureWidth);
videoStreamChunk.setPictureHeight(pictureHeight);
videoStreamChunk.setCodecId(fourCC);
streamSpecificBytes = 31;
}
/*
* Setting common values for audio and video
*/
result.setStreamNumber(streamNumber);
result.setStreamSpecificDataSize(streamSpecificDataSize);
result.setTypeSpecificDataSize(typeSpecificDataSize);
result.setTimeOffset(timeOffset);
result.setContentEncrypted(contentEncrypted);
result.setPosition(chunkStart);
/*
* Now skip remainder of chunks bytes. chunk-length - 24 (size of
* GUID and chunklen) - streamSpecificBytes(stream type specific
* data) - 54 (common data)
*/
stream
.skip(chunkLength.longValue() - 24 - streamSpecificBytes
- 54);
}
return result;
}
}