private long parseDataPacket(Stream inStream, long currentOffset, MpegStream.DemuxOptionsStruct demuxOptions) { long packetSize = 0; AsfDataPacketPayloadParsingObject dataPacketPayloadParsingObject; AsfDataPacketPayloadObject dataPacketPayloadObject; // get payload parsing info dataPacketPayloadParsingObject = this.parseAsfDataPacketPayloadParsingObject(inStream, currentOffset); currentOffset += dataPacketPayloadParsingObject.PacketOverheadLength; packetSize += dataPacketPayloadParsingObject.PacketOverheadLength; // parse payload(s) for (int i = 0; i < dataPacketPayloadParsingObject.NumberOfPayloads; i++) { dataPacketPayloadObject = this.parseAsfDataPacketPayloadObject(inStream, currentOffset, dataPacketPayloadParsingObject, demuxOptions); currentOffset += dataPacketPayloadObject.PayloadSize; packetSize += dataPacketPayloadObject.PayloadSize; } // skip padding currentOffset += dataPacketPayloadParsingObject.PaddingLength; packetSize += dataPacketPayloadParsingObject.PaddingLength; return(packetSize); }
protected virtual void DoFinalTasks(MpegStream.DemuxOptionsStruct demuxOptions) { foreach (uint key in this.streamWriterDictionary.Keys) { try { } catch (Exception ex) { if (this.streamWriterDictionary[key] != null) { throw new Exception(String.Format("Exception building header for file: {0}{1}{2}", this.streamWriterDictionary[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 (this.streamWriterDictionary[key] != null && this.streamWriterDictionary[key].CanRead) { this.streamWriterDictionary[key].Close(); this.streamWriterDictionary[key].Dispose(); } } } }
protected virtual void DoFinalTasks(Dictionary <uint, FileStream> streamWriters, MpegStream.DemuxOptionsStruct demuxOptions) { foreach (uint key in streamWriters.Keys) { if (streamWriters[key] != null && streamWriters[key].CanRead) { streamWriters[key].Close(); streamWriters[key].Dispose(); } } }
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 virtual void DemultiplexStreams(MpegStream.DemuxOptionsStruct demuxOptions) { long currentOffset = 0; long fileSize; long blockSize; long videoChunkSize; Dictionary <uint, FileStream> streamOutputWriters = new Dictionary <uint, FileStream>(); ChunkStruct currentChunk = new ChunkStruct(); ChunkStruct[] audioChunks; try { using (FileStream fs = File.OpenRead(this.FilePath)) { this.ReadHeader(fs, currentOffset); fileSize = fs.Length; currentOffset = ParseFile.GetNextOffset(fs, currentOffset, DataStartBytes) + 4; while (currentOffset < fileSize) { if (currentOffset == 0x4C7DC) { } blockSize = this.GetBlockSize(fs, currentOffset); if (blockSize > 0) { // write video block to stream currentChunk = this.GetVideoChunk(fs, currentOffset); if (demuxOptions.ExtractVideo && (currentChunk.Chunk != null)) { this.writeChunkToStream(currentChunk.Chunk, currentChunk.ChunkId, streamOutputWriters, this.FileExtensionVideo); } // NDS -- currentBlockId = (uint)(BitConverter.ToUInt16(ParseFile.ParseSimpleOffset(fs, currentOffset, 2), 0) & 0x00FF); // write audio block to stream if (demuxOptions.ExtractAudio && (this.AudioStreamCount > 0)) { videoChunkSize = currentChunk.Chunk == null ? 0 : currentChunk.Chunk.Length; audioChunks = this.GetAudioChunk(fs, currentOffset, blockSize, videoChunkSize); for (uint i = 0; i < this.AudioStreamCount; i++) { if (audioChunks[i].Chunk != null) { this.writeChunkToStream(audioChunks[i].Chunk, audioChunks[i].ChunkId, streamOutputWriters, this.FileExtensionAudio); } } } // move offset currentOffset += blockSize; } else { break; } } } // using (FileStream fs = File.OpenRead(this.FilePath)) } catch (Exception ex) { throw new Exception(String.Format("Exception processing block at offset 0x{0}: {1}{2}", currentOffset.ToString("X"), ex.Message, Environment.NewLine)); } finally { // clean up this.DoFinalTasks(streamOutputWriters, demuxOptions); } }
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 //------------------ } }
public virtual void DemultiplexStreams(MpegStream.DemuxOptionsStruct demuxOptions) { long currentOffset = 0; long fileSize; long packetEndOffset; uint audioPacketSize; byte[] audioPacket; byte[] emptyAudioPacket = new byte[] { 0x00, 0x00, 0x00, 0x00 }; uint videoPacketSize; byte[] videoPacket; long currentPacketOffset; Dictionary <uint, FileStream> streamOutputWriters = new Dictionary <uint, FileStream>(); // set audio extension based on flags if (demuxOptions.SplitAudioStreams) { this.FileExtensionAudio = BinkStream.DefaultFileExtensionAudioSplit; } else { this.FileExtensionAudio = BinkStream.DefaultFileExtensionAudioMulti; } try { using (FileStream fs = File.OpenRead(this.FilePath)) { fileSize = fs.Length; currentOffset = 0; // parse the header this.ParseHeader(fs, currentOffset); // setup new offsets and first frame this.NewFrameOffsetsVideo = new uint[this.FrameCount]; this.NewFrameOffsetsVideo[0] = this.FrameOffsetList[0].FrameOffset - (this.AudioTrackCount * 0xC); // subtract audio frame header info // setup audio frames this.NewFrameOffsetsAudio = new uint[this.AudioTrackCount][]; if (demuxOptions.SplitAudioStreams) { this.FileExtensionAudio = BinkStream.DefaultFileExtensionAudioSplit; for (uint i = 0; i < this.AudioTrackCount; i++) { this.NewFrameOffsetsAudio[i] = new uint[this.FrameCount]; this.NewFrameOffsetsAudio[i][0] = this.FrameOffsetList[0].FrameOffset - ((this.AudioTrackCount - 1) * 0xC); // only need one audio header area } } else if (this.AudioTrackCount > 0) { this.FileExtensionAudio = BinkStream.DefaultFileExtensionAudioMulti; this.NewFrameOffsetsAudio[0] = new uint[this.FrameCount]; this.NewFrameOffsetsAudio[0][0] = this.FrameOffsetList[0].FrameOffset; // all header info stays } ////////////////////// // process each frame ////////////////////// for (uint frameId = 0; frameId < this.FrameCount; frameId++) { try { currentPacketOffset = 0; //// check to see if final frame offset is file size frame //if (this.FrameOffsetList[frameId].FrameOffset + currentPacketOffset >= fileSize) //{ // break; //} if (demuxOptions.SplitAudioStreams) { ////////////////// // extract audio - separate tracks ////////////////// for (uint audioTrackId = 0; audioTrackId < this.AudioTrackCount; audioTrackId++) { audioPacketSize = BitConverter.ToUInt32(ParseFile.ParseSimpleOffset(fs, this.FrameOffsetList[frameId].FrameOffset + currentPacketOffset, 4), 0); audioPacketSize += 4; if (demuxOptions.ExtractAudio) { audioPacket = ParseFile.ParseSimpleOffset(fs, this.FrameOffsetList[frameId].FrameOffset + currentPacketOffset, (int)audioPacketSize); this.writeChunkToStream(audioPacket, this.AudioTrackIds[audioTrackId], streamOutputWriters, this.FileExtensionAudio); } currentPacketOffset += audioPacketSize; // goto next packet // update audio frame id if ((frameId + 1) < this.FrameCount) { this.NewFrameOffsetsAudio[audioTrackId][frameId + 1] = this.NewFrameOffsetsAudio[audioTrackId][frameId] + audioPacketSize; } } } else { //////////////////////////////////// // extract audio - combine tracks //////////////////////////////////// for (uint audioTrackId = 0; audioTrackId < this.AudioTrackCount; audioTrackId++) { audioPacketSize = BitConverter.ToUInt32(ParseFile.ParseSimpleOffset(fs, this.FrameOffsetList[frameId].FrameOffset + currentPacketOffset, 4), 0); audioPacketSize += 4; if ((demuxOptions.ExtractAudio)) { audioPacket = ParseFile.ParseSimpleOffset(fs, this.FrameOffsetList[frameId].FrameOffset + currentPacketOffset, (int)audioPacketSize); this.writeChunkToStream(audioPacket, 0, streamOutputWriters, this.FileExtensionAudio); } currentPacketOffset += audioPacketSize; // goto next packet } // update audio frame id if ((this.AudioTrackCount > 0) && ((frameId + 1) < this.FrameCount)) { this.NewFrameOffsetsAudio[0][frameId + 1] = this.NewFrameOffsetsAudio[0][frameId] + (uint)currentPacketOffset; } } ///////////////// // extract video ///////////////// if (frameId == (this.FrameCount - 1)) // last frame { packetEndOffset = fileSize; } else { packetEndOffset = this.FrameOffsetList[frameId + 1].FrameOffset; } videoPacketSize = (uint)(packetEndOffset - (this.FrameOffsetList[frameId].FrameOffset + currentPacketOffset)); if (demuxOptions.ExtractVideo) { // parse video packet videoPacket = ParseFile.ParseSimpleOffset(fs, this.FrameOffsetList[frameId].FrameOffset + currentPacketOffset, (int)videoPacketSize); this.writeChunkToStream(videoPacket, 0xFFFF, streamOutputWriters, this.FileExtensionVideo); } // update video frame offset if ((frameId + 1) < this.NewFrameOffsetsVideo.Length) { this.NewFrameOffsetsVideo[frameId + 1] = this.NewFrameOffsetsVideo[frameId] + (uint)videoPacketSize; } } catch (Exception fex) { throw new Exception(String.Format("Exception processing frame 0x{0} at offset 0x{1}: {2}{3}", frameId.ToString("X"), this.FrameOffsetList[frameId].FrameOffset.ToString("X"), fex.Message, Environment.NewLine)); } } // for (uint frameId = 0; frameId < this.FrameCount; frameId++) } // using (FileStream fs = File.OpenRead(this.FilePath)) } catch (Exception ex) { throw new Exception(String.Format("Exception processing block at offset 0x{0}: {1}{2}", currentOffset.ToString("X"), ex.Message, Environment.NewLine)); } finally { // clean up this.DoFinalTasks(streamOutputWriters, demuxOptions); } }
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(); } } } }
public virtual void DemultiplexStreams(MpegStream.DemuxOptionsStruct demuxOptions) { long currentOffset = -1; long fileSize; byte[] chunkId; byte[] fullChunk; uint chunkSize = 0; long mvhdOffset = -1; long schlOffset = -1; long shenOffset = -1; Dictionary <string, FileStream> streamWriters = new Dictionary <string, FileStream>(); try { using (FileStream fs = File.OpenRead(this.FilePath)) { fileSize = fs.Length; // find header first header (audio or video) mvhdOffset = ParseFile.GetNextOffset(fs, 0, ElectronicArtsVp6Stream.MVHD_BYTES); if (mvhdOffset == 0) // video header comes first { currentOffset = mvhdOffset; } else // audio header comes first { schlOffset = ParseFile.GetNextOffset(fs, 0, ElectronicArtsVp6Stream.SCHl_BYTES); if ((schlOffset > -1) && (schlOffset < mvhdOffset)) { currentOffset = schlOffset; } else { shenOffset = ParseFile.GetNextOffset(fs, 0, ElectronicArtsVp6Stream.SHEN_BYTES); if ((shenOffset > -1) && (shenOffset < mvhdOffset)) { currentOffset = shenOffset; } } } // verify headers found if (mvhdOffset >= 0) { if (currentOffset >= 0) { // process file while (currentOffset < fileSize) { // get chunk chunkId = ParseFile.ParseSimpleOffset(fs, currentOffset, 4); // get chunk size chunkSize = (uint)BitConverter.ToUInt32(ParseFile.ParseSimpleOffset(fs, currentOffset + 4, 4), 0); // audio chunk if (demuxOptions.ExtractAudio && this.IsThisAnAudioBlock(chunkId)) { fullChunk = ParseFile.ParseSimpleOffset(fs, currentOffset, (int)chunkSize); this.writeChunkToStream(fullChunk, "audio", streamWriters, this.FileExtensionAudio); } // video chunk if (demuxOptions.ExtractVideo && this.IsThisAVideoBlock(chunkId)) { fullChunk = ParseFile.ParseSimpleOffset(fs, currentOffset, (int)chunkSize); this.writeChunkToStream(fullChunk, "video", streamWriters, this.FileExtensionVideo); } // unknown chunk if (!this.IsThisAnAudioBlock(chunkId) && !this.IsThisAVideoBlock(chunkId)) { fullChunk = ParseFile.ParseSimpleOffset(fs, currentOffset, (int)chunkSize); this.writeChunkToStream(fullChunk, "unknown", streamWriters, ".bin"); } // move to next chunk currentOffset += (long)chunkSize; } } else { throw new Exception(String.Format("Cannot find MVHD, SCHl, or SHEN headers.{0}", Environment.NewLine)); } } else { throw new Exception(String.Format("Cannot find MVHD header.{0}", Environment.NewLine)); } // if (mvhdOffset >= 0) } } catch (Exception ex) { throw new Exception(ex.Message); } finally { this.DoFinalTasks(streamWriters); } }
public void DemultiplexStreams(MpegStream.DemuxOptionsStruct demuxOptions) { long currentOffset = 0; uint frameCount = 1; uint nextFrameSize; byte[] currentFrame; byte[] videoChunkSizeBytes = null; uint videoChunkSize; byte[] audioChunkSizeBytes = null; uint audioChunkSize; long dataStart; byte[] videoChunk; byte[] audioChunk; // bool isAudioHeaderWritten = false; Dictionary <string, bool> isAudioHeaderWritten = new Dictionary <string, bool>(); bool isVideoHeaderWritten = false; byte[] thpHeader; byte[] firstFrameSize; long headerLocation; uint previousFrameSizeVideo = 0; uint previousFrameSizeAudio = 0; uint nextFrameSizeVideo; uint nextFrameSizeAudio; byte[] previousFrameSizeBytes; byte[] nextFrameSizeBytes; uint totalDataSize = 0; byte[] totalDataSizeBytes; byte[] fourEmptyBytes = new byte[] { 0x00, 0x00, 0x00, 0x00 }; long videoFrameOffset = 0; long audioFrameOffset = 0; byte[] lastOffsetBytes; string audioStreamHashKey; byte[] bigEndianOne = new byte[] { 0x00, 0x00, 0x00, 0x01 }; Dictionary <string, FileStream> streamWriters = new Dictionary <string, FileStream>(); try { using (FileStream fs = File.OpenRead(this.FilePath)) { headerLocation = ParseFile.GetNextOffset(fs, currentOffset, MAGIC_BYTES); currentOffset = headerLocation; if (currentOffset > -1) { // read header this.ReadHeader(fs, currentOffset); nextFrameSize = this.FirstFrameSize; // get component info this.ParseComponents(fs); // process frames currentOffset = this.FirstFrameOffset; while (currentOffset <= this.LastFrameOffset) { // read frame currentFrame = ParseFile.ParseSimpleOffset(fs, (long)currentOffset, (int)nextFrameSize); // get size of next frame nextFrameSize = ByteConversion.GetUInt32BigEndian(ParseFile.ParseSimpleOffset(currentFrame, 0, 4)); // get size of next audio/video frame (for writing output frame headers) if (frameCount < this.NumberOfFrames) { nextFrameSizeVideo = ByteConversion.GetUInt32BigEndian(ParseFile.ParseSimpleOffset(fs, currentOffset + currentFrame.Length + 8, 4)); nextFrameSizeAudio = ByteConversion.GetUInt32BigEndian(ParseFile.ParseSimpleOffset(fs, currentOffset + currentFrame.Length + 0xC, 4)); } else { nextFrameSizeVideo = 0; nextFrameSizeAudio = 0; } videoChunkSizeBytes = ParseFile.ParseSimpleOffset(currentFrame, 8, 4); videoChunkSize = ByteConversion.GetUInt32BigEndian(videoChunkSizeBytes); if (this.ContainsAudio) { audioChunkSizeBytes = ParseFile.ParseSimpleOffset(currentFrame, 0xC, 4); audioChunkSize = ByteConversion.GetUInt32BigEndian(audioChunkSizeBytes); dataStart = 0x10; } else { audioChunkSize = 0; dataStart = 0xC; } #region WRITE VIDEO /////////////// // write video /////////////// if (demuxOptions.ExtractVideo) { if (streamWriters.ContainsKey("video")) { videoFrameOffset = streamWriters["video"].Length; } // attach THP header if (!isVideoHeaderWritten) { // get original header thpHeader = ParseFile.ParseSimpleOffset(fs, headerLocation, (int)(fs.Length - this.DataSize)); // clean out audio info thpHeader = this.RemoveAudioInfoFromThpHeader(thpHeader); // update first frame size in header firstFrameSize = ByteConversion.GetBytesBigEndian((uint)(videoChunkSize + 0xC)); Array.Copy(firstFrameSize, 0, thpHeader, 0x18, 4); // write updated header this.writeChunkToStream(thpHeader, "video", streamWriters, this.FileExtensionVideo); isVideoHeaderWritten = true; } // add frame header // write next frame size nextFrameSizeBytes = ByteConversion.GetBytesBigEndian((uint)(nextFrameSizeVideo + 0xC)); this.writeChunkToStream(nextFrameSizeBytes, "video", streamWriters, this.FileExtensionVideo); // write previous frame size previousFrameSizeBytes = ByteConversion.GetBytesBigEndian((uint)(previousFrameSizeVideo + 0xC)); this.writeChunkToStream(nextFrameSizeBytes, "video", streamWriters, this.FileExtensionVideo); // write video size this.writeChunkToStream(videoChunkSizeBytes, "video", streamWriters, this.FileExtensionVideo); // write data videoChunk = ParseFile.ParseSimpleOffset(currentFrame, (int)dataStart, (int)videoChunkSize); this.writeChunkToStream(videoChunk, "video", streamWriters, this.FileExtensionVideo); // save previous bytes for next frame previousFrameSizeVideo = videoChunkSize; } #endregion #region WRITE AUDIO /////////////// // write audio /////////////// if (demuxOptions.ExtractAudio && this.ContainsAudio) { //if (this.NumberOfAudioBlocksPerFrame > 1) //{ // int x = 1; //} // add blocks for (int i = 0; i < this.NumberOfAudioBlocksPerFrame; i++) { audioStreamHashKey = String.Format("track_{0}", i.ToString("D2")); // write file header if (streamWriters.ContainsKey(audioStreamHashKey)) { audioFrameOffset = streamWriters[audioStreamHashKey].Position; } // attach THP header if (!isAudioHeaderWritten.ContainsKey(audioStreamHashKey) || isAudioHeaderWritten[audioStreamHashKey] == false) { // get original header thpHeader = ParseFile.ParseSimpleOffset(fs, headerLocation, (int)(fs.Length - this.DataSize)); // clean out video info thpHeader = this.RemoveVideoInfoFromThpHeader(thpHeader); // update first frame size in header firstFrameSize = ByteConversion.GetBytesBigEndian((uint)(audioChunkSize + 0x10)); Array.Copy(firstFrameSize, 0, thpHeader, 0x18, 4); // set NumberOfAudioBlocksPerFrame to 1 Array.Copy(bigEndianOne, 0, thpHeader, 0x50, 4); // write updated header this.writeChunkToStream(thpHeader, audioStreamHashKey, streamWriters, this.FileExtensionAudio); isAudioHeaderWritten.Add(audioStreamHashKey, true); } ////////////////////// // write frame header ////////////////////// // write next frame size nextFrameSizeBytes = ByteConversion.GetBytesBigEndian((uint)(nextFrameSizeAudio + 0x10)); this.writeChunkToStream(nextFrameSizeBytes, audioStreamHashKey, streamWriters, this.FileExtensionAudio); // write previous frame size previousFrameSizeBytes = ByteConversion.GetBytesBigEndian((uint)(previousFrameSizeAudio + 0x10)); this.writeChunkToStream(nextFrameSizeBytes, audioStreamHashKey, streamWriters, this.FileExtensionAudio); // write video size (zero) this.writeChunkToStream(fourEmptyBytes, audioStreamHashKey, streamWriters, this.FileExtensionAudio); // write audio size for this frame this.writeChunkToStream(audioChunkSizeBytes, audioStreamHashKey, streamWriters, this.FileExtensionAudio); // write chunk audioChunk = ParseFile.ParseSimpleOffset(currentFrame, (int)(dataStart + videoChunkSize + (i * audioChunkSize)), (int)audioChunkSize); this.writeChunkToStream(audioChunk, audioStreamHashKey, streamWriters, this.FileExtensionAudio); // set previous frame size for next frame previousFrameSizeAudio = audioChunkSize; } } #endregion // increment offset and frame counter currentOffset += currentFrame.Length; frameCount++; } // fix headers as needed // data size foreach (string key in streamWriters.Keys) { totalDataSize = (uint)(streamWriters[key].Length - this.FirstFrameOffset); totalDataSizeBytes = ByteConversion.GetBytesBigEndian(totalDataSize); streamWriters[key].Position = 0x1C; streamWriters[key].Write(totalDataSizeBytes, 0, 4); } // frame offsets for (int i = 0; i < this.NumberOfAudioBlocksPerFrame; i++) { audioStreamHashKey = String.Format("audio_{0}", i.ToString("DD")); if (streamWriters.ContainsKey(audioStreamHashKey)) { lastOffsetBytes = ByteConversion.GetBytesBigEndian((uint)audioFrameOffset); streamWriters[audioStreamHashKey].Position = 0x2C; streamWriters[audioStreamHashKey].Write(lastOffsetBytes, 0, 4); } } if (streamWriters.ContainsKey("video")) { lastOffsetBytes = ByteConversion.GetBytesBigEndian((uint)videoFrameOffset); streamWriters["video"].Position = 0x2C; streamWriters["video"].Write(lastOffsetBytes, 0, 4); } } else { throw new FormatException("Cannot find THP header."); } } // using (FileStream fs = File.OpenRead(this.FilePath)) } catch (Exception ex) { throw new Exception(ex.Message, ex); } finally { foreach (string key in streamWriters.Keys) { // close writers if (streamWriters[key] != null && streamWriters[key].CanWrite) { streamWriters[key].Close(); streamWriters[key].Dispose(); } } } }
public virtual void DemultiplexStreams(MpegStream.DemuxOptionsStruct demuxOptions) { long currentOffset = 0; long packetOffset = 0; long packetSize; long fileSize; Dictionary <uint, FileStream> streamOutputWriters = new Dictionary <uint, FileStream>(); Guid checkGuid; ulong blockSize; try { using (FileStream fs = File.OpenRead(this.FilePath)) { fileSize = fs.Length; currentOffset = 0; currentOffset = ParseFile.GetNextOffset(fs, 0, MicrosoftAsfContainer.ASF_HEADER_BYTES); if (currentOffset > -1) { while (currentOffset < fileSize) { // get guid checkGuid = new Guid(ParseFile.ParseSimpleOffset(fs, currentOffset, 0x10)); blockSize = BitConverter.ToUInt64(ParseFile.ParseSimpleOffset(fs, (currentOffset + 0x10), 8), 0); // process block if (checkGuid.Equals(MicrosoftAsfContainer.ASF_Header_Object)) { // parse header this.parseHeader(fs, currentOffset); } else if (checkGuid.Equals(MicrosoftAsfContainer.ASF_Data_Object)) { // parse data object this.DataObject = this.parseDataObject(fs, currentOffset); // process data packets packetOffset = currentOffset + 0x32; // header has been parsed for (ulong i = 0; i < this.DataObject.TotalDataPackets; i++) { // parse packet try { packetSize = this.parseDataPacket(fs, packetOffset, demuxOptions); // move to next packet if (packetSize < 0) { throw new Exception(String.Format("Error parsing data packet at offset 0x{0}.", packetOffset.ToString("X8"))); } else { packetOffset += packetSize; } } catch (Exception ex) { throw new Exception(String.Format("Error parsing data packet at offset 0x{0}: {1}.{2}", packetOffset.ToString("X8"), ex.Message, Environment.NewLine)); } } } // increment counter currentOffset += (long)blockSize; } // while } else { throw new Exception(String.Format("ASF/WMV Header not found.{0}", Environment.NewLine)); } } // using (FileStream fs = File.OpenRead(this.FilePath)) } catch (Exception ex) { throw new Exception(String.Format("Exception processing block at offset 0x{0}: {1}{2}", currentOffset.ToString("X"), ex.Message, Environment.NewLine)); } finally { // clean up this.DoFinalTasks(demuxOptions); } }
private AsfDataPacketPayloadObject parseAsfDataPacketPayloadObject(Stream inStream, long currentOffset, AsfDataPacketPayloadParsingObject payloadParsingObject, MpegStream.DemuxOptionsStruct demuxOptions) { AsfDataPacketPayloadObject packetPayloadObject = new AsfDataPacketPayloadObject(); uint bytesRead = 0; uint valueOffset = 0; uint packetLength; packetPayloadObject.StreamNumber = ParseFile.ParseSimpleOffset(inStream, currentOffset, 1)[0]; packetPayloadObject.KeyFrame = (byte)((packetPayloadObject.StreamNumber & 0x80) >> 7); packetPayloadObject.StreamNumber = (byte)(packetPayloadObject.StreamNumber & 0x7F); valueOffset += 1; packetPayloadObject.MediaObjectNumber = this.GetLengthTypeValue(inStream, currentOffset + valueOffset, payloadParsingObject.MediaObjectNumberLengthType, ref bytesRead); valueOffset += bytesRead; packetPayloadObject.OffsetIntoMediaObject = this.GetLengthTypeValue(inStream, currentOffset + valueOffset, payloadParsingObject.OffsetIntoMediaObjectLengthType, ref bytesRead); valueOffset += bytesRead; packetPayloadObject.ReplicatedDataLength = this.GetLengthTypeValue(inStream, currentOffset + valueOffset, payloadParsingObject.ReplicatedDataLengthType, ref bytesRead); valueOffset += bytesRead; if (packetPayloadObject.ReplicatedDataLength == 1) { throw new FormatException(String.Format("Error processing data packet payload at offset 0x{0}, compressed payloads are not supported.", currentOffset.ToString("X8"))); } // get replicated data packetPayloadObject.ReplicatedData = ParseFile.ParseSimpleOffset(inStream, currentOffset + valueOffset, (int)packetPayloadObject.ReplicatedDataLength); valueOffset += packetPayloadObject.ReplicatedDataLength; if (payloadParsingObject.MultiplePayloadsPresent) { packetPayloadObject.PayloadDataLength = this.GetLengthTypeValue(inStream, currentOffset + valueOffset, payloadParsingObject.PayloadLengthType, ref bytesRead); valueOffset += bytesRead; } else { packetLength = payloadParsingObject.PacketLengthType == LengthType.NotExist ? this.Header.FileProperties.MinimumPacketSize : payloadParsingObject.PacketLength; packetPayloadObject.PayloadDataLength = packetLength - payloadParsingObject.PacketOverheadLength - valueOffset - payloadParsingObject.PaddingLength; } packetPayloadObject.PayloadData = ParseFile.ParseSimpleOffset(inStream, currentOffset + valueOffset, (int)packetPayloadObject.PayloadDataLength); valueOffset += packetPayloadObject.PayloadDataLength; // set payload size and get raw block packetPayloadObject.PayloadSize = valueOffset; // packetPayloadObject.RawBlock = ParseFile.ParseSimpleOffset(inStream, currentOffset, (int)packetPayloadObject.PayloadSize); // write raw data to stream if ((demuxOptions.ExtractAudio) && this.IsAudioStream(packetPayloadObject.StreamNumber)) { this.writeChunkToStream(packetPayloadObject.PayloadData, (uint)packetPayloadObject.StreamNumber, this.FileExtensionAudio); } if ((demuxOptions.ExtractVideo) && this.IsVideoStream(packetPayloadObject.StreamNumber)) { this.writeChunkToStream(packetPayloadObject.PayloadData, (uint)packetPayloadObject.StreamNumber, this.FileExtensionVideo); } return(packetPayloadObject); }
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); }
public virtual void DemultiplexStreams(MpegStream.DemuxOptionsStruct demuxOptions) { long currentOffset = -1; long fileSize; byte[] dummy; uint blocksProcessed = 0; uint audioFramesProcessed = 0; uint videoFramesProcessed = 0; uint bytesProcessed = 0; uint expectedBytesProcessed = 0; BlockHeader blockHeader = new BlockHeader(); FrameHeader frameHeader = new FrameHeader(); bool isFirstVideoFrame = true; bool isFirstAudioFrame = true; byte[] fullChunk; uint audioChunkSize; uint audioChunkSamples; long blockStart; long frameStart; Dictionary <string, FileStream> streamWriters = new Dictionary <string, FileStream>(); try { using (FileStream fs = File.OpenRead(this.FilePath)) { fileSize = fs.Length; #region HEADER CHECK // check header dummy = ParseFile.ParseSimpleOffset(fs, 0, 0x10); if (ParseFile.CompareSegment(dummy, 0, HVQM4_13_SIGNATURE)) { this.FileRevision = VersionType.HVQM4_13; currentOffset = 0; } else if (ParseFile.CompareSegment(dummy, 0, HVQM4_15_SIGNATURE)) { this.FileRevision = VersionType.HVQM4_15; currentOffset = 0; } else { throw new Exception("HVQM4 signature not found at offset 0x00"); } #endregion // parse file if (currentOffset >= 0) { // get header this.ParseHeader(fs, 0); currentOffset = this.HeaderSize + 4; // process file while ((currentOffset < fileSize) && (blocksProcessed < this.Blocks)) { // reset flags isFirstVideoFrame = true; isFirstAudioFrame = true; audioFramesProcessed = 0; videoFramesProcessed = 0; //-------------- // parse block //-------------- blockStart = currentOffset; blocksProcessed++; // parse block header this.ParseBlockHeader(fs, currentOffset, ref blockHeader); currentOffset += blockHeader.GetSize(); bytesProcessed = 0; while (bytesProcessed < blockHeader.BlockSize) { frameStart = currentOffset; // verify we haven't processed too much if (audioFramesProcessed > blockHeader.AudioFrameCount) { throw new Exception(String.Format("Processed more audio frames than expected for block starting at 0x{0}", blockStart.ToString("X8"))); } else if (videoFramesProcessed > blockHeader.VideoFrameCount) { throw new Exception(String.Format("Processed more video frames than expected for block starting at 0x{0}", blockStart.ToString("X8"))); } // parse frame header this.ParseFrameHeader(fs, currentOffset, ref frameHeader); currentOffset += frameHeader.GetSize(); bytesProcessed += (uint)frameHeader.GetSize(); //--------------- // process frame //--------------- // audio chunk if (demuxOptions.ExtractAudio && frameHeader.IsAudioFrame(isFirstAudioFrame)) { audioChunkSamples = ParseFile.ReadUintBE(fs, currentOffset); audioChunkSize = (audioChunkSamples * this.AudioChannels) / 2; // get full frame for now fullChunk = ParseFile.ParseSimpleOffset(fs, currentOffset, (int)frameHeader.FrameSize); // different frames have different IMA info //if (isFirstAudioFrame) //{ // fullChunk = ParseFile.ParseSimpleOffset(fs, currentOffset + 6, (int)audioChunkSize); //} //else //{ // fullChunk = ParseFile.ParseSimpleOffset(fs, currentOffset + 4, (int)audioChunkSize); //} this.writeChunkToStream(fullChunk, "audio", streamWriters, this.FileExtensionAudio); isFirstAudioFrame = false; audioFramesProcessed++; } // video chunk else if (demuxOptions.ExtractVideo && frameHeader.IsVideoFrame(isFirstVideoFrame, this.FileRevision)) { fullChunk = ParseFile.ParseSimpleOffset(fs, currentOffset, (int)frameHeader.FrameSize); this.writeChunkToStream(fullChunk, "video", streamWriters, this.FileExtensionVideo); isFirstVideoFrame = false; videoFramesProcessed++; } //unknown else { fullChunk = ParseFile.ParseSimpleOffset(fs, currentOffset, (int)frameHeader.FrameSize); this.writeChunkToStream(fullChunk, "unknown", streamWriters, ".bin"); } // update number of bytes processed bytesProcessed += frameHeader.FrameSize; // move to next frame currentOffset += frameHeader.FrameSize; } // while (bytesProcessed < blockHeader.BlockSize) // verify proper number of bytes processed if (blocksProcessed < this.Blocks) { bytesProcessed = bytesProcessed + (uint)(blockHeader.GetSize() + 4); expectedBytesProcessed = ParseFile.ReadUintBE(fs, currentOffset); if (expectedBytesProcessed != bytesProcessed) { throw new Exception(String.Format( "Bytes processed 0x{0}does not match expected bytes processed {1} for block starting at 0x{2}.", bytesProcessed.ToString("X8"), expectedBytesProcessed.ToString("X8"), blockStart.ToString("X8"))); } else { currentOffset += 4; } } } } else { throw new Exception(String.Format("Cannot find MVHD header.{0}", Environment.NewLine)); } } } catch (Exception ex) { throw new Exception(ex.Message); } finally { this.DoFinalTasks(streamWriters); } }
public virtual void DemultiplexStreams(MpegStream.DemuxOptionsStruct demuxOptions) { long currentOffset = 0; long fileSize; long blockEndOffset; StreamChunkStruct[] streamChunks; Dictionary <uint, FileStream> streamOutputWriters = new Dictionary <uint, FileStream>(); try { using (FileStream fs = File.OpenRead(this.FilePath)) { fileSize = fs.Length; currentOffset = 0; while (currentOffset < fileSize) { blockEndOffset = 0; streamChunks = parseStreamChunk(fs, currentOffset); if (streamChunks.Length > 0) { foreach (StreamChunkStruct sc in streamChunks) { blockEndOffset = sc.AbsoluteOffset + sc.ChunkSize; if (this.isVideoBlock(sc.StreamChunkType)) { if (demuxOptions.ExtractVideo) { this.writeChunkToStream(sc.ChunkData, sc.StreamChunkId, streamOutputWriters, RacjinDsiStream.DefaultFileExtensionVideo); } } else if (this.isAudioBlock(sc.StreamChunkType)) { if (demuxOptions.ExtractAudio) { this.writeChunkToStream(sc.ChunkData, sc.StreamChunkId, streamOutputWriters, RacjinDsiStream.DefaultFileExtensionAudio); } } else { throw new Exception(String.Format("Exception processing block at offset 0x{0}: {1}{2}", currentOffset.ToString("X"), "Unknown Stream Type Identifier", Environment.NewLine)); } } // move offset currentOffset = blockEndOffset; currentOffset = (currentOffset + RacjinDsiStream.BlockAlignment - 1) / RacjinDsiStream.BlockAlignment * RacjinDsiStream.BlockAlignment; } else { break; } } } // using (FileStream fs = File.OpenRead(this.FilePath)) } catch (Exception ex) { throw new Exception(String.Format("Exception processing block at offset 0x{0}: {1}{2}", currentOffset.ToString("X"), ex.Message, Environment.NewLine)); } finally { // clean up this.DoFinalTasks(streamOutputWriters, demuxOptions); } }