public TSPlaylistFile(
            BDROM bdrom,
            string name,
            List<TSStreamClip> clips)
        {
            BDROM = bdrom;
            Name = name;
            IsCustom = true;
            foreach (TSStreamClip clip in clips)
            {
                TSStreamClip newClip = new TSStreamClip(
                    clip.StreamFile, clip.StreamClipFile);

                newClip.Name = clip.Name;
                newClip.TimeIn = clip.TimeIn;
                newClip.TimeOut = clip.TimeOut;
                newClip.Length = newClip.TimeOut - newClip.TimeIn;
                newClip.RelativeTimeIn = TotalLength;
                newClip.RelativeTimeOut = newClip.RelativeTimeIn + newClip.Length;
                newClip.AngleIndex = clip.AngleIndex;
                newClip.Chapters.Add(clip.TimeIn);
                StreamClips.Add(newClip);

                if (newClip.AngleIndex > AngleCount)
                {
                    AngleCount = newClip.AngleIndex;
                }
                if (newClip.AngleIndex == 0)
                {
                    Chapters.Add(newClip.RelativeTimeIn);
                }
            }
            LoadStreamClips();
            IsInitialized = true;
        }
Example #2
0
 public bool IsCompatible(TSStreamClip clip)
 {
     foreach (TSStream stream1 in StreamFile.Streams.Values)
     {
         if (clip.StreamFile.Streams.ContainsKey(stream1.PID))
         {
             TSStream stream2 = clip.StreamFile.Streams[stream1.PID];
             if (stream1.StreamType != stream2.StreamType)
             {
                 return false;
             }
         }
     }
     return true;
 }
