protected virtual void DoFinalTasks(Dictionary <uint, FileStream> streamWriters, MpegStream.DemuxOptionsStruct demuxOptions) { GenhCreationStruct gcStruct; string sourceFile; string genhFile; foreach (uint key in streamWriters.Keys) { // create GENH since MIB support is spotty if (demuxOptions.AddHeader) { if (streamWriters[key].Name.EndsWith(this.FileExtensionAudio)) { sourceFile = streamWriters[key].Name; streamWriters[key].Close(); streamWriters[key].Dispose(); gcStruct = new GenhCreationStruct(); gcStruct.Format = "0x00"; gcStruct.HeaderSkip = "0"; gcStruct.Interleave = "0x100"; gcStruct.Channels = "2"; gcStruct.Frequency = "48000"; gcStruct.NoLoops = true; genhFile = GenhUtil.CreateGenhFile(sourceFile, gcStruct); // delete original file if (!String.IsNullOrEmpty(genhFile)) { File.Delete(sourceFile); } } } // close streams if open if (streamWriters[key] != null && streamWriters[key].CanRead) { streamWriters[key].Close(); streamWriters[key].Dispose(); } } }
public void DemultiplexStreams(MpegStream.DemuxOptionsStruct demuxStruct) { long fileSize; long currentOffset = 0; long blockStart = 0; long packetSize; long nextPacketSize = -1; long videoPacketSize; long[] audioStreamPacketSizes; Dictionary <string, FileStream> streamOutputWriters = new Dictionary <string, FileStream>(); long audioStreamOffset; long videoStreamOffset; GenhCreationStruct gcStruct; string genhFile; using (FileStream fs = File.Open(this.FilePath, FileMode.Open, FileAccess.Read)) { fileSize = fs.Length; while ((nextPacketSize != 0) && (currentOffset < fileSize)) { blockStart = currentOffset; if (currentOffset == 0) { // get main header this.FileHeader = new XmvVideoDataHeader(); this.FileHeader.MagicBytes = ParseFile.ParseSimpleOffset(fs, 0xC, 4); if (!ParseFile.CompareSegment(this.FileHeader.MagicBytes, 0, XmvMagicBytes)) { throw new FormatException(String.Format("XMV Magic Bytes: 'xobX' not found at offset 0xC{0}", Environment.NewLine)); } this.FileHeader.InitialPacketSize = ParseFile.ParseSimpleOffset(fs, 4, 4); this.FileHeader.VideoWidth = ParseFile.ParseSimpleOffset(fs, 0x14, 4); this.FileHeader.VideoHeight = ParseFile.ParseSimpleOffset(fs, 0x18, 4); // get audio subheaders this.FileHeader.AudioStreamCount = (UInt32)BitConverter.ToUInt16(ParseFile.ParseSimpleOffset(fs, 0x20, 2), 0); this.FileHeader.AudioHeaders = new XmvAudioDataHeader[this.FileHeader.AudioStreamCount]; for (uint i = 0; i < this.FileHeader.AudioStreamCount; i++) { this.FileHeader.AudioHeaders[i] = new XmvAudioDataHeader(); this.FileHeader.AudioHeaders[i].WaveFormat = ParseFile.ParseSimpleOffset(fs, 0x24 + (i * 0xC), 2); this.FileHeader.AudioHeaders[i].ChannelCount = ParseFile.ParseSimpleOffset(fs, 0x24 + (i * 0xC) + 2, 2); this.FileHeader.AudioHeaders[i].SamplesPerSecond = ParseFile.ParseSimpleOffset(fs, 0x24 + (i * 0xC) + 4, 4); this.FileHeader.AudioHeaders[i].BitsPerSample = ParseFile.ParseSimpleOffset(fs, 0x24 + (i * 0xC) + 8, 4); } // set next packet size nextPacketSize = (long)BitConverter.ToUInt32(this.FileHeader.InitialPacketSize, 0); currentOffset = 0x24 + (this.FileHeader.AudioStreamCount * 0xC); } // set packet size of current packet packetSize = nextPacketSize; // get size of next packet nextPacketSize = (long)BitConverter.ToUInt32(ParseFile.ParseSimpleOffset(fs, currentOffset, 4), 0); // get size of video data videoPacketSize = BitConverter.ToUInt32(ParseFile.ParseSimpleOffset(fs, currentOffset + 4, 4), 0); videoPacketSize &= 0x000FFFFF; videoPacketSize -= (this.FileHeader.AudioStreamCount * 4); //------------------ // write video data //------------------ if (demuxStruct.ExtractVideo) { this.FileHeader.OutputPath = Path.Combine(Path.GetDirectoryName(this.FilePath), String.Format("{0}.xmv.raw", Path.GetFileNameWithoutExtension(this.FilePath))); // add output stream to Dictionary if (!streamOutputWriters.ContainsKey(this.FileHeader.OutputPath)) { streamOutputWriters.Add(this.FileHeader.OutputPath, new FileStream(this.FileHeader.OutputPath, FileMode.Create, FileAccess.ReadWrite)); } // write the video packet videoStreamOffset = currentOffset + 0xC + (this.FileHeader.AudioStreamCount * 4); streamOutputWriters[this.FileHeader.OutputPath].Write(ParseFile.ParseSimpleOffset(fs, videoStreamOffset, (int)videoPacketSize), 0, (int)videoPacketSize); } //------------------ // write audio data //------------------ if (demuxStruct.ExtractAudio) { // setup audio for writing audioStreamPacketSizes = new long[this.FileHeader.AudioStreamCount]; audioStreamOffset = currentOffset + 0xC + (this.FileHeader.AudioStreamCount * 4) + videoPacketSize; for (uint i = 0; i < this.FileHeader.AudioStreamCount; i++) { audioStreamPacketSizes[i] = BitConverter.ToUInt32(ParseFile.ParseSimpleOffset(fs, currentOffset + 0xC + (i * 4), 4), 0); // write audio streams this.FileHeader.AudioHeaders[i].OutputPath = Path.Combine(Path.GetDirectoryName(this.FilePath), String.Format("{0}_{1}.raw", Path.GetFileNameWithoutExtension(this.FilePath), i.ToString("X2"))); // add output stream to Dictionary if (!streamOutputWriters.ContainsKey(this.FileHeader.AudioHeaders[i].OutputPath)) { streamOutputWriters.Add(this.FileHeader.AudioHeaders[i].OutputPath, new FileStream(this.FileHeader.AudioHeaders[i].OutputPath, FileMode.Create, FileAccess.ReadWrite)); } // write this audio packet streamOutputWriters[this.FileHeader.AudioHeaders[i].OutputPath].Write(ParseFile.ParseSimpleOffset(fs, audioStreamOffset, (int)audioStreamPacketSizes[i]), 0, (int)audioStreamPacketSizes[i]); // increase source offset to next packet audioStreamOffset += audioStreamPacketSizes[i]; } } currentOffset = blockStart + packetSize; } // (currentOffset < fileSize) //------------------- // close all writers //------------------- foreach (string k in streamOutputWriters.Keys) { if (streamOutputWriters[k].CanRead) { streamOutputWriters[k].Close(); streamOutputWriters[k].Dispose(); } } // interleave audio // is this needed at all, ONLY FOR MULTI-STREAM, SINGLE CHANNEL PER STREAM? //------------------ // add audio header //------------------ if (demuxStruct.ExtractAudio && demuxStruct.AddHeader) { for (int i = 0; i < this.FileHeader.AudioStreamCount; i++) { if (BitConverter.ToUInt16(this.FileHeader.AudioHeaders[i].WaveFormat, 0) == 0x69) { gcStruct = new GenhCreationStruct(); gcStruct.Format = "0x01"; gcStruct.HeaderSkip = "0"; gcStruct.Interleave = "0x1"; gcStruct.Channels = BitConverter.ToUInt16(this.FileHeader.AudioHeaders[i].ChannelCount, 0).ToString(); gcStruct.Frequency = BitConverter.ToUInt16(this.FileHeader.AudioHeaders[i].SamplesPerSecond, 0).ToString(); gcStruct.NoLoops = true; genhFile = GenhUtil.CreateGenhFile(this.FileHeader.AudioHeaders[i].OutputPath, gcStruct); // delete original file if (!String.IsNullOrEmpty(genhFile)) { File.Delete(this.FileHeader.AudioHeaders[i].OutputPath); } } } } //------------------ // add video header //------------------ } }
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); } } } } }
protected override void DoFinalTasks(Dictionary <uint, FileStream> streamWriters, MpegStream.DemuxOptionsStruct demuxOptions) { GenhCreationStruct gcStruct; ushort frequency; string sourceFile; string genhFile = null; string rawFile; foreach (uint key in streamWriters.Keys) { if (demuxOptions.AddHeader && (key != MobiclipWiiStream.VideoChunkId) && (this.AudioStreamFeatures[key].StreamType != null) && (this.AudioStreamFeatures[key].StreamType == AudioChunkSignaturePcm)) { if (streamWriters[key].Name.EndsWith(this.FileExtensionAudio)) { sourceFile = streamWriters[key].Name; streamWriters[key].Close(); streamWriters[key].Dispose(); gcStruct = new GenhCreationStruct(); switch (this.AudioStreamFeatures[key].StreamType) { case AudioChunkSignaturePcm: gcStruct.Format = "0x04"; gcStruct.HeaderSkip = "0"; gcStruct.Interleave = "0x2"; gcStruct.Channels = this.AudioStreamFeatures[key].Channels.ToString(); gcStruct.Frequency = this.AudioStreamFeatures[key].Frequency.ToString(); gcStruct.NoLoops = true; genhFile = GenhUtil.CreateGenhFile(sourceFile, gcStruct); break; default: break; } // delete original file if (!String.IsNullOrEmpty(genhFile)) { File.Delete(sourceFile); } } } else if (key != MobiclipWiiStream.VideoChunkId) { // update raw file extension if (this.AudioStreamFeatures[key].StreamType == AudioChunkSignatureA3) { rawFile = streamWriters[key].Name; streamWriters[key].Close(); streamWriters[key].Dispose(); File.Copy(rawFile, Path.ChangeExtension(rawFile, FileExtensionAudioA3)); File.Delete(rawFile); } } } base.DoFinalTasks(streamWriters, demuxOptions); }
private void createGenhs(GenhCreatorStruct pGenhCreatorStruct, DoWorkEventArgs e) { int progress; GenhCreationStruct genhCreationStruct; this.maxFiles = pGenhCreatorStruct.SourcePaths.Length; string outputFilePath = String.Empty; string extractedFilePath; string outputMessageAction = String.Empty; StringBuilder outputMessage = new StringBuilder(); int progressReportingPercentage = 10; int progressReportingPercentageIncrementValue = 10; foreach (string file in pGenhCreatorStruct.SourcePaths) { progress = (++this.fileCount * 100) / this.maxFiles; // throttle output to prevent locking up the GUI if ((progress > progressReportingPercentage) || (this.fileCount == this.maxFiles)) { this.progressStruct.Clear(); this.progressStruct.FileName = file; ReportProgress(progress, this.progressStruct); } if (File.Exists(file)) { if (pGenhCreatorStruct.DoExtract) { outputFilePath = GenhUtil.ExtractGenhFile(file, true, true, true); outputMessageAction = "Extracted"; } else { genhCreationStruct = pGenhCreatorStruct.ToGenhCreationStruct(); if (pGenhCreatorStruct.DoCreation) { outputFilePath = GenhUtil.CreateGenhFile(file, genhCreationStruct); outputMessageAction = "Created"; } else if (pGenhCreatorStruct.DoEdit) { extractedFilePath = GenhUtil.ExtractGenhFile(file, false, false, false); if (!String.IsNullOrEmpty(extractedFilePath)) { genhCreationStruct.SourcePaths = new string[1]; genhCreationStruct.SourcePaths[0] = extractedFilePath; outputFilePath = GenhUtil.CreateGenhFile(extractedFilePath, genhCreationStruct); File.Delete(extractedFilePath); } outputMessageAction = "Edited"; } } if (!String.IsNullOrEmpty(outputFilePath)) { outputMessage.AppendFormat("{0} {1}.{2}", outputFilePath, outputMessageAction, Environment.NewLine); } // throttle output to prevent locking up the GUI if ((progress > progressReportingPercentage) || (this.fileCount == this.maxFiles)) { progressReportingPercentage += progressReportingPercentageIncrementValue; this.progressStruct.Clear(); this.progressStruct.GenericMessage = outputMessage.ToString(); ReportProgress(Constants.ProgressMessageOnly, this.progressStruct); outputMessage.Length = 0; } } } }