/*
* @(#)StreamParserAudio
*
* Copyright (c) 2005-2009 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.io.IDDBufferedOutputStream;
import net.sourceforge.dvb.projectx.audio.MpaDecoder;
import net.sourceforge.dvb.projectx.audio.AudioFormat;
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;
/**
* main thread
*/
public class StreamProcessAudio extends StreamProcessBase {
private final int AC3_AUDIOSTREAM = 0;
private final int MP3_AUDIOSTREAM = 1;
private final int MP2_AUDIOSTREAM = 2;
private final int MP1_AUDIOSTREAM = 3;
private final int DTS_AUDIOSTREAM = 4;
private final int WAV_AUDIOSTREAM = 5;
private final int AAC_AUDIOSTREAM = 6;
private final int NO_AUDIOSTREAM = 10;
private MpaDecoder MPADecoder = null;
private PushbackInputStream InputStream;
private IDDBufferedOutputStream OutputStream_Ch1;
private IDDBufferedOutputStream OutputStream_Ch2;
private String FileName_Ch1;
private String FileName_Ch2;
private boolean HasNewFormat;
private boolean Debug;
private boolean CreateChapters;
private boolean WriteEnabled;
private boolean AddWaveHeaderACM;
private boolean AddWaveHeaderBWF;
private boolean AddWaveHeaderAC3;
private boolean DecodeMpgAudio;
private boolean AC3_ReplaceWithSilence;
private boolean AC3_Patch1stHeader;
private boolean AC3_BitrateAdaption;
private boolean ContainsVideoPTS;
private boolean ContainsAudioPTS;
private boolean CreateM2sIndex;
private boolean Message_2;
private boolean Message_7;
private boolean PitchAudio;
private boolean AllowSpaces;
private boolean ValidateCRC;
private boolean FillGapsWithLastFrame;
private boolean LimitPts;
private boolean AllowFormatChanges;
private boolean AddFrames;
private boolean DownMix;
private boolean ChangeByteorder;
private boolean AddRiffHeader;
private boolean AddAiffHeader;
private boolean ClearCRC;
private boolean IgnoreErrors;
private boolean CreateDDWave;
private boolean FadeInOut;
private boolean Normalize;
private boolean RenameAudio;
private int FadeInOutMillis;
private int ResampleAudioMode;
private int PitchValue;
private int AudioType;
private long ModeChangeCount;
private long ModeChangeCount_JSS;
private final long ModeChangeCount_Max = 100;
private FrameExportInfo FrameExportInfo;
private int MpaConversionMode;
private final int MpaConversion_None = 0;
private final int MpaConversion_Mode1 = 1; //single to 3D
private final int MpaConversion_Mode2 = 2; //single to jst
private final int MpaConversion_Mode3 = 3; //single to st
private final int MpaConversion_Mode4 = 4; //st-dual to 2 single
private final int MpaConversion_Mode5 = 5; //st-dual to 2 jst - doubled single
private final int MpaConversion_Mode6 = 6; //auto-dual to 2 jst - doubled single
private long FileLength;
private final long FileLength_Min = 100;
private double TimeCounter;
private long FramePosition;
private long CurrentFramePosition;
private long TimePosition;
private String str_wav = ".wav";
private String str_ac3 = ".ac3";
private String str_mpa = ".mpa";
private String str_mp1 = ".mp1";
private String str_mp2 = ".mp2";
private String str_mp3 = ".mp3";
private String str_mp4 = ".mp4";
private String str_dts = ".dts";
private String str_aif = ".aif";
private String str_pcm = ".pcm";
private String str_new = ".new";
private String str_aac = ".aac";
/**
*
*/
public StreamProcessAudio(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);
}
/**
* start method for adjusting audio at TimePosition
*/
private void processStream(JobCollection collection, XInputFile xInputFile, String filename_pts, String filename_type, String videofile_pts, int isElementaryStream)
{
Common.updateProgressBar(Resource.getString("audio.progress") + " " + xInputFile.getName(), 0, 0);
Normalize = collection.getSettings().getBooleanProperty(Keys.KEY_AudioPanel_Normalize);
DecodeMpgAudio = collection.getSettings().getBooleanProperty(Keys.KEY_AudioPanel_decodeMpgAudio);
if (MPADecoder == null)
MPADecoder = new MpaDecoder();
MpaDecoder.RESET = false;
MpaDecoder.MAX_VALUE = Normalize ? (Integer.parseInt(collection.getSettings().getProperty(Keys.KEY_AudioPanel_NormalizeValue)) * 32767 / 100) : 32767;
MpaDecoder.MULTIPLY = Normalize ? 32767 : 1;
MpaDecoder.NORMALIZE = Normalize;
MpaDecoder.PRESCAN = MpaDecoder.NORMALIZE;
//
MpaDecoder.LEVELSCAN = false;
//
if (MpaDecoder.MAX_VALUE > 32767)
{
MpaDecoder.MAX_VALUE = 32767;
Common.setMessage(Resource.getString("audio.msg.normalize.fixed") + " 100%");
}
/**
* messages
*/
MpaConversionMode = collection.getSettings().getIntProperty(Keys.KEY_AudioPanel_losslessMpaConversionMode);
if (MpaConversionMode > MpaConversion_None)
Common.setMessage(Resource.getString("audio.convert") + " " + Keys.ITEMS_losslessMpaConversionMode[MpaConversionMode]);
if (DecodeMpgAudio)
{
Common.setMessage(Resource.getString("audio.decode"));
Common.setMessage("-> " + Keys.ITEMS_resampleAudioMode[collection.getSettings().getIntProperty(Keys.KEY_AudioPanel_resampleAudioMode)]);
if (Normalize)
Common.setMessage("-> " + Resource.getString(Keys.KEY_AudioPanel_Normalize[0]) + " " + (100 * MpaDecoder.MAX_VALUE / 32767) + "%");
if (collection.getSettings().getBooleanProperty(Keys.KEY_AudioPanel_Downmix))
Common.setMessage("-> " + Resource.getString(Keys.KEY_AudioPanel_Downmix[0]));
if (collection.getSettings().getBooleanProperty(Keys.KEY_AudioPanel_fadeInOut))
Common.setMessage("-> " + Resource.getString(Keys.KEY_AudioPanel_fadeInOut[0]));
if (collection.getSettings().getBooleanProperty(Keys.KEY_AudioPanel_changeByteorder))
Common.setMessage("-> " + Resource.getString(Keys.KEY_AudioPanel_changeByteorder[0]));
if (collection.getSettings().getBooleanProperty(Keys.KEY_AudioPanel_addRiffHeader))
Common.setMessage("-> " + Resource.getString(Keys.KEY_AudioPanel_addRiffHeader[0]));
if (collection.getSettings().getBooleanProperty(Keys.KEY_AudioPanel_addAiffHeader))
Common.setMessage("-> " + Resource.getString(Keys.KEY_AudioPanel_addAiffHeader[0]));
}
/**
* restart loop
*/
while (processAudio(collection, xInputFile, filename_pts, filename_type, videofile_pts, isElementaryStream))
{
CommonParsing.setAudioProcessingFlags(CommonParsing.getAudioProcessingFlags() & ~0xCL);
Common.setMessage(" ");
Common.setMessage(Resource.getString("audio.restart") + " " + ((CommonParsing.getAudioProcessingFlags()>>>18) - 1));
if (DecodeMpgAudio && Normalize)
Common.setMessage("-> normalize: multiply factor: " + MpaDecoder.MULTIPLY);
if ( (0x10000L & CommonParsing.getAudioProcessingFlags()) != 0)
MpaConversionMode = MpaConversion_None;
}
CommonParsing.setAudioProcessingFlags(CommonParsing.getAudioProcessingFlags() & 3L);
}
/**
* method for audio processing
*/
private boolean processAudio(JobCollection collection, XInputFile xInputFile, String filename_pts, String filename_type, String videofile_pts, int isElementaryStream)
{
String fchild = isElementaryStream == CommonParsing.ES_TYPE ? collection.getOutputName(xInputFile.getName()) : xInputFile.getName();
String fparent = collection.getOutputNameParent(fchild);
Common.getGuiInterface().showAVOffset(Resource.getString("MainPanel.AudioVideoOffset"));
Common.getGuiInterface().showExportStatus(Resource.getString("MainPanel.nonVideoExportStatus"));
JobProcessing job_processing = collection.getJobProcessing();
if (isElementaryStream == CommonParsing.ES_TYPE && job_processing.getSplitSize() > 0)
fparent += "(" + job_processing.getSplitPart() + ")";
FileName_Ch1 = fparent + ".$mpL$";
FileName_Ch2 = fparent + ".$mpR$";
getSettings(collection);
boolean insertSilenceLoop = false;
boolean preloop = true;
boolean missing_syncword = false;
boolean is_DTS = false;
boolean is_AC3 = false;
ContainsAudioPTS = false;
ContainsVideoPTS = false;
HasNewFormat = true;
WriteEnabled = false;
byte[] header_copy = new byte[4];
byte[][] newframes = new byte[2][1];
byte[][] copyframe= new byte[2][1];
byte[] silent_Frame = new byte[0];
byte[] pushback = new byte[10];
byte[] frame = new byte[1];
byte[] pushmpa = new byte[4];
byte[] push24 = new byte[24];
long[] ptsval = {0};
long[] ptspos = {0};
long[] vptsval = {0};
long[] vtime = {0};
long[] insertion_counter = new long[2];
String audio_type[] = { "(ac3)", "(mp3)", "(mp2)", "(mp1)", "(dts)", "(pcm)" };
String tmp_str = null;
setFramePosition(0);
setCurrentFramePosition(0);
setTimePosition(0);
setTimeCounter(0.0);
ModeChangeCount = 0;
ModeChangeCount_JSS = 0;
FileLength = 0;
int pitch[] = { 1, PitchValue };
int minSync = 0;
FrameExportInfo = new FrameExportInfo();
AudioType = -1;
int x = 0;
int smpte_offs = 0;
int[] video_timeIndex = new int[4];
int layer = 0;
int returncode = 0;
int es_streamtype = determineStreamType(filename_type);
/**
* pre-init audioparser
*/
AudioFormat audio = new AudioFormat(es_streamtype);
/**
* pre-check for toggling ac3<->dts, or mpa<->aac
*/
AudioFormat test_audio;
if (es_streamtype != CommonParsing.MPEG_AUDIO)
test_audio = new AudioFormat(CommonParsing.DTS_AUDIO);
else
test_audio = new AudioFormat(CommonParsing.AAC_AUDIO);
try {
//System.gc();
long[][] obj = loadTempOtherPts(filename_pts, "audio.msg.pts.discard", "audio.msg.pts.firstonly", "audio.msg.pts.start_end", "", 0, IgnoreErrors, Debug);
if (obj != null)
{
ptsval = obj[0];
ptspos = obj[1];
ContainsAudioPTS = true;
obj = null;
}
obj = loadTempVideoPts(videofile_pts, Debug);
if (obj != null)
{
vptsval = obj[0];
vtime = obj[1];
ContainsVideoPTS = true;
obj = null;
}
//System.gc();
FileLength = xInputFile.length();
long[] addf = { 0, 0 };
if (FileLength < 1000)
Common.setMessage(" Filesize < 1000 byte");
initInputStream(xInputFile);
initOutputStreams();
initProjectFiles();
ByteArrayOutputStream silentFrameBuffer = new ByteArrayOutputStream();
// check pts matching area
if (ContainsVideoPTS && ContainsAudioPTS)
{
int jump = checkPTSMatch(vptsval, ptsval);
if (jump < 0)
{
Common.setMessage(Resource.getString("audio.msg.pts.mismatch"));
ContainsVideoPTS = false;
x = 0;
}
else
x = jump;
}
// processing with or without video-main-pts
if (ContainsVideoPTS)
Common.setMessage(Resource.getString("audio.msg.adjust.at.videopts"));
else if (ContainsAudioPTS && isElementaryStream != CommonParsing.ES_TYPE)
Common.setMessage(Resource.getString("audio.msg.adjust.at.ownpts"));
// the index to start with processing
if (ContainsAudioPTS)
{
setTimePosition(ptsval[x]);
setFramePosition(ptspos[x]);
}
if (getFramePosition() > 0)
skipInputStream(getFramePosition());
//init extra wave header
audio.initExtraWaveHeader(AddWaveHeaderACM, AddWaveHeaderBWF, AddWaveHeaderAC3);
// add preceding wave header
addWaveHeader(audio, es_streamtype);
// main loop
// while ((returncode = processData(audio, es_streamtype) < 0)
// {}
bigloop:
while (true)
{
// init FFT/window for mpa decoding for 1 file
initDecoder(audio, es_streamtype);
// init decoding of ancillary data
audio.setAncillaryDataDecoder(Message_7, Debug);
/**
* PCM Audio
*/
if (es_streamtype == CommonParsing.LPCM_AUDIO)
{
processPCMData(job_processing, audio, vptsval, ptsval);
break bigloop;
}
/**
* AC-3/DTS Audio
*/
readloopdd:
while ((es_streamtype == CommonParsing.AC3_AUDIO || es_streamtype == CommonParsing.DTS_AUDIO) && getFramePosition() < FileLength - 10)
{
Common.updateProgressBar(getFramePosition(), FileLength);
if (Debug)
System.out.println("\n FramePosition " + getFramePosition());
while (pause())
{}
if (isCancelled(job_processing))
break bigloop;
/**
* updates global audio_error and framecounter variable
*/
CommonParsing.setAudioProcessingFlags((0x3FFFFL & CommonParsing.getAudioProcessingFlags()) | ((long)FrameExportInfo.getWrittenFrames())<<18);
/**
* fix VBR & restart processing
*/
if ((0xCL & CommonParsing.getAudioProcessingFlags()) != 0)
{
closeInputStream();
closeOutputStreams();
return true;
}
if (ptspos[x + 1] != -1 && getFramePosition() > ptspos[x + 1])
{
Common.setMessage(Resource.getString("audio.msg.pts.wo_frame") + " (" + ptspos[x + 1] + "/" + getFramePosition() + ")");
x++;
}
/**
* read 10 bytes for headercheck
*/
countFramePosition(readInputStream(pushback, 0, 10));
/**
* parse header
*/
ERRORCODE = (is_AC3 || !is_DTS) ? audio.parseHeader(pushback, 0) : 0;
if (ERRORCODE < 1)
{
if (!is_AC3 || is_DTS)
ERRORCODE = test_audio.parseHeader(pushback, 0);
if (ERRORCODE < 1)
{
unreadInputStream(pushback, 1, 9);
if (Message_2 && !missing_syncword)
Common.setMessage(Resource.getString("audio.msg.syncword.lost", " " + (getFramePosition() - 10)) + " " + formatFrameTime(getTimeCounter()));
missing_syncword = true;
countFramePosition(-9);
continue readloopdd;
}
is_DTS = true;
is_AC3 = false;
//set special type
es_streamtype = CommonParsing.DTS_AUDIO;
audio = new AudioFormat(es_streamtype);
audio.parseHeader(pushback, 0);
}
else
{
is_DTS = false;
is_AC3 = true;
}
OutputStream_Ch1.setWave(CreateDDWave, is_AC3, is_DTS, audio.getBitrate());
/**
* prepare fo read entire frame
*/
countFramePosition(-unreadInputStream(pushback, 0, 10));
/**
* read entire frame
*/
if (frame.length != audio.getSize())
frame = new byte[audio.getSize()];
readInputStream(frame, 0, audio.getSize());
/**
* startfileposition of current frame
*/
setCurrentFramePosition(getFramePosition());
/**
* expected position for following frame
*/
countFramePosition(audio.getSize());
if (PitchAudio)
{ // skip a frame
if (pitch[1] * pitch[0] == FrameExportInfo.getWrittenFrames())
{
Common.setMessage(Resource.getString("audio.msg.frame.discard") + " " + FrameExportInfo.getWrittenFrames() + " (" + pitch[0] + ")");
pitch[0]++;
continue readloopdd;
}
}
/**
* finish loop if last frame in file is shorter than nominal size
*/
if ( getFramePosition() > FileLength )
break readloopdd;
/**
* read following frame header, not if it is the last frame
* check following frameheader for valid , if not starting with next byte
*/
smpte_offs = 0;
if (getFramePosition() < FileLength - 10)
{
//int d = 0;
if (!AllowSpaces)
{
readInputStream(push24, 0, 24);
miniloop:
for (; smpte_offs < (is_DTS ? 15 : 17); smpte_offs++)
{ //smpte
ERRORCODE = audio.parseNextHeader(push24, smpte_offs);
if (ERRORCODE > 0)
break miniloop;
}
unreadInputStream(push24, 0, 24);
}
if (ERRORCODE < 1)
{
unreadInputStream(frame, 1, frame.length - 1);
setFramePosition(getCurrentFramePosition() + 1);
continue readloopdd;
}
else
{
AudioType = is_DTS ? DTS_AUDIOSTREAM : AC3_AUDIOSTREAM;
// read for unread option when CRC fails
readInputStream(push24, 0, smpte_offs);
countFramePosition(smpte_offs);
}
}
if (ValidateCRC && (ERRORCODE = audio.validateCRC(frame, 2, audio.getSize())) != 0 )
{
Common.setMessage(Resource.getString("audio.msg.crc.error", "" + ERRORCODE) + " " + getCurrentFramePosition());
//dont apply smpte pre-read when an error occurs
if (smpte_offs > 0)
unreadInputStream(push24, 0, smpte_offs);
unreadInputStream(frame, 2, frame.length - 2);
setFramePosition(getCurrentFramePosition() + 2);
continue readloopdd;
}
if (Message_2 && missing_syncword)
Common.setMessage(Resource.getString("audio.msg.syncword.found") + " " + getCurrentFramePosition());
missing_syncword = false;
/**
* check for change in frametype
*/
determineFormatChange(audio, es_streamtype);
audio.saveHeader();
frame = getReplacementFrame(audio, frame, es_streamtype);
// TimePosition ist hier aktuelle audiopts
Common.setFps(FrameExportInfo.getWrittenFrames());
/**
* preloop if audio starts later than video, and i must insert
*/
if ( (preloop && video_timeIndex[0] >= vptsval.length) || !( preloop && ContainsVideoPTS && vptsval[video_timeIndex[0]] < getTimePosition() - (audio.getFrameTimeLength() / 2.0) ) )
preloop=false;
else
{
/**
* patch ac-3 to 3/2
*/
if (!is_DTS && AC3_Patch1stHeader && FrameExportInfo.getWrittenFrames() == 0)
frame = audio.editFrame(frame, 1);
long precount = vptsval[video_timeIndex[0]];
insertion_counter[0] = (long) getTimeCounter();
insertion_counter[1] = 0;
silentFrameBuffer.reset();
/**
* insert silence ac3
*/
if (!is_DTS && !FillGapsWithLastFrame)
{
for (int c = 0; c < Common.getAC3list().size(); c++)
{
byte[] ac3data = (byte[]) Common.getAC3list().get(c);
if ( (0xFE & ac3data[4]) != (0xFE & frame[4]) || ( (7 & ac3data[5]) != (7 & frame[5]) ) || (0xE0&ac3data[6])!=(0xE0&frame[6]) )
continue;
//
ac3data = audio.editFrame(ac3data, 4);
silentFrameBuffer.write(ac3data);
break;
}
}
else
silentFrameBuffer.write(frame);
/**
* pre inserting
*/
while (precount < getTimePosition() - (audio.getFrameTimeLength() / 2.0))
{
/**
* check if frame write should paused
*/
if (ContainsVideoPTS && video_timeIndex[1] < vptsval.length)
{
sync_value_1 = (double) (precount - vptsval[video_timeIndex[1] + 1]);
sync_value_2 = (double) (getTimeCounter() - vtime[video_timeIndex[1] + 1]);
if ((double) Math.abs(sync_value_2) <= audio.getFrameTimeLength() / 2.0 )
{
WriteEnabled = false;
video_timeIndex[1] += 2;
}
else if ((double) Math.abs(sync_value_1) <= audio.getFrameTimeLength() / 2.0 )
{
WriteEnabled = false;
video_timeIndex[1] += 2;
}
}
/**
* calculate A/V Offset for true
*/
if (ContainsVideoPTS && (video_timeIndex[0] < vptsval.length))
{
sync_value_3 = precount - vptsval[video_timeIndex[0]];
sync_value_4 = getTimeCounter() - vtime[video_timeIndex[0]];
if (Debug)
System.out.println(" �" + sync_value_3 + "/" + sync_value_4 + "/" + (sync_value_4 - sync_value_3));
if (!WriteEnabled && (double) Math.abs((getTimeCounter() - vtime[video_timeIndex[0]]) - (precount - vptsval[video_timeIndex[0]])) <= (double) audio.getFrameTimeLength() / 2.0 )
{
WriteEnabled = true;
video_timeIndex[0] += 2;
sync_value_1 = precount - vptsval[video_timeIndex[0] - 2];
sync_value_2 = getTimeCounter() - vtime[video_timeIndex[0] - 2];
Common.getGuiInterface().showAVOffset("" + (int)(sync_value_1 / 90) + "/" + (int)(sync_value_2 / 90) + "/" + (int)((sync_value_2 - sync_value_1) / 90));
if (Debug)
System.out.println(" �" + sync_value_1 + "/" + sync_value_2 + "/" + (sync_value_2 - sync_value_1));
}
}
/**
* calculate A/V Offset for true
*/
if ((video_timeIndex[0] < vptsval.length) )
{
if ((double) Math.abs(vptsval[video_timeIndex[0]] - precount) <= ((double) audio.getFrameTimeLength() / 2.0) )
{
WriteEnabled = true;
video_timeIndex[0] += 2;
sync_value_1 = precount - vptsval[video_timeIndex[0] - 2];
sync_value_2 = getTimeCounter() - vtime[video_timeIndex[0] - 2];
Common.getGuiInterface().showAVOffset("" + (int)(sync_value_1 / 90) + "/" + (int)(sync_value_2 / 90) + "/" + (int)((sync_value_2 - sync_value_1) / 90));
if (Debug)
System.out.println(" �" + sync_value_1 + "/" + sync_value_2 + "/" + (sync_value_2 - sync_value_1));
}
/**
* calculate A/V Offset for false
*/
if (WriteEnabled && (double) Math.abs((getTimeCounter() - vtime[video_timeIndex[0] - 2]) - (precount - vptsval[video_timeIndex[0]-2])) > (double) audio.getFrameTimeLength() / 2.0 )
{
WriteEnabled = false;
video_timeIndex[0] -= 2;
}
}
/**
* write message
*/
Common.getGuiInterface().showExportStatus((WriteEnabled || !ContainsVideoPTS) ? Resource.getString("audio.status.pre-insert") : Resource.getString("audio.status.pause"));
/**
* stop if no more audio needed
*/
if (!checkLastAudioBound(ContainsVideoPTS, precount, vptsval, FileLength))
break readloopdd;
if (WriteEnabled)
{
writeFrame(audio, silentFrameBuffer.toByteArray(), newframes, ContainsVideoPTS, es_streamtype);
FrameExportInfo.countPreInsertedFrames(1);
insertion_counter[1]++;
}
precount += audio.getFrameTimeLength();
if (Debug)
System.out.println(FrameExportInfo.getSummary() + " @ " + formatFrameTime(getTimeCounter()) + " ");
} // end while
setFramePosition(getCurrentFramePosition());
unreadInputStream(frame, 0, frame.length);
if (insertion_counter[1] > 0)
Common.setMessage(Resource.getString("audio.msg.summary.pre-insert", "" + insertion_counter[1], FramesToTime((int)insertion_counter[1], audio.getFrameTimeLength())) + " " + formatFrameTime(insertion_counter[0]));
continue readloopdd;
} // end if preloop
/**
* check if frame write should pause
*/
if (ContainsVideoPTS)
WriteEnabled = SyncCheck(video_timeIndex, getTimeCounter(), audio.getFrameTimeLength(), getTimePosition(), FrameExportInfo.getWrittenFrames(), vptsval, vtime, WriteEnabled, Debug, "ac3-1");
/**
* message
*/
Common.getGuiInterface().showExportStatus((WriteEnabled || !ContainsVideoPTS) ? Resource.getString("audio.status.write") : Resource.getString("audio.status.pause"));
if (Debug)
System.out.println(" k)" + getTimePosition() + " l)" + (audio.getFrameTimeLength() / 2.0) + " u)" + audio.getSize() + " m)" + WriteEnabled + " FramePosition)"+video_timeIndex[1]+" o)"+video_timeIndex[0]+" p)"+ getFramePosition());
/**
* stop if no more audio needed
*/
if (!checkLastAudioBound(ContainsVideoPTS, getTimePosition(), vptsval, FileLength))
break readloopdd;
/**
* message
*/
messageSourceFormat(job_processing, audio, ContainsVideoPTS, getTimeCounter());
/**
* remove CRC, unused
*/
audio.removeCRC(frame, ClearCRC);
/**
* patch ac-3 to 3/2
*/
if (!is_DTS && AC3_Patch1stHeader && FrameExportInfo.getWrittenFrames() == 0)
frame = audio.editFrame(frame, 1);
if (Debug)
{
System.out.println(FrameExportInfo.getSummary() + " @ " + formatFrameTime(getTimeCounter()));
System.out.println(" x" + ((x < ptspos.length - 1) ? x + "/" + ptsval[x + 1] + "/" + ptspos[x + 1] : "-"));
}
// end pts of this, start pts for next frame!!
countTimePosition(audio.getFrameTimeLength());
silentFrameBuffer.reset();
silentFrameBuffer.write(frame);
//simple sync
if (LimitPts && ptspos[x + 1] != -1 && ptspos[x + 1] < getFramePosition())
{
if (Debug)
System.out.println(" minSync " + minSync + "/ " + x);
if ( (++minSync) < 20)
x++;
else
minSync = 0;
}
// frame is in last pes packet or packet end not yet reached
// normal condition
if (writeSuccessiveFrame(audio, frame, newframes, ContainsVideoPTS, getFramePosition(), ptspos, x, es_streamtype))
continue readloopdd;
minSync = 0;
// frame is on pes packet corner
// less than a half of frame time to packet end, so write it and count to next index
if ((double) Math.abs(ptsval[x + 1] - getTimePosition()) < (audio.getFrameTimeLength() / 2.0))
{
setTimePosition(ptsval[++x]);
writeFrame(audio, frame, newframes, ContainsVideoPTS, es_streamtype);
insertion_counter[0] = (long) getTimeCounter();
insertion_counter[1] = 0;
// check sync after resetting
if (Math.abs(video_timeIndex[2]) >= (audio.getFrameTimeLength() / 2.0) || Math.abs(video_timeIndex[3]) >= (audio.getFrameTimeLength() / 2.0))
{
// 1 zus�tzl. frame einf�gen
if (video_timeIndex[2] < 0 || video_timeIndex[3] < 0)
{
// gui message
Common.getGuiInterface().showExportStatus((WriteEnabled || !ContainsVideoPTS) ? Resource.getString("audio.status.insert") : Resource.getString("audio.status.pause"));
if (!ContainsVideoPTS || (ContainsVideoPTS && WriteEnabled))
{
Common.setMessage("!> A/V sync discontinuity in next audio packet @ " + formatFrameTime(getTimeCounter()));
writeFrame(audio, frame, newframes, ContainsVideoPTS, es_streamtype);
FrameExportInfo.countInsertedFrames(1);
insertion_counter[1]++;
Common.setMessage(Resource.getString("audio.msg.summary.insert", "" + insertion_counter[1], FramesToTime((int)insertion_counter[1], audio.getFrameTimeLength())) + " " + formatFrameTime(insertion_counter[0]));
}
/** else // a-v async in schnittpause
{
countTimeCounter(-audio.getFrameTimeLength());
Common.setMessage("!> A/V sync discontinuity in next audio packet @ " + formatFrameTime(getTimeCounter()));
Common.setMessage(Resource.getString("audio.msg.summary.skip") + " " + formatFrameTime(getTimeCounter()));
}
**/
if (Debug)
{
System.out.println(FrameExportInfo.getSummary() + " @ " + formatFrameTime(getTimeCounter()));
System.out.println("tl: " + getTimePosition() + " x" + ((x < ptspos.length - 1) ? x + "/" + ptsval[x + 1] + "/" + ptspos[x + 1] : "-"));
}
}
}
continue readloopdd;
}
if (ptsval[x + 1] > getTimePosition())
insertSilenceLoop = true;
if (ptsval[x + 1] < getTimePosition())
{
setTimePosition(ptsval[++x]);
Common.setMessage(Resource.getString("audio.msg.summary.skip") + " " + formatFrameTime(getTimeCounter()));
FrameExportInfo.countSkippedFrames(1);
}
if (insertSilenceLoop)
{
writeFrame(audio, frame, newframes, ContainsVideoPTS, es_streamtype);
countTimePosition(audio.getFrameTimeLength());
/**
* insert silence ac3
*/
if (!is_DTS && !FillGapsWithLastFrame)
{
for (int c = 0; c < Common.getAC3list().size(); c++)
{
byte[] ac3data = (byte[]) Common.getAC3list().get(c);
if ( (0xFE & ac3data[4]) != (0xFE & frame[4]) || ( (7 & ac3data[5]) != (7 & frame[5]) ) || (0xE0 & ac3data[6]) != (0xE0 & frame[6]) )
continue;
silentFrameBuffer.reset();
//
ac3data = audio.editFrame(ac3data, 4);
silentFrameBuffer.write(ac3data);
break;
}
}
insertion_counter[0] = (long) getTimeCounter();
insertion_counter[1] = 0;
//
// check a+v sync
if (ContainsVideoPTS)
WriteEnabled = SyncCheck(video_timeIndex, getTimeCounter(), audio.getFrameTimeLength(), getTimePosition(), FrameExportInfo.getWrittenFrames(), vptsval, vtime, WriteEnabled, Debug, "ac3-2sil");
//
while (ptsval[x + 1] > (getTimePosition() - (audio.getFrameTimeLength() / 2.0)) )
{
Common.getGuiInterface().showExportStatus((WriteEnabled || !ContainsVideoPTS) ? Resource.getString("audio.status.insert") : Resource.getString("audio.status.pause"));
if (!ContainsVideoPTS || (ContainsVideoPTS && WriteEnabled))
{
writeFrame(audio, silentFrameBuffer.toByteArray(), newframes, ContainsVideoPTS, es_streamtype);
FrameExportInfo.countInsertedFrames(1);
insertion_counter[1]++;
}
if (Debug)
{
System.out.println(FrameExportInfo.getSummary() + " @ " + formatFrameTime(getTimeCounter()) + " ");
System.out.println(" t)" + getTimePosition());
System.out.println(" x" + ((x < ptspos.length - 1) ? x + "/" + ptsval[x + 1] + "/" + ptspos[x + 1] : "-"));
}
// check a+v sync
if (ContainsVideoPTS)
WriteEnabled = SyncCheck(video_timeIndex, getTimeCounter(), audio.getFrameTimeLength(), getTimePosition(), FrameExportInfo.getWrittenFrames(), vptsval, vtime, WriteEnabled, Debug, "ac3-3sil");
countTimePosition(audio.getFrameTimeLength());
} // end while insert
insertSilenceLoop = false;
if (insertion_counter[1] > 0)
Common.setMessage(Resource.getString("audio.msg.summary.insert", "" + insertion_counter[1], FramesToTime((int)insertion_counter[1], audio.getFrameTimeLength())) + " " + formatFrameTime(insertion_counter[0]));
// reset PTS after inserting
setTimePosition(ptsval[++x]);
//
// check a+v sync
if (ContainsVideoPTS)
WriteEnabled = SyncCheck(video_timeIndex, getTimeCounter(), audio.getFrameTimeLength(), getTimePosition(), FrameExportInfo.getWrittenFrames(), vptsval, vtime, WriteEnabled, Debug, "ac3-4sil");
//
insertion_counter[0] = (long) getTimeCounter();
insertion_counter[1] = 0;
// check sync after resetting
if (Math.abs(video_timeIndex[2]) >= audio.getFrameTimeLength() || Math.abs(video_timeIndex[3]) >= audio.getFrameTimeLength())
{
// 1 zus�tzl. frame einf�gen
if (video_timeIndex[2] < 0 || video_timeIndex[3] < 0)
{
// gui message
Common.getGuiInterface().showExportStatus((WriteEnabled || !ContainsVideoPTS) ? Resource.getString("audio.status.insert") : Resource.getString("audio.status.pause"));
if (!ContainsVideoPTS || (ContainsVideoPTS && WriteEnabled))
{
Common.setMessage("!> A/V sync discontinuity in next audio packet (insert) @ " + formatFrameTime(getTimeCounter()));
writeFrame(audio, silentFrameBuffer.toByteArray(), newframes, ContainsVideoPTS, es_streamtype);
FrameExportInfo.countInsertedFrames(1);
insertion_counter[1]++;
}
/** else // a-v async in schnittpause
{
countTimeCounter(-audio.getFrameTimeLength());
Common.setMessage("!> A/V sync discontinuity in next audio packet (insert) @ " + formatFrameTime(getTimeCounter()));
Common.setMessage(Resource.getString("audio.msg.summary.skip") + " " + formatFrameTime(getTimeCounter()));
}
**/
if (Debug)
{
System.out.println(FrameExportInfo.getSummary() + " @ " + formatFrameTime(getTimeCounter()));
System.out.println("tl: " + getTimePosition() + " x" + ((x < ptspos.length - 1) ? x + "/" + ptsval[x + 1] + "/" + ptspos[x + 1] : "-"));
}
}
}
if (insertion_counter[1] > 0)
Common.setMessage(Resource.getString("audio.msg.summary.insert", "" + insertion_counter[1], FramesToTime((int)insertion_counter[1], audio.getFrameTimeLength())) + " " + formatFrameTime(insertion_counter[0]));
continue readloopdd;
} // end if insertSilenceLoop
if ( (getCurrentFramePosition() + audio.getSize()) >= FileLength )
break readloopdd;
} // end while
/**
* add frames at the end
*/
if ((es_streamtype == CommonParsing.AC3_AUDIO || es_streamtype == CommonParsing.DTS_AUDIO) && AddFrames && ContainsVideoPTS && WriteEnabled && (video_timeIndex[1] < vptsval.length))
{
countTimePosition(audio.getFrameTimeLength());
addf[0] = (long) getTimeCounter();
/**
* insert silence ac3
*/
if (!is_DTS && !FillGapsWithLastFrame)
{
for (int c = 0; c < Common.getAC3list().size(); c++)
{
byte[] ac3data = (byte[]) Common.getAC3list().get(c);
if ( (0xFE & ac3data[4]) != (0xFE & frame[4]) || ( (7 & ac3data[5]) != (7 & frame[5]) ) || (0xE0 & ac3data[6]) != (0xE0 & frame[6]) )
continue;
silentFrameBuffer.reset();
//
ac3data = audio.editFrame(ac3data, 4);
silentFrameBuffer.write(ac3data);
break;
}
}
while ( video_timeIndex[1] < vptsval.length )
{
while (vtime[video_timeIndex[1] + 1] > getTimeCounter() && (double) Math.abs(vtime[video_timeIndex[1] + 1] - getTimeCounter()) > (double) audio.getFrameTimeLength() / 2.0)
{
Common.getGuiInterface().showExportStatus(Resource.getString("audio.status.add"));
writeFrame(audio, silentFrameBuffer.toByteArray(), newframes, ContainsVideoPTS, es_streamtype);
FrameExportInfo.countAddedFrames(1);
countTimePosition(audio.getFrameTimeLength());
addf[1]++;
if (Debug)
{
System.out.println(FrameExportInfo.getSummary() + " @ " + formatFrameTime(getTimeCounter()));
System.out.print(" t)" + (long)(getTimePosition() - audio.getFrameTimeLength()) + " w)" + video_timeIndex[1]);
}
}
video_timeIndex[1] += 2;
}
video_timeIndex[1] -= 2;
countTimePosition(-audio.getFrameTimeLength());
if (Debug)
System.out.println(" eot_video:" + (vptsval[video_timeIndex[1] + 1] / 90) + "ms, eot_audio:" + (getTimePosition() / 90) + "ms ");
}
// mpa start
/**
* MPEG1+2 Audio Layer 1,2,3
*/
readloop:
while (es_streamtype == CommonParsing.MPEG_AUDIO && getFramePosition() < FileLength - 4) // = 4 mpa header bytes
{
Common.updateProgressBar(getFramePosition(), FileLength);
if (Debug)
System.out.println("\n FramePosition " + getFramePosition());
while (pause())
{}
if (isCancelled(job_processing))
break bigloop;
/**
* updates global audio_error and framecounter variable
*/
CommonParsing.setAudioProcessingFlags((0x3FFFFL & CommonParsing.getAudioProcessingFlags()) | ((long)FrameExportInfo.getWrittenFrames())<<18);
/**
* fix VBR & restart processing
*/
if (MpaDecoder.RESET)
{
closeInputStream();
closeOutputStreams();
return true;
}
/**
* fix VBR & restart processing
*/
if (!MpaDecoder.PRESCAN && (0xCL & CommonParsing.getAudioProcessingFlags()) != 0)
{
closeInputStream();
closeOutputStreams();
return true;
}
if (ptspos[x + 1] != -1 && getFramePosition() > ptspos[x + 1])
{
Common.setMessage(Resource.getString("audio.msg.pts.wo_frame") + " (" + ptspos[x + 1] + "/" + getFramePosition() + ")");
x++;
}
/**
* read x bytes for headercheck
*/
countFramePosition(readInputStream(pushmpa, 0, pushmpa.length));
/**
* parse header
*/
if ((ERRORCODE = audio.parseHeader(pushmpa, 0)) < 1)
{
// test for AAC
//ERRORCODE = test_audio.parseHeader(pushmpa, 0);
//Common.setMessage("ec " + ERRORCODE + " /pos " + getFramePosition());
unreadInputStream(pushmpa, 1, pushmpa.length - 1);
if (Message_2 && !missing_syncword)
Common.setMessage(Resource.getString("audio.msg.syncword.lost", " " + (getFramePosition() - 4)) + " " + formatFrameTime(getTimeCounter()));
missing_syncword = true;
countFramePosition(-(pushmpa.length - 1));
continue readloop;
}
// prepare to read entire frame, reset to start of frame
countFramePosition(-unreadInputStream(pushmpa, 0, pushmpa.length));
// read entire frame
if (frame.length != audio.getSize())
frame = new byte[audio.getSize()];
readInputStream(frame, 0, audio.getSize());
copyMpaFrameHeader(frame, header_copy);
// startfileposition of current frame
setCurrentFramePosition(getFramePosition());
// expected position for following frame
countFramePosition(audio.getSize());
// pitch
if (PitchAudio)
{ // skip a frame
if (pitch[1] * pitch[0] == FrameExportInfo.getWrittenFrames())
{
Common.setMessage(Resource.getString("audio.msg.frame.discard") + " " + FrameExportInfo.getWrittenFrames() + " (" + pitch[0] + ")");
pitch[0]++;
continue readloop;
}
}
// save current frame for copying, delete crc if nec.
if (FillGapsWithLastFrame)
{
if (copyframe[0].length != frame.length)
copyframe[0] = new byte[frame.length];
System.arraycopy(frame, 0, copyframe[0], 0, frame.length);
audio.removeCRC(copyframe[0], ClearCRC);
}
// finish loop if last frame in file is shorter than nominal size
if (getFramePosition() > FileLength)
break readloop;
// read following frame header, not if it is the last frame
// check following frameheader for valid mpegaudio, if not starting with next byte
if (getFramePosition() < FileLength - 4)
{
if (!AllowSpaces)
{
readInputStream(pushmpa, 0, pushmpa.length);
ERRORCODE = audio.parseNextHeader(pushmpa, 0);
unreadInputStream(pushmpa, 0, pushmpa.length);
if (ERRORCODE < 1)
{
unreadInputStream(frame, 1, frame.length - 1);
setFramePosition(getCurrentFramePosition() + 1);
continue readloop;
}
}
AudioType = audio.getLayer();
}
// check CRC
if (ValidateCRC && (ERRORCODE = audio.validateCRC(frame, 0, audio.getSize())) != 0 )
{
Common.setMessage(Resource.getString("audio.msg.crc.error", "") + " " + getCurrentFramePosition());
unreadInputStream(frame, 2, frame.length - 2);
setFramePosition(getCurrentFramePosition() + 2);
continue readloop;
}
// check for change in frametype, if not allowed, handle as unknown
if (!determineFormatChange(audio, es_streamtype))
{
if (!missing_syncword)
Common.setMessage("!> change in frame type not accepted @ " + getCurrentFramePosition());
unreadInputStream(frame, 2, frame.length - 2);
setFramePosition(getCurrentFramePosition() + 2);
continue readloop;
}
// all right till now
if (Message_2 && missing_syncword)
Common.setMessage(Resource.getString("audio.msg.syncword.found") + " " + getCurrentFramePosition());
missing_syncword = false;
// frame accepted
audio.saveHeader();
// read & decode ancillary data like RDS
if ((tmp_str = audio.decodeAncillaryData(frame, getTimeCounter())) != null)
Common.setMessage(tmp_str);
// TimePosition ist hier aktuelle audiopts frame start
Common.setFps(FrameExportInfo.getWrittenFrames());
// message
if (Debug)
System.out.println(" k)" + getTimePosition() +" l)" + (audio.getFrameTimeLength() / 2.0) + " m)" + WriteEnabled + " FramePosition)" + video_timeIndex[1] + " o)" + video_timeIndex[0] + " p)" + getFramePosition());
// preloop if audio starts later than video, and i must insert
if ( (preloop && ContainsVideoPTS && video_timeIndex[0] >= vptsval.length) || !( preloop && ContainsVideoPTS && vptsval[video_timeIndex[0]] < getTimePosition() - (audio.getFrameTimeLength() / 2.0) ) )
preloop = false;
else
{
if (silent_Frame.length != audio.getSizeBase())
silent_Frame = new byte[audio.getSizeBase()]; //silence without padd, std
else
Arrays.fill(silent_Frame, (byte) 0);
System.arraycopy(header_copy, 0, silent_Frame, 0, 4); //copy last header data
silent_Frame[1] |= 1; //mark noCRC
silent_Frame[2] &= ~2; //remove padding bit
long precount = vptsval[video_timeIndex[0]];
insertion_counter[0] = (long) getTimeCounter();
insertion_counter[1] = 0;
while ( precount < getTimePosition() - (audio.getFrameTimeLength() / 2.0) )
{ //better for RTS
// check if frame write should pause
if (ContainsVideoPTS && video_timeIndex[1] < vptsval.length)
{
sync_value_1 = (double) (precount - vptsval[video_timeIndex[1] + 1]);
sync_value_2 = (double) (getTimeCounter() - vtime[video_timeIndex[1] + 1]);
if ( (double) Math.abs(sync_value_2) <= (audio.getFrameTimeLength() / 2.0) )
{
WriteEnabled = false;
video_timeIndex[1] += 2;
}
else if ((double) Math.abs(sync_value_1) <= (audio.getFrameTimeLength() / 2.0) )
{
WriteEnabled = false;
video_timeIndex[1] += 2;
}
}
// calculate A/V Offset for true
if (ContainsVideoPTS && video_timeIndex[0] < vptsval.length)
{
sync_value_3 = precount - vptsval[video_timeIndex[0]];
sync_value_4 = getTimeCounter() - vtime[video_timeIndex[0]];
if (Debug)
System.out.println(" �" + sync_value_3 + "/" + sync_value_4 + "/" + (sync_value_4 - sync_value_3));
if (!WriteEnabled && (double) Math.abs((getTimeCounter() - vtime[video_timeIndex[0]]) -
(precount - vptsval[video_timeIndex[0]]) ) <= (double)audio.getFrameTimeLength() / 2.0 )
{
WriteEnabled = true;
video_timeIndex[0] += 2;
sync_value_1 = precount - vptsval[video_timeIndex[0] - 2];
sync_value_2 = getTimeCounter() - vtime[video_timeIndex[0] - 2];
Common.getGuiInterface().showAVOffset("" + (int)(sync_value_1 / 90) + "/" + (int)(sync_value_2 / 90) + "/" + (int)((sync_value_2 - sync_value_1) / 90));
if (Debug)
System.out.println(" �" + sync_value_1 + "/" + sync_value_2 + "/" + (sync_value_2 - sync_value_1));
}
}
// calculate A/V Offset for true
if (video_timeIndex[0] < vptsval.length)
{
if ((double) Math.abs(vptsval[video_timeIndex[0]] - precount) <= (double) (audio.getFrameTimeLength() / 2.0))
{
WriteEnabled = true;
video_timeIndex[0] += 2;
sync_value_1 = precount - vptsval[video_timeIndex[0] - 2];
sync_value_2 = getTimeCounter() - vtime[video_timeIndex[0] - 2];
Common.getGuiInterface().showAVOffset("" + (int)(sync_value_1 / 90) + "/" + (int)(sync_value_2 / 90) + "/" + (int)((sync_value_2 - sync_value_1) / 90));
if (Debug)
System.out.println(" �" + sync_value_1 + "/" + sync_value_2 + "/" + (sync_value_2 - sync_value_1));
}
// calculate A/V Offset for false
if (WriteEnabled && Math.abs((getTimeCounter() - vtime[video_timeIndex[0] - 2]) -
(precount - vptsval[video_timeIndex[0] - 2]) ) > audio.getFrameTimeLength() / 2.0 )
{
WriteEnabled = false;
video_timeIndex[0] -= 2;
}
}
// message
Common.getGuiInterface().showExportStatus((WriteEnabled || !ContainsVideoPTS) ? Resource.getString("audio.status.pre-insert") : Resource.getString("audio.status.pause"));
// stop if no more audio needed
if (!checkLastAudioBound(ContainsVideoPTS, precount, vptsval, FileLength))
break readloop;
if (WriteEnabled)
{
writeFrame(audio, FillGapsWithLastFrame ? copyframe[0] : silent_Frame, newframes, ContainsVideoPTS, es_streamtype);
FrameExportInfo.countPreInsertedFrames(1);
insertion_counter[1]++;
}
precount += audio.getFrameTimeLength();
if (Debug)
System.out.println(FrameExportInfo.getSummary() + " @ " + formatFrameTime(getTimeCounter()));
} // end while
setFramePosition(getCurrentFramePosition());
unreadInputStream(frame, 0, frame.length);
if (insertion_counter[1] > 0)
Common.setMessage(Resource.getString("audio.msg.summary.pre-insert", "" + insertion_counter[1], FramesToTime((int)insertion_counter[1], audio.getFrameTimeLength())) + " " + formatFrameTime(insertion_counter[0]));
continue readloop;
} // end of pre-loop
// check for A+V sync
if (ContainsVideoPTS)
WriteEnabled = SyncCheck(video_timeIndex, getTimeCounter(), audio.getFrameTimeLength(), getTimePosition(), FrameExportInfo.getWrittenFrames(), vptsval, vtime, WriteEnabled, Debug, "mpa-1");
// gui message
Common.getGuiInterface().showExportStatus((WriteEnabled || !ContainsVideoPTS) ? Resource.getString("audio.status.write") : Resource.getString("audio.status.pause"));
// stop if no more audio needed
if (!checkLastAudioBound(ContainsVideoPTS, getTimePosition(), vptsval, FileLength))
break readloop;
// gui message
messageSourceFormat(job_processing, audio, ContainsVideoPTS, getTimeCounter());
// endpts of current frame, startpts of next frame
countTimePosition(audio.getFrameTimeLength());
// TimePosition ist hier n�chste audiopts frame start
// message
if (Debug)
{
System.out.println(FrameExportInfo.getSummary() + " @ " + formatFrameTime(getTimeCounter()));
System.out.println("ntl: " + getTimePosition() + " x" + ((x < ptspos.length - 1) ? x + "/" + ptsval[x + 1] + "/" + ptspos[x + 1] : "-"));
}
// remove CRC
audio.removeCRC(frame, ClearCRC);
// copy frame header , for gaps
copyMpaFrameHeader(frame, header_copy);
// simple sync
if (LimitPts && ptspos[x + 1] != -1 && ptspos[x + 1] < getFramePosition())
{
if (Debug)
System.out.println(" minSync " + minSync + "/ " + x);
if ((++minSync) < 20)
x++;
else
minSync = 0;
}
// frame is in last pes packet or packet end not yet reached
// normal condition
if (writeSuccessiveFrame(audio, frame, newframes, ContainsVideoPTS, getFramePosition(), ptspos, x, es_streamtype))
continue readloop;
minSync = 0;
// message
if (Debug)
System.out.println("ZZ " + getTimePosition() + " /pvx " + ptsval[x] + " /pvx+1 " + ptsval[x + 1] + " /endFramePosition " + getFramePosition());
// frame is on pes packet corner
// less than a half of frame time to packet end, so write it and count to next index
if ((double) Math.abs(ptsval[x + 1] - getTimePosition()) < (audio.getFrameTimeLength() / 2.0))
{
setTimePosition(ptsval[++x]);
writeFrame(audio, frame, newframes, ContainsVideoPTS, es_streamtype);
insertion_counter[0] = (long) getTimeCounter();
insertion_counter[1] = 0;
// check sync after resetting
if (Math.abs(video_timeIndex[2]) >= (audio.getFrameTimeLength() / 2.0) || Math.abs(video_timeIndex[3]) >= (audio.getFrameTimeLength() / 2.0))
{
// 1 zus�tzl. frame einf�gen
if (video_timeIndex[2] < 0 || video_timeIndex[3] < 0)
{
// gui message
Common.getGuiInterface().showExportStatus((WriteEnabled || !ContainsVideoPTS) ? Resource.getString("audio.status.insert") : Resource.getString("audio.status.pause"));
if (!ContainsVideoPTS || (ContainsVideoPTS && WriteEnabled))
{
Common.setMessage("!> A/V sync discontinuity in next audio packet @ " + formatFrameTime(getTimeCounter()));
writeFrame(audio, frame, newframes, ContainsVideoPTS, es_streamtype);
FrameExportInfo.countInsertedFrames(1);
insertion_counter[1]++;
Common.setMessage(Resource.getString("audio.msg.summary.insert", "" + insertion_counter[1], FramesToTime((int)insertion_counter[1], audio.getFrameTimeLength())) + " " + formatFrameTime(insertion_counter[0]));
}
/** else // a-v async in schnittpause
{
countTimeCounter(-audio.getFrameTimeLength());
Common.setMessage("!> A/V sync discontinuity in next audio packet @ " + formatFrameTime(getTimeCounter()));
Common.setMessage(Resource.getString("audio.msg.summary.skip") + " " + formatFrameTime(getTimeCounter()));
}
**/
if (Debug)
{
System.out.println(FrameExportInfo.getSummary() + " @ " + formatFrameTime(getTimeCounter()));
System.out.println("tl: " + getTimePosition() + " x" + ((x < ptspos.length - 1) ? x + "/" + ptsval[x + 1] + "/" + ptspos[x + 1] : "-"));
}
}
}
continue readloop;
}
// more than or equal of a half of frame time is missing, so fill it
if (ptsval[x + 1] > getTimePosition())
insertSilenceLoop = true;
// frame time is later than next indexed frame, so skip it and count to next index
if (ptsval[x + 1] < getTimePosition())
{
setTimePosition(ptsval[++x]);
Common.setMessage(Resource.getString("audio.msg.summary.skip") + " " + formatFrameTime(getTimeCounter()));
FrameExportInfo.countSkippedFrames(1);
}
// insert condition
if (insertSilenceLoop)
{
// silentframe auslagern zu audio.class !!
if (silent_Frame.length != audio.getSizeBase())
silent_Frame = new byte[audio.getSizeBase()]; //silence without padd, std
else
Arrays.fill(silent_Frame, (byte) 0);
System.arraycopy(header_copy, 0, silent_Frame, 0, 4); //copy last header data
silent_Frame[1] |= 1; //mark noCRC
silent_Frame[2] &= ~2; //remove padding bit
insertion_counter[0] = (long) getTimeCounter();
insertion_counter[1] = 0;
// solange n�chster ptsval minus n�chster framebeginn ist gr��er der halben framezeit, f�ge stille ein
while (ptsval[x + 1] > (getTimePosition() - (audio.getFrameTimeLength() / 2.0)))
{
// gui message
Common.getGuiInterface().showExportStatus((WriteEnabled || !ContainsVideoPTS) ? Resource.getString("audio.status.insert") : Resource.getString("audio.status.pause"));
if (!ContainsVideoPTS || (ContainsVideoPTS && WriteEnabled))
{
writeFrame(audio, FillGapsWithLastFrame ? copyframe[0] : silent_Frame, newframes, ContainsVideoPTS, es_streamtype);
FrameExportInfo.countInsertedFrames(1);
insertion_counter[1]++;
}
if (Debug)
{
System.out.println(FrameExportInfo.getSummary() + " @ " + formatFrameTime(getTimeCounter()));
System.out.println("tl: " + getTimePosition() + " x" + ((x < ptspos.length - 1) ? x + "/" + ptsval[x + 1] + "/" + ptspos[x + 1] : "-"));
}
// check a+v sync
if (ContainsVideoPTS)
WriteEnabled = SyncCheck(video_timeIndex, getTimeCounter(), audio.getFrameTimeLength(), getTimePosition(), FrameExportInfo.getWrittenFrames(), vptsval, vtime, WriteEnabled, Debug, "mpac-2sil");
countTimePosition(audio.getFrameTimeLength());
} // end while
insertSilenceLoop = false;
if (insertion_counter[1] > 0)
Common.setMessage(Resource.getString("audio.msg.summary.insert", "" + insertion_counter[1], FramesToTime((int)insertion_counter[1], audio.getFrameTimeLength())) + " " + formatFrameTime(insertion_counter[0]));
// set PTS after inserting to new index
setTimePosition(ptsval[++x]);
insertion_counter[0] = (long) getTimeCounter();
insertion_counter[1] = 0;
// check sync after resetting
if (Math.abs(video_timeIndex[2]) >= audio.getFrameTimeLength() || Math.abs(video_timeIndex[3]) >= audio.getFrameTimeLength())
{
// 1 zus�tzl. frame einf�gen
if (video_timeIndex[2] < 0 || video_timeIndex[3] < 0)
{
// gui message
Common.getGuiInterface().showExportStatus((WriteEnabled || !ContainsVideoPTS) ? Resource.getString("audio.status.insert") : Resource.getString("audio.status.pause"));
if (!ContainsVideoPTS || (ContainsVideoPTS && WriteEnabled))
{
Common.setMessage("!> A/V sync discontinuity in next audio packet (insert) @ " + formatFrameTime(getTimeCounter()));
writeFrame(audio, FillGapsWithLastFrame ? copyframe[0] : silent_Frame, newframes, ContainsVideoPTS, es_streamtype);
FrameExportInfo.countInsertedFrames(1);
insertion_counter[1]++;
}
/** else // a-v async in schnittpause
{
countTimeCounter(-audio.getFrameTimeLength());
Common.setMessage("!> A/V sync discontinuity in next audio packet (insert) @ " + formatFrameTime(getTimeCounter()));
Common.setMessage(Resource.getString("audio.msg.summary.skip") + " " + formatFrameTime(getTimeCounter()));
}
**/
if (Debug)
{
System.out.println(FrameExportInfo.getSummary() + " @ " + formatFrameTime(getTimeCounter()));
System.out.println("tl: " + getTimePosition() + " x" + ((x < ptspos.length - 1) ? x + "/" + ptsval[x + 1] + "/" + ptspos[x + 1] : "-"));
}
}
}
if (insertion_counter[1] > 0)
Common.setMessage(Resource.getString("audio.msg.summary.insert", "" + insertion_counter[1], FramesToTime((int)insertion_counter[1], audio.getFrameTimeLength())) + " " + formatFrameTime(insertion_counter[0]));
continue readloop;
} // end insertion
// avail. frame size too short, so end here
if ( (getCurrentFramePosition() + audio.getSize()) >= FileLength )
break readloop;
} // end while
if (Debug)
System.out.println(FrameExportInfo.getSummary() + " @ " + formatFrameTime(getTimeCounter()));
/**
* add frames at the end
*/
if (es_streamtype == CommonParsing.MPEG_AUDIO && AddFrames && ContainsVideoPTS && WriteEnabled && (video_timeIndex[1] < vptsval.length))
{
countTimePosition(audio.getFrameTimeLength());
addf[0] = (long) getTimeCounter();
if (silent_Frame.length != audio.getSizeBase())
silent_Frame = new byte[audio.getSizeBase()]; //silence without padd, std
else
Arrays.fill(silent_Frame, (byte) 0);
System.arraycopy(header_copy, 0, silent_Frame, 0, 4); //copy last header data
silent_Frame[1] |= 1; //mark noCRC
silent_Frame[2] &= ~2; //remove padding bit
while (video_timeIndex[1] < vptsval.length)
{
while ( vtime[video_timeIndex[1] + 1] > getTimeCounter() &&
(double) Math.abs(vtime[video_timeIndex[1] + 1] - getTimeCounter()) > (double) audio.getFrameTimeLength() / 2.0 )
{
writeFrame(audio, FillGapsWithLastFrame ? copyframe[0] : silent_Frame, newframes, ContainsVideoPTS, es_streamtype);
FrameExportInfo.countAddedFrames(1);
countTimePosition(audio.getFrameTimeLength());
addf[1]++;
Common.getGuiInterface().showExportStatus(Resource.getString("audio.status.add"));
if (Debug)
{
System.out.println(FrameExportInfo.getSummary() + " @ " + formatFrameTime(getTimeCounter()));
System.out.print(" t)" + (long)(getTimePosition() - audio.getFrameTimeLength()) + " w)" + video_timeIndex[1]);
}
}
video_timeIndex[1] += 2;
}
video_timeIndex[1] -= 2;
countTimePosition(-audio.getFrameTimeLength());
if (Debug)
System.out.println(" eot_video:" + (vptsval[video_timeIndex[1] + 1] / 90) + "ms, eot_audio:" + ((getTimePosition()) / 90) + "ms ");
} //end add mpa
/**
* restart decoding after a peak search
*/
if (es_streamtype == CommonParsing.MPEG_AUDIO && DecodeMpgAudio && MpaDecoder.PRESCAN && !MpaDecoder.RESET)
{
MpaDecoder.PRESCAN = false;
MpaDecoder.NORMALIZE = false;
closeInputStream();
closeOutputStreams();
return true;
}
break;
} // end while bigloop
if (addf[1] > 0)
Common.setMessage(Resource.getString("audio.msg.summary.add", "" + addf[1], FramesToTime((int)addf[1], audio.getFrameTimeLength())) + " " + formatFrameTime(addf[0]));
Common.getGuiInterface().showExportStatus(Resource.getString("audio.status.finish"));
String tc = formatFrameTime(getTimeCounter());
Common.setMessage(Resource.getString("audio.msg.summary.frames", "" + FrameExportInfo.getWrittenFrames() + "-" + FrameExportInfo.getShortSummary(), "" + tc));
if (ModeChangeCount_JSS > 0)
Common.setMessage(Resource.getString("audio.msg.summary.jstereo", String.valueOf(ModeChangeCount_JSS)));
closeInputStream();
silentFrameBuffer.close();
closeOutputStreams();
String[][] es_audio_str = {
{ str_ac3, str_mp3, str_mp2, str_mp1, str_dts },
{ (str_new + str_ac3), (str_new + str_mp3), (str_new + str_mp2), (str_new + str_mp1), (str_new + str_dts) }
};
if (RenameAudio)
setExtension(es_audio_str, str_mpa, (str_new + str_mpa));
if (DecodeMpgAudio && audio.getLayer() > 1)
{
if (MpaDecoder.WAVE)
setExtension(es_audio_str, str_wav);
else if (AddAiffHeader)
setExtension(es_audio_str, str_aif);
else
setExtension(es_audio_str, str_pcm);
}
else if (AddWaveHeaderBWF || AddWaveHeaderACM)
{
setExtension(es_audio_str, str_wav);
}
if (AddWaveHeaderAC3)
{
for (int j = 0; j < 2; j++)
es_audio_str[j][0] += str_wav;
}
else if (CreateDDWave)
{
es_audio_str[0][0] += str_wav;
es_audio_str[1][0] += str_wav;
es_audio_str[0][4] += str_wav;
es_audio_str[1][4] += str_wav;
}
//finish wave header
fillWaveHeader(audio, es_streamtype);
File audioout1 = new File(FileName_Ch1);
File audioout2 = new File(FileName_Ch2);
job_processing.countMediaFilesExportLength(audioout1.length());
job_processing.countMediaFilesExportLength(audioout2.length());
if (DecodeMpgAudio)
audio_type[1] = audio_type[2] = "(pcm)";
String comparedata = "";
if (AudioType < 0)
AudioType = NO_AUDIOSTREAM;
else
comparedata = Resource.getString("audio.msg.audio") + " " + Common.adaptString(job_processing.countAudioStream(), 2) + " " + audio_type[AudioType] + ":\t" + FrameExportInfo.getWrittenFrames() + " Frames\t" + tc + "\t" + infoPTSMatch(filename_pts, videofile_pts, ContainsVideoPTS, ContainsAudioPTS) + FrameExportInfo.getShortSummary();
/**
*
*/
switch (AudioType)
{
case AC3_AUDIOSTREAM:
case DTS_AUDIOSTREAM:
case MP1_AUDIOSTREAM:
case MP3_AUDIOSTREAM:
finishOutputFiles(job_processing, fparent, es_audio_str[isElementaryStream][AudioType], audioout1, audioout2, comparedata, OutputStream_Ch1, OutputStream_Ch2);
break;
case MP2_AUDIOSTREAM:
if (MpaConversionMode >= MpaConversion_Mode4)
finishOutputFiles(job_processing, fparent, "[L]" + es_audio_str[0][AudioType], "[R]" + es_audio_str[0][AudioType], audioout1, audioout2, comparedata, OutputStream_Ch1, OutputStream_Ch2);
else
finishOutputFiles(job_processing, fparent, es_audio_str[isElementaryStream][AudioType], audioout1, audioout2, comparedata, OutputStream_Ch1, OutputStream_Ch2);
break;
case WAV_AUDIOSTREAM:
finishOutputFiles(job_processing, fparent, (str_new + str_wav), audioout1, audioout2, comparedata, OutputStream_Ch1, OutputStream_Ch2);
break;
case NO_AUDIOSTREAM:
Common.setMessage(Resource.getString("audio.msg.noaudio"));
finishOutputFiles(job_processing, null, null, audioout1, audioout2, comparedata, OutputStream_Ch1, OutputStream_Ch2);
break;
}
} catch (IOException e) {
Common.setExceptionMessage(e);
}
Common.updateProgressBar(FileLength, FileLength);
return false;
}
/**
* new extension
*/
private void setExtension(String[][] str, String new_str)
{
for (int j = 0; j < 2; j++)
for (int i = 1; i < 4; i++)
str[j][i] += new_str;
}
/**
* new extension for mpa - replace
*/
private void setExtension(String[][] str, String new_str_1, String new_str_2)
{
for (int i = 1; i < 4; i++)
{
str[0][i] = new_str_1;
str[1][i] = new_str_2;
}
}
/**
* message source format change
*/
private void messageSourceFormat(JobProcessing job_processing, AudioFormat audio, boolean ContainsVideoPTS, double _TimeCounter)
{
if (!HasNewFormat || (ContainsVideoPTS && !WriteEnabled))
return;
String header = audio.displayHeader();
if (ModeChangeCount < ModeChangeCount_Max)
{
String str = formatFrameTime(_TimeCounter);
Common.setMessage(Resource.getString("audio.msg.source", header) + " " + str);
if (CreateChapters)
job_processing.getChapters().addChapter(str, header);
}
else if (Debug)
System.out.println("=> src_audio: " + header + " @ " + formatFrameTime(_TimeCounter));
if (ModeChangeCount == ModeChangeCount_Max)
Common.setMessage(Resource.getString("audio.msg.source.max"));
ModeChangeCount++;
HasNewFormat = false;
}
/**
* pts value to time value
*/
private String formatFrameTime(long time_value)
{
return Common.formatTime_1(time_value / 90L);
}
/**
* getFramePosition
*/
private long getFramePosition()
{
return FramePosition;
}
/**
* setFramePosition
*/
private void setFramePosition(long value)
{
FramePosition = value;
}
/**
* countFramePosition
*/
private void countFramePosition(long value)
{
FramePosition += value;
}
/**
* getCurrentFramePosition
*/
private long getCurrentFramePosition()
{
return CurrentFramePosition;
}
/**
* setCurrentFramePosition
*/
private void setCurrentFramePosition(long value)
{
CurrentFramePosition = value;
}
/**
* countCurrentFramePosition
*/
private void countCurrentFramePosition(long value)
{
CurrentFramePosition += value;
}
/**
* getTimePosition
*/
private long getTimePosition()
{
return TimePosition;
}
/**
* setTimePosition
*/
private void setTimePosition(long value)
{
TimePosition = value;
}
/**
* setTimePosition
*/
private void setTimePosition(double value)
{
TimePosition = (long) value;
}
/**
* countTimePosition
*/
private void countTimePosition(long value)
{
TimePosition += value;
}
/**
* countTimePosition
*/
private void countTimePosition(double value)
{
TimePosition += (long) value;
}
/**
* getTimeCounter
*/
private double getTimeCounter()
{
return TimeCounter;
}
/**
* setTimeCounter
*/
private void setTimeCounter(double value)
{
TimeCounter = value;
}
/**
* countTimeCounter
*/
private void countTimeCounter(double value)
{
TimeCounter += value;
}
/**
* copy frame header , for gaps
*/
private void copyMpaFrameHeader(byte[] frame, byte[] header_copy)
{
System.arraycopy(frame, 0, header_copy, 0, 4);
header_copy[3] &= 0xCF;
header_copy[2] &= ~2;
}
/**
* stop if no more audio needed
*/
private boolean checkLastAudioBound(boolean ContainsVideoPTS, long time_value, long[] vptsval, long FileLength)
{
if (!ContainsVideoPTS)
return true;
if (time_value > vptsval[vptsval.length - 1] + 10000)
{
Common.updateProgressBar(FileLength, FileLength);
return false;
}
return true;
}
/**
*
*/
private boolean writeSuccessiveFrame(AudioFormat audio, byte[] frame, byte[][] newframes, boolean ContainsVideoPTS, long _FramePosition, long[] ptspos, int x, int es_streamtype)
{
// frame is in last pes packet or packet end not yet reached
if (ptspos[x + 1] != -1 && ptspos[x + 1] <= _FramePosition)
return false;
//always true
writeFrame(audio, frame, newframes, ContainsVideoPTS, es_streamtype);
return true;
}
/**
*
*/
private boolean writeFrame(AudioFormat audio, byte[] frame, byte[][] newframes, boolean ContainsVideoPTS, int es_streamtype)
{
if (ContainsVideoPTS && !WriteEnabled)
return false;
switch (es_streamtype)
{
case CommonParsing.AC3_AUDIO:
// set bitrate
if (AC3_BitrateAdaption)
frame = audio.editFrame(frame, 2);
if (AddWaveHeaderAC3)
audio.parseRiffData(frame, 1);
writeChannel1(frame);
break;
case CommonParsing.MPEG_AUDIO:
if (DecodeMpgAudio && audio.getLayer() > 0)
{
writeChannel1(MpaDecoder.decodeArray(frame));
if (MpaConversionMode >= MpaConversion_Mode4)
writeChannel2(MpaDecoder.get2ndArray());
}
else if (MpaConversionMode != MpaConversion_None)
{
newframes = audio.convertFrame(frame, MpaConversionMode);
writeChannel1(newframes[0]);
if (MpaConversionMode >= MpaConversion_Mode4)
writeChannel2(newframes[1]);
}
else
{
writeChannel1(frame);
audio.parseRiffData(frame, 1);
}
break;
case CommonParsing.DTS_AUDIO:
writeChannel1(frame);
break;
}
FrameExportInfo.countWrittenFrames(1);
countTimeCounter(audio.getFrameTimeLength());
// if (Debug)
// System.out.println(FrameExportInfo.getSummary() + " @ " + formatFrameTime(TimeCounter) + " ");
//if (FrameExportInfo.getWrittenFrames() > 77000)
// Common.setMessage(FrameExportInfo.getSummary() + " @ " + formatFrameTime(getTimeCounter()) + " ");
return true;
}
/**
*
*/
private void initOutputStreams()
{
try {
OutputStream_Ch1 = new IDDBufferedOutputStream(new FileOutputStream(FileName_Ch1), 2048000);
OutputStream_Ch2 = new IDDBufferedOutputStream(new FileOutputStream(FileName_Ch2), MpaConversionMode >= 4 ? 2048000 : 65536);
} catch (Exception e) {
Common.setExceptionMessage(e);
}
}
/**
*
*/
private void closeOutputStreams()
{
try {
OutputStream_Ch1.flush();
OutputStream_Ch1.close();
OutputStream_Ch2.flush();
OutputStream_Ch2.close();
} catch (Exception e) {
Common.setExceptionMessage(e);
}
}
/**
*
*/
private void writeChannel1(byte[] array)
{
writeChannel(array, 1);
}
/**
*
*/
private void writeChannel2(byte[] array)
{
writeChannel(array, 2);
}
/**
*
*/
private void writeChannels(byte[] array)
{
writeChannels(array, array);
}
/**
*
*/
private void writeChannels(byte[][] arrays)
{
writeChannels(arrays[0], arrays[1]);
}
/**
*
*/
private void writeChannels(byte[] array1, byte[] array2)
{
writeChannel(array1, 1);
if (MpaConversionMode >= MpaConversion_Mode4)
writeChannel(array2, 2);
}
/**
*
*/
private void writeChannel(byte[] array, int index)
{
try {
switch (index)
{
case 1:
OutputStream_Ch1.write(array);
return;
case 2:
OutputStream_Ch2.write(array);
return;
}
} catch (Exception e) {
Common.setExceptionMessage(e);
}
}
/**
*
*/
private void initInputStream(XInputFile xInputFile)
{
try {
InputStream = new PushbackInputStream(xInputFile.getInputStream(), 1000000);
} catch (Exception e) {
Common.setExceptionMessage(e);
}
}
/**
*
*/
private void closeInputStream()
{
try {
InputStream.close();
} catch (Exception e) {
Common.setExceptionMessage(e);
}
}
/**
*
*/
private int readInputStream(byte[] array)
{
return readInputStream(array, 0, array.length);
}
/**
*
*/
private int readInputStream(byte[] array, int offset, int length)
{
int value = 0;
try {
value = InputStream.read(array, offset, length);
if (value < length)
Arrays.fill(array, offset + value, offset + length, (byte) 0);
} catch (Exception e) {
Common.setExceptionMessage(e);
}
return value;
}
/**
*
*/
private int unreadInputStream(byte[] array, int offset, int length)
{
int value = 0;
try {
InputStream.unread(array, offset, length);
value = length;
} catch (Exception e) {
Common.setExceptionMessage(e);
}
return value;
}
/**
*
*/
private long skipInputStream(long length)
{
long value = 0L;
try {
value = InputStream.skip(length);
} catch (Exception e) {
Common.setExceptionMessage(e);
}
return value;
}
/**
*
*/
private boolean isCancelled(JobProcessing job_processing)
{
if (!CommonParsing.isProcessCancelled())
return false;
CommonParsing.setProcessCancelled(false);
job_processing.setSplitSize(0);
return true;
}
/**
* ac3 3.2 replacement
*/
private byte[] getReplacementFrame(AudioFormat audio, byte[] array, int es_streamtype)
{
if (es_streamtype != CommonParsing.AC3_AUDIO || !AC3_ReplaceWithSilence)
return array;
//is 3/2
if (audio.getMode() == 7)
return array;
AudioFormat ac3_test = new AudioFormat(CommonParsing.AC3_AUDIO);
byte[] ac3data;
for (int i = 0, j = Common.getAC3list().size(); i < j; i++)
{
ac3data = (byte[]) Common.getAC3list().get(i);
ac3_test.parseHeader(ac3data, 0);
if (ac3_test.getMode() != 7 || ac3_test.getSamplingFrequency() != audio.getSamplingFrequency())
continue;
if (ac3_test.getBitrate() != audio.getBitrate())
continue;
array = new byte[ac3data.length];
System.arraycopy(ac3data, 0, array, 0, array.length);
//
ac3data = audio.editFrame(ac3data, 4);
break;
}
return array;
}
/**
* check for change in frametype
*/
private boolean determineFormatChange(AudioFormat audio, int es_streamtype)
{
boolean accept = true;
int returncode = audio.compareHeader();
if (returncode > 0)
{
if (!AllowFormatChanges && (returncode & 0x7) != 0 && FrameExportInfo.getWrittenFrames() > 0)
return !accept;
HasNewFormat = true;
if (es_streamtype == CommonParsing.MPEG_AUDIO && returncode == 0x20)
{
ModeChangeCount_JSS++;
HasNewFormat = false;
}
}
if (FrameExportInfo.getWrittenFrames() == 0)
HasNewFormat = true;
return accept;
}
/**
* prepare wave header
*/
private void addWaveHeader(AudioFormat audio, int es_streamtype)
{
switch (es_streamtype)
{
case CommonParsing.AC3_AUDIO:
if (AddWaveHeaderAC3)
{
writeChannel1(audio.getExtraWaveHeader(1, true));
Common.setMessage(Resource.getString("audio.msg.addriff.ac3"));
}
else if (CreateDDWave)
writeChannel1(audio.getRiffHeader());
return;
case CommonParsing.MPEG_AUDIO:
writeChannel1(audio.getExtraWaveHeader(1, true));
if (MpaConversionMode >= MpaConversion_Mode4)
writeChannel2(audio.getExtraWaveHeader(2, true));
return;
case CommonParsing.DTS_AUDIO:
if (CreateDDWave)
writeChannel1(audio.getRiffHeader());
return;
}
}
/**
* finish wave header
*/
private void fillWaveHeader(AudioFormat audio, int es_streamtype)
{
long tmp_value = (long) (getTimeCounter() / 90.0f);
try {
if (DecodeMpgAudio && es_streamtype == CommonParsing.MPEG_AUDIO && MpaDecoder.WAVE)
{
if (audio.getLayer() > 1)
{
MpaDecoder.fillRIFF(FileName_Ch1, FadeInOut, FadeInOutMillis);
if (MpaConversionMode >= MpaConversion_Mode4)
MpaDecoder.fillRIFF(FileName_Ch2, FadeInOut, FadeInOutMillis);
}
else
{
MpaDecoder.deleteRIFF(FileName_Ch1);
if (MpaConversionMode >= MpaConversion_Mode4)
MpaDecoder.deleteRIFF(FileName_Ch2);
}
}
else if (DecodeMpgAudio && es_streamtype == CommonParsing.MPEG_AUDIO && AddAiffHeader)
{
if (audio.getLayer() > 1)
{
MpaDecoder.fillAiff(FileName_Ch1, tmp_value, FadeInOut, FadeInOutMillis);
if (MpaConversionMode >= MpaConversion_Mode4)
MpaDecoder.fillAiff(FileName_Ch2, tmp_value, FadeInOut, FadeInOutMillis);
}
else
{
MpaDecoder.deleteAiff(FileName_Ch1);
if (MpaConversionMode >= MpaConversion_Mode4)
MpaDecoder.deleteAiff(FileName_Ch2);
}
}
else if (!DecodeMpgAudio && (AddWaveHeaderBWF || AddWaveHeaderACM) && es_streamtype == CommonParsing.MPEG_AUDIO)
{
RandomAccessFile[] rifffile = {
new RandomAccessFile(FileName_Ch1, "rw"),
new RandomAccessFile(FileName_Ch2, "rw")
};
audio.setExtraWaveLength(rifffile[0].length(), tmp_value, 1);
audio.setExtraWaveLength(rifffile[1].length(), tmp_value, 2);
rifffile[0].seek(0);
rifffile[1].seek(0);
rifffile[0].write(audio.getExtraWaveHeader(1, false));
if (MpaConversionMode >= MpaConversion_Mode4)
rifffile[1].write(audio.getExtraWaveHeader(2, false));
rifffile[0].close();
rifffile[1].close();
}
else if (AddWaveHeaderAC3 && es_streamtype == CommonParsing.AC3_AUDIO)
{
RandomAccessFile rifffile = new RandomAccessFile(FileName_Ch1, "rw");
audio.setExtraWaveLength(rifffile.length(), tmp_value, 1);
rifffile.seek(0);
rifffile.write(audio.getExtraWaveHeader(1, false));
rifffile.close();
}
else if (es_streamtype == CommonParsing.LPCM_AUDIO)
audio.fillRiffHeader(FileName_Ch1);
else if (CreateDDWave && es_streamtype == CommonParsing.AC3_AUDIO)
audio.fillStdRiffHeader(FileName_Ch1, tmp_value);
else if (CreateDDWave && es_streamtype == CommonParsing.DTS_AUDIO)
audio.fillStdRiffHeader(FileName_Ch1, tmp_value);
} catch (Exception e) {
Common.setExceptionMessage(e);
}
}
/**
* init project files
*/
private void initProjectFiles()
{
if (CreateM2sIndex)
{
OutputStream_Ch1.InitIdd(FileName_Ch1, 2);
OutputStream_Ch2.InitIdd(FileName_Ch2, 2);
}
}
/**
* determine given stream type
*/
private int determineStreamType(String str)
{
int value = CommonParsing.MPEG_AUDIO; //"mp" std
if (str.equals("ac")) //means dts, too
value = CommonParsing.AC3_AUDIO;
else if (str.equals("dt")) //later, other handling
value = CommonParsing.DTS_AUDIO;
else if (str.equals("wa"))
value = CommonParsing.LPCM_AUDIO;
return value;
}
/**
*
*/
private void finishOutputFiles(JobProcessing job_processing, String new_file_out_parent, String new_file_out_child, File tmp_file_out_1, File tmp_file_out_2, String info, IDDBufferedOutputStream output_stream_1, IDDBufferedOutputStream output_stream_2)
{
finishOutputFile(job_processing, null, null, tmp_file_out_2, info, output_stream_2);
finishOutputFile(job_processing, new_file_out_parent, new_file_out_child, tmp_file_out_1, info, output_stream_1);
}
/**
*
*/
private void finishOutputFiles(JobProcessing job_processing, String new_file_out_parent, String new_file_out_child_1, String new_file_out_child_2, File tmp_file_out_1, File tmp_file_out_2, String info, IDDBufferedOutputStream output_stream_1, IDDBufferedOutputStream output_stream_2)
{
finishOutputFile(job_processing, new_file_out_parent, new_file_out_child_2, tmp_file_out_2, info, output_stream_2);
finishOutputFile(job_processing, new_file_out_parent, new_file_out_child_1, tmp_file_out_1, info, output_stream_1);
}
/**
*
*/
private void finishOutputFile(JobProcessing job_processing, String new_file_out_parent, String new_file_out_child, File tmp_file_out, String info, IDDBufferedOutputStream output_stream)
{
try {
if (new_file_out_parent == null)
{
tmp_file_out.delete();
output_stream.deleteIdd();
return;
}
if (new_file_out_child == null)
{
if (tmp_file_out.length() < FileLength_Min)
tmp_file_out.delete();
output_stream.deleteIdd();
return;
}
File new_file_out = new File(new_file_out_parent + new_file_out_child);
if (new_file_out.exists())
new_file_out.delete();
if (tmp_file_out.length() < FileLength_Min)
tmp_file_out.delete();
else
{
Common.renameTo(tmp_file_out, new_file_out);
Common.setMessage(Resource.getString("msg.newfile", "") + " '" + new_file_out.toString() + "'");
job_processing.addSummaryInfo(info + "\t'" + new_file_out.toString() + "'");
}
output_stream.renameIddTo(new_file_out);
} catch (Exception e) {
Common.setExceptionMessage(e);
}
}
/**
* messages
*/
private void messageSettings()
{
if (IgnoreErrors)
Common.setMessage("-> " + Resource.getString(Keys.KEY_Audio_ignoreErrors[0]));
if (AllowSpaces)
Common.setMessage("-> " + Resource.getString(Keys.KEY_AudioPanel_allowSpaces[0]));
if (LimitPts)
Common.setMessage("-> " + Resource.getString(Keys.KEY_Audio_limitPts[0]));
if (AllowFormatChanges)
Common.setMessage("-> " + Resource.getString(Keys.KEY_Audio_allowFormatChanges[0]));
if (ValidateCRC)
Common.setMessage("-> " + Resource.getString(Keys.KEY_AudioPanel_validateCRC[0]));
if (ClearCRC)
Common.setMessage("-> " + Resource.getString(Keys.KEY_AudioPanel_clearCRC[0]));
if (AC3_Patch1stHeader)
Common.setMessage("-> " + Resource.getString(Keys.KEY_AudioPanel_AC3_patch1stHeader[0]));
if (AC3_ReplaceWithSilence)
Common.setMessage("-> " + Resource.getString(Keys.KEY_AudioPanel_AC3_replaceWithSilence[0]));
if (AC3_BitrateAdaption)
Common.setMessage("-> " + Resource.getString(Keys.KEY_AudioPanel_AC3_BitrateAdaption[0]));
if (FillGapsWithLastFrame)
Common.setMessage("-> " + Resource.getString(Keys.KEY_AudioPanel_fillGapsWithLastFrame[0]));
if (AddFrames)
Common.setMessage("-> " + Resource.getString(Keys.KEY_AudioPanel_addFrames[0]));
if (CreateDDWave)
Common.setMessage("-> " + Resource.getString(Keys.KEY_AudioPanel_createDDWave[0]));
if (AddWaveHeaderACM)
Common.setMessage("-> " + Resource.getString(Keys.KEY_AudioPanel_addRiffToMpgAudioL3[0]));
if (AddWaveHeaderBWF)
Common.setMessage("-> " + Resource.getString(Keys.KEY_AudioPanel_addRiffToMpgAudio[0]));
if (AddWaveHeaderAC3)
Common.setMessage("-> " + Resource.getString(Keys.KEY_AudioPanel_addRiffToAc3[0]));
}
/**
* settings
*/
private void getSettings(JobCollection collection)
{
Debug = Common.getSettings().getBooleanProperty(Keys.KEY_DebugLog);
Message_2 = Common.getSettings().getBooleanProperty(Keys.KEY_MessagePanel_Msg2);
Message_7 = Common.getSettings().getBooleanProperty(Keys.KEY_MessagePanel_Msg7);
CreateChapters = collection.getSettings().getBooleanProperty(Keys.KEY_ExternPanel_createChapters);
RenameAudio = collection.getSettings().getBooleanProperty(Keys.KEY_ExternPanel_renameAudio);
AddWaveHeaderACM = collection.getSettings().getBooleanProperty(Keys.KEY_AudioPanel_addRiffToMpgAudioL3);
AddWaveHeaderBWF = collection.getSettings().getBooleanProperty(Keys.KEY_AudioPanel_addRiffToMpgAudio);
AddWaveHeaderAC3 = collection.getSettings().getBooleanProperty(Keys.KEY_AudioPanel_addRiffToAc3);
AC3_ReplaceWithSilence = collection.getSettings().getBooleanProperty(Keys.KEY_AudioPanel_AC3_replaceWithSilence);
AC3_Patch1stHeader = collection.getSettings().getBooleanProperty(Keys.KEY_AudioPanel_AC3_patch1stHeader);
AC3_BitrateAdaption = collection.getSettings().getBooleanProperty(Keys.KEY_AudioPanel_AC3_BitrateAdaption);
CreateM2sIndex = collection.getSettings().getBooleanProperty(Keys.KEY_ExternPanel_createM2sIndex);
PitchAudio = collection.getSettings().getBooleanProperty(Keys.KEY_AudioPanel_pitchAudio);
AllowSpaces = collection.getSettings().getBooleanProperty(Keys.KEY_AudioPanel_allowSpaces);
ValidateCRC = collection.getSettings().getBooleanProperty(Keys.KEY_AudioPanel_validateCRC);
FillGapsWithLastFrame = collection.getSettings().getBooleanProperty(Keys.KEY_AudioPanel_fillGapsWithLastFrame);
LimitPts = collection.getSettings().getBooleanProperty(Keys.KEY_Audio_limitPts);
AllowFormatChanges = collection.getSettings().getBooleanProperty(Keys.KEY_Audio_allowFormatChanges);
AddFrames = collection.getSettings().getBooleanProperty(Keys.KEY_AudioPanel_addFrames);
DownMix = collection.getSettings().getBooleanProperty(Keys.KEY_AudioPanel_Downmix);
ChangeByteorder = collection.getSettings().getBooleanProperty(Keys.KEY_AudioPanel_changeByteorder);
AddRiffHeader = collection.getSettings().getBooleanProperty(Keys.KEY_AudioPanel_addRiffHeader);
AddAiffHeader = collection.getSettings().getBooleanProperty(Keys.KEY_AudioPanel_addAiffHeader);
ClearCRC = collection.getSettings().getBooleanProperty(Keys.KEY_AudioPanel_clearCRC);
IgnoreErrors = collection.getSettings().getBooleanProperty(Keys.KEY_Audio_ignoreErrors);
CreateDDWave = collection.getSettings().getBooleanProperty(Keys.KEY_AudioPanel_createDDWave);
FadeInOut = collection.getSettings().getBooleanProperty(Keys.KEY_AudioPanel_fadeInOut);
Normalize = collection.getSettings().getBooleanProperty(Keys.KEY_AudioPanel_Normalize);
FadeInOutMillis = collection.getSettings().getIntProperty(Keys.KEY_AudioPanel_fadeInOutMillis);
ResampleAudioMode = collection.getSettings().getIntProperty(Keys.KEY_AudioPanel_resampleAudioMode);
PitchValue = collection.getSettings().getIntProperty(Keys.KEY_AudioPanel_PitchValue);
messageSettings();
}
/**
* init FFT/window for mpa decoding for 1 file
*/
private void initDecoder(AudioFormat audio, int es_streamtype)
{
if (es_streamtype != CommonParsing.MPEG_AUDIO)
return;
if (!DecodeMpgAudio)
return;
MpaDecoder.init_work(ResampleAudioMode);
MpaDecoder.DOWNMIX = DownMix;
MpaDecoder.MONO = (DownMix || MpaConversionMode == MpaConversion_Mode4);
MpaDecoder.MOTOROLA = ChangeByteorder;
MpaDecoder.WAVE = AddRiffHeader;
if (AddRiffHeader)
writeChannels(MpaDecoder.RIFF);
if (AddAiffHeader)
writeChannels(MpaDecoder.AIFF);
}
/**
*
*/
private int processData(AudioFormat audio, int es_streamtype)
{
int returncode = 0;
// add preceding wave header
addWaveHeader(audio, es_streamtype);
// init FFT/window for mpa decoding for 1 file
initDecoder(audio, es_streamtype);
// init decoding of ancillary data
audio.setAncillaryDataDecoder(Message_7, Debug);
return returncode;
}
/**
* PCM Audio
*/
private void processPCMData(JobProcessing job_processing, AudioFormat audio, long[] vptsval, long[] ptsval)
{
// parse header
byte[] array = new byte[1000];
readInputStream(array);
audio.parseHeader(array, 0);
unreadInputStream(array, audio.getEmphasis(), 1000 - audio.getEmphasis());
Common.setMessage(Resource.getString("audio.msg.source", audio.saveAndDisplayHeader()) + " " + formatFrameTime(getTimeCounter()));
AudioType = WAV_AUDIOSTREAM;
setFramePosition(audio.getEmphasis()); //start of pcm data
long pcm_end_pos = audio.getEmphasis() + audio.getSizeBase(); //whole sample data size
setTimePosition(ptsval[0]);
writeChannel1(audio.getRiffHeader());
long sample_bytes;
long skip_bytes;
long sample_pts;
long skip_pts;
int sample_size;
int read_size = 960000 / audio.getMode();
// Size/8 * Channel = bytes per sample
// 16bit/8 * 2 = 4
// per sample: Audio.Time_length = 90000.0 / Samplefre
// 48000hz = 1.875 ticks (of 90khz) 1 frame = 192 samples = 360ticks
// 44100hz = 2.040816
for (int j = 0; j < ptsval.length - 1; j++)
{
for (int i = 0, k = vptsval.length; i < k; i += 2)
{
while (pause())
{}
if (isCancelled(job_processing))
return;
//jump back (not yet) or insert silent samples
if (ContainsVideoPTS && vptsval[i] < getTimePosition())
{
sample_pts = vptsval[i + 1] > getTimePosition() ? getTimePosition() - vptsval[i] : vptsval[i + 1] - vptsval[i];
sample_bytes = (long) Math.round(1.0 * audio.getSamplingFrequency() * sample_pts / 90000.0) * audio.getMode();
if (Debug)
System.out.println("i " + sample_pts + "/" + sample_bytes + "/" + getFramePosition() + "/" + getTimePosition());
for (long sample_pos = 0; sample_pos < sample_bytes; )
{
sample_size = (sample_bytes - sample_pos) >= read_size ? read_size : (int)(sample_bytes - sample_pos);
if (sample_size != array.length)
array = new byte[sample_size];
sample_pos += sample_size;
writeChannel1(array);
}
countTimeCounter(sample_pts);
FrameExportInfo.countWrittenFrames(sample_bytes / audio.getMode());
Common.setFps(FrameExportInfo.getWrittenFrames());
if (vptsval[i + 1] > getTimePosition())
{
sample_pts = vptsval[i + 1] - getTimePosition();
sample_bytes = (long) Math.round(1.0 * audio.getSamplingFrequency() * sample_pts / 90000.0) * audio.getMode();
if (Debug)
System.out.println("b " + sample_pts + "/" + sample_bytes + "/" + getFramePosition() + "/" + getTimePosition());
for (long sample_pos = 0; sample_pos < sample_bytes; )
{
sample_size = (sample_bytes - sample_pos) >= read_size ? read_size : (int)(sample_bytes - sample_pos);
if (sample_size != array.length)
array = new byte[sample_size];
readInputStream(array);
sample_pos += sample_size;
writeChannel1(array);
}
countFramePosition(sample_bytes);
countTimePosition(sample_pts);
countTimeCounter(sample_pts);
FrameExportInfo.countWrittenFrames(sample_bytes / audio.getMode());
}
}
else
{
skip_pts = ContainsVideoPTS ? vptsval[i] - getTimePosition() : 0;
skip_bytes = (long) Math.round(1.0 * audio.getSamplingFrequency() * skip_pts / 90000.0) * audio.getMode();
sample_pts = ContainsVideoPTS ? vptsval[i + 1] - vptsval[i] : (long)(1.0 * (audio.getSizeBase() / audio.getMode()) / audio.getSamplingFrequency() * 90000.0);
sample_bytes = (long) Math.round(1.0 * audio.getSamplingFrequency() * sample_pts / 90000.0) * audio.getMode();
for (long skip_pos = 0; skip_pos < skip_bytes; )
skip_pos += skipInputStream(skip_bytes - skip_pos);
countFramePosition(skip_bytes);
if (Debug)
System.out.println("c " + skip_pts + "/" + skip_bytes + "/" + sample_pts + "/" + sample_bytes + "/" + getFramePosition() + "/" + getTimePosition());
for (long sample_pos = 0; sample_pos < sample_bytes; )
{
sample_size = (sample_bytes - sample_pos) >= read_size ? read_size : (int)(sample_bytes - sample_pos);
if (sample_size != array.length)
array = new byte[sample_size];
readInputStream(array);
sample_pos += sample_size;
writeChannel1(array);
}
countTimePosition(skip_pts + sample_pts);
countTimeCounter(sample_pts);
countFramePosition(sample_bytes);
FrameExportInfo.countWrittenFrames(sample_bytes / audio.getMode());
}
if (Debug)
System.out.println(FrameExportInfo.getSummary() + " @ " + formatFrameTime(getTimeCounter()));
Common.updateProgressBar(getFramePosition(), FileLength);
if (Debug)
System.out.println("FramePosition " + getFramePosition());
}
break;
}
}
/**
* wri + pre + skip + ins + add
*/
class FrameExportInfo {
private int writtenFrames;
private int preInsertedFrames;
private int skippedFrames;
private int insertedFrames;
private int addedFrames;
private String head = "Audio Frames: wri-pre-skip-ins-add: ";
private String delim = "-";
public FrameExportInfo()
{
reset();
}
public void reset()
{
writtenFrames = 0;
preInsertedFrames = 0;
skippedFrames = 0;
insertedFrames = 0;
addedFrames = 0;
}
public int getWrittenFrames()
{
return writtenFrames;
}
public String getSummary()
{
StringBuffer sb = new StringBuffer(head);
sb.append(writtenFrames);
sb.append(delim);
sb.append(getShortSummary());
return sb.toString();
}
public String getShortSummary()
{
StringBuffer sb = new StringBuffer();
sb.append(preInsertedFrames);
sb.append(delim);
sb.append(skippedFrames);
sb.append(delim);
sb.append(insertedFrames);
sb.append(delim);
sb.append(addedFrames);
return sb.toString();
}
public void countWrittenFrames(long value)
{
writtenFrames += ((int) value);
}
public void countWrittenFrames(int value)
{
writtenFrames += value;
}
public void countPreInsertedFrames(int value)
{
preInsertedFrames += value;
}
public void countSkippedFrames(int value)
{
skippedFrames += value;
}
public void countInsertedFrames(int value)
{
insertedFrames += value;
}
public void countAddedFrames(int value)
{
addedFrames += value;
}
}
}