/* * @(#)IDDBufferedOutputStream.java - export * * Copyright (c) 2003-2008 by dvb.matt, All Rights Reserved. * * This file is part of ProjectX, a free Java based demux utility. * By the authors, ProjectX is intended for educational purposes only, * as a non-commercial test project. * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /** * cuttermaran info part from Arnaud * */ package net.sourceforge.dvb.projectx.io; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; import java.util.Arrays; import net.sourceforge.dvb.projectx.common.Common; import net.sourceforge.dvb.projectx.parser.CommonParsing; public class IDDBufferedOutputStream extends BufferedOutputStream { long pos = 0; int type = 0; String name = ""; String chaptersname = ""; boolean sequenceend = false; boolean chapters = false; boolean CreateAc3Wave = false; boolean CreateDtsWave = false; boolean CreateDts48Wave = false; byte[][] IddHeader = { { (byte)'i', (byte)'d', (byte)'d', 2 }, //video V2 { (byte)'i', (byte)'d', (byte)'d', 3 } //audio V3 }; /** * Lil' endian - header, one frame, length of this frame in bits */ byte[] DD_header = { 0x72, (byte)0xF8, 0x1F, 0x4E, 1, 0, 0, 0 }; byte[] padding_block = null; BufferedOutputStream IddOut = null; PrintWriter ChaptersOut = null; // cminfo ----- BEGIN ----- private String aInfoName = ""; private BufferedOutputStream aInfoOut = null; // --- cminfo --- private boolean aInfoSeqEnd = false; private BitWalker aBitWalker = null; private StringBuffer aStringBuffer = null; // cminfo ------ END ------ int filenumber = 1; /** * */ public IDDBufferedOutputStream(OutputStream out) { super(out); } /** * */ public IDDBufferedOutputStream(OutputStream out, int size) { super(out, size); } /** * */ public synchronized void write(byte b[], int off, int len) throws IOException { switch (type) { case 3: //vdrindex if ((0xF0 & b[off + 3]) != 0xE0) break; for (int a = off + 9 + (0xFF & b[8]), ret; a < off + len - 3; a++) { if ((ret = CommonParsing.validateStartcode(b, a)) < 0) { a += (-ret) - 1; continue; } if (b[a + 3] != 0) { a += 3; continue; } if (a + 5 >= off + len) break; int frametype = (7 & b[a + 5]>>>3); if (frametype == 0 || frametype > 3) break; IddOut.write(VdrIndex()); //pos IddOut.write(frametype); //type IddOut.write(filenumber); IddOut.write(new byte[2]); break; } break; case 1: //idd Video // cminfo ----- BEGIN ----- if (aInfoOut != null) { writeInfo(b, off, len); if (IddOut == null) break; } // cminfo ------ END ------ for (int a = off, ret; a < off + len - 3; a++) { if ((ret = CommonParsing.validateStartcode(b, a)) < 0) { a += (-ret) - 1; continue; } if ((0xFF & b[a + 3]) == 0xB3) { IddOut.write(0xB3); IddOut.write(littleEndian(a - off)); a += 12; } else if ((0xFF & b[a + 3]) == 0xB7) { IddOut.write(0xB7); IddOut.write(littleEndian(a - off)); sequenceend = true; a += 3; } else if ((0xFF & b[a + 3]) == 0xB8) { IddOut.write(0xB8); IddOut.write(littleEndian(a - off)); a += 7; } else if (b[a + 3] == 0) { IddOut.write(0); //type IddOut.write(littleEndian(a - off)); //pos int tref = (3 & b[a + 5]>>>6) | (0xFF & b[a + 4])<<2; IddOut.write(0xFF & tref); IddOut.write(tref>>>8); IddOut.write(7 & b[a + 5]>>>3); //pic a += 8; } } break; case 2: //idd audio if ( !(pos == 0 && b.length <= 0x50)) IddOut.write(littleEndian(0)); } /** * build new frame with header + padding */ if (CreateAc3Wave) { int bitlen = len<<3; DD_header[6] = (byte) (0xFF & bitlen); DD_header[7] = (byte) (0xFF & bitlen>>8); super.write(DD_header, 0, 8); // header pos += 8; Common.changeByteOrder(b, off, len); super.write(b, off, len); // the reversed frame super.write(padding_block, len, padding_block.length - len); // the padding zero's pos += padding_block.length; } /** * build new frame with padding */ else if (CreateDtsWave) { if (CreateDts48Wave) { int len_1 = len > 0x800 ? 0x1000 : 0x800; System.arraycopy(b, off, padding_block, 0, len); //copy frame Arrays.fill(padding_block, len, len_1 + 1, (byte)0); Common.changeByteOrder(padding_block, 0, len_1); super.write(padding_block, 0, len_1); // the reversed frame pos += len_1; } else { int j = 0; long val; for (int i = off, k = off + len; i < k; i += 7, j += 8) { val = CommonParsing.getValue(b, i, 7, !CommonParsing.BYTEREORDERING); padding_block[j] = (byte)(0xFF & val>>42); padding_block[j + 1] = (byte)((byte)(0xFC & val>>48)>>2); padding_block[j + 2] = (byte)(0xFF & val>>28); padding_block[j + 3] = (byte)((byte)(0xFC & val>>34)>>2); padding_block[j + 4] = (byte)(0xFF & val>>14); padding_block[j + 5] = (byte)((byte)(0xFC & val>>20)>>2); padding_block[j + 6] = (byte)(0xFF & val); padding_block[j + 7] = (byte)((byte)(0xFC & val>>6)>>2); } super.write(padding_block, 0, j); // the reversed frame pos += j; } } else { super.write(b, off, len); pos += len; } } /** * */ public synchronized void write(int b) throws IOException { super.write(b); pos++; } /** * */ public byte[] VdrIndex() { byte bpos[] = new byte[4]; for (int a = 0; a < 4; a++) bpos[a] = (byte)(0xFFL & pos>>>(a * 8)); return bpos; } /** * */ public void setWave(boolean b1, boolean b2, boolean b3, int val) throws IOException { if (!b1) return; CreateAc3Wave = b2; CreateDtsWave = b3; CreateDts48Wave = (CreateDtsWave && val > 1411200); if (padding_block == null) padding_block = new byte[0x17F8]; } /** * */ public void InitVdr(String vdrname, int file_number) throws IOException { name = vdrname; filenumber = file_number + 1; type = 3; IddOut = new BufferedOutputStream(new FileOutputStream(name, filenumber == 1 ? false : true), 655350); } /** * */ public String renameVdrTo(String parent, String oldName) { String num = "000" + filenumber + ".vdr"; String newName = parent + num.substring(num.length() - 7); File nname = new File(newName); File oname = new File(oldName); if (!oname.getName().equals(nname.getName()) && nname.exists()) nname.delete(); Common.renameTo(oname, nname); return newName; } /** * */ public byte[] littleEndian(int off) { byte bpos[] = new byte[8]; for (int a = 0; a < 8; a++) bpos[a] = (byte)(0xFFL & (pos + off)>>>(a * 8)); return bpos; } /** * */ public void InitIdd(String iddname, int iddtype) { try { name = iddname + ".id"; type = iddtype; IddOut = new BufferedOutputStream(new FileOutputStream(name), 655350); IddOut.write(IddHeader[type - 1]); } catch (IOException e) { Common.setExceptionMessage(e); } } /** * */ public void renameIddTo(File newName) { String str = newName.toString(); File nname = new File(str + ".idd"); File file = new File(str + ".m2s.txt"); if (newName.exists()) { if (nname.exists()) nname.delete(); if (new File(name).exists()) Common.renameTo(new File(name), nname); } else new File(name).delete(); if (chapters) { if (file.exists()) file.delete(); if (new File(chaptersname).exists()) Common.renameTo(new File(chaptersname), file); } } /** * */ public void renameVideoIddTo(String newName) { File nname = new File(newName + ".idd"); if (nname.exists()) nname.delete(); Common.renameTo(new File(name), nname); } /** * */ public void deleteIdd() { new File(name).delete(); new File(chaptersname).delete(); } /** * */ public void InitChapters(String filename) throws IOException { chaptersname = filename + ".chp"; chapters = true; ChaptersOut = new PrintWriter(new FileOutputStream(chaptersname)); } /** * */ public void addChapter(String str) throws IOException { if (!chapters) return; ChaptersOut.println(str); } /** * */ public synchronized void flush() throws IOException { super.flush(); } /** * */ public synchronized void close() throws IOException { if (chapters) { ChaptersOut.flush(); ChaptersOut.close(); } switch (type) { case 1: // cminfo ----- BEGIN ----- if (aInfoOut != null) { closeInfo(); if (IddOut == null) break; } // cminfo ------ END ------ if(!sequenceend) { IddOut.write(0xB7); IddOut.write(littleEndian(0)); } IddOut.flush(); IddOut.close(); IddOut = null; // cminfo break; case 2: IddOut.write(littleEndian(0)); case 3: IddOut.flush(); IddOut.close(); } super.close(); } // cminfo ----- BEGIN ----- /** * @param inpName * @throws IOException */ public void InitInfo(String inpName) throws IOException { aInfoName = inpName + ".info"; type = 1; aInfoOut = new BufferedOutputStream(new FileOutputStream(aInfoName), 655350); // ??? aInfoOut.write((byte)0xEF); aInfoOut.write((byte)0xBB); aInfoOut.write((byte)0xBF); StringBuffer tmpBuf = getStringBuffer(); tmpBuf.setLength(0); tmpBuf.append("<?xml version=\"1.0\" encoding=\"utf-8\"?><IndexContainer xmlns=\"http://www.cuttermaran.de\"><Version>1.61</Version>"); dumpInfo(tmpBuf); } /** * @param newName */ public void renameVideoInfoTo(String newName) { File nname = new File(newName + ".info"); if (nname.exists()) nname.delete(); Common.renameTo(new File(aInfoName), nname); // 2 Minuten - 120000ms (?) f�r CM dazuschummeln ;-) nname.setLastModified(nname.lastModified() + 120000); } private void dumpInfo(StringBuffer inpBuf) throws IOException { int len = (inpBuf == null) ? 0 : inpBuf.length(); for (int i = 0; i < len; i++) // for i aInfoOut.write((byte) inpBuf.charAt(i)); } /** * @throws IOException */ private synchronized void closeInfo() throws IOException { StringBuffer tmpBuf = getStringBuffer(); tmpBuf.setLength(0); if (!aInfoSeqEnd) { tmpBuf.append("<SeqEnd adr=\""); tmpBuf.append(pos); tmpBuf.append('\"'); tmpBuf.append(" />"); } tmpBuf.append("</IndexContainer>"); dumpInfo(tmpBuf); aInfoOut.flush(); aInfoOut.close(); aInfoOut = null; aInfoSeqEnd = false; setBitWalker(null); setStringBuffer(null); } /** * */ public void deleteInfo() { new File(aInfoName).delete(); } /** * Write .info for CM * * @param b * @param off * @param len * @throws IOException */ private synchronized void writeInfo(byte b[], int off, int len) throws IOException { if (aInfoOut == null) return; for (int a = off, ret; a < off + len - 3; a++) { if ((ret = CommonParsing.validateStartcode(b, a)) < 0) { a += (-ret) - 1; continue; } StringBuffer tmpBuf; if ((0xFF & b[a + 3]) == 0xB3) { int ratio = 0xF & b[a + 7] >>> 4; tmpBuf = getStringBuffer(); tmpBuf.setLength(0); tmpBuf.append("<Seq adr=\""); tmpBuf.append(pos + a - off); tmpBuf.append('\"'); tmpBuf.append(" ratio=\""); tmpBuf.append(ratio); tmpBuf.append('\"'); tmpBuf.append(" />"); dumpInfo(tmpBuf); a += 12; } else if ((0xFF & b[a + 3]) == 0xB7) { tmpBuf = getStringBuffer(); tmpBuf.setLength(0); tmpBuf.append("<SeqEnd adr=\""); tmpBuf.append(pos + a - off); tmpBuf.append('\"'); tmpBuf.append(" />"); dumpInfo(tmpBuf); aInfoSeqEnd = true; a += 3; } else if ((0xFF & b[a + 3]) == 0xB8) { tmpBuf = getStringBuffer(); tmpBuf.setLength(0); tmpBuf.append("<GOP adr=\""); tmpBuf.append(pos + a - off); tmpBuf.append('\"'); tmpBuf.append(" />"); dumpInfo(tmpBuf); a += 7; } else if (b[a + 3] == 0) { tmpBuf = getStringBuffer(); tmpBuf.setLength(0); tmpBuf.append("<Pic adr=\""); tmpBuf.append(pos + a - off); tmpBuf.append('\"'); int tref = (3 & b[a + 5] >>> 6) | (0xFF & b[a + 4]) << 2; tmpBuf.append(" tempRef=\""); tmpBuf.append(tref); tmpBuf.append('\"'); int typ = 7 & b[a + 5] >>> 3; tmpBuf.append(" type=\""); tmpBuf.append(typ); tmpBuf.append('\"'); // picture_structure BitWalker tmpWalker = getBitWalker(); tmpWalker.setBuf(b, a + 3); int struct = tmpWalker.getPictureStructure(true); if (struct != BitWalker.FRAME_PICTURE) { tmpBuf.append(" struct=\""); tmpBuf.append(struct); tmpBuf.append('\"'); } tmpBuf.append(" />"); dumpInfo(tmpBuf); a += 8; } } // for a } private BitWalker getBitWalker() { if (aBitWalker == null) aBitWalker = new BitWalker(); return aBitWalker; } private void setBitWalker(BitWalker inpBitWalker) { aBitWalker = inpBitWalker; } private StringBuffer getStringBuffer() { if (aStringBuffer == null) aStringBuffer = new StringBuffer(); return aStringBuffer; } private void setStringBuffer(StringBuffer inpStringBuffer) { aStringBuffer = inpStringBuffer; } // cminfo ------ END ------ }