Example #3
0
        public TSPlaylistFile(
            string name,
            List<TSStreamClip> clips)
        {
            Name = name;
            foreach (TSStreamClip clip in clips)
            {
                TSStreamClip newClip = new TSStreamClip(
                    clip.StreamFile, clip.StreamClipFile);

                newClip.Name = clip.Name;
                newClip.TimeIn = clip.TimeIn;
                newClip.TimeOut = clip.TimeOut;
                newClip.Length = newClip.TimeOut - newClip.TimeIn;
                newClip.RelativeTimeIn = TotalLength;
                newClip.RelativeTimeOut = newClip.RelativeTimeIn + newClip.Length;
                newClip.Chapters.Add(clip.TimeIn);
                StreamClips.Add(newClip);

                Chapters.Add(newClip.RelativeTimeIn);
            }
            LoadStreamClips();
            IsInitialized = true;
        }
        public void Scan()
            //Dictionary<string, TSStreamFile> streamFiles,
            //Dictionary<string, TSStreamClipFile> streamClipFiles)
        {
            FileStream fileStream = null;
            BinaryReader fileReader = null;

            int streamFileCount = 0;
            Dictionary<string, TSStreamClipFile> streamClipFiles = new Dictionary<string, TSStreamClipFile>();

            try
            {
#if DEBUG
                Debug.WriteLine(string.Format(
                    "Scanning {0}...", Name));
#endif
                Streams.Clear();
                StreamClips.Clear();

                fileStream = File.OpenRead(FileInfo.FullName);
                fileReader = new BinaryReader(fileStream);

                byte[] data = new byte[fileStream.Length];
                int dataLength = fileReader.Read(data, 0, data.Length);

                byte[] fileType = new byte[8];
                Array.Copy(data, 0, fileType, 0, fileType.Length);
                
                FileType = ASCIIEncoding.ASCII.GetString(fileType);
                if ((FileType != "MPLS0100" && FileType != "MPLS0200") 
                    /*|| data[45] != 1*/)
                {
                    throw new Exception(string.Format(
                        "Playlist {0} has an unknown file type {1}.",
                        FileInfo.Name, FileType));
                }
#if DEBUG
                Debug.WriteLine(string.Format(
                    "\tFileType: {0}", FileType));
#endif
                int playlistIndex =
                    ((int)data[8] << 24) +
                    ((int)data[9] << 16) +
                    ((int)data[10] << 8) +
                    ((int)data[11]);

                // TODO: Hack for bad TSRemux output.
                int playlistLength = data.Length - playlistIndex - 4;
                int playlistLengthCorrect =
                    ((int)data[playlistIndex] << 24) +
                    ((int)data[playlistIndex + 1] << 16) +
                    ((int)data[playlistIndex + 2] << 8) +
                    ((int)data[playlistIndex + 3]);

                byte[] playlistData = new byte[playlistLength];
                Array.Copy(data, playlistIndex + 4, 
                    playlistData, 0, playlistData.Length);

                streamFileCount =
                    (((int)playlistData[2] << 8) + (int)playlistData[3]);
#if DEBUG
                Debug.WriteLine(string.Format(
                    "\tStreamFileCount: {0}", streamFileCount));
#endif
                List<TSStreamClip> chapterClips = new List<TSStreamClip>();
                int streamFileOffset = 6;
                for (int streamFileIndex = 0; 
                    streamFileIndex < streamFileCount; 
                    streamFileIndex++)
                {
                    byte[] streamFileNameData = new byte[5];
                    Array.Copy(playlistData, streamFileOffset + 2, 
                        streamFileNameData, 0, streamFileNameData.Length);

                    //TSStreamFile streamFile = null;
                    //string streamFileName = string.Format(
                    //    "{0}.M2TS",
                    //    ASCIIEncoding.ASCII.GetString(streamFileNameData));
                    //if (streamFiles.ContainsKey(streamFileName))
                    //{
                    //    streamFile = streamFiles[streamFileName];
                    //}
                    //if (streamFile == null)
                    //{
                    //    throw new Exception(string.Format(
                    //        "Playlist {0} referenced missing file {1}.",
                    //        FileInfo.Name, streamFileName));
                    //}

                    TSStreamClipFile streamClipFile = null;
                    string streamClipFileName = string.Format(
                        "{0}.CLPI",
                        ASCIIEncoding.ASCII.GetString(streamFileNameData));
                    string streamClipFilePath = Path.Combine(Path.Combine(FileInfo.Directory.Parent.FullName, "CLIPINF"),
                      streamClipFileName);
                    if (File.Exists(streamClipFilePath) && !streamClipFiles.ContainsKey(streamClipFileName)) 
                      streamClipFiles.Add(streamClipFileName, new TSStreamClipFile(new FileInfo(streamClipFilePath)));

                    if (streamClipFiles.ContainsKey(streamClipFileName))
                    {
                        streamClipFile = streamClipFiles[streamClipFileName];
                    }
                    if (streamClipFile == null)
                    {
                        throw new Exception(string.Format(
                            "Playlist {0} referenced missing file {1}.",
                            FileInfo.Name, streamClipFileName));
                    }
                    
                    byte condition = (byte)
                        (playlistData[streamFileOffset + 12] & 0xF);

                    ulong timeIn =
                        ((ulong)playlistData[streamFileOffset + 14] << 24) +
                        ((ulong)playlistData[streamFileOffset + 15] << 16) +
                        ((ulong)playlistData[streamFileOffset + 16] << 8) +
                        ((ulong)playlistData[streamFileOffset + 17]);

                    ulong timeOut =
                        ((ulong)playlistData[streamFileOffset + 18] << 24) +
                        ((ulong)playlistData[streamFileOffset + 19] << 16) +
                        ((ulong)playlistData[streamFileOffset + 20] << 8) +
                        ((ulong)playlistData[streamFileOffset + 21]);

                    TSStreamClip streamClip = new TSStreamClip(
                        //streamFile, 
                        streamClipFile);

                    streamClip.TimeIn = (double)timeIn / 45000;
                    streamClip.TimeOut = (double)timeOut / 45000;
                    streamClip.Length = streamClip.TimeOut - streamClip.TimeIn;
                    streamClip.RelativeTimeIn = TotalLength;
                    streamClip.RelativeTimeOut = streamClip.RelativeTimeIn + streamClip.Length;
                    StreamClips.Add(streamClip);
                    chapterClips.Add(streamClip);
#if DEBUG
                    Debug.WriteLine(string.Format(
                        "\t{0} {1} {2} {3}", 
                        streamClip.Name,
                        streamClip.TimeIn.TotalSeconds,
                        streamClip.TimeOut.TotalSeconds,
                        streamClip.Length.TotalSeconds));
#endif
                    if ((playlistData[streamFileOffset + 12] & 0x10) > 0)
                    {
                        int angleCount = playlistData[streamFileOffset + 34];
                        if (angleCount - 1 > AngleCount)
                        {
                            AngleCount = angleCount - 1;
                        }
                        for (int angle = 0; angle < (angleCount - 1); angle++)
                        {
                            byte[] angleFileNameData = new byte[5];
                            int angleOffset = 
                                streamFileOffset + 26 + ((angle + 1) * 10);
                            Array.Copy(playlistData, angleOffset, 
                                angleFileNameData, 0, angleFileNameData.Length);

                            //TSStreamFile angleFile = null;
                            //string angleFileName = string.Format(
                            //    "{0}.M2TS",
                            //    ASCIIEncoding.ASCII.GetString(angleFileNameData));
                            //if (streamFiles.ContainsKey(angleFileName))
                            //{
                            //    angleFile = streamFiles[angleFileName];
                            //}
                            //if (angleFile == null)
                            //{
                            //    throw new Exception(string.Format(
                            //        "Playlist {0} referenced missing angle file {1}.",
                            //        FileInfo.Name, angleFileName));
                            //}

                            TSStreamClipFile angleClipFile = null;
                            string angleClipFileName = string.Format(
                                "{0}.CLPI",
                                ASCIIEncoding.ASCII.GetString(angleFileNameData));
                            if (streamClipFiles.ContainsKey(angleClipFileName))
                            {
                                angleClipFile = streamClipFiles[angleClipFileName];
                            }
                            if (angleClipFile == null)
                            {
                                throw new Exception(string.Format(
                                    "Playlist {0} referenced missing angle file {1}.",
                                    FileInfo.Name, angleClipFileName));
                            }

                            TSStreamClip angleClip =
                                new TSStreamClip(//angleFile, 
                                  angleClipFile);
                            angleClip.AngleIndex = angle + 1;
                            angleClip.TimeIn = streamClip.TimeIn;
                            angleClip.TimeOut = streamClip.TimeOut;
                            angleClip.RelativeTimeIn = streamClip.RelativeTimeIn;
                            angleClip.RelativeTimeOut = streamClip.RelativeTimeOut;
                            angleClip.Length = streamClip.Length;
                            StreamClips.Add(angleClip);
#if DEBUG
                            Debug.WriteLine(string.Format(
                                "\t\t{0}", angleFileName));
#endif
                        }
                    }
                    streamFileOffset += 2 +
                        ((int)playlistData[streamFileOffset] << 8) +
                        ((int)playlistData[streamFileOffset + 1]);
                }

                int chaptersIndex =
                    ((int)data[12] << 24) +
                    ((int)data[13] << 16) +
                    ((int)data[14] << 8) +
                    ((int)data[15]);

                int chaptersLength =
                    ((int)data[chaptersIndex] << 24) +
                    ((int)data[chaptersIndex + 1] << 16) +
                    ((int)data[chaptersIndex + 2] << 8) +
                    ((int)data[chaptersIndex + 3]);

                byte[] chapterData = 
                    new byte[chaptersLength];
                Array.Copy(data, chaptersIndex + 4, 
                    chapterData, 0, chaptersLength);

                int chapterCount = 
                    ((int)chapterData[0] << 8) + chapterData[1];
                int chapterOffset = 2;
                for (int chapterIndex = 0; 
                    chapterIndex < chapterCount; 
                    chapterIndex++)
                {
                    if (chapterData[chapterOffset + 1] == 1)
                    {
                        int streamFileIndex =
                            ((int)chapterData[chapterOffset + 2] << 8) + 
                            chapterData[chapterOffset + 3];

                        TSStreamClip streamClip = chapterClips[streamFileIndex];

                        long chapterTime =
                            ((long)chapterData[chapterOffset + 4] << 24) +
                            ((long)chapterData[chapterOffset + 5] << 16) +
                            ((long)chapterData[chapterOffset + 6] << 8) +
                            ((long)chapterData[chapterOffset + 7]);

                        double chapterSeconds = (double)chapterTime / 45000;
                        double relativeSeconds =
                            chapterSeconds -
                            streamClip.TimeIn +
                            streamClip.RelativeTimeIn;

                        // TODO: Ignore short last chapter?
                        if (TotalLength - relativeSeconds > 1.0)
                        {
                            streamClip.Chapters.Add(chapterSeconds);
                            this.Chapters.Add(relativeSeconds);
                        }
#if DEBUG
                        Debug.WriteLine(string.Format(
                            "\t{0} {1} {2}", 
                            chapterIndex, 
                            streamClip.Name, 
                            chapter.TotalSeconds));
#endif
                    }
                    chapterOffset += 14;
                }
#if DEBUG
                Debug.WriteLine(string.Format(
                    "\tLength: {0}", Length.TotalSeconds));
                Debug.WriteLine(string.Format(
                    "\tAngleLength: {0}", AngleLength.TotalSeconds));
#endif
                //LoadStreamClips();
                IsInitialized = true;
            }
            finally
            {
                if (fileReader != null)
                {
                    fileReader.Close();
                }
                if (fileStream != null)
                {
                    fileStream.Close();
                }
            }
        }
        private static StreamClip Transform(TSStreamClip tsStreamClip, int index)
        {
            Debug.Assert(tsStreamClip.StreamFile != null, "tsStreamClip.StreamFile is null", tsStreamClip.Name);

            return new StreamClip(tsStreamClip.StreamFile.FileInfo, tsStreamClip.Name, tsStreamClip.FileSize, index, tsStreamClip.AngleIndex, tsStreamClip.Length);
        }
 /// <summary>
 /// Guards against a bug in BDInfo where a non-existent stream clip (00121.m2ts) gets created with a <c>null</c> <see cref="TSStreamClip.StreamFile"/>
 /// when scanning CASINO_ROYAL.
 /// </summary>
 private static bool StreamFileExists(TSStreamClip tsStreamClip)
 {
     return tsStreamClip.StreamFile != null;
 }
 private static bool IsDefaultAngle(TSStreamClip tsStreamClip)
 {
     return tsStreamClip.AngleIndex == 0;
 }
        public void Scan(
            Dictionary<string, TSStreamFile> streamFiles,
            Dictionary<string, TSStreamClipFile> streamClipFiles)
        {
            FileStream fileStream = null;
            BinaryReader fileReader = null;
        
            try
            {
                Streams.Clear();
                StreamClips.Clear();

                fileStream = File.OpenRead(FileInfo.FullName);
                fileReader = new BinaryReader(fileStream);

                byte[] data = new byte[fileStream.Length];
                int dataLength = fileReader.Read(data, 0, data.Length);

                int pos = 0;

                FileType = ReadString(data, 8, ref pos);
                if (FileType != "MPLS0100" && FileType != "MPLS0200")
                {
                    throw new Exception(string.Format(
                        "Playlist {0} has an unknown file type {1}.",
                        FileInfo.Name, FileType));
                }

                int playlistOffset = ReadInt32(data, ref pos);
                int chaptersOffset = ReadInt32(data, ref pos);
                int extensionsOffset = ReadInt32(data, ref pos);

                pos = playlistOffset;

                int playlistLength = ReadInt32(data, ref pos);
                int playlistReserved = ReadInt16(data, ref pos);
                int itemCount = ReadInt16(data, ref pos);
                int subitemCount = ReadInt16(data, ref pos);

                List<TSStreamClip> chapterClips = new List<TSStreamClip>();
                for (int itemIndex = 0; itemIndex < itemCount; itemIndex++)
                {
                    int itemStart = pos;
                    int itemLength = ReadInt16(data, ref pos);
                    string itemName = ReadString(data, 5, ref pos);
                    string itemType = ReadString(data, 4, ref pos);

                    TSStreamFile streamFile = null;
                    string streamFileName = string.Format(
                        "{0}.M2TS", itemName);
                    if (streamFiles.ContainsKey(streamFileName))
                    {
                        streamFile = streamFiles[streamFileName];
                    }
                    if (streamFile == null)
                    {
                        Debug.WriteLine(string.Format(
                            "Playlist {0} referenced missing file {1}.",
                            FileInfo.Name, streamFileName));
                    }

                    TSStreamClipFile streamClipFile = null;
                    string streamClipFileName = string.Format(
                        "{0}.CLPI", itemName);
                    if (streamClipFiles.ContainsKey(streamClipFileName))
                    {
                        streamClipFile = streamClipFiles[streamClipFileName];
                    }
                    if (streamClipFile == null)
                    {
                        throw new Exception(string.Format(
                            "Playlist {0} referenced missing file {1}.",
                            FileInfo.Name, streamFileName));
                    }

                    pos += 1;
                    int multiangle = (data[pos] >> 4) & 0x01;
                    int condition = data[pos] & 0x0F;
                    pos += 2;

                    double timeIn = (double)ReadInt32(data, ref pos) / 45000;
                    double timeOut = (double)ReadInt32(data, ref pos) / 45000;

                    TSStreamClip streamClip = new TSStreamClip(
                        streamFile, streamClipFile);

                    streamClip.Name = streamFileName; //TODO
                    streamClip.TimeIn = timeIn;
                    streamClip.TimeOut = timeOut;
                    streamClip.Length = streamClip.TimeOut - streamClip.TimeIn;
                    streamClip.RelativeTimeIn = TotalLength;
                    streamClip.RelativeTimeOut = streamClip.RelativeTimeIn + streamClip.Length;
                    StreamClips.Add(streamClip);
                    chapterClips.Add(streamClip);

                    pos += 12;
                    if (multiangle > 0)
                    {
                        int angles = data[pos];
                        pos += 2;
                        for (int angle = 0; angle < angles - 1; angle++)
                        {
                            string angleName = ReadString(data, 5, ref pos);
                            string angleType = ReadString(data, 4, ref pos);
                            pos += 1;

                            TSStreamFile angleFile = null;
                            string angleFileName = string.Format(
                                "{0}.M2TS", angleName);
                            if (streamFiles.ContainsKey(angleFileName))
                            {
                                angleFile = streamFiles[angleFileName];
                            }
                            if (angleFile == null)
                            {
                                throw new Exception(string.Format(
                                    "Playlist {0} referenced missing angle file {1}.",
                                    FileInfo.Name, angleFileName));
                            }

                            TSStreamClipFile angleClipFile = null;
                            string angleClipFileName = string.Format(
                                "{0}.CLPI", angleName);
                            if (streamClipFiles.ContainsKey(angleClipFileName))
                            {
                                angleClipFile = streamClipFiles[angleClipFileName];
                            }
                            if (angleClipFile == null)
                            {
                                throw new Exception(string.Format(
                                    "Playlist {0} referenced missing angle file {1}.",
                                    FileInfo.Name, angleClipFileName));
                            }

                            TSStreamClip angleClip =
                                new TSStreamClip(angleFile, angleClipFile);
                            angleClip.AngleIndex = angle + 1;
                            angleClip.TimeIn = streamClip.TimeIn;
                            angleClip.TimeOut = streamClip.TimeOut;
                            angleClip.RelativeTimeIn = streamClip.RelativeTimeIn;
                            angleClip.RelativeTimeOut = streamClip.RelativeTimeOut;
                            angleClip.Length = streamClip.Length;
                            StreamClips.Add(angleClip);
                        }
                        if (angles - 1 > AngleCount) AngleCount = angles - 1;
                    }

                    int streamInfoLength = ReadInt16(data, ref pos);
                    pos += 2;
                    int streamCountVideo = data[pos++];
                    int streamCountAudio = data[pos++];
                    int streamCountPG = data[pos++];
                    int streamCountIG = data[pos++];
                    int streamCountSecondaryAudio = data[pos++];
                    int streamCountSecondaryVideo = data[pos++];
                    int streamCountPIP = data[pos++];
                    pos += 5;

#if DEBUG
                    Debug.WriteLine(string.Format(
                        "{0} : {1} -> V:{2} A:{3} PG:{4} IG:{5} 2A:{6} 2V:{7} PIP:{8}", 
                        Name, streamFileName, streamCountVideo, streamCountAudio, streamCountPG, streamCountIG, 
                        streamCountSecondaryAudio, streamCountSecondaryVideo, streamCountPIP));
#endif

                    for (int i = 0; i < streamCountVideo; i++)
                    {
                        TSStream stream = CreatePlaylistStream(data, ref pos);
                        if (stream != null) PlaylistStreams[stream.PID] = stream;
                    }
                    for (int i = 0; i < streamCountAudio; i++)
                    {
                        TSStream stream = CreatePlaylistStream(data, ref pos);
                        if (stream != null) PlaylistStreams[stream.PID] = stream;
                    }
                    for (int i = 0; i < streamCountPG; i++)
                    {
                        TSStream stream = CreatePlaylistStream(data, ref pos);
                        if (stream != null) PlaylistStreams[stream.PID] = stream;
                    }
                    for (int i = 0; i < streamCountIG; i++)
                    {
                        TSStream stream = CreatePlaylistStream(data, ref pos);
                        if (stream != null) PlaylistStreams[stream.PID] = stream;
                    }
                    for (int i = 0; i < streamCountSecondaryAudio; i++)
                    {
                        TSStream stream = CreatePlaylistStream(data, ref pos);
                        if (stream != null) PlaylistStreams[stream.PID] = stream;
                        pos += 2;
                    }
                    for (int i = 0; i < streamCountSecondaryVideo; i++)
                    {
                        TSStream stream = CreatePlaylistStream(data, ref pos);
                        if (stream != null) PlaylistStreams[stream.PID] = stream;
                        pos += 6;
                    }
                    /*
                     * TODO
                     * 
                    for (int i = 0; i < streamCountPIP; i++)
                    {
                        TSStream stream = CreatePlaylistStream(data, ref pos);
                        if (stream != null) PlaylistStreams[stream.PID] = stream;
                    }
                    */

                    pos += itemLength - (pos - itemStart) + 2;
                }

                pos = chaptersOffset + 4;

                int chapterCount = ReadInt16(data, ref pos);

                for (int chapterIndex = 0;
                    chapterIndex < chapterCount;
                    chapterIndex++)
                {
                    int chapterType = data[pos+1];

                    if (chapterType == 1)
                    {
                        int streamFileIndex =
                            ((int)data[pos + 2] << 8) + data[pos + 3];

                        long chapterTime =
                            ((long)data[pos + 4] << 24) +
                            ((long)data[pos + 5] << 16) +
                            ((long)data[pos + 6] << 8) +
                            ((long)data[pos + 7]);

                        TSStreamClip streamClip = chapterClips[streamFileIndex];

                        double chapterSeconds = (double)chapterTime / 45000;

                        double relativeSeconds =
                            chapterSeconds -
                            streamClip.TimeIn +
                            streamClip.RelativeTimeIn;

                        // TODO: Ignore short last chapter?
                        if (TotalLength - relativeSeconds > 1.0)
                        {
                            streamClip.Chapters.Add(chapterSeconds);
                            this.Chapters.Add(relativeSeconds);
                        }
                    }
                    else
                    {
                        // TODO: Handle other chapter types?
                    }
                    pos += 14;
                }
            }
            finally
            {
                if (fileReader != null)
                {
                    fileReader.Close();
                }
                if (fileStream != null)
                {
                    fileStream.Close();
                }
            }
        }
