/* * @(#)StreamParser * * Copyright (c) 2005-2006 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 * */ package net.sourceforge.dvb.projectx.parser; import java.io.File; import java.io.InputStream; import java.io.IOException; import java.io.PushbackInputStream; import java.io.RandomAccessFile; import java.io.ByteArrayOutputStream; import java.io.BufferedOutputStream; import java.io.FileOutputStream; import java.util.Arrays; import java.util.List; import java.util.ArrayList; import java.util.Hashtable; import java.util.Date; import java.util.TimeZone; import java.text.DateFormat; import java.text.SimpleDateFormat; import net.sourceforge.dvb.projectx.common.Common; import net.sourceforge.dvb.projectx.common.Resource; import net.sourceforge.dvb.projectx.common.Keys; import net.sourceforge.dvb.projectx.common.JobCollection; import net.sourceforge.dvb.projectx.common.JobProcessing; import net.sourceforge.dvb.projectx.xinput.XInputFile; import net.sourceforge.dvb.projectx.parser.CommonParsing; import net.sourceforge.dvb.projectx.parser.StreamConverter; import net.sourceforge.dvb.projectx.parser.StreamDemultiplexer; import net.sourceforge.dvb.projectx.parser.StreamProcessBase; import net.sourceforge.dvb.projectx.audio.AudioFormat; import net.sourceforge.dvb.projectx.io.IDDBufferedOutputStream; /** * main thread */ public class StreamProcessLPCMAudio extends StreamProcessBase { /** * */ public StreamProcessLPCMAudio(JobCollection collection, XInputFile xInputFile, String filename_pts, String filename_type, String videofile_pts, int isElementaryStream) { super(); processStream(collection, xInputFile, filename_pts, filename_type, videofile_pts, isElementaryStream); } /** * LPCM stream */ private void processStream(JobCollection collection, XInputFile xInputFile, String filename_pts, String filename_type, String videofile_pts, int isElementaryStream) { String fchild = collection.getOutputName(xInputFile.getName()); String fparent = collection.getOutputNameParent(fchild); JobProcessing job_processing = collection.getJobProcessing(); String pcmfile = fparent + (isElementaryStream == CommonParsing.ES_TYPE ? ".new": "") + ".wav"; byte[] parser = new byte[16]; byte[] packet = new byte[0xFFFF]; long size = xInputFile.length(); long count = 0; long startPoint = 0; long time_difference = 0; long source_pts = 0; long new_pts = 0; long first_pts = -1; long packet_pts = 0; long ModeChangeCount = 0; boolean vptsdata = false; boolean ptsdata = false; boolean write = false; boolean missing_syncword = false; boolean newformat = false; boolean debug = collection.getSettings().getBooleanProperty(Keys.KEY_DebugLog); boolean message_2 = collection.getSettings().getBooleanProperty(Keys.KEY_MessagePanel_Msg2); int samples = 0; int x = 0; int v = 0; int packetlength = 0; int parserlength = parser.length; AudioFormat LPCM_Audio = new AudioFormat(CommonParsing.LPCM_AUDIO); try { PushbackInputStream in = new PushbackInputStream(xInputFile.getInputStream(), 20); IDDBufferedOutputStream out = new IDDBufferedOutputStream( new FileOutputStream(pcmfile), 2048000); Common.setMessage(Resource.getString("lpcm.msg.develop")); Common.setMessage(Resource.getString("lpcm.msg.tmpfile", xInputFile.getName(), "" + size)); Common.updateProgressBar(Resource.getString("lpcm.progress") + " " + xInputFile.getName(), 0, 0); long[] ptsval = { 0 }; long[] ptspos = { 0 }; long[] vptsval = { 0 }; long[][] obj = loadTempVideoPts(videofile_pts, debug); if (obj != null) { vptsval = obj[0]; vptsdata = true; obj = null; } /*** * preloading audio PTS file is disabled, too big caused by too many PTS, will overload memory * pts is here inluded in each packet instead */ ptsdata = true; if (vptsdata && ptsdata) { //int jump = checkPTSMatch(vptsval, ptsval); //temp. check disabled int jump = 0; if (jump < 0) { Common.setMessage(Resource.getString("lpcm.msg.pts.mismatch")); vptsdata = false; x = 0; } else x = jump; } if (vptsdata && ptsdata) { Common.setMessage(Resource.getString("lpcm.msg.adjust.at.video")); time_difference = vptsval[0]; } if (!vptsdata && ptsdata) { Common.setMessage(Resource.getString("lpcm.msg.adjust.at.own")); time_difference = 0; } if (ptsdata) { source_pts = ptsval[x]; startPoint = ptspos[x]; } //don't need it anymore ptsval = null; ptspos = null; while (count < startPoint) count += in.skip(startPoint - count); out.write(LPCM_Audio.getRiffHeader()); //wav header readloop: while ( count < size ) { Common.updateProgressBar(count, size); //yield(); while (pause()) {} if (CommonParsing.isProcessCancelled()) { CommonParsing.setProcessCancelled(false); job_processing.setSplitSize(0); break readloop; } //special X header in.read(parser, 0, parserlength); // find "PCM" if (parser[0] != 0x50 || parser[1] != 0x43 || parser[2] != 0x4D) { if (message_2 && !missing_syncword) Common.setMessage(Resource.getString("lpcm.msg.syncword.lost") + " " + count); in.unread(parser, 1, parserlength - 1); missing_syncword = true; count++; continue readloop; } if (message_2 && missing_syncword) Common.setMessage(Resource.getString("lpcm.msg.syncword.found") + " " + count); missing_syncword = false; packet_pts = 0; packetlength = ((0xFF & parser[8])<<8 | (0xFF & parser[9])) - 6; // packetlength <= 0 not handled ! in.read(packet, 0, packetlength); count += parserlength; count += packetlength; // 5 bytes of packet pts, auslagern for (int a = 0; a < 5; a++) packet_pts |= (0xFFL & parser[3 + a])<<(a * 8); if (packet_pts != 0) source_pts = packet_pts; if (first_pts == -1) first_pts = source_pts; if (debug) System.out.println(" " + (count - packetlength) + "/ " + packetlength + "/ " + source_pts); if (LPCM_Audio.parseHeader(parser, 10) < 0) continue readloop; if (LPCM_Audio.compareHeader() > 0 || samples == 0 ) newformat = true; LPCM_Audio.saveHeader(); if (ptsdata) { write = !vptsdata; rangeloop: while (vptsdata && v < vptsval.length) //sample_start_pts must be in range ATM { if (source_pts < vptsval[v]) break rangeloop; else if (source_pts == vptsval[v] || source_pts < vptsval[v + 1]) { write = true; break rangeloop; } v += 2; if (v < vptsval.length) time_difference += (vptsval[v] - vptsval[v - 1]); } } else write = true; if (write) { new_pts = source_pts - time_difference; if (newformat) { if (ModeChangeCount < 100) Common.setMessage(Resource.getString("lpcm.msg.source", LPCM_Audio.displayHeader()) + " " + Common.formatTime_1( (long)(new_pts / 90.0f))); else if (ModeChangeCount == 100) Common.setMessage(Resource.getString("lpcm.msg.source.max")); ModeChangeCount++; newformat = false; //yield(); } Common.changeByteOrder(packet, 0, packetlength); if ((packetlength & 1) != 0) Common.setMessage(Resource.getString("lpcm.msg.error.align")); out.write(packet, 0, packetlength); samples++; Common.getGuiInterface().showExportStatus(Resource.getString("audio.status.write")); } else Common.getGuiInterface().showExportStatus(Resource.getString("audio.status.pause")); if (debug) System.out.println(" -> " + write + "/ " + v + "/ " + new_pts + "/ " + time_difference + "/ " + samples); Common.setFps(samples); } in.close(); out.flush(); out.close(); if (filename_pts.equals("-1") || ptsdata) Common.setMessage(Resource.getString("lpcm.msg.pts.start_end", Common.formatTime_1(first_pts / 90)) + " " + Common.formatTime_1(source_pts / 90)); Common.setMessage(Resource.getString("lpcm.msg.summary", " " + samples)); File pcmfile1 = new File(pcmfile); if (samples == 0) pcmfile1.delete(); else { long playtime = LPCM_Audio.fillRiffHeader(pcmfile); //update riffheader Common.setMessage(Resource.getString("msg.newfile") + " " + pcmfile); job_processing.countMediaFilesExportLength(pcmfile1.length()); job_processing.addSummaryInfo(Resource.getString("lpcm.summary", Common.adaptString(job_processing.countPictureStream(), 2), "" + samples, Common.formatTime_1(playtime)) + infoPTSMatch(filename_pts, videofile_pts, vptsdata, ptsdata) + "\t'" + pcmfile1 + "'"); } } catch (IOException e2) { Common.setExceptionMessage(e2); } } }