public CriUsmStream(string path) : base(path) { UsesSameIdForMultipleAudioTracks = true; FileExtensionAudio = DefaultAudioExtension; FileExtensionVideo = DefaultVideoExtension; BlockIdDictionary.Clear(); BlockIdDictionary[BitConverter.ToUInt32(ALP_BYTES, 0)] = new BlockSizeStruct(PacketSizeType.SizeBytes, 4); // @ALP BlockIdDictionary[BitConverter.ToUInt32(CRID_BYTES, 0)] = new BlockSizeStruct(PacketSizeType.SizeBytes, 4); // CRID BlockIdDictionary[BitConverter.ToUInt32(SFV_BYTES, 0)] = new BlockSizeStruct(PacketSizeType.SizeBytes, 4); // @SFV BlockIdDictionary[BitConverter.ToUInt32(SFA_BYTES, 0)] = new BlockSizeStruct(PacketSizeType.SizeBytes, 4); // @SFA BlockIdDictionary[BitConverter.ToUInt32(SBT_BYTES, 0)] = new BlockSizeStruct(PacketSizeType.SizeBytes, 4); // @SBT BlockIdDictionary[BitConverter.ToUInt32(CUE_BYTES, 0)] = new BlockSizeStruct(PacketSizeType.SizeBytes, 4); // @CUE }
public virtual Dictionary <string, byte[]> DemultiplexStreams(DemuxOptionsStruct demuxOptions) { using (FileStream fs = File.OpenRead(this.FilePath)) { long fileSize = fs.Length; long currentOffset = 0; byte[] currentBlockId; uint currentBlockIdVal; byte[] currentBlockIdNaming; BlockSizeStruct blockStruct = new BlockSizeStruct(); byte[] blockSizeArray; uint blockSize; int audioBlockSkipSize; int videoBlockSkipSize; int audioBlockFooterSize; int videoBlockFooterSize; int cutSize; bool eofFlagFound = false; Dictionary <uint, MemoryStream> streamOutputWriters = new Dictionary <uint, MemoryStream>(); Dictionary <uint, string> FilenameTable = new Dictionary <uint, string>(); string outputFileName; byte streamId = 0; // for types that have multiple streams in the same block ID uint currentStreamKey; // hash key for each file bool isAudioBlock; string audioFileExtension; // look for first packet currentOffset = this.GetStartOffset(fs, currentOffset); currentOffset = ParseFile.GetNextOffset(fs, currentOffset, this.GetPacketStartBytes()); if (currentOffset != -1) { while (currentOffset < fileSize) { try { // get the current block currentBlockId = ParseFile.ParseSimpleOffset(fs, currentOffset, 4); // get value to use as key to hash table currentBlockIdVal = BitConverter.ToUInt32(currentBlockId, 0); if (BlockIdDictionary.ContainsKey(currentBlockIdVal)) { // get info about this block type blockStruct = BlockIdDictionary[currentBlockIdVal]; switch (blockStruct.SizeType) { ///////////////////// // Static Block Size ///////////////////// case PacketSizeType.Static: currentOffset += blockStruct.Size; // skip this block break; ////////////////// // End of Stream ////////////////// case PacketSizeType.Eof: eofFlagFound = true; // set EOF block found so we can exit the loop break; ////////////////////// // Varying Block Size ////////////////////// case PacketSizeType.SizeBytes: // Get the block size blockSizeArray = ParseFile.ParseSimpleOffset(fs, currentOffset + currentBlockId.Length, blockStruct.Size); if (!this.BlockSizeIsLittleEndian) { Array.Reverse(blockSizeArray); } switch (blockStruct.Size) { case 4: blockSize = (uint)BitConverter.ToUInt32(blockSizeArray, 0); break; case 2: blockSize = (uint)BitConverter.ToUInt16(blockSizeArray, 0); break; case 1: blockSize = (uint)blockSizeArray[0]; break; default: throw new ArgumentOutOfRangeException(String.Format("Unhandled size block size.{0}", Environment.NewLine)); } // if block type is audio or video, extract it isAudioBlock = this.IsThisAnAudioBlock(currentBlockId); if ((demuxOptions.ExtractAudio && isAudioBlock) || (demuxOptions.ExtractVideo && this.IsThisAVideoBlock(currentBlockId))) { // reset stream id streamId = 0; // if audio block, get the stream number from the queue if (isAudioBlock && this.UsesSameIdForMultipleAudioTracks) { streamId = this.GetStreamId(fs, currentOffset); currentStreamKey = (streamId | currentBlockIdVal); } else { currentStreamKey = currentBlockIdVal; } // check if we've already started parsing this stream if (!streamOutputWriters.ContainsKey(currentStreamKey)) { // convert block id to little endian for naming currentBlockIdNaming = BitConverter.GetBytes(currentStreamKey); Array.Reverse(currentBlockIdNaming); // build output file name outputFileName = Path.GetFileNameWithoutExtension(this.FilePath); outputFileName = outputFileName + "_" + BitConverter.ToUInt32(currentBlockIdNaming, 0).ToString("X8"); // add proper extension if (this.IsThisAnAudioBlock(currentBlockId)) { audioFileExtension = this.GetAudioFileExtension(fs, currentOffset); outputFileName += audioFileExtension; if (!this.StreamIdFileType.ContainsKey(streamId)) { this.StreamIdFileType.Add(streamId, audioFileExtension); } } else { this.FileExtensionVideo = this.GetVideoFileExtension(fs, currentOffset); outputFileName += this.FileExtensionVideo; } // add output directory FilenameTable[currentStreamKey] = outputFileName; // add an output stream for writing streamOutputWriters[currentStreamKey] = new MemoryStream(); } // write the block if (this.IsThisAnAudioBlock(currentBlockId)) { // write audio audioBlockSkipSize = this.GetAudioPacketHeaderSize(fs, currentOffset) + GetAudioPacketSubHeaderSize(fs, currentOffset, streamId); audioBlockFooterSize = this.GetAudioPacketFooterSize(fs, currentOffset); cutSize = (int)(blockSize - audioBlockSkipSize - audioBlockFooterSize); if (cutSize > 0) { streamOutputWriters[currentStreamKey].Write(ParseFile.ParseSimpleOffset(fs, currentOffset + currentBlockId.Length + blockSizeArray.Length + audioBlockSkipSize, (int)(blockSize - audioBlockSkipSize)), 0, cutSize); } } else { // write video videoBlockSkipSize = this.GetVideoPacketHeaderSize(fs, currentOffset); videoBlockFooterSize = this.GetVideoPacketFooterSize(fs, currentOffset); cutSize = (int)(blockSize - videoBlockSkipSize - videoBlockFooterSize); if (cutSize > 0) { streamOutputWriters[currentStreamKey].Write(ParseFile.ParseSimpleOffset(fs, currentOffset + currentBlockId.Length + blockSizeArray.Length + videoBlockSkipSize, (int)(blockSize - videoBlockSkipSize)), 0, cutSize); } } } // move to next block currentOffset += currentBlockId.Length + blockSizeArray.Length + blockSize; blockSizeArray = new byte[] { }; break; default: break; } } else // this is an undexpected block type { this.CloseAllWriters(streamOutputWriters); Array.Reverse(currentBlockId); throw new FormatException(String.Format("Block ID at 0x{0} not found in table: 0x{1}", currentOffset.ToString("X8"), BitConverter.ToUInt32(currentBlockId, 0).ToString("X8"))); } // exit loop if EOF block found if (eofFlagFound) { break; } } catch (Exception _ex) { this.CloseAllWriters(streamOutputWriters); throw new Exception(String.Format("Error parsing file at offset {0), '{1}'", currentOffset.ToString("X8"), _ex.Message), _ex); } } // while (currentOffset < fileSize) } else { this.CloseAllWriters(streamOutputWriters); throw new FormatException(String.Format("Cannot find Pack Header for file: {0}{1}", Path.GetFileName(this.FilePath), Environment.NewLine)); } return(this.DoFinalTasks(fs, FilenameTable, streamOutputWriters, demuxOptions.AddHeader)); } }