Example #9
0
 private static string GetClipKey(TSStreamClip clip)
 {
     return string.Format("{0}{1}", clip.Length, clip.FileSize);
 }
Example #10
0
        public TSPlaylistFile(
            BDROM bdrom,
            string name,
            IEnumerable<TSStreamClip> clips)
        {
            BDROM = bdrom;
            Name = name;
            FullName = Path.Combine(bdrom.DirectoryPLAYLIST.FullName, Name).ToUpper();
            IsCustom = true;

            foreach (var clip in clips)
            {
                var newClip = new TSStreamClip(clip.StreamFile, clip.StreamClipFile)
                                  {
                                      Name = clip.Name,
                                      TimeIn = clip.TimeIn,
                                      TimeOut = clip.TimeOut,
                                      RelativeTimeIn = TotalLength,
                                      AngleIndex = clip.AngleIndex
                                  };

                newClip.Length = newClip.TimeOut - newClip.TimeIn;
                newClip.RelativeTimeOut = newClip.RelativeTimeIn + newClip.Length;
                newClip.Chapters.Add(clip.TimeIn);

                StreamClips.Add(newClip);

                if (newClip.AngleIndex > AngleCount)
                {
                    AngleCount = newClip.AngleIndex;
                }
                if (newClip.AngleIndex == 0)
                {
                    Chapters.Add(newClip.RelativeTimeIn);
                }
            }

            LoadStreamClips();
            _isInitialized = true;
        }
Example #11
0
        private void LoadStreamClips()
        {
            AngleClips.Clear();
            if (AngleCount > 0)
            {
                for (int angleIndex = 0; angleIndex < AngleCount; angleIndex++)
                {
                    AngleClips.Add(new Dictionary <double, TSStreamClip>());
                }
            }

            TSStreamClip referenceClip = null;

            if (StreamClips.Count > 0)
            {
                referenceClip = StreamClips[0];
            }
            foreach (TSStreamClip clip in StreamClips)
            {
                if (clip.StreamClipFile.Streams.Count > referenceClip.StreamClipFile.Streams.Count)
                {
                    referenceClip = clip;
                }
                else if (clip.Length > referenceClip.Length)
                {
                    referenceClip = clip;
                }
                if (AngleCount > 0)
                {
                    if (clip.AngleIndex == 0)
                    {
                        for (int angleIndex = 0; angleIndex < AngleCount; angleIndex++)
                        {
                            AngleClips[angleIndex][clip.RelativeTimeIn] = clip;
                        }
                    }
                    else
                    {
                        AngleClips[clip.AngleIndex - 1][clip.RelativeTimeIn] = clip;
                    }
                }
            }

            foreach (TSStream clipStream
                     in referenceClip.StreamClipFile.Streams.Values)
            {
                if (!Streams.ContainsKey(clipStream.PID))
                {
                    TSStream stream = clipStream.Clone();
                    Streams[clipStream.PID] = stream;

                    if (!IsCustom && !PlaylistStreams.ContainsKey(stream.PID))
                    {
                        stream.IsHidden = true;
                        HasHiddenTracks = true;
                    }

                    if (stream.IsVideoStream)
                    {
                        VideoStreams.Add((TSVideoStream)stream);
                    }
                    else if (stream.IsAudioStream)
                    {
                        AudioStreams.Add((TSAudioStream)stream);
                    }
                    else if (stream.IsGraphicsStream)
                    {
                        GraphicsStreams.Add((TSGraphicsStream)stream);
                    }
                    else if (stream.IsTextStream)
                    {
                        TextStreams.Add((TSTextStream)stream);
                    }
                }
            }

            if (referenceClip.StreamFile != null)
            {
                // TODO: Better way to add this in?
                if (BDInfoSettings.EnableSSIF &&
                    referenceClip.StreamFile.InterleavedFile != null &&
                    referenceClip.StreamFile.Streams.ContainsKey(4114) &&
                    !Streams.ContainsKey(4114))
                {
                    TSStream stream = referenceClip.StreamFile.Streams[4114].Clone();
                    Streams[4114] = stream;
                    if (stream.IsVideoStream)
                    {
                        VideoStreams.Add((TSVideoStream)stream);
                    }
                }

                foreach (TSStream clipStream
                         in referenceClip.StreamFile.Streams.Values)
                {
                    if (Streams.ContainsKey(clipStream.PID))
                    {
                        TSStream stream = Streams[clipStream.PID];

                        if (stream.StreamType != clipStream.StreamType)
                        {
                            continue;
                        }

                        if (clipStream.BitRate > stream.BitRate)
                        {
                            stream.BitRate = clipStream.BitRate;
                        }
                        stream.IsVBR = clipStream.IsVBR;

                        if (stream.IsVideoStream &&
                            clipStream.IsVideoStream)
                        {
                            ((TSVideoStream)stream).EncodingProfile =
                                ((TSVideoStream)clipStream).EncodingProfile;
                        }
                        else if (stream.IsAudioStream &&
                                 clipStream.IsAudioStream)
                        {
                            TSAudioStream audioStream     = (TSAudioStream)stream;
                            TSAudioStream clipAudioStream = (TSAudioStream)clipStream;

                            if (clipAudioStream.ChannelCount > audioStream.ChannelCount)
                            {
                                audioStream.ChannelCount = clipAudioStream.ChannelCount;
                            }
                            if (clipAudioStream.LFE > audioStream.LFE)
                            {
                                audioStream.LFE = clipAudioStream.LFE;
                            }
                            if (clipAudioStream.SampleRate > audioStream.SampleRate)
                            {
                                audioStream.SampleRate = clipAudioStream.SampleRate;
                            }
                            if (clipAudioStream.BitDepth > audioStream.BitDepth)
                            {
                                audioStream.BitDepth = clipAudioStream.BitDepth;
                            }
                            if (clipAudioStream.DialNorm < audioStream.DialNorm)
                            {
                                audioStream.DialNorm = clipAudioStream.DialNorm;
                            }
                            if (clipAudioStream.AudioMode != TSAudioMode.Unknown)
                            {
                                audioStream.AudioMode = clipAudioStream.AudioMode;
                            }
                            if (clipAudioStream.CoreStream != null &&
                                audioStream.CoreStream == null)
                            {
                                audioStream.CoreStream = (TSAudioStream)
                                                         clipAudioStream.CoreStream.Clone();
                            }
                        }
                    }
                }
            }

            for (int i = 0; i < AngleCount; i++)
            {
                AngleStreams.Add(new Dictionary <ushort, TSStream>());
            }

            if (!BDInfoSettings.KeepStreamOrder)
            {
                VideoStreams.Sort(CompareVideoStreams);
            }
            foreach (TSStream stream in VideoStreams)
            {
                SortedStreams.Add(stream);
                for (int i = 0; i < AngleCount; i++)
                {
                    TSStream angleStream = stream.Clone();
                    angleStream.AngleIndex           = i + 1;
                    AngleStreams[i][angleStream.PID] = angleStream;
                    SortedStreams.Add(angleStream);
                }
            }

            if (!BDInfoSettings.KeepStreamOrder)
            {
                AudioStreams.Sort(CompareAudioStreams);
            }
            foreach (TSStream stream in AudioStreams)
            {
                SortedStreams.Add(stream);
            }

            if (!BDInfoSettings.KeepStreamOrder)
            {
                GraphicsStreams.Sort(CompareGraphicsStreams);
            }
            foreach (TSStream stream in GraphicsStreams)
            {
                SortedStreams.Add(stream);
            }

            if (!BDInfoSettings.KeepStreamOrder)
            {
                TextStreams.Sort(CompareTextStreams);
            }
            foreach (TSStream stream in TextStreams)
            {
                SortedStreams.Add(stream);
            }
        }
Example #12
0
        public void Scan(
            Dictionary <string, TSStreamFile> streamFiles,
            Dictionary <string, TSStreamClipFile> streamClipFiles)
        {
            FileStream   fileStream = null;
            BinaryReader fileReader = null;

            try
            {
                Streams.Clear();
                StreamClips.Clear();

                fileStream = File.OpenRead(FileInfo.FullName);
                fileReader = new BinaryReader(fileStream);

                byte[] data       = new byte[fileStream.Length];
                int    dataLength = fileReader.Read(data, 0, data.Length);

                int pos = 0;

                FileType = ReadString(data, 8, ref pos);
                if (FileType != "MPLS0100" && FileType != "MPLS0200")
                {
                    throw new Exception(string.Format(
                                            "Playlist {0} has an unknown file type {1}.",
                                            FileInfo.Name, FileType));
                }

                int playlistOffset   = ReadInt32(data, ref pos);
                int chaptersOffset   = ReadInt32(data, ref pos);
                int extensionsOffset = ReadInt32(data, ref pos);

                pos = playlistOffset;

                int playlistLength   = ReadInt32(data, ref pos);
                int playlistReserved = ReadInt16(data, ref pos);
                int itemCount        = ReadInt16(data, ref pos);
                int subitemCount     = ReadInt16(data, ref pos);

                List <TSStreamClip> chapterClips = new List <TSStreamClip>();
                for (int itemIndex = 0; itemIndex < itemCount; itemIndex++)
                {
                    int    itemStart  = pos;
                    int    itemLength = ReadInt16(data, ref pos);
                    string itemName   = ReadString(data, 5, ref pos);
                    string itemType   = ReadString(data, 4, ref pos);

                    TSStreamFile streamFile     = null;
                    string       streamFileName = string.Format(
                        "{0}.M2TS", itemName);
                    if (streamFiles.ContainsKey(streamFileName))
                    {
                        streamFile = streamFiles[streamFileName];
                    }
                    if (streamFile == null)
                    {
                        Debug.WriteLine(string.Format(
                                            "Playlist {0} referenced missing file {1}.",
                                            FileInfo.Name, streamFileName));
                    }

                    TSStreamClipFile streamClipFile     = null;
                    string           streamClipFileName = string.Format(
                        "{0}.CLPI", itemName);
                    if (streamClipFiles.ContainsKey(streamClipFileName))
                    {
                        streamClipFile = streamClipFiles[streamClipFileName];
                    }
                    if (streamClipFile == null)
                    {
                        throw new Exception(string.Format(
                                                "Playlist {0} referenced missing file {1}.",
                                                FileInfo.Name, streamFileName));
                    }

                    pos += 1;
                    int multiangle = (data[pos] >> 4) & 0x01;
                    int condition  = data[pos] & 0x0F;
                    pos += 2;

                    double timeIn  = (double)ReadInt32(data, ref pos) / 45000;
                    double timeOut = (double)ReadInt32(data, ref pos) / 45000;

                    TSStreamClip streamClip = new TSStreamClip(
                        streamFile, streamClipFile);

                    streamClip.Name            = streamFileName; //TODO
                    streamClip.TimeIn          = timeIn;
                    streamClip.TimeOut         = timeOut;
                    streamClip.Length          = streamClip.TimeOut - streamClip.TimeIn;
                    streamClip.RelativeTimeIn  = TotalLength;
                    streamClip.RelativeTimeOut = streamClip.RelativeTimeIn + streamClip.Length;
                    StreamClips.Add(streamClip);
                    chapterClips.Add(streamClip);

                    pos += 12;
                    if (multiangle > 0)
                    {
                        int angles = data[pos];
                        pos += 2;
                        for (int angle = 0; angle < angles - 1; angle++)
                        {
                            string angleName = ReadString(data, 5, ref pos);
                            string angleType = ReadString(data, 4, ref pos);
                            pos += 1;

                            TSStreamFile angleFile     = null;
                            string       angleFileName = string.Format(
                                "{0}.M2TS", angleName);
                            if (streamFiles.ContainsKey(angleFileName))
                            {
                                angleFile = streamFiles[angleFileName];
                            }
                            if (angleFile == null)
                            {
                                throw new Exception(string.Format(
                                                        "Playlist {0} referenced missing angle file {1}.",
                                                        FileInfo.Name, angleFileName));
                            }

                            TSStreamClipFile angleClipFile     = null;
                            string           angleClipFileName = string.Format(
                                "{0}.CLPI", angleName);
                            if (streamClipFiles.ContainsKey(angleClipFileName))
                            {
                                angleClipFile = streamClipFiles[angleClipFileName];
                            }
                            if (angleClipFile == null)
                            {
                                throw new Exception(string.Format(
                                                        "Playlist {0} referenced missing angle file {1}.",
                                                        FileInfo.Name, angleClipFileName));
                            }

                            TSStreamClip angleClip =
                                new TSStreamClip(angleFile, angleClipFile);
                            angleClip.AngleIndex      = angle + 1;
                            angleClip.TimeIn          = streamClip.TimeIn;
                            angleClip.TimeOut         = streamClip.TimeOut;
                            angleClip.RelativeTimeIn  = streamClip.RelativeTimeIn;
                            angleClip.RelativeTimeOut = streamClip.RelativeTimeOut;
                            angleClip.Length          = streamClip.Length;
                            StreamClips.Add(angleClip);
                        }
                        if (angles - 1 > AngleCount)
                        {
                            AngleCount = angles - 1;
                        }
                    }

                    int streamInfoLength = ReadInt16(data, ref pos);
                    pos += 2;
                    int streamCountVideo          = data[pos++];
                    int streamCountAudio          = data[pos++];
                    int streamCountPG             = data[pos++];
                    int streamCountIG             = data[pos++];
                    int streamCountSecondaryAudio = data[pos++];
                    int streamCountSecondaryVideo = data[pos++];
                    int streamCountPIP            = data[pos++];
                    pos += 5;

#if DEBUG
                    Debug.WriteLine(string.Format(
                                        "{0} : {1} -> V:{2} A:{3} PG:{4} IG:{5} 2A:{6} 2V:{7} PIP:{8}",
                                        Name, streamFileName, streamCountVideo, streamCountAudio, streamCountPG, streamCountIG,
                                        streamCountSecondaryAudio, streamCountSecondaryVideo, streamCountPIP));
#endif

                    for (int i = 0; i < streamCountVideo; i++)
                    {
                        TSStream stream = CreatePlaylistStream(data, ref pos);
                        if (stream != null)
                        {
                            PlaylistStreams[stream.PID] = stream;
                        }
                    }
                    for (int i = 0; i < streamCountAudio; i++)
                    {
                        TSStream stream = CreatePlaylistStream(data, ref pos);
                        if (stream != null)
                        {
                            PlaylistStreams[stream.PID] = stream;
                        }
                    }
                    for (int i = 0; i < streamCountPG; i++)
                    {
                        TSStream stream = CreatePlaylistStream(data, ref pos);
                        if (stream != null)
                        {
                            PlaylistStreams[stream.PID] = stream;
                        }
                    }
                    for (int i = 0; i < streamCountIG; i++)
                    {
                        TSStream stream = CreatePlaylistStream(data, ref pos);
                        if (stream != null)
                        {
                            PlaylistStreams[stream.PID] = stream;
                        }
                    }
                    for (int i = 0; i < streamCountSecondaryAudio; i++)
                    {
                        TSStream stream = CreatePlaylistStream(data, ref pos);
                        if (stream != null)
                        {
                            PlaylistStreams[stream.PID] = stream;
                        }
                        pos += 2;
                    }
                    for (int i = 0; i < streamCountSecondaryVideo; i++)
                    {
                        TSStream stream = CreatePlaylistStream(data, ref pos);
                        if (stream != null)
                        {
                            PlaylistStreams[stream.PID] = stream;
                        }
                        pos += 6;
                    }

                    /*
                     * TODO
                     *
                     * for (int i = 0; i < streamCountPIP; i++)
                     * {
                     *  TSStream stream = CreatePlaylistStream(data, ref pos);
                     *  if (stream != null) PlaylistStreams[stream.PID] = stream;
                     * }
                     */

                    pos += itemLength - (pos - itemStart) + 2;
                }

                pos = chaptersOffset + 4;

                int chapterCount = ReadInt16(data, ref pos);

                for (int chapterIndex = 0;
                     chapterIndex < chapterCount;
                     chapterIndex++)
                {
                    int chapterType = data[pos + 1];

                    if (chapterType == 1)
                    {
                        int streamFileIndex =
                            ((int)data[pos + 2] << 8) + data[pos + 3];

                        long chapterTime =
                            ((long)data[pos + 4] << 24) +
                            ((long)data[pos + 5] << 16) +
                            ((long)data[pos + 6] << 8) +
                            ((long)data[pos + 7]);

                        TSStreamClip streamClip = chapterClips[streamFileIndex];

                        double chapterSeconds = (double)chapterTime / 45000;

                        double relativeSeconds =
                            chapterSeconds -
                            streamClip.TimeIn +
                            streamClip.RelativeTimeIn;

                        // TODO: Ignore short last chapter?
                        if (TotalLength - relativeSeconds > 1.0)
                        {
                            streamClip.Chapters.Add(chapterSeconds);
                            this.Chapters.Add(relativeSeconds);
                        }
                    }
                    else
                    {
                        // TODO: Handle other chapter types?
                    }
                    pos += 14;
                }
            }
            finally
            {
                if (fileReader != null)
                {
                    fileReader.Close();
                }
                if (fileStream != null)
                {
                    fileStream.Close();
                }
            }
        }
