FlacTagWriterpublic class FlacTagWriter extends Object
Fields Summary |
---|
public static Logger | logger | private MetadataBlock | streamInfoBlock | private List | metadataBlockPadding | private List | metadataBlockApplication | private List | metadataBlockSeekTable | private List | metadataBlockCueSheet | private FlacTagCreator | tc | private FlacTagReader | reader |
Methods Summary |
---|
private int | computeAvailableRoom()
int length = 0;
for (MetadataBlock aMetadataBlockApplication : metadataBlockApplication)
{
length += aMetadataBlockApplication.getLength();
}
for (MetadataBlock aMetadataBlockSeekTable : metadataBlockSeekTable)
{
length += aMetadataBlockSeekTable.getLength();
}
for (MetadataBlock aMetadataBlockCueSheet : metadataBlockCueSheet)
{
length += aMetadataBlockCueSheet.getLength();
}
for (MetadataBlock aMetadataBlockPadding : metadataBlockPadding)
{
length += aMetadataBlockPadding.getLength();
}
return length;
| private int | computeNeededRoom()
int length = 0;
for (MetadataBlock aMetadataBlockApplication : metadataBlockApplication)
{
length += aMetadataBlockApplication.getLength();
}
for (MetadataBlock aMetadataBlockSeekTable : metadataBlockSeekTable)
{
length += aMetadataBlockSeekTable.getLength();
}
for (MetadataBlock aMetadataBlockCueSheet : metadataBlockCueSheet)
{
length += aMetadataBlockCueSheet.getLength();
}
return length;
| public void | delete(java.io.RandomAccessFile raf, java.io.RandomAccessFile tempRaf)Delete Tag from file
//This will save the file without any Comment or PictureData blocks
FlacTag emptyTag = new FlacTag(null, new ArrayList<MetadataBlockDataPicture>());
raf.seek(0);
tempRaf.seek(0);
write(emptyTag, raf, tempRaf);
| public void | write(org.jaudiotagger.tag.Tag tag, java.io.RandomAccessFile raf, java.io.RandomAccessFile rafTemp)Write tag to file
logger.config("Writing tag");
//Clean up old data
streamInfoBlock=null;
metadataBlockPadding.clear();
metadataBlockApplication.clear();
metadataBlockSeekTable.clear();
metadataBlockCueSheet.clear();
//Read existing data
FlacStreamReader flacStream = new FlacStreamReader(raf);
try
{
flacStream.findStream();
}
catch (CannotReadException cre)
{
throw new CannotWriteException(cre.getMessage());
}
boolean isLastBlock = false;
while (!isLastBlock)
{
MetadataBlockHeader mbh = MetadataBlockHeader.readHeader(raf);
switch (mbh.getBlockType())
{
case STREAMINFO:
{
streamInfoBlock = new MetadataBlock(mbh,new MetadataBlockDataStreamInfo(mbh, raf));
break;
}
case VORBIS_COMMENT:
case PADDING:
case PICTURE:
{
//All these will be replaced by the new metadata so we just treat as padding in order
//to determine how much space is already allocated in the file
raf.seek(raf.getFilePointer() + mbh.getDataLength());
MetadataBlockData mbd = new MetadataBlockDataPadding(mbh.getDataLength());
metadataBlockPadding.add(new MetadataBlock(mbh, mbd));
break;
}
case APPLICATION:
{
MetadataBlockData mbd = new MetadataBlockDataApplication(mbh, raf);
metadataBlockApplication.add(new MetadataBlock(mbh, mbd));
break;
}
case SEEKTABLE:
{
MetadataBlockData mbd = new MetadataBlockDataSeekTable(mbh, raf);
metadataBlockSeekTable.add(new MetadataBlock(mbh, mbd));
break;
}
case CUESHEET:
{
MetadataBlockData mbd = new MetadataBlockDataCueSheet(mbh, raf);
metadataBlockCueSheet.add(new MetadataBlock(mbh, mbd));
break;
}
default:
{
//What are the consequences of doing this
raf.seek(raf.getFilePointer() + mbh.getDataLength());
break;
}
}
isLastBlock = mbh.isLastBlock();
}
//Number of bytes in the existing file available before audio data
int availableRoom = computeAvailableRoom();
//Minimum Size of the New tag data without padding
int newTagSize = tc.convert(tag).limit();
//Number of bytes required for new tagdata and other metadata blocks
int neededRoom = newTagSize + computeNeededRoom();
//Go to start of Flac within file
raf.seek(flacStream.getStartOfFlacInFile());
logger.config("Writing tag available bytes:" + availableRoom + ":needed bytes:" + neededRoom);
//There is enough room to fit the tag without moving the audio just need to
//adjust padding accordingly need to allow space for padding header if padding required
if ((availableRoom == neededRoom) || (availableRoom > neededRoom + MetadataBlockHeader.HEADER_LENGTH))
{
//Jump over Id3 (if exists) Flac and StreamInfoBlock
raf.seek(flacStream.getStartOfFlacInFile() + FlacStreamReader.FLAC_STREAM_IDENTIFIER_LENGTH);
//Write StreamInfo, we always write this first even if wasn't first in original spec
raf.write(streamInfoBlock.getHeader().getBytesWithoutIsLastBlockFlag());
raf.write(streamInfoBlock.getData().getBytes());
//Write Application Blocks
for (MetadataBlock aMetadataBlockApplication : metadataBlockApplication)
{
raf.write(aMetadataBlockApplication.getHeader().getBytesWithoutIsLastBlockFlag());
raf.write(aMetadataBlockApplication.getData().getBytes());
}
//Write Seek Table Blocks
for (MetadataBlock aMetadataBlockSeekTable : metadataBlockSeekTable)
{
raf.write(aMetadataBlockSeekTable.getHeader().getBytesWithoutIsLastBlockFlag());
raf.write(aMetadataBlockSeekTable.getData().getBytes());
}
//Write Cue sheet Blocks
for (MetadataBlock aMetadataBlockCueSheet : metadataBlockCueSheet)
{
raf.write(aMetadataBlockCueSheet.getHeader().getBytesWithoutIsLastBlockFlag());
raf.write(aMetadataBlockCueSheet.getData().getBytes());
}
//Write tag (and padding)
raf.getChannel().write(tc.convert(tag, availableRoom - neededRoom));
}
//Need to move audio
else
{
//Skip to start of Audio
//If Flac tag contains ID3header or something before start of official Flac header copy it over
if(flacStream.getStartOfFlacInFile()>0)
{
raf.seek(0);
rafTemp.getChannel().transferFrom(raf.getChannel(), 0, flacStream.getStartOfFlacInFile());
rafTemp.seek(flacStream.getStartOfFlacInFile());
}
rafTemp.writeBytes(FlacStreamReader.FLAC_STREAM_IDENTIFIER);
rafTemp.writeByte(0); //To ensure never set Last-metadata-block flag even if was before
int uptoStreamHeaderSize = flacStream.getStartOfFlacInFile()
+ FlacStreamReader.FLAC_STREAM_IDENTIFIER_LENGTH
+ MetadataBlockHeader.BLOCK_TYPE_LENGTH;
rafTemp.seek(uptoStreamHeaderSize);
raf.seek(uptoStreamHeaderSize);
rafTemp.getChannel().transferFrom(
raf.getChannel(),
uptoStreamHeaderSize,
MetadataBlockHeader.BLOCK_LENGTH + MetadataBlockDataStreamInfo.STREAM_INFO_DATA_LENGTH);
int dataStartSize = flacStream.getStartOfFlacInFile()
+ FlacStreamReader.FLAC_STREAM_IDENTIFIER_LENGTH
+ MetadataBlockHeader.HEADER_LENGTH
+ MetadataBlockDataStreamInfo.STREAM_INFO_DATA_LENGTH;
rafTemp.seek(dataStartSize);
//Write all the metadatablocks
for (MetadataBlock aMetadataBlockApplication : metadataBlockApplication)
{
rafTemp.write(aMetadataBlockApplication.getHeader().getBytesWithoutIsLastBlockFlag());
rafTemp.write(aMetadataBlockApplication.getData().getBytes());
}
for (MetadataBlock aMetadataBlockSeekTable : metadataBlockSeekTable)
{
rafTemp.write(aMetadataBlockSeekTable.getHeader().getBytesWithoutIsLastBlockFlag());
rafTemp.write(aMetadataBlockSeekTable.getData().getBytes());
}
for (MetadataBlock aMetadataBlockCueSheet : metadataBlockCueSheet)
{
rafTemp.write(aMetadataBlockCueSheet.getHeader().getBytesWithoutIsLastBlockFlag());
rafTemp.write(aMetadataBlockCueSheet.getData().getBytes());
}
//Write tag data use default padding
rafTemp.write(tc.convert(tag, FlacTagCreator.DEFAULT_PADDING).array());
//Write audio to new file
raf.seek(dataStartSize + availableRoom);
//Issue #385
//Transfer 'size' bytes from raf at its current position to rafTemp at position but do it in batches
//to prevent OutOfMemory exceptions
long amountToBeWritten=raf.getChannel().size() - raf.getChannel().position();
long written = 0;
long chunksize = TagOptionSingleton.getInstance().getWriteChunkSize();
long count = amountToBeWritten / chunksize;
long mod = amountToBeWritten % chunksize;
for(int i = 0; i<count; i++)
{
written+=rafTemp.getChannel().transferFrom(raf.getChannel(), rafTemp.getChannel().position(), chunksize);
rafTemp.getChannel().position(rafTemp.getChannel().position() + chunksize);
}
written+=rafTemp.getChannel().transferFrom(raf.getChannel(), rafTemp.getChannel().position(), mod);
if(written!=amountToBeWritten)
{
throw new CannotWriteException("Was meant to write "+amountToBeWritten+" bytes but only written "+written+" bytes");
}
}
|
|