📄 oggvorbistagwriter.java
字号:
/*
* Entagged Audio Tag library
* Copyright (c) 2003-2005 Rapha�l Slinckx <raphael@slinckx.net>
* 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 com.hadeslee.audiotag.audio.ogg;
import com.hadeslee.audiotag.audio.exceptions.CannotReadException;
import com.hadeslee.audiotag.audio.exceptions.CannotWriteException;
import com.hadeslee.audiotag.tag.vorbiscomment.VorbisCommentTag;
import com.hadeslee.audiotag.audio.ogg.OggVorbisTagReader;
import com.hadeslee.audiotag.audio.ogg.util.OggCRCFactory;
import com.hadeslee.audiotag.audio.ogg.util.OggPageHeader;
import com.hadeslee.audiotag.tag.Tag;
import java.io.*;
import java.nio.*;
import java.util.logging.Logger;
/**
* Write Vorbis Tag within an ogg
* <p/>
* VorbisComment holds the tag information within an ogg file
*/
public class OggVorbisTagWriter
{
// Logger Object
public static Logger logger = Logger.getLogger("com.hadeslee.jaudiotagger.audio.ogg");
private OggVorbisCommentTagCreator tc = new OggVorbisCommentTagCreator();
private OggVorbisTagReader reader = new OggVorbisTagReader();
public void delete(RandomAccessFile raf, RandomAccessFile tempRaf) throws IOException, CannotReadException,CannotWriteException
{
VorbisCommentTag tag = null;
try
{
tag = (VorbisCommentTag) reader.read(raf);
}
catch (CannotReadException e)
{
write(new VorbisCommentTag(), raf, tempRaf);
return;
}
VorbisCommentTag emptyTag = new VorbisCommentTag();
emptyTag.setVendor(tag.getVendor());
write(emptyTag, raf, tempRaf);
}
public void write(Tag tag, RandomAccessFile raf, RandomAccessFile rafTemp) throws CannotReadException,CannotWriteException, IOException
{
logger.info("Starting to write file:");
//1st Page:Identification Header
logger.fine("Read identificationHeader:");
OggPageHeader pageHeader = OggPageHeader.read (raf);
raf.seek(0);
//Write 1st page (unchanged) and place writer pointer at end of data
rafTemp.getChannel().transferFrom(raf.getChannel(), 0,
pageHeader.getPageLength() + OggPageHeader.OGG_PAGE_HEADER_FIXED_LENGTH + pageHeader.getSegmentTable().length);
rafTemp.skipBytes(pageHeader.getPageLength()
+ OggPageHeader.OGG_PAGE_HEADER_FIXED_LENGTH
+ pageHeader.getSegmentTable().length);
logger.fine("Written identificationHeader:");
//2nd page:Comment and Setup if there is enough room
logger.fine("Read 2ndpage:");
OggPageHeader secondPageHeader = OggPageHeader.read (raf);
//2nd Page:Store the end of Header
long secondPageHeaderEndPos = raf.getFilePointer();
//Get header sizes
raf.seek(0);
OggVorbisTagReader.OggVorbisHeaderSizes vorbisHeaderSizes = reader.readOggVorbisHeaderSizes(raf);
//Convert the OggVorbisComment header to raw packet data
ByteBuffer newComment = tc.convert(tag);
//Compute new comment length(this may need to be spread over multiple pages)
int newCommentLength = newComment.capacity();
//Calculate size of setupheader
int setupHeaderLength = vorbisHeaderSizes.getSetupHeaderSize();
int oldCommentLength = vorbisHeaderSizes.getCommentHeaderSize();
//Calculate new size of new 2nd page
int newSecondPageLength = setupHeaderLength + newCommentLength;
logger.fine("Old Page size: " +secondPageHeader.getPageLength());
logger.fine("Setup Header Size: "+setupHeaderLength);
logger.fine("Old comment: " +oldCommentLength);
logger.fine("New comment: " +newCommentLength);
logger.fine("New Page Size: "+newSecondPageLength);
if(isCommentAndSetupHeaderFitsOnASinglePage(newCommentLength,setupHeaderLength))
{
//And if comment and setup header originally fitted on both, the length of the 2nd
//page must be less than maximum size allowed
//AND
//there must be two packets with last being complete because they may have
//elected to split the data over multiple pages instead of using up whole page - (as long
//as the last lacing value is 255 they can do this)
if(
(secondPageHeader.getPageLength()<OggPageHeader.MAXIMUM_PAGE_DATA_SIZE)
&&
(secondPageHeader.getPacketList().size()==2)
&&
(!secondPageHeader.isLastPacketIncomplete())
)
{
logger.info("Header and Setup remain on single page:");
replaceSecondPageOnly(
oldCommentLength,
setupHeaderLength,
newCommentLength,
newSecondPageLength,
secondPageHeader,
newComment,
secondPageHeaderEndPos,
raf,
rafTemp);
}
//Original 2nd page spanned multiple pages so more work to do
else
{
logger.info("Header and Setup now on single page:");
replaceSecondPageAndRenumberPageSeqs(
vorbisHeaderSizes,
newCommentLength,
newSecondPageLength,
secondPageHeader,
newComment,
raf,
rafTemp);
}
}
//Bit more complicated, have to create a load of new pages and renumber audio
else
{
logger.info("Header and Setup remain on multiple page:");
replacePagesAndRenumberPageSeqs(
vorbisHeaderSizes,
newCommentLength,
secondPageHeader,
newComment,
raf,
rafTemp);
}
}
/**
* Usually can use this method, previously comment and setup header all fit on page 2
* and they still do, so just replace this page. And copy further pages as is.
*
* @param setupHeaderLength
* @param oldCommentLength
* @param newCommentLength
* @param newSecondPageLength
* @param secondPageHeader
* @param newComment
* @param secondPageHeaderEndPos
* @param raf
* @param rafTemp
* @throws IOException
*/
private void replaceSecondPageOnly(int oldCommentLength, int setupHeaderLength, int newCommentLength, int newSecondPageLength, OggPageHeader secondPageHeader, ByteBuffer newComment, long secondPageHeaderEndPos, RandomAccessFile raf, RandomAccessFile rafTemp) throws IOException
{
byte[] segmentTable = createSegmentTable(newCommentLength, setupHeaderLength);
int newSecondPageHeaderLength = OggPageHeader.OGG_PAGE_HEADER_FIXED_LENGTH + segmentTable.length;
ByteBuffer secondPageBuffer = ByteBuffer.allocate(newSecondPageLength + newSecondPageHeaderLength);
secondPageBuffer.order(ByteOrder.LITTLE_ENDIAN);
//Build the new 2nd page header, can mostly be taken from the original upto the segment length
//OggS capture
secondPageBuffer.put(secondPageHeader.getRawHeaderData(), 0, OggPageHeader.OGG_PAGE_HEADER_FIXED_LENGTH - 1);
//Number of page Segments
secondPageBuffer.put((byte) segmentTable.length);
//Page segment table
for (int i = 0; i < segmentTable.length; i++)
{
secondPageBuffer.put(segmentTable[i]);
}
//Add New VorbisComment
secondPageBuffer.put(newComment);
//Add setup Header
raf.seek(secondPageHeaderEndPos);
raf.skipBytes(oldCommentLength);
raf.getChannel().read(secondPageBuffer);
//CRC should be zero before calculating it
secondPageBuffer.putInt(OggPageHeader.FIELD_PAGE_CHECKSUM_POS, 0);
//Compute CRC over the new second page
byte[] crc = OggCRCFactory.computeCRC(secondPageBuffer.array());
for (int i = 0; i < crc.length; i++)
{
secondPageBuffer.put(OggPageHeader.FIELD_PAGE_CHECKSUM_POS + i, crc[i]);
}
//Transfer the second page bytebuffer content and write to temp file
secondPageBuffer.rewind();
rafTemp.getChannel().write(secondPageBuffer);
//Write the rest of the original file
rafTemp.getChannel().transferFrom(raf.getChannel(), rafTemp.getFilePointer(), raf.length() - raf.getFilePointer());
}
/**
* Previously comment and/or setup header on a number of pages
* now can just replace this page fitting al on 2nd page, and renumber subsequent sequence pages
*
* @param originalHeaderSizes
* @param newCommentLength
* @param newSecondPageLength
* @param secondPageHeader
* @param newComment
* @param raf
* @param rafTemp
* @throws IOException
*/
private void replaceSecondPageAndRenumberPageSeqs(OggVorbisTagReader.OggVorbisHeaderSizes originalHeaderSizes,
int newCommentLength,
int newSecondPageLength,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -