예제 #1
0
        public MpegStream(string path)
        {
            this.FilePath = path;
            this.UsesSameIdForMultipleAudioTracks = false;
            this.SubTitleExtractionSupported      = false;
            this.BlockSizeIsLittleEndian          = false;

            //********************
            // Add Slice Packets
            //********************
            byte[]          sliceBytes;
            uint            sliceBytesValue;
            BlockSizeStruct blockSize = new BlockSizeStruct(PacketSizeType.Static, 0xE);

            for (byte i = 0; i <= 0xAF; i++)
            {
                sliceBytes      = new byte[] { 0x00, 0x00, 0x01, i };
                sliceBytesValue = BitConverter.ToUInt32(sliceBytes, 0);
                this.BlockIdDictionary.Add(sliceBytesValue, blockSize);
            }
        }
예제 #2
0
        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));
            }
        }