protected override void DoFinalTasks(FileStream sourceFileStream, Dictionary <uint, FileStream> outputFiles, bool addHeader) { byte[] headerBytes; byte[] aa3HeaderBytes; uint headerBlock; string sourceFile; foreach (uint streamId in outputFiles.Keys) { if (this.IsThisAnAudioBlock(BitConverter.GetBytes(streamId)) && outputFiles[streamId].Name.EndsWith(Atrac3AudioExtension)) { headerBytes = ParseFile.ParseSimpleOffset(outputFiles[streamId], 0, 0x8); // remove all header chunks string cleanedFile = FileUtil.RemoveAllChunksFromFile(outputFiles[streamId], headerBytes); // close stream and rename file sourceFile = outputFiles[streamId].Name; outputFiles[streamId].Close(); outputFiles[streamId].Dispose(); File.Delete(sourceFile); File.Move(cleanedFile, sourceFile); // add header if (addHeader) { Array.Reverse(headerBytes); headerBlock = BitConverter.ToUInt32(headerBytes, 4); string headeredFile = Path.ChangeExtension(sourceFile, Atrac3Plus.FileExtensionPsp); aa3HeaderBytes = Atrac3Plus.GetAa3Header(headerBlock); FileUtil.AddHeaderToFile(aa3HeaderBytes, sourceFile, headeredFile); File.Delete(sourceFile); } } //else if (this.IsThisAnAudioBlock(BitConverter.GetBytes(streamId)) && // outputFiles[streamId].Name.EndsWith(SubTitleExtension)) //{ // this.ConvertSubtitles(streamId, outputFiles[streamId]); //} } }
protected override void DoTaskForFile(string pPath, IVgmtWorkerStruct pXmaConverterStruct, DoWorkEventArgs e) { XmaConverterStruct taskStruct = (XmaConverterStruct)pXmaConverterStruct; string workingFolder; string workingFile; string workingSourceFile; string consoleOutput = String.Empty; string consoleError = String.Empty; uint riffFrequency; uint riffChannelCount; uint riffFileSize; string riffHeaderedFile; byte[] riffHeaderBytes; uint loopStart; uint loopLength; uint loopEnd; byte[] posBytes; //------------------ // output file name //------------------ this.ShowOutput(pPath, String.Format("[{0}]", Path.GetFileName(pPath)), false); //---------------------- // build working folder //---------------------- workingFolder = this.createWorkingFolder(pPath, taskStruct); //------------------------------------ // copy source file to working folder //------------------------------------ workingSourceFile = Path.Combine(workingFolder, Path.GetFileName(pPath)); File.Copy(pPath, workingSourceFile, true); taskStruct.NumberOfStreams = 1; for (int i = 0; i < taskStruct.NumberOfStreams; i++) { // set working file workingFile = workingSourceFile; #region XMAPARSE //--------------------------- // xma_parse.exe //--------------------------- if (taskStruct.DoXmaParse) { this.ShowOutput(pPath, "---- calling xma_parse.exe", false); // call xma_parse and set output as working_file for next step workingFile = this.callXmaParse(workingFolder, workingFile, taskStruct, out consoleOutput, out consoleError); // show output if (taskStruct.ShowExeOutput && !String.IsNullOrEmpty(consoleOutput)) { this.ShowOutput(pPath, consoleOutput, false); } // clear errors if ignore is selected, but only if a file was created if (taskStruct.XmaParseIgnoreErrors && (File.Exists(workingFile))) { consoleError = String.Empty; } } // #endregion #region RIFF HEADER if ((taskStruct.DoRiffHeader) && (String.IsNullOrEmpty(consoleError))) { //----------------- // get RIFF header //----------------- this.ShowOutput(pPath, "---- adding RIFF header.", false); // frequency if (taskStruct.GetFrequencyFromRiffHeader) { riffFrequency = (uint)RiffUtil.GetFrequencyFromRiffHeader(workingSourceFile); } else if (taskStruct.GetFrequencyFromOffset) { using (FileStream fs = File.OpenRead(workingSourceFile)) { riffFrequency = (uint)ParseFile.GetVaryingByteValueAtAbsoluteOffset(fs, taskStruct.RiffHeaderFrequencyOffsetInfo, true); } } else { riffFrequency = (uint)ByteConversion.GetLongValueFromString(taskStruct.RiffFrequency); } // channels if (taskStruct.GetChannelsFromRiffHeader) { riffChannelCount = RiffUtil.GetChannelsFromRiffHeader(workingSourceFile); } else if (taskStruct.GetChannelsFromOffset) { using (FileStream fs = File.OpenRead(workingSourceFile)) { riffChannelCount = (uint)ParseFile.GetVaryingByteValueAtAbsoluteOffset(fs, taskStruct.RiffHeaderChannelOffsetInfo, true); if (riffChannelCount > 2) { riffChannelCount = 2; } } } else { riffChannelCount = (uint)ByteConversion.GetLongValueFromString(taskStruct.RiffChannelCount); } riffFileSize = (uint)new FileInfo(workingFile).Length; riffHeaderBytes = this.getRiffHeader(riffFrequency, riffChannelCount, riffFileSize); //------------------------- // add RIFF header to file //------------------------- riffHeaderedFile = Path.ChangeExtension(workingFile, RIFF_COPY_OUTPUT_EXTENSION); FileUtil.AddHeaderToFile(riffHeaderBytes, workingFile, riffHeaderedFile); // set working file for next workingFile = riffHeaderedFile; } else if (!String.IsNullOrEmpty(consoleError)) { // dispay xma_parse.exe error this.ShowOutput(pPath, consoleError, true); } #endregion #region POS CREATOR //----------- // POS Maker //----------- if ((taskStruct.DoPosMaker) && (String.IsNullOrEmpty(consoleError))) { this.ShowOutput(pPath, "---- creating POS file", false); // loop start if (taskStruct.PosLoopStartIsStatic) { loopStart = (uint)ByteConversion.GetLongValueFromString(taskStruct.PosLoopStartStaticValue); } else { using (FileStream fs = File.OpenRead(workingSourceFile)) { loopStart = (uint)ParseFile.GetVaryingByteValueAtAbsoluteOffset(fs, taskStruct.PosLoopStartOffsetInfo, true); if (!String.IsNullOrEmpty(taskStruct.PosLoopStartOffsetInfo.CalculationString)) { string calculationString = taskStruct.PosLoopStartOffsetInfo.CalculationString.Replace(CalculatingOffsetDescription.OFFSET_VARIABLE_STRING, loopStart.ToString()); loopStart = (uint)ByteConversion.GetLongValueFromString(MathUtil.Evaluate(calculationString)); } } } // loop length if (taskStruct.PosLoopEndIsStatic) { loopLength = (uint)ByteConversion.GetLongValueFromString(taskStruct.PosLoopEndStaticValue); } else { using (FileStream fs = File.OpenRead(workingSourceFile)) { loopLength = (uint)ParseFile.GetVaryingByteValueAtAbsoluteOffset(fs, taskStruct.PosLoopEndOffsetInfo, true); if (!String.IsNullOrEmpty(taskStruct.PosLoopEndOffsetInfo.CalculationString)) { string calculationString = taskStruct.PosLoopEndOffsetInfo.CalculationString.Replace(CalculatingOffsetDescription.OFFSET_VARIABLE_STRING, loopLength.ToString()); loopLength = (uint)ByteConversion.GetLongValueFromString(MathUtil.Evaluate(calculationString)); } } } if (loopLength > 0) { loopEnd = loopStart + loopLength; // build .pos array and write to file posBytes = new byte[8]; Array.Copy(BitConverter.GetBytes(loopStart), 0, posBytes, 0, 4); Array.Copy(BitConverter.GetBytes(loopEnd), 0, posBytes, 4, 4); using (FileStream fs = File.Open(Path.ChangeExtension(workingSourceFile, ".pos"), FileMode.Create, FileAccess.Write)) { fs.Write(posBytes, 0, posBytes.Length); } } } #endregion #region TOWAV //----------- // ToWav.exe //----------- if ((taskStruct.DoToWav) && (String.IsNullOrEmpty(consoleError))) { this.ShowOutput(pPath, "---- calling ToWav.exe", false); // call ToWav.exe and set working file for next step (if ever needed) workingFile = this.callToWav(workingFolder, workingFile, taskStruct, out consoleOutput, out consoleError); // show output if (taskStruct.ShowExeOutput && !String.IsNullOrEmpty(consoleOutput)) { this.ShowOutput(pPath, consoleOutput, false); } // dispay ToWav.exe error if (!String.IsNullOrEmpty(consoleError)) { this.ShowOutput(pPath, consoleError, true); } } #endregion #region XMAENCODE //--------------- // XmaEncode.exe //--------------- else if ((taskStruct.DoXmaEncode) && (String.IsNullOrEmpty(consoleError))) { this.ShowOutput(pPath, "---- calling xmaencode.exe", false); // call xmaencode.exe and set working file for next step (if ever needed) workingFile = this.callXmaEncode(workingFolder, workingFile, taskStruct, out consoleOutput, out consoleError); // show output if (taskStruct.ShowExeOutput && !String.IsNullOrEmpty(consoleOutput)) { this.ShowOutput(pPath, consoleOutput, false); } // dispay xmaencode.exe error if (!String.IsNullOrEmpty(consoleError)) { this.ShowOutput(pPath, consoleError, true); } } #endregion } // for (int i = 0; i < taskStruct.NumberOfStreams; i++) //---------------------- // clean working folder //---------------------- this.cleanWorkingFolder(pPath, workingSourceFile, taskStruct); }
protected virtual void DoFinalTasks(Dictionary <uint, FileStream> streamWriters, MpegStream.DemuxOptionsStruct demuxOptions) { string sourceFile; string headeredFile; int headerSize; byte[] headerBytes; byte[] frameOffsetBytes; uint previousFrameOffset; uint frameOffset; uint maxFrameSize; uint fileLength; int audioTrackIndex; uint frameStartLocation; byte[] dummyValues = new byte[4]; foreach (uint key in streamWriters.Keys) { try { if (demuxOptions.AddHeader) { ////////////////////// // Multi-Track Audio ////////////////////// if (streamWriters[key].Name.EndsWith(BinkStream.DefaultFileExtensionAudioMulti)) { ////////////////////////// // update original header ////////////////////////// headerBytes = new byte[this.FullHeader.Length]; Array.Copy(this.FullHeader, headerBytes, this.FullHeader.Length); // set frame start location frameStartLocation = 0x2C + (this.AudioTrackCount * 0xC); if (this.BinkVersion == BinkType.Version02) { frameStartLocation += 4; } // set file size fileLength = (uint)(streamWriters[key].Length + headerBytes.Length - 8); // set video size to minimum Array.Copy(BitConverter.GetBytes((uint)1), 0, headerBytes, 0x14, 4); Array.Copy(BitConverter.GetBytes((uint)1), 0, headerBytes, 0x18, 4); // insert file length Array.Copy(BitConverter.GetBytes(fileLength), 0, headerBytes, 4, 4); // insert frame offsets previousFrameOffset = 0; frameOffset = 0; maxFrameSize = 0; for (uint i = 0; i < this.FrameCount; i++) { // set previous offset previousFrameOffset = frameOffset; frameOffset = this.NewFrameOffsetsAudio[0][i]; if (this.FrameOffsetList[i].IsKeyFrame) { // add key frame bit frameOffsetBytes = BitConverter.GetBytes(frameOffset | 1); } else { frameOffsetBytes = BitConverter.GetBytes(frameOffset); } // insert offset Array.Copy(frameOffsetBytes, 0, headerBytes, (frameStartLocation + (i * 4)), 4); // calculate max frame size if ((frameOffset - previousFrameOffset) > maxFrameSize) { maxFrameSize = frameOffset - previousFrameOffset; } } // Add last frame offset (EOF) fileLength = (uint)(streamWriters[key].Length + headerBytes.Length); Array.Copy(BitConverter.GetBytes(fileLength), 0, headerBytes, (frameStartLocation + (this.FrameCount * 4)), 4); // insert max frame size if ((fileLength - frameOffset) > maxFrameSize) { maxFrameSize = fileLength - frameOffset; } Array.Copy(BitConverter.GetBytes(maxFrameSize), 0, headerBytes, 0xC, 4); // append to file sourceFile = streamWriters[key].Name; headeredFile = sourceFile + ".headered"; streamWriters[key].Close(); streamWriters[key].Dispose(); FileUtil.AddHeaderToFile(headerBytes, streamWriters[key].Name, headeredFile); File.Delete(streamWriters[key].Name); File.Move(headeredFile, streamWriters[key].Name); } ////////////////////// // Split Track Audio ////////////////////// else if (streamWriters[key].Name.EndsWith(BinkStream.DefaultFileExtensionAudioSplit)) { ////////////////////////// // update original header ////////////////////////// headerBytes = new byte[this.FullHeader.Length]; Array.Copy(this.FullHeader, headerBytes, this.FullHeader.Length); // set video size to minimum Array.Copy(BitConverter.GetBytes((uint)1), 0, headerBytes, 0x14, 4); Array.Copy(BitConverter.GetBytes((uint)1), 0, headerBytes, 0x18, 4); // get track info audioTrackIndex = this.getIndexForSplitAudioTrackFileName(streamWriters[key].Name); // resize header since all audio info except this track will be removied headerSize = (int)(0x2C + 0xC + ((this.FrameCount + 1) * 4)); if (this.BinkVersion == BinkType.Version02) { headerSize += 4; } Array.Resize(ref headerBytes, headerSize); // insert audio info for this track headerBytes[0x28] = 1; Array.Copy(this.FullHeader, 0x2C + (audioTrackIndex * 4), headerBytes, 0x2C, 4); // only one audio track, audio track id must equal zero if (this.BinkVersion == BinkType.Version01) { Array.Copy(this.FullHeader, 0x2C + (this.AudioTrackCount * 4) + (audioTrackIndex * 4), headerBytes, 0x30, 4); Array.Copy(BitConverter.GetBytes((uint)0), 0, headerBytes, 0x34, 4); } else if (this.BinkVersion == BinkType.Version02) { Array.Copy(this.FullHeader, 0x30 + (audioTrackIndex * 4), headerBytes, 0x30, 4); Array.Copy(this.FullHeader, 0x30 + (this.AudioTrackCount * 4) + (audioTrackIndex * 4), headerBytes, 0x34, 4); Array.Copy(BitConverter.GetBytes((uint)0), 0, headerBytes, 0x38, 4); } else { throw new FormatException("Unsupported Bink type for split audio streams."); } // set file size fileLength = (uint)(streamWriters[key].Length + headerBytes.Length - 8); Array.Copy(BitConverter.GetBytes(fileLength), 0, headerBytes, 4, 4); // insert frame offsets previousFrameOffset = 0; frameOffset = 0; maxFrameSize = 0; frameStartLocation = 0x2C + 0xC; if (this.BinkVersion == BinkType.Version02) { frameStartLocation += 4; } for (uint i = 0; i < this.FrameCount; i++) { // set previous offset previousFrameOffset = frameOffset; frameOffset = this.NewFrameOffsetsAudio[audioTrackIndex][i]; if (this.FrameOffsetList[i].IsKeyFrame) { // add key frame bit frameOffsetBytes = BitConverter.GetBytes(this.NewFrameOffsetsAudio[audioTrackIndex][i] | 1); } else { frameOffsetBytes = BitConverter.GetBytes(this.NewFrameOffsetsAudio[audioTrackIndex][i]); } // insert offset Array.Copy(frameOffsetBytes, 0, headerBytes, (frameStartLocation + (i * 4)), 4); // calculate max frame size if ((frameOffset - previousFrameOffset) > maxFrameSize) { maxFrameSize = frameOffset - previousFrameOffset; } } // Add last frame offset (EOF) fileLength = (uint)(streamWriters[key].Length + headerBytes.Length); Array.Copy(BitConverter.GetBytes(fileLength), 0, headerBytes, (frameStartLocation + (this.FrameCount * 4)), 4); // insert max frame size if ((fileLength - frameOffset) > maxFrameSize) { maxFrameSize = fileLength - frameOffset; } Array.Copy(BitConverter.GetBytes(maxFrameSize), 0, headerBytes, 0xC, 4); // append to file sourceFile = streamWriters[key].Name; headeredFile = sourceFile + ".headered"; streamWriters[key].Close(); streamWriters[key].Dispose(); FileUtil.AddHeaderToFile(headerBytes, streamWriters[key].Name, headeredFile); File.Delete(streamWriters[key].Name); File.Move(headeredFile, streamWriters[key].Name); } ////////////////////// // Video ////////////////////// else if (streamWriters[key].Name.EndsWith(BinkStream.DefaultFileExtensionVideo)) { ////////////////////////// // update original header ////////////////////////// headerBytes = new byte[this.FullHeader.Length]; Array.Copy(this.FullHeader, headerBytes, this.FullHeader.Length); // resize header since audio info will be removied headerSize = (int)(0x2C + ((this.FrameCount + 1) * 4)); if (this.BinkVersion == BinkType.Version02) { headerSize += 4; } Array.Resize(ref headerBytes, headerSize); // set file size fileLength = (uint)(streamWriters[key].Length + headerBytes.Length - 8); Array.Copy(BitConverter.GetBytes(fileLength), 0, headerBytes, 4, 4); // set audio track count to zero headerBytes[0x28] = 0; // insert frame offsets previousFrameOffset = 0; frameOffset = 0; maxFrameSize = 0; frameStartLocation = 0x2C; if (this.BinkVersion == BinkType.Version02) { frameStartLocation += 4; } for (uint i = 0; i < this.FrameCount; i++) { // set previous offset previousFrameOffset = frameOffset; frameOffset = this.NewFrameOffsetsVideo[i]; if (this.FrameOffsetList[i].IsKeyFrame) { // add key frame bit frameOffsetBytes = BitConverter.GetBytes(this.NewFrameOffsetsVideo[i] | 1); } else { frameOffsetBytes = BitConverter.GetBytes(this.NewFrameOffsetsVideo[i]); } // insert frame offset Array.Copy(frameOffsetBytes, 0, headerBytes, (frameStartLocation + (i * 4)), 4); // calculate max frame size if ((frameOffset - previousFrameOffset) > maxFrameSize) { maxFrameSize = frameOffset - previousFrameOffset; } } // Add last frame offset (EOF) fileLength = (uint)(streamWriters[key].Length + headerBytes.Length); Array.Copy(BitConverter.GetBytes(fileLength), 0, headerBytes, (frameStartLocation + (this.FrameCount * 4)), 4); // insert max frame size if ((fileLength - frameOffset) > maxFrameSize) { maxFrameSize = fileLength - frameOffset; } Array.Copy(BitConverter.GetBytes(maxFrameSize), 0, headerBytes, 0xC, 4); // append to file sourceFile = streamWriters[key].Name; headeredFile = sourceFile + ".headered"; streamWriters[key].Close(); streamWriters[key].Dispose(); FileUtil.AddHeaderToFile(headerBytes, streamWriters[key].Name, headeredFile); File.Delete(streamWriters[key].Name); File.Move(headeredFile, streamWriters[key].Name); } } } catch (Exception ex) { if (streamWriters[key] != null) { throw new Exception(String.Format("Exception building header for file: {0}{1}{2}", streamWriters[key].Name, ex.Message, Environment.NewLine)); } else { throw new Exception(String.Format("Exception building header for file: {0}{1}{2}", "UNKNOWN", ex.Message, Environment.NewLine)); } } finally { // close streams if open if (streamWriters[key] != null && streamWriters[key].CanRead) { streamWriters[key].Close(); streamWriters[key].Dispose(); } } } }
protected override void DoFinalTasks(FileStream sourceFileStream, Dictionary <uint, FileStream> outputFiles, bool addHeader) { byte[] headerBytes; byte[] aa3HeaderBytes; uint headerBlock; string sourceFile; long streamInfoOffset; byte streamIdByte; byte streamIdCheckByte; byte channelCount; GenhCreationStruct gcStruct; string genhFile; foreach (uint streamId in outputFiles.Keys) { if (this.IsThisAnAudioBlock(BitConverter.GetBytes(streamId))) { if (outputFiles[streamId].Name.EndsWith(Atrac3AudioExtension)) { headerBytes = ParseFile.ParseSimpleOffset(outputFiles[streamId], 0, 0x8); // remove all header chunks string cleanedFile = FileUtil.RemoveAllChunksFromFile(outputFiles[streamId], headerBytes); // close stream and rename file sourceFile = outputFiles[streamId].Name; outputFiles[streamId].Close(); outputFiles[streamId].Dispose(); File.Delete(sourceFile); File.Move(cleanedFile, sourceFile); // add header if (addHeader) { Array.Reverse(headerBytes); headerBlock = BitConverter.ToUInt32(headerBytes, 4); string headeredFile = Path.ChangeExtension(sourceFile, Atrac3Plus.FileExtension); aa3HeaderBytes = Atrac3Plus.GetAa3Header(headerBlock); FileUtil.AddHeaderToFile(aa3HeaderBytes, sourceFile, headeredFile); File.Delete(sourceFile); } } else if (addHeader && outputFiles[streamId].Name.EndsWith(LpcmAudioExtension)) { // get this block's stream id streamIdByte = BitConverter.GetBytes(streamId)[0]; // get location of first audio stream info block streamInfoOffset = ParseFile.GetNextOffset(sourceFileStream, 0, PamAudioStreamInfoStartBytes); // find matching info block while ((streamInfoOffset > -1)) { streamIdCheckByte = ParseFile.ParseSimpleOffset(sourceFileStream, streamInfoOffset + 0x4, 1)[0]; if (streamIdCheckByte == streamIdByte) { // get channel count channelCount = ParseFile.ParseSimpleOffset(sourceFileStream, streamInfoOffset + 0x11, 1)[0]; // close stream and build GENH file sourceFile = outputFiles[streamId].Name; outputFiles[streamId].Close(); outputFiles[streamId].Dispose(); gcStruct = new GenhCreationStruct(); gcStruct.Format = "0x03"; gcStruct.HeaderSkip = "0"; gcStruct.Interleave = "0x2"; gcStruct.Channels = channelCount.ToString(); gcStruct.Frequency = "48000"; gcStruct.NoLoops = true; genhFile = GenhUtil.CreateGenhFile(sourceFile, gcStruct); // delete original file if (!String.IsNullOrEmpty(genhFile)) { File.Delete(sourceFile); } break; } streamInfoOffset = ParseFile.GetNextOffset(sourceFileStream, streamInfoOffset + 1, PamAudioStreamInfoStartBytes); } } } } }