//Creates the ByteBuffer for the ogg tag public ByteBuffer Convert(Tag tag) { ByteBuffer ogg = creator.Create(tag); int tagLength = ogg.Capacity + 8; ByteBuffer buf = new ByteBuffer(tagLength); //[packet type=comment0x03]['vorbis'] buf.Put( new byte[]{(byte) 0x03, (byte) 0x76, (byte) 0x6f, (byte) 0x72, (byte) 0x62, (byte) 0x69, (byte) 0x73} ); //The actual tag buf.Put(ogg); //Framing bit = 1 buf.Put( (byte) 0x01 ); buf.Rewind(); return buf; }
//Creates the ByteBuffer for the ogg tag protected override void Create(Tag tag, ByteBuffer buf, IList fields, int tagSize, int padding) { string vendorstring; if (tag.HasField("vendor")) vendorstring = tag.Get("vendor")[0] as string; else //FIXME: Do something about this vendorstring = "DefaultVendor"; byte[] vendorBytes = Utils.GetBytes(vendorstring, "UTF-8"); buf.Put( new byte[]{(byte)(vendorBytes.Length&0xFF), (byte)((vendorBytes.Length & 0xFF00) >> 8) , (byte)((vendorBytes.Length & 0xFF0000) >> 16), (byte)((vendorBytes.Length & 0xFF000000) >> 24) } ); buf.Put( vendorBytes ); //[user comment list length] buf.Put( Utils.GetNumber(fields.Count) ); foreach(byte[] field in fields) { buf.Put(field); } }
//Creates the ByteBuffer for the ogg tag public ByteBuffer Create(Tag tag, int paddingSize) { ByteBuffer ogg = creator.Create(tag); int tagLength = ogg.Capacity + 4; ByteBuffer buf = new ByteBuffer( tagLength + paddingSize ); //CREATION OF CVORBIS COMMENT METADATA BLOCK HEADER //If we have padding, the comment is not the last block (bit[0] = 0) //If there is no padding, the comment is the last block (bit[0] = 1) byte type = (paddingSize > 0) ? (byte)0x04 : (byte) 0x84; buf.Put(type); int commentLength = tagLength - 4; //Comment length buf.Put( new byte[] { (byte)((commentLength & 0xFF0000) >> 16), (byte)((commentLength & 0xFF00) >> 8) , (byte)(commentLength&0xFF) } ); //The actual tag buf.Put(ogg); //PADDING if(paddingSize >=4) { int paddingDataSize = paddingSize - 4; buf.Put((byte)0x81); //Last frame, padding 0x81 buf.Put(new byte[]{ (byte)((paddingDataSize&0xFF0000)>>16),(byte)((paddingDataSize&0xFF00)>>8),(byte)(paddingDataSize&0xFF) }); for(int i = 0; i< paddingDataSize; i++) buf.Put((byte)0); } buf.Rewind(); return buf; }
public ByteBuffer synchronize(ByteBuffer b) { ByteBuffer bb = new ByteBuffer(b.Capacity); while(b.Remaining >= 1) { byte cur = b.Get(); bb.Put(cur); if((cur&0xFF) == 0xFF && b.Remaining >=1 && b.Peek() == 0x00) { //First part of synchronization b.Get(); } } //We have finished filling the new bytebuffer, so set the limit, and rewind bb.Limit = bb.Position; bb.Rewind(); return bb; }
public void Write(Tag tag, Stream raf, Stream rafTemp) { //Read firstPage---------------------------------------------------- raf.Seek(26, SeekOrigin.Begin); byte[] b = new byte[4]; int pageSegments = raf.ReadByte()&0xFF; //Unsigned raf.Seek(0, SeekOrigin.Begin); b = new byte[27 + pageSegments]; raf.Read(b, 0, b.Length); OggPageHeader firstPage = new OggPageHeader(b); //------------------------------------------------------------------ raf.Seek(0, SeekOrigin.Begin); //write 1st page (unchanged)---------------------------------------- byte[] pageBytes = new byte[firstPage.PageLength + 27 + pageSegments]; raf.Read(pageBytes, 0, pageBytes.Length); rafTemp.Write(pageBytes, 0, pageBytes.Length); //rafTemp.Seek(firstPage.PageLength + raf.Position, SeekOrigin.Current); //------------------------------------------------------------------ //Read 2nd page----------------------------------------------------- long pos = raf.Position; raf.Seek(raf.Position + 26, SeekOrigin.Begin); pageSegments = raf.ReadByte()&0xFF; //Unsigned raf.Seek(pos, SeekOrigin.Begin); b = new byte[27 + pageSegments]; raf.Read(b, 0, b.Length); OggPageHeader secondPage = new OggPageHeader(b); long secondPageEndPos = raf.Position; //------------------------------------------------------------------ //Compute old comment length---------------------------------------- int oldCommentLength = 7; // [.vorbis] raf.Seek(raf.Position + 7, SeekOrigin.Begin); b = new byte[4]; raf.Read(b, 0, b.Length); int vendorstringLength = Utils.GetNumber(b, 0,3); oldCommentLength += 4 + vendorstringLength; raf.Seek(raf.Position + vendorstringLength, SeekOrigin.Begin); b = new byte[4]; raf.Read(b, 0, b.Length); int userComments = Utils.GetNumber(b, 0,3); oldCommentLength += 4; for (int i = 0; i < userComments; i++) { b = new byte[4]; raf.Read(b, 0, b.Length); int commentLength = Utils.GetNumber(b, 0,3); oldCommentLength += 4 + commentLength; raf.Seek(raf.Position + commentLength, SeekOrigin.Begin); } int isValid = raf.ReadByte(); oldCommentLength += 1; if (isValid != 1) throw new CannotWriteException("Unable to retreive old tag informations"); //------------------------------------------------------------------ //Get the new comment and create the container bytebuffer for 2nd page--- ByteBuffer newComment = tc.Convert(tag); int newCommentLength = newComment.Capacity; int newSecondPageLength = secondPage.PageLength - oldCommentLength + newCommentLength; byte[] segmentTable = CreateSegmentTable(oldCommentLength,newCommentLength,secondPage); int newSecondPageHeaderLength = 27 + segmentTable.Length; ByteBuffer secondPageBuffer = new ByteBuffer(newSecondPageLength + newSecondPageHeaderLength); //------------------------------------------------------------------ //Build the new second page header---------------------------------- //OggS capture secondPageBuffer.Put(Utils.GetBytes("OggS")); //Stream struct revision secondPageBuffer.Put((byte) 0); //header_type_flag secondPageBuffer.Put((byte) 0); //absolute granule position secondPageBuffer.Put( new byte[] { (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0 }); //stream serial number secondPageBuffer.Put(Utils.GetNumber(secondPage.SerialNumber)); //page sequence no secondPageBuffer.Put(Utils.GetNumber(secondPage.PageSequence)); //CRC (to be computed later) secondPageBuffer.Put(new byte[] {(byte) 0, (byte) 0, (byte) 0, (byte) 0 }); int crcOffset = 22; if (segmentTable.Length > 255) { throw new CannotWriteException ("In this special case we need to " + "create a new page, since we still hadn't the time for that " + "we won't write because it wouldn't create an ogg file."); } //page_segments nb. secondPageBuffer.Put((byte)segmentTable.Length); //page segment table for (int i = 0; i < segmentTable.Length; i++) secondPageBuffer.Put(segmentTable[i]); //------------------------------------------------------------------ //Add to the new second page the new comment------------------------ secondPageBuffer.Put(newComment); //------------------------------------------------------------------ //Add the remaining old second page (encoding infos, etc)----------- raf.Seek(secondPageEndPos+oldCommentLength, SeekOrigin.Begin); secondPageBuffer.Put(raf); //------------------------------------------------------------------ //Compute CRC over the new second page------------------------------ byte[] crc = OggCRCFactory.ComputeCRC(secondPageBuffer.Data); for (int i = 0; i < crc.Length; i++) { secondPageBuffer.Put(crcOffset + i, crc[i]); } //------------------------------------------------------------------ //Transfer the second page bytebuffer content----------------------- secondPageBuffer.Rewind(); rafTemp.Write(secondPageBuffer.Data, 0, secondPageBuffer.Data.Length); //------------------------------------------------------------------ //Write the rest of the original file------------------------------- byte[] buf = new byte[65536]; int read = raf.Read(buf, 0, buf.Length); while (read != 0) { rafTemp.Write(buf, 0, read); read = raf.Read(buf, 0, buf.Length); } //rafTemp.getChannel().transferFrom(raf.getChannel(), rafTemp.Position, raf.Length() - raf.Position); //------------------------------------------------------------------ }
protected override void Create(Tag tag, ByteBuffer buf, IList fields, int tagSize, int paddingSize) { //APETAGEX------------------ buf.Put(Utils.GetBytes("APETAGEX")); //Version 2.0 (aka 2000) buf.Put( new byte[] {(byte)0xD0,0x07,0x00,0x00} ); //Tag size int size = tagSize - 32; buf.Put(Utils.GetNumber(size)); //Number of fields int listLength = fields.Count; buf.Put(Utils.GetNumber(listLength)); //Flags buf.Put( new byte[] {0x00,0x00,0x00,(byte)0xA0} ); //means: We have a header and a footer, this is the header //Reserved 8-bytes 0x00 buf.Put( new byte[] {0,0,0,0,0,0,0,0} ); //Now each field is saved: foreach(byte[] field in fields) { buf.Put(field); } //APETAGEX------------------ buf.Put(Utils.GetBytes("APETAGEX")); //APETAGEX //Version 2.0 (aka 2000) buf.Put( new byte[] {(byte)0xD0,0x07,0x00,0x00} ); //Tag size buf.Put(Utils.GetNumber(size)); //Number of fields buf.Put(Utils.GetNumber(listLength)); //Flags buf.Put( new byte[] {0x00,0x00,0x00,(byte)0x80} ); //means: We have a header and a footer, this is the footer //Reserved 8-bytes 0x00 buf.Put( new byte[] {0,0,0,0,0,0,0,0} ); //---------------------------------------------------------------------------- }