Example #13
0
        public void Generate(BDROM BDROM, List <TSPlaylistFile> playlists, BDInfo.runner.ScanBDROMResult scanResult, String savePath)
        {
            Playlists = playlists;

            StreamWriter reportFile = null;

            /* if (BDInfoSettings.AutosaveReport)
             * {*/
            string reportName = string.Format(
                "BDINFO.{0}.txt",
                BDROM.VolumeLabel);

            reportFile = File.CreateText(Path.Combine(savePath, reportName));
            //}
            //textBoxReport.Text = "";

            string report     = "";
            string protection = (BDROM.IsBDPlus ? "BD+" : "AACS");
            string bdjava     = (BDROM.IsBDJava ? "Yes" : "No");

            report += string.Format(
                "{0,-16}{1}\r\n", "Disc Title:", BDROM.VolumeLabel);
            report += string.Format(
                "{0,-16}{1:N0} bytes\r\n", "Disc Size:", BDROM.Size);
            report += string.Format(
                "{0,-16}{1}\r\n", "Protection:", protection);
            report += string.Format(
                "{0,-16}{1}\r\n", "BD-Java:", bdjava);

            List <string> extraFeatures = new List <string>();

            if (BDROM.Is50Hz)
            {
                extraFeatures.Add("50Hz Content");
            }
            if (BDROM.Is3D)
            {
                extraFeatures.Add("Blu-ray 3D");
            }
            if (BDROM.IsDBOX)
            {
                extraFeatures.Add("D-BOX Motion Code");
            }
            if (BDROM.IsPSP)
            {
                extraFeatures.Add("PSP Digital Copy");
            }
            if (extraFeatures.Count > 0)
            {
                report += string.Format(
                    "{0,-16}{1}\r\n", "Extras:", string.Join(", ", extraFeatures.ToArray()));
            }
            report += string.Format(
                "{0,-16}{1}\r\n", "BDInfo:", Application.ProductVersion);

            report += "\r\n";
            report += string.Format(
                "{0,-16}{1}\r\n", "Notes:", "");
            report += "\r\n";
            report += "BDINFO HOME:\r\n";
            report += "  Cinema Squid\r\n";
            report += "    http://www.cinemasquid.com/blu-ray/tools/bdinfo\r\n";
            report += "\r\n";
            report += "INCLUDES FORUMS REPORT FOR:\r\n";
            report += "  AVS Forum Blu-ray Audio and Video Specifications Thread\r\n";
            report += "    http://www.avsforum.com/avs-vb/showthread.php?t=1155731\r\n";
            report += "\r\n";

            if (scanResult.ScanException != null)
            {
                report += string.Format(
                    "WARNING: Report is incomplete because: {0}\r\n",
                    scanResult.ScanException.Message);
            }
            if (scanResult.FileExceptions.Count > 0)
            {
                report += "WARNING: File errors were encountered during scan:\r\n";
                foreach (string fileName in scanResult.FileExceptions.Keys)
                {
                    Exception fileException = scanResult.FileExceptions[fileName];
                    report += string.Format(
                        "\r\n{0}\t{1}\r\n", fileName, fileException.Message);
                    report += string.Format(
                        "{0}\r\n", fileException.StackTrace);
                }
            }

            foreach (TSPlaylistFile playlist in playlists)
            {
                string summary = "";

                string title    = playlist.Name;
                string discSize = string.Format(
                    "{0:N0}", BDROM.Size);

                TimeSpan playlistTotalLength =
                    new TimeSpan((long)(playlist.TotalLength * 10000000));
                string totalLength = string.Format(
                    "{0:D1}:{1:D2}:{2:D2}.{3:D3}",
                    playlistTotalLength.Hours,
                    playlistTotalLength.Minutes,
                    playlistTotalLength.Seconds,
                    playlistTotalLength.Milliseconds);
                string totalLengthShort = string.Format(
                    "{0:D1}:{1:D2}:{2:D2}",
                    playlistTotalLength.Hours,
                    playlistTotalLength.Minutes,
                    playlistTotalLength.Seconds);
                string totalSize = string.Format(
                    "{0:N0}", playlist.TotalSize);
                string totalBitrate = string.Format(
                    "{0:F2}",
                    Math.Round((double)playlist.TotalBitRate / 10000) / 100);

                TimeSpan playlistAngleLength =
                    new TimeSpan((long)(playlist.TotalAngleLength * 10000000));
                string totalAngleLength = string.Format(
                    "{0:D1}:{1:D2}:{2:D2}.{3:D3}",
                    playlistAngleLength.Hours,
                    playlistAngleLength.Minutes,
                    playlistAngleLength.Seconds,
                    playlistAngleLength.Milliseconds);
                string totalAngleSize = string.Format(
                    "{0:N0}", playlist.TotalAngleSize);
                string totalAngleBitrate = string.Format(
                    "{0:F2}",
                    Math.Round((double)playlist.TotalAngleBitRate / 10000) / 100);

                List <string> angleLengths       = new List <string>();
                List <string> angleSizes         = new List <string>();
                List <string> angleBitrates      = new List <string>();
                List <string> angleTotalLengths  = new List <string>();
                List <string> angleTotalSizes    = new List <string>();
                List <string> angleTotalBitrates = new List <string>();
                if (playlist.AngleCount > 0)
                {
                    for (int angleIndex = 0; angleIndex < playlist.AngleCount; angleIndex++)
                    {
                        double angleLength    = 0;
                        ulong  angleSize      = 0;
                        ulong  angleTotalSize = 0;
                        if (angleIndex < playlist.AngleClips.Count &&
                            playlist.AngleClips[angleIndex] != null)
                        {
                            foreach (TSStreamClip clip in playlist.AngleClips[angleIndex].Values)
                            {
                                angleTotalSize += clip.PacketSize;
                                if (clip.AngleIndex == angleIndex + 1)
                                {
                                    angleSize   += clip.PacketSize;
                                    angleLength += clip.Length;
                                }
                            }
                        }

                        angleSizes.Add(string.Format(
                                           "{0:N0}", angleSize));

                        TimeSpan angleTimeSpan =
                            new TimeSpan((long)(angleLength * 10000000));

                        angleLengths.Add(string.Format(
                                             "{0:D1}:{1:D2}:{2:D2}.{3:D3}",
                                             angleTimeSpan.Hours,
                                             angleTimeSpan.Minutes,
                                             angleTimeSpan.Seconds,
                                             angleTimeSpan.Milliseconds));

                        angleTotalSizes.Add(string.Format(
                                                "{0:N0}", angleTotalSize));

                        angleTotalLengths.Add(totalLength);

                        double angleBitrate = 0;
                        if (angleLength > 0)
                        {
                            angleBitrate = Math.Round((double)(angleSize * 8) / angleLength / 10000) / 100;
                        }
                        angleBitrates.Add(string.Format("{0:F2}", angleBitrate));

                        double angleTotalBitrate = 0;
                        if (playlist.TotalLength > 0)
                        {
                            angleTotalBitrate = Math.Round((double)(angleTotalSize * 8) / playlist.TotalLength / 10000) / 100;
                        }
                        angleTotalBitrates.Add(string.Format(
                                                   "{0:F2}", angleTotalBitrate));
                    }
                }

                string videoCodec   = "";
                string videoBitrate = "";
                if (playlist.VideoStreams.Count > 0)
                {
                    TSStream videoStream = playlist.VideoStreams[0];
                    videoCodec   = videoStream.CodecAltName;
                    videoBitrate = string.Format(
                        "{0:F2}", Math.Round((double)videoStream.BitRate / 10000) / 100);
                }

                string audio1        = "";
                string languageCode1 = "";
                if (playlist.AudioStreams.Count > 0)
                {
                    TSAudioStream audioStream = playlist.AudioStreams[0];

                    languageCode1 = audioStream.LanguageCode;

                    audio1 = string.Format(
                        "{0} {1}",
                        audioStream.CodecAltName,
                        audioStream.ChannelDescription);

                    if (audioStream.BitRate > 0)
                    {
                        audio1 += string.Format(
                            " {0}Kbps",
                            (int)Math.Round((double)audioStream.BitRate / 1000));
                    }

                    if (audioStream.SampleRate > 0 &&
                        audioStream.BitDepth > 0)
                    {
                        audio1 += string.Format(
                            " ({0}kHz/{1}-bit)",
                            (int)Math.Round((double)audioStream.SampleRate / 1000),
                            audioStream.BitDepth);
                    }
                }

                string audio2 = "";
                if (playlist.AudioStreams.Count > 1)
                {
                    for (int i = 1; i < playlist.AudioStreams.Count; i++)
                    {
                        TSAudioStream audioStream = playlist.AudioStreams[i];

                        if (audioStream.LanguageCode == languageCode1 &&
                            audioStream.StreamType != TSStreamType.AC3_PLUS_SECONDARY_AUDIO &&
                            audioStream.StreamType != TSStreamType.DTS_HD_SECONDARY_AUDIO &&
                            !(audioStream.StreamType == TSStreamType.AC3_AUDIO &&
                              audioStream.ChannelCount == 2))
                        {
                            audio2 = string.Format(
                                "{0} {1}",
                                audioStream.CodecAltName, audioStream.ChannelDescription);

                            if (audioStream.BitRate > 0)
                            {
                                audio2 += string.Format(
                                    " {0}Kbps",
                                    (int)Math.Round((double)audioStream.BitRate / 1000));
                            }

                            if (audioStream.SampleRate > 0 &&
                                audioStream.BitDepth > 0)
                            {
                                audio2 += string.Format(
                                    " ({0}kHz/{1}-bit)",
                                    (int)Math.Round((double)audioStream.SampleRate / 1000),
                                    audioStream.BitDepth);
                            }
                            break;
                        }
                    }
                }

                report += "\r\n";
                report += "********************\r\n";
                report += "PLAYLIST: " + playlist.Name + "\r\n";
                report += "********************\r\n";
                report += "\r\n";
                report += "<--- BEGIN FORUMS PASTE --->\r\n";
                report += "[code]\r\n";

                report += string.Format(
                    "{0,-64}{1,-8}{2,-8}{3,-16}{4,-16}{5,-8}{6,-8}{7,-42}{8}\r\n",
                    "",
                    "",
                    "",
                    "",
                    "",
                    "Total",
                    "Video",
                    "",
                    "");

                report += string.Format(
                    "{0,-64}{1,-8}{2,-8}{3,-16}{4,-16}{5,-8}{6,-8}{7,-42}{8}\r\n",
                    "Title",
                    "Codec",
                    "Length",
                    "Movie Size",
                    "Disc Size",
                    "Bitrate",
                    "Bitrate",
                    "Main Audio Track",
                    "Secondary Audio Track");

                report += string.Format(
                    "{0,-64}{1,-8}{2,-8}{3,-16}{4,-16}{5,-8}{6,-8}{7,-42}{8}\r\n",
                    "-----",
                    "------",
                    "-------",
                    "--------------",
                    "--------------",
                    "-------",
                    "-------",
                    "------------------",
                    "---------------------");

                report += string.Format(
                    "{0,-64}{1,-8}{2,-8}{3,-16}{4,-16}{5,-8}{6,-8}{7,-42}{8}\r\n",
                    title,
                    videoCodec,
                    totalLengthShort,
                    totalSize,
                    discSize,
                    totalBitrate,
                    videoBitrate,
                    audio1,
                    audio2);

                report += "[/code]\r\n";
                report += "\r\n";
                report += "[code]\r\n";

                report += "\r\n";
                report += "DISC INFO:\r\n";
                report += "\r\n";

                report += string.Format(
                    "{0,-16}{1}\r\n", "Disc Title:", BDROM.VolumeLabel);
                report += string.Format(
                    "{0,-16}{1:N0} bytes\r\n", "Disc Size:", BDROM.Size);
                report += string.Format(
                    "{0,-16}{1}\r\n", "Protection:", protection);
                report += string.Format(
                    "{0,-16}{1}\r\n", "BD-Java:", bdjava);
                if (extraFeatures.Count > 0)
                {
                    report += string.Format(
                        "{0,-16}{1}\r\n", "Extras:", string.Join(", ", extraFeatures.ToArray()));
                }
                report += string.Format(
                    "{0,-16}{1}\r\n", "BDInfo:", Application.ProductVersion);

                report += "\r\n";
                report += "PLAYLIST REPORT:\r\n";
                report += "\r\n";
                report += string.Format(
                    "{0,-24}{1}\r\n", "Name:", title);
                report += string.Format(
                    "{0,-24}{1} (h:m:s.ms)\r\n", "Length:", totalLength);
                report += string.Format(
                    "{0,-24}{1:N0} bytes\r\n", "Size:", totalSize);
                report += string.Format(
                    "{0,-24}{1} Mbps\r\n", "Total Bitrate:", totalBitrate);
                if (playlist.AngleCount > 0)
                {
                    for (int angleIndex = 0; angleIndex < playlist.AngleCount; angleIndex++)
                    {
                        report += "\r\n";
                        report += string.Format(
                            "{0,-24}{1} (h:m:s.ms) / {2} (h:m:s.ms)\r\n", string.Format("Angle {0} Length:", angleIndex + 1),
                            angleLengths[angleIndex], angleTotalLengths[angleIndex]);
                        report += string.Format(
                            "{0,-24}{1:N0} bytes / {2:N0} bytes\r\n", string.Format("Angle {0} Size:", angleIndex + 1),
                            angleSizes[angleIndex], angleTotalSizes[angleIndex]);
                        report += string.Format(
                            "{0,-24}{1} Mbps / {2} Mbps\r\n", string.Format("Angle {0} Total Bitrate:", angleIndex + 1),
                            angleBitrates[angleIndex], angleTotalBitrates[angleIndex], angleIndex);
                    }
                    report += "\r\n";
                    report += string.Format(
                        "{0,-24}{1} (h:m:s.ms)\r\n", "All Angles Length:", totalAngleLength);
                    report += string.Format(
                        "{0,-24}{1} bytes\r\n", "All Angles Size:", totalAngleSize);
                    report += string.Format(
                        "{0,-24}{1} Mbps\r\n", "All Angles Bitrate:", totalAngleBitrate);
                }

                /*
                 * report += string.Format(
                 *  "{0,-24}{1}\r\n", "Description:", "");
                 */

                summary += string.Format(
                    "Disc Title: {0}\r\n", BDROM.VolumeLabel);
                summary += string.Format(
                    "Disc Size: {0:N0} bytes\r\n", BDROM.Size);
                summary += string.Format(
                    "Protection: {0}\r\n", protection);
                summary += string.Format(
                    "BD-Java: {0}\r\n", bdjava);
                summary += string.Format(
                    "Playlist: {0}\r\n", title);
                summary += string.Format(
                    "Size: {0:N0} bytes\r\n", totalSize);
                summary += string.Format(
                    "Length: {0}\r\n", totalLength);
                summary += string.Format(
                    "Total Bitrate: {0} Mbps\r\n", totalBitrate);

                if (playlist.HasHiddenTracks)
                {
                    report += "\r\n(*) Indicates included stream hidden by this playlist.\r\n";
                }

                if (playlist.VideoStreams.Count > 0)
                {
                    report += "\r\n";
                    report += "VIDEO:\r\n";
                    report += "\r\n";
                    report += string.Format(
                        "{0,-24}{1,-20}{2,-16}\r\n",
                        "Codec",
                        "Bitrate",
                        "Description");
                    report += string.Format(
                        "{0,-24}{1,-20}{2,-16}\r\n",
                        "-----",
                        "-------",
                        "-----------");

                    foreach (TSStream stream in playlist.SortedStreams)
                    {
                        if (!stream.IsVideoStream)
                        {
                            continue;
                        }

                        string streamName = stream.CodecName;
                        if (stream.AngleIndex > 0)
                        {
                            streamName += string.Format(
                                " ({0})", stream.AngleIndex);
                        }

                        string streamBitrate = string.Format(
                            "{0:D}",
                            (int)Math.Round((double)stream.BitRate / 1000));
                        if (stream.AngleIndex > 0)
                        {
                            streamBitrate += string.Format(
                                " ({0:D})",
                                (int)Math.Round((double)stream.ActiveBitRate / 1000));
                        }
                        streamBitrate += " kbps";

                        report += string.Format(
                            "{0,-24}{1,-20}{2,-16}\r\n",
                            (stream.IsHidden ? "* " : "") + streamName,
                            streamBitrate,
                            stream.Description);

                        summary += string.Format(
                            (stream.IsHidden ? "* " : "") + "Video: {0} / {1} / {2}\r\n",
                            streamName,
                            streamBitrate,
                            stream.Description);
                    }
                }

                if (playlist.AudioStreams.Count > 0)
                {
                    report += "\r\n";
                    report += "AUDIO:\r\n";
                    report += "\r\n";
                    report += string.Format(
                        "{0,-32}{1,-16}{2,-16}{3,-16}\r\n",
                        "Codec",
                        "Language",
                        "Bitrate",
                        "Description");
                    report += string.Format(
                        "{0,-32}{1,-16}{2,-16}{3,-16}\r\n",
                        "-----",
                        "--------",
                        "-------",
                        "-----------");

                    foreach (TSStream stream in playlist.SortedStreams)
                    {
                        if (!stream.IsAudioStream)
                        {
                            continue;
                        }

                        string streamBitrate = string.Format(
                            "{0:D} kbps",
                            (int)Math.Round((double)stream.BitRate / 1000));

                        report += string.Format(
                            "{0,-32}{1,-16}{2,-16}{3,-16}\r\n",
                            (stream.IsHidden ? "* " : "") + stream.CodecName,
                            stream.LanguageName,
                            streamBitrate,
                            stream.Description);

                        summary += string.Format(
                            (stream.IsHidden ? "* " : "") + "Audio: {0} / {1} / {2}\r\n",
                            stream.LanguageName,
                            stream.CodecName,
                            stream.Description);
                    }
                }

                if (playlist.GraphicsStreams.Count > 0)
                {
                    report += "\r\n";
                    report += "SUBTITLES:\r\n";
                    report += "\r\n";
                    report += string.Format(
                        "{0,-32}{1,-16}{2,-16}{3,-16}\r\n",
                        "Codec",
                        "Language",
                        "Bitrate",
                        "Description");
                    report += string.Format(
                        "{0,-32}{1,-16}{2,-16}{3,-16}\r\n",
                        "-----",
                        "--------",
                        "-------",
                        "-----------");

                    foreach (TSStream stream in playlist.SortedStreams)
                    {
                        if (!stream.IsGraphicsStream)
                        {
                            continue;
                        }

                        string streamBitrate = string.Format(
                            "{0:F3} kbps",
                            (double)stream.BitRate / 1000);

                        report += string.Format(
                            "{0,-32}{1,-16}{2,-16}{3,-16}\r\n",
                            (stream.IsHidden ? "* " : "") + stream.CodecName,
                            stream.LanguageName,
                            streamBitrate,
                            stream.Description);

                        summary += string.Format(
                            (stream.IsHidden ? "* " : "") + "Subtitle: {0} / {1}\r\n",
                            stream.LanguageName,
                            streamBitrate,
                            stream.Description);
                    }
                }

                if (playlist.TextStreams.Count > 0)
                {
                    report += "\r\n";
                    report += "TEXT:\r\n";
                    report += "\r\n";
                    report += string.Format(
                        "{0,-32}{1,-16}{2,-16}{3,-16}\r\n",
                        "Codec",
                        "Language",
                        "Bitrate",
                        "Description");
                    report += string.Format(
                        "{0,-32}{1,-16}{2,-16}{3,-16}\r\n",
                        "-----",
                        "--------",
                        "-------",
                        "-----------");

                    foreach (TSStream stream in playlist.SortedStreams)
                    {
                        if (!stream.IsTextStream)
                        {
                            continue;
                        }

                        string streamBitrate = string.Format(
                            "{0:F3} kbps",
                            (double)stream.BitRate / 1000);

                        report += string.Format(
                            "{0,-32}{1,-16}{2,-16}{3,-16}\r\n",
                            (stream.IsHidden ? "* " : "") + stream.CodecName,
                            stream.LanguageName,
                            streamBitrate,
                            stream.Description);
                    }
                }

                report += "\r\n";
                report += "FILES:\r\n";
                report += "\r\n";
                report += string.Format(
                    "{0,-16}{1,-16}{2,-16}{3,-16}{4,-16}\r\n",
                    "Name",
                    "Time In",
                    "Length",
                    "Size",
                    "Total Bitrate");
                report += string.Format(
                    "{0,-16}{1,-16}{2,-16}{3,-16}{4,-16}\r\n",
                    "----",
                    "-------",
                    "------",
                    "----",
                    "-------------");

                foreach (TSStreamClip clip in playlist.StreamClips)
                {
                    string clipName = clip.DisplayName;

                    if (clip.AngleIndex > 0)
                    {
                        clipName += string.Format(
                            " ({0})", clip.AngleIndex);
                    }

                    string clipSize = string.Format(
                        "{0:N0}", clip.PacketSize);

                    TimeSpan clipInSpan =
                        new TimeSpan((long)(clip.RelativeTimeIn * 10000000));
                    TimeSpan clipOutSpan =
                        new TimeSpan((long)(clip.RelativeTimeOut * 10000000));
                    TimeSpan clipLengthSpan =
                        new TimeSpan((long)(clip.Length * 10000000));

                    string clipTimeIn = string.Format(
                        "{0:D1}:{1:D2}:{2:D2}.{3:D3}",
                        clipInSpan.Hours,
                        clipInSpan.Minutes,
                        clipInSpan.Seconds,
                        clipInSpan.Milliseconds);
                    string clipLength = string.Format(
                        "{0:D1}:{1:D2}:{2:D2}.{3:D3}",
                        clipLengthSpan.Hours,
                        clipLengthSpan.Minutes,
                        clipLengthSpan.Seconds,
                        clipLengthSpan.Milliseconds);

                    string clipBitrate = Math.Round(
                        (double)clip.PacketBitRate / 1000).ToString("N0");

                    report += string.Format(
                        "{0,-16}{1,-16}{2,-16}{3,-16}{4,-16}\r\n",
                        clipName,
                        clipTimeIn,
                        clipLength,
                        clipSize,
                        clipBitrate);
                }

                report += "\r\n";
                report += "CHAPTERS:\r\n";
                report += "\r\n";
                report += string.Format(
                    "{0,-16}{1,-16}{2,-16}{3,-16}{4,-16}{5,-16}{6,-16}{7,-16}{8,-16}{9,-16}{10,-16}{11,-16}{12,-16}\r\n",
                    "Number",
                    "Time In",
                    "Length",
                    "Avg Video Rate",
                    "Max 1-Sec Rate",
                    "Max 1-Sec Time",
                    "Max 5-Sec Rate",
                    "Max 5-Sec Time",
                    "Max 10Sec Rate",
                    "Max 10Sec Time",
                    "Avg Frame Size",
                    "Max Frame Size",
                    "Max Frame Time");
                report += string.Format(
                    "{0,-16}{1,-16}{2,-16}{3,-16}{4,-16}{5,-16}{6,-16}{7,-16}{8,-16}{9,-16}{10,-16}{11,-16}{12,-16}\r\n",
                    "------",
                    "-------",
                    "------",
                    "--------------",
                    "--------------",
                    "--------------",
                    "--------------",
                    "--------------",
                    "--------------",
                    "--------------",
                    "--------------",
                    "--------------",
                    "--------------");

                Queue <double> window1Bits         = new Queue <double>();
                Queue <double> window1Seconds      = new Queue <double>();
                double         window1BitsSum      = 0;
                double         window1SecondsSum   = 0;
                double         window1PeakBitrate  = 0;
                double         window1PeakLocation = 0;

                Queue <double> window5Bits         = new Queue <double>();
                Queue <double> window5Seconds      = new Queue <double>();
                double         window5BitsSum      = 0;
                double         window5SecondsSum   = 0;
                double         window5PeakBitrate  = 0;
                double         window5PeakLocation = 0;

                Queue <double> window10Bits         = new Queue <double>();
                Queue <double> window10Seconds      = new Queue <double>();
                double         window10BitsSum      = 0;
                double         window10SecondsSum   = 0;
                double         window10PeakBitrate  = 0;
                double         window10PeakLocation = 0;

                double chapterPosition         = 0;
                double chapterBits             = 0;
                long   chapterFrameCount       = 0;
                double chapterSeconds          = 0;
                double chapterMaxFrameSize     = 0;
                double chapterMaxFrameLocation = 0;

                ushort diagPID = playlist.VideoStreams[0].PID;

                int chapterIndex = 0;
                int clipIndex    = 0;
                int diagIndex    = 0;

                while (chapterIndex < playlist.Chapters.Count)
                {
                    TSStreamClip clip = null;
                    TSStreamFile file = null;

                    if (clipIndex < playlist.StreamClips.Count)
                    {
                        clip = playlist.StreamClips[clipIndex];
                        file = clip.StreamFile;
                    }

                    double chapterStart = playlist.Chapters[chapterIndex];
                    double chapterEnd;
                    if (chapterIndex < playlist.Chapters.Count - 1)
                    {
                        chapterEnd = playlist.Chapters[chapterIndex + 1];
                    }
                    else
                    {
                        chapterEnd = playlist.TotalLength;
                    }
                    double chapterLength = chapterEnd - chapterStart;

                    List <TSStreamDiagnostics> diagList = null;

                    if (clip != null &&
                        clip.AngleIndex == 0 &&
                        file != null &&
                        file.StreamDiagnostics.ContainsKey(diagPID))
                    {
                        diagList = file.StreamDiagnostics[diagPID];

                        while (diagIndex < diagList.Count &&
                               chapterPosition < chapterEnd)
                        {
                            TSStreamDiagnostics diag = diagList[diagIndex++];

                            if (diag.Marker < clip.TimeIn)
                            {
                                continue;
                            }

                            chapterPosition =
                                diag.Marker -
                                clip.TimeIn +
                                clip.RelativeTimeIn;

                            double seconds = diag.Interval;
                            double bits    = diag.Bytes * 8.0;

                            chapterBits    += bits;
                            chapterSeconds += seconds;

                            if (diag.Tag != null)
                            {
                                chapterFrameCount++;
                            }

                            window1SecondsSum += seconds;
                            window1Seconds.Enqueue(seconds);
                            window1BitsSum += bits;
                            window1Bits.Enqueue(bits);

                            window5SecondsSum += diag.Interval;
                            window5Seconds.Enqueue(diag.Interval);
                            window5BitsSum += bits;
                            window5Bits.Enqueue(bits);

                            window10SecondsSum += seconds;
                            window10Seconds.Enqueue(seconds);
                            window10BitsSum += bits;
                            window10Bits.Enqueue(bits);

                            if (bits > chapterMaxFrameSize * 8)
                            {
                                chapterMaxFrameSize     = bits / 8;
                                chapterMaxFrameLocation = chapterPosition;
                            }
                            if (window1SecondsSum > 1.0)
                            {
                                double bitrate = window1BitsSum / window1SecondsSum;
                                if (bitrate > window1PeakBitrate &&
                                    chapterPosition - window1SecondsSum > 0)
                                {
                                    window1PeakBitrate  = bitrate;
                                    window1PeakLocation = chapterPosition - window1SecondsSum;
                                }
                                window1BitsSum    -= window1Bits.Dequeue();
                                window1SecondsSum -= window1Seconds.Dequeue();
                            }
                            if (window5SecondsSum > 5.0)
                            {
                                double bitrate = window5BitsSum / window5SecondsSum;
                                if (bitrate > window5PeakBitrate &&
                                    chapterPosition - window5SecondsSum > 0)
                                {
                                    window5PeakBitrate  = bitrate;
                                    window5PeakLocation = chapterPosition - window5SecondsSum;
                                    if (window5PeakLocation < 0)
                                    {
                                        window5PeakLocation = 0;
                                        window5PeakLocation = 0;
                                    }
                                }
                                window5BitsSum    -= window5Bits.Dequeue();
                                window5SecondsSum -= window5Seconds.Dequeue();
                            }
                            if (window10SecondsSum > 10.0)
                            {
                                double bitrate = window10BitsSum / window10SecondsSum;
                                if (bitrate > window10PeakBitrate &&
                                    chapterPosition - window10SecondsSum > 0)
                                {
                                    window10PeakBitrate  = bitrate;
                                    window10PeakLocation = chapterPosition - window10SecondsSum;
                                }
                                window10BitsSum    -= window10Bits.Dequeue();
                                window10SecondsSum -= window10Seconds.Dequeue();
                            }
                        }
                    }
                    if (diagList == null ||
                        diagIndex == diagList.Count)
                    {
                        if (clipIndex < playlist.StreamClips.Count)
                        {
                            clipIndex++; diagIndex = 0;
                        }
                        else
                        {
                            chapterPosition = chapterEnd;
                        }
                    }
                    if (chapterPosition >= chapterEnd)
                    {
                        ++chapterIndex;

                        TimeSpan window1PeakSpan     = new TimeSpan((long)(window1PeakLocation * 10000000));
                        TimeSpan window5PeakSpan     = new TimeSpan((long)(window5PeakLocation * 10000000));
                        TimeSpan window10PeakSpan    = new TimeSpan((long)(window10PeakLocation * 10000000));
                        TimeSpan chapterMaxFrameSpan = new TimeSpan((long)(chapterMaxFrameLocation * 10000000));
                        TimeSpan chapterStartSpan    = new TimeSpan((long)(chapterStart * 10000000));
                        TimeSpan chapterEndSpan      = new TimeSpan((long)(chapterEnd * 10000000));
                        TimeSpan chapterLengthSpan   = new TimeSpan((long)(chapterLength * 10000000));

                        double chapterBitrate = 0;
                        if (chapterLength > 0)
                        {
                            chapterBitrate = chapterBits / chapterLength;
                        }
                        double chapterAvgFrameSize = 0;
                        if (chapterFrameCount > 0)
                        {
                            chapterAvgFrameSize = chapterBits / chapterFrameCount / 8;
                        }

                        report += string.Format(
                            "{0,-16}{1,-16}{2,-16}{3,-16}{4,-16}{5,-16}{6,-16}{7,-16}{8,-16}{9,-16}{10,-16}{11,-16}{12,-16}\r\n",
                            chapterIndex,
                            string.Format("{0:D1}:{1:D2}:{2:D2}.{3:D3}", chapterStartSpan.Hours, chapterStartSpan.Minutes, chapterStartSpan.Seconds, chapterStartSpan.Milliseconds),
                            string.Format("{0:D1}:{1:D2}:{2:D2}.{3:D3}", chapterLengthSpan.Hours, chapterLengthSpan.Minutes, chapterLengthSpan.Seconds, chapterLengthSpan.Milliseconds),
                            string.Format("{0:N0} kbps", Math.Round(chapterBitrate / 1000)),
                            string.Format("{0:N0} kbps", Math.Round(window1PeakBitrate / 1000)),
                            string.Format("{0:D2}:{1:D2}:{2:D2}.{3:D3}", window1PeakSpan.Hours, window1PeakSpan.Minutes, window1PeakSpan.Seconds, window1PeakSpan.Milliseconds),
                            string.Format("{0:N0} kbps", Math.Round(window5PeakBitrate / 1000)),
                            string.Format("{0:D2}:{1:D2}:{2:D2}.{3:D3}", window5PeakSpan.Hours, window5PeakSpan.Minutes, window5PeakSpan.Seconds, window5PeakSpan.Milliseconds),
                            string.Format("{0:N0} kbps", Math.Round(window10PeakBitrate / 1000)),
                            string.Format("{0:D2}:{1:D2}:{2:D2}.{3:D3}", window10PeakSpan.Hours, window10PeakSpan.Minutes, window10PeakSpan.Seconds, window10PeakSpan.Milliseconds),
                            string.Format("{0:N0} bytes", chapterAvgFrameSize),
                            string.Format("{0:N0} bytes", chapterMaxFrameSize),
                            string.Format("{0:D2}:{1:D2}:{2:D2}.{3:D3}", chapterMaxFrameSpan.Hours, chapterMaxFrameSpan.Minutes, chapterMaxFrameSpan.Seconds, chapterMaxFrameSpan.Milliseconds));

                        window1Bits         = new Queue <double>();
                        window1Seconds      = new Queue <double>();
                        window1BitsSum      = 0;
                        window1SecondsSum   = 0;
                        window1PeakBitrate  = 0;
                        window1PeakLocation = 0;

                        window5Bits         = new Queue <double>();
                        window5Seconds      = new Queue <double>();
                        window5BitsSum      = 0;
                        window5SecondsSum   = 0;
                        window5PeakBitrate  = 0;
                        window5PeakLocation = 0;

                        window10Bits         = new Queue <double>();
                        window10Seconds      = new Queue <double>();
                        window10BitsSum      = 0;
                        window10SecondsSum   = 0;
                        window10PeakBitrate  = 0;
                        window10PeakLocation = 0;

                        chapterBits             = 0;
                        chapterSeconds          = 0;
                        chapterFrameCount       = 0;
                        chapterMaxFrameSize     = 0;
                        chapterMaxFrameLocation = 0;
                    }
                }

                if (BDInfoSettings.GenerateStreamDiagnostics)
                {
                    report += "\r\n";
                    report += "STREAM DIAGNOSTICS:\r\n";
                    report += "\r\n";
                    report += string.Format(
                        "{0,-16}{1,-16}{2,-16}{3,-16}{4,-24}{5,-24}{6,-24}{7,-16}{8,-16}\r\n",
                        "File",
                        "PID",
                        "Type",
                        "Codec",
                        "Language",
                        "Seconds",
                        "Bitrate",
                        "Bytes",
                        "Packets");
                    report += string.Format(
                        "{0,-16}{1,-16}{2,-16}{3,-16}{4,-24}{5,-24}{6,-24}{7,-16}{8,-16}\r\n",
                        "----",
                        "---",
                        "----",
                        "-----",
                        "--------",
                        "--------------",
                        "--------------",
                        "-------------",
                        "-----",
                        "-------");

                    Dictionary <string, TSStreamClip> reportedClips = new Dictionary <string, TSStreamClip>();
                    foreach (TSStreamClip clip in playlist.StreamClips)
                    {
                        if (clip.StreamFile == null)
                        {
                            continue;
                        }
                        if (reportedClips.ContainsKey(clip.Name))
                        {
                            continue;
                        }
                        reportedClips[clip.Name] = clip;

                        string clipName = clip.DisplayName;
                        if (clip.AngleIndex > 0)
                        {
                            clipName += string.Format(" ({0})", clip.AngleIndex);
                        }
                        foreach (TSStream clipStream in clip.StreamFile.Streams.Values)
                        {
                            if (!playlist.Streams.ContainsKey(clipStream.PID))
                            {
                                continue;
                            }

                            TSStream playlistStream =
                                playlist.Streams[clipStream.PID];

                            string clipBitRate = "0";
                            string clipSeconds = "0";

                            if (clip.StreamFile.Length > 0)
                            {
                                clipSeconds =
                                    clip.StreamFile.Length.ToString("F3");
                                clipBitRate = Math.Round(
                                    (double)clipStream.PayloadBytes * 8 /
                                    clip.StreamFile.Length / 1000).ToString("N0");
                            }
                            string language = "";
                            if (playlistStream.LanguageCode != null &&
                                playlistStream.LanguageCode.Length > 0)
                            {
                                language = string.Format(
                                    "{0} ({1})", playlistStream.LanguageCode, playlistStream.LanguageName);
                            }

                            report += string.Format(
                                "{0,-16}{1,-16}{2,-16}{3,-16}{4,-24}{5,-24}{6,-24}{7,-16}{8,-16}\r\n",
                                clipName,
                                string.Format("{0} (0x{1:X})", clipStream.PID, clipStream.PID),
                                string.Format("0x{0:X2}", (byte)clipStream.StreamType),
                                clipStream.CodecShortName,
                                language,
                                clipSeconds,
                                clipBitRate,
                                clipStream.PayloadBytes.ToString("N0"),
                                clipStream.PacketCount.ToString("N0"));
                        }
                    }
                }

                report += "\r\n";
                report += "[/code]\r\n";
                report += "<---- END FORUMS PASTE ---->\r\n";
                report += "\r\n";

                if (BDInfoSettings.GenerateTextSummary)
                {
                    report += "QUICK SUMMARY:\r\n\r\n";
                    report += summary;
                    report += "\r\n";
                }

                if (/*BDInfoSettings.AutosaveReport &&*/ reportFile != null)
                {
                    try { reportFile.Write(report); }
                    catch { }
                }
                //textBoxReport.Text += report;
                report = "";
                GC.Collect();
            }

            if (/*BDInfoSettings.AutosaveReport &&*/ reportFile != null)
            {
                try { reportFile.Write(report); }
                catch { }
            }
            //textBoxReport.Text += report;

            if (reportFile != null)
            {
                reportFile.Close();
            }
        }