Exemplo n.º 1
0
        private void input_FileSelected(FileBar sender, FileBarEventArgs args)
        {
            audioDelay.Value = PrettyFormatting.getDelayAndCheck(input.Filename) ?? 0;

            bool bFound = false;

            foreach (KeyValuePair <string, string> strLanguage in LanguageSelectionContainer.Languages)
            {
                if (input.Filename.ToLower(System.Globalization.CultureInfo.InvariantCulture).Contains(strLanguage.Key.ToLower(System.Globalization.CultureInfo.InvariantCulture)))
                {
                    SetLanguage(strLanguage.Key);
                    bFound = true;
                    break;
                }
            }
            if (!bFound && input.Filename.ToLower(System.Globalization.CultureInfo.InvariantCulture).EndsWith(".idx"))
            {
                List <SubtitleInfo> subTracks;
                idxReader.readFileProperties(input.Filename, out subTracks);
                if (subTracks.Count > 0)
                {
                    SetLanguage(LanguageSelectionContainer.Short2FullLanguageName(subTracks[0].Name));
                }
            }
            raiseEvent();
        }
Exemplo n.º 2
0
        private void input_FileSelected(FileBar sender, FileBarEventArgs args)
        {
            audioDelay.Value = PrettyFormatting.getDelayAndCheck(input.Filename) ?? 0;

            string strLanguage = LanguageSelectionContainer.GetLanguageFromFileName(System.IO.Path.GetFileNameWithoutExtension(input.Filename));

            if (!String.IsNullOrEmpty(strLanguage))
            {
                SetLanguage(strLanguage);
            }
            else if (input.Filename.ToLowerInvariant().EndsWith(".idx"))
            {
                List <SubtitleInfo> subTracks;
                idxReader.readFileProperties(input.Filename, out subTracks);
                if (subTracks.Count > 0)
                {
                    SetLanguage(LanguageSelectionContainer.LookupISOCode(subTracks[0].Name));
                }
            }

            raiseEvent();
        }
Exemplo n.º 3
0
        /// <summary>
        /// get Audio Language from the IFO file
        /// </summary>
        /// <param name="fileName">name of the IFO file</param>
        /// <param name="count">the audio stream number</param>
        /// <returns>Language as String</returns>
        public static string getAudioLanguage(string FileName, int count)
        {
            FileStream   fs = new FileStream(FileName, FileMode.Open, FileAccess.Read);
            BinaryReader br = new BinaryReader(fs);
            Stream       sr = br.BaseStream;

            // go to audio stream number
            sr.Seek(0x203, SeekOrigin.Begin);
            byte a = br.ReadByte();

            sr.Seek(2, SeekOrigin.Current);
            if (count > 0)
            {
                sr.Seek(8 * count, SeekOrigin.Current);
            }
            byte[] buff = new byte[2];
            br.Read(buff, 0, 2);
            string ShortLangCode = String.Format("{0}{1}", (char)buff[0], (char)buff[1]);
            string audioLang     = LanguageSelectionContainer.Short2FullLanguageName(ShortLangCode);

            fs.Close();
            return(audioLang);
        }
Exemplo n.º 4
0
        /// <summary>
        /// fills the <see cref="TitleInfo"/> with informations
        /// </summary>
        private void GetTitleInfo(int titleSetNumber, ref TitleInfo item)
        {
            item.VideoStream     = new VideoProperties();
            item.AudioStreams    = new List <AudioProperties>();
            item.SubtitleStreams = new List <SubpictureProperties>();
            item.Chapters        = new List <TimeSpan>();

            var buffer = new byte[192];

            using (var fs = File.OpenRead(Path.Combine(_path, $"VTS_{titleSetNumber:00}_0.IFO")))
            {
                fs.Seek(0x00C8, SeekOrigin.Begin);
                fs.Read(buffer, 0, 4);
                fs.Seek(0x0200, SeekOrigin.Begin);
                fs.Read(buffer, 0, 2);

                item.VideoStream.DisplayFormat = (DvdVideoPermittedDisplayFormat)GetBits(buffer, 2, 0);
                item.VideoStream.AspectRatio   = (DvdVideoAspectRatio)GetBits(buffer, 2, 2);
                item.VideoStream.VideoStandard = (DvdVideoStandard)GetBits(buffer, 2, 4);

                switch (item.VideoStream.VideoStandard)
                {
                case DvdVideoStandard.NTSC:
                    item.VideoStream.Framerate            = 30000f / 1001f;
                    item.VideoStream.FrameRateNumerator   = 30000;
                    item.VideoStream.FrameRateDenominator = 1001;
                    break;

                case DvdVideoStandard.PAL:
                    item.VideoStream.Framerate            = 25f;
                    item.VideoStream.FrameRateNumerator   = 25;
                    item.VideoStream.FrameRateDenominator = 1;
                    break;
                }
                item.VideoStream.CodingMode      = (DvdVideoMpegVersion)GetBits(buffer, 2, 6);
                item.VideoStream.VideoResolution = (DvdVideoResolution)GetBits(buffer, 3, 11) +
                                                   ((int)item.VideoStream.VideoStandard * 8);

                fs.Read(buffer, 0, 2);
                var numAudio = GetBits(buffer, 16, 0);
                for (var audioNum = 0; audioNum < numAudio; audioNum++)
                {
                    fs.Read(buffer, 0, 8);
                    var langMode    = GetBits(buffer, 2, 2);
                    var codingMode  = GetBits(buffer, 3, 5);
                    var audioStream = new AudioProperties
                    {
                        CodingMode   = (DvdAudioFormat)codingMode,
                        Channels     = GetBits(buffer, 3, 8) + 1,
                        SampleRate   = 48000,
                        Quantization = (DvdAudioQuantization)GetBits(buffer, 2, 14),
                        StreamId     = DvdAudioId.ID[codingMode] + audioNum,
                        StreamIndex  = audioNum + 1
                    };

                    if (langMode == 1)
                    {
                        var langChar1 = (char)GetBits(buffer, 8, 16);
                        var langChar2 = (char)GetBits(buffer, 8, 24);

                        audioStream.Language = LanguageSelectionContainer.LookupISOCode($"{langChar1}{langChar2}");
                    }
                    else
                    {
                        audioStream.Language = LanguageSelectionContainer.LookupISOCode("  ");
                    }
                    audioStream.Extension = (DvdAudioType)GetBits(buffer, 8, 40);
                    item.AudioStreams.Add(audioStream);
                }

                fs.Seek(0x0254, SeekOrigin.Begin);
                fs.Read(buffer, 0, 2);
                var numSubs = GetBits(buffer, 16, 0);
                for (var subNum = 0; subNum < numSubs; subNum++)
                {
                    fs.Read(buffer, 0, 6);
                    var langMode = GetBits(buffer, 2, 0);
                    var sub      = new SubpictureProperties
                    {
                        Format      = (DvdSubpictureFormat)GetBits(buffer, 3, 5),
                        StreamId    = 0x20 + subNum,
                        StreamIndex = subNum + 1
                    };

                    if (langMode == 1)
                    {
                        var langChar1 = (char)GetBits(buffer, 8, 16);
                        var langChar2 = (char)GetBits(buffer, 8, 24);

                        var langCode = langChar1.ToString(CultureInfo.InvariantCulture) +
                                       langChar2.ToString(CultureInfo.InvariantCulture);

                        sub.Language = LanguageSelectionContainer.LookupISOCode(langCode);
                    }
                    else
                    {
                        sub.Language = LanguageSelectionContainer.LookupISOCode("  ");
                    }
                    sub.Extension = (DvdSubpictureType)GetBits(buffer, 8, 40);
                    item.SubtitleStreams.Add(sub);
                }

                fs.Seek(0xCC, SeekOrigin.Begin);
                fs.Read(buffer, 0, 4);
                var pgciSector = GetBits(buffer, 32, 0);
                var pgciAdress = pgciSector * SectorLength;

                fs.Seek(pgciAdress, SeekOrigin.Begin);
                fs.Read(buffer, 0, 8);

                fs.Seek(8 * (item.TitleNumberInSet - 1), SeekOrigin.Current);
                fs.Read(buffer, 0, 8);
                var offsetPgc = GetBits(buffer, 32, 32);
                fs.Seek(pgciAdress + offsetPgc + 2, SeekOrigin.Begin);

                fs.Read(buffer, 0, 6);
                var numCells = GetBits(buffer, 8, 8);

                var hour   = GetBits(buffer, 8, 16);
                var minute = GetBits(buffer, 8, 24);
                var second = GetBits(buffer, 8, 32);
                var msec   = GetBits(buffer, 8, 40);

                item.VideoStream.Runtime = DvdTime2TimeSpan(hour, minute, second, msec);

                fs.Seek(224, SeekOrigin.Current);
                fs.Read(buffer, 0, 2);
                var cellmapOffset = GetBits(buffer, 16, 0);

                fs.Seek(pgciAdress + cellmapOffset + offsetPgc, SeekOrigin.Begin);

                var chapter = new TimeSpan();
                item.Chapters.Add(chapter);

                for (var i = 0; i < numCells; i++)
                {
                    fs.Read(buffer, 0, 24);
                    var chapHour   = GetBits(buffer, 8, 4 * 8);
                    var chapMinute = GetBits(buffer, 8, 5 * 8);
                    var chapSecond = GetBits(buffer, 8, 6 * 8);
                    var chapMsec   = GetBits(buffer, 8, 7 * 8);
                    chapter = chapter.Add(DvdTime2TimeSpan(chapHour, chapMinute, chapSecond, chapMsec));

                    item.Chapters.Add(chapter);
                }
            }
        }
Exemplo n.º 5
0
        /// <summary>
        /// get several Audio Informations from the IFO file
        /// </summary>
        /// <param name="fileName">name of the IFO file</param>
        /// <param name="verbose">to have complete infos or not</param>
        /// <returns>several infos as String</returns>
        public static AudioTrackInfo[] GetAudioInfos(string FileName, bool verbose)
        {
            FileStream   fs = new FileStream(FileName, FileMode.Open, FileAccess.Read);
            BinaryReader br = new BinaryReader(fs);
            Stream       sr = br.BaseStream;

            // go to audio stream number
            sr.Seek(0x203, SeekOrigin.Begin);

            byte a = br.ReadByte();

            if (a > 8)
            {
                a = 8; // force the max #. According to the specs 8 is the max value for audio streams.
            }
            AudioTrackInfo[] ati = new AudioTrackInfo[a];

            for (int i = 0; i < a; i++)
            {
                ati[i] = new AudioTrackInfo();
                byte[] array = new byte[2];
                fs.Read(array, 0, 2);
                string        cm      = GetAudioCodingMode(array);
                string        sp      = GetAudioSamplingRate(array);
                int           ch      = (int)((GetAudioChannels(array)) + 1);
                byte          trackID = 0xBD;
                StringBuilder ad      = new StringBuilder();

                switch (cm)
                {
                case "AC3":  trackID = (byte)(0x80 + i); break;

                case "LPCM": trackID = (byte)(0xA0 + i); break;

                case "DTS":  trackID = (byte)(0x88 + i); break;
                }

                if (verbose)
                {
                    string mce = "Not Present";
                    if (GetAudioMultichannelExt(array))
                    {
                        mce = "Present";
                    }
                    string lt = GetAudioLanguageType(array);
                    string ap = GetAudioApplicationMode(array);
                    string aq = GetAudioQuantization(array);

                    ad.AppendFormat("Track# : {0:00} - [{1:X}]", i, trackID, Environment.NewLine);
                    ad.AppendFormat("Coding Mode            : {0}", cm, Environment.NewLine);
                    ad.AppendFormat("Multichannel Extension : {0}", mce, Environment.NewLine);
                    ad.AppendFormat("Language Type          : {0}", lt, Environment.NewLine);
                    ad.AppendFormat("Application Mode       : {0}", ap, Environment.NewLine);
                    ad.AppendFormat("Quantization           : {0}", aq, Environment.NewLine);
                    ad.AppendFormat("Sampling Rate          : {0}", sp, Environment.NewLine);
                    ad.AppendFormat("Channels               : {0}", ch, Environment.NewLine);
                }

                byte[] buff = new byte[2];
                br.Read(buff, 0, 2);
                string ShortLangCode = String.Format("{0}{1}", (char)buff[0], (char)buff[1]);

                sr.Seek(1, SeekOrigin.Current);
                byte[] l = new byte[1];
                fs.Read(l, 0, 1);
                string lce = GetAudioLanguageCodeExt(l);

                ati[i].TrackID      = trackID;
                ati[i].NbChannels   = ch + " channels";
                ati[i].SamplingRate = sp;
                ati[i].Type         = cm;
                ati[i].Language     = LanguageSelectionContainer.Short2FullLanguageName(ShortLangCode);
                if (verbose)
                {
                    ad.AppendFormat("Language              : {0} - {1}", LanguageSelectionContainer.Short2FullLanguageName(ShortLangCode), ShortLangCode, Environment.NewLine);
                    ad.AppendFormat("Language Extension    : {0}", lce, Environment.NewLine);
                    ad.AppendLine();
                    ati[i].Description = ad.ToString();
                }
                else
                {
                    ati[i].Description = String.Format("[{0:X}] - {1} - {2}ch / {3} / {4}", trackID, cm, ch, sp, LanguageSelectionContainer.Short2FullLanguageName(ShortLangCode));
                }

                // go to the next audio stream
                sr.Seek(2, SeekOrigin.Current);
            }

            fs.Close();

            return(ati);
        }
Exemplo n.º 6
0
        /// <summary>
        /// get several Subtitles Informations from the IFO file
        /// </summary>
        /// <param name="fileName">name of the IFO file</param>
        /// <returns>several infos as String</returns>
        public static string[] GetSubtitlesStreamsInfos(string FileName)
        {
            byte[] buff = new byte[2];
            byte   s    = 0;

            string[] subdesc = new string[s];

            try
            {
                FileStream   fs = new FileStream(FileName, FileMode.Open, FileAccess.Read);
                BinaryReader br = new BinaryReader(fs);
                Stream       sr = br.BaseStream;

                // go to the substream #1
                sr.Seek(0x255, SeekOrigin.Begin);

                s = br.ReadByte();
                if (s > 32)
                {
                    s = 32; // force the max #. According to the specs 32 is the max value for subtitles streams.
                }
                subdesc = new string[s];

                // go to the Language Code
                sr.Seek(2, SeekOrigin.Current);

                for (int i = 0; i < s; i++)
                {
                    // Presence (1 bit), Coding Mode (1bit), Short Language Code (2bits), Language Extension (1bit), Sub Picture Caption Type (1bit)
                    br.Read(buff, 0, 2);
                    string ShortLangCode = String.Format("{0}{1}", (char)buff[0], (char)buff[1]);

                    subdesc[i] = "[" + String.Format("{0:00}", i) + "]  - " + LanguageSelectionContainer.Short2FullLanguageName(ShortLangCode);

                    // Go to Code Extension
                    sr.Seek(1, SeekOrigin.Current);
                    buff[0] = br.ReadByte();

                    switch (buff[0] & 0x0F)
                    {
                    // from http://dvd.sourceforge.net/dvdinfo/sprm.html
                    case 1: subdesc[i] += " (Caption/Normal Size Char)"; break;

                    case 2: subdesc[i] += " (Caption/Large Size Char)"; break;

                    case 3: subdesc[i] += " (Caption For Children)"; break;

                    case 5: subdesc[i] += " (Closed Caption/Normal Size Char)"; break;

                    case 6: subdesc[i] += " (Closed Caption/Large Size Char)"; break;

                    case 7: subdesc[i] += " (Closed Caption For Children)"; break;

                    case 9: subdesc[i] += " (Forced Caption)"; break;

                    case 13: subdesc[i] += " (Director Comments/Normal Size Char)"; break;

                    case 14: subdesc[i] += " (Director Comments/Large Size Char)"; break;

                    case 15: subdesc[i] += " (Director Comments for Children)"; break;
                    }

                    if (buff[0] == 0)
                    {
                        buff[0] = 1;
                    }

                    // go to the next sub stream
                    sr.Seek(2, SeekOrigin.Current);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
            return(subdesc);
        }
Exemplo n.º 7
0
        /// <summary>
        /// get several Subtitles Informations from the IFO file
        /// </summary>
        /// <param name="fileName">name of the IFO file</param>
        /// <returns>several infos as String</returns>
        public static string[] GetSubtitlesStreamsInfos(string FileName, int iPGC, bool bGetAllStreams)
        {
            byte[] buff = new byte[4];
            byte   s    = 0;

            string[] subdesc    = new string[s];
            string[] substreams = new string[s];

            try
            {
                FileStream   fs = new FileStream(FileName, FileMode.Open, FileAccess.Read);
                BinaryReader br = new BinaryReader(fs);
                Stream       sr = br.BaseStream;

                // go to the substream #1
                sr.Seek(0x255, SeekOrigin.Begin);

                s = br.ReadByte();
                if (s > 32 || bGetAllStreams)
                {
                    s = 32; // force the max #. According to the specs 32 is the max value for subtitles streams.
                }
                subdesc = new string[s];

                // go to the Language Code
                sr.Seek(2, SeekOrigin.Current);

                for (int i = 0; i < s; i++)
                {
                    // Presence (1 bit), Coding Mode (1bit), Short Language Code (2bits), Language Extension (1bit), Sub Picture Caption Type (1bit)
                    br.Read(buff, 0, 2);

                    if (buff[0] == 0 && buff[1] == 0)
                    {
                        subdesc[i] = "unknown";
                    }
                    else
                    {
                        string ShortLangCode = String.Format("{0}{1}", (char)buff[0], (char)buff[1]);
                        subdesc[i] = LanguageSelectionContainer.Short2FullLanguageName(ShortLangCode);
                    }

                    // Go to Code Extension
                    sr.Seek(1, SeekOrigin.Current);
                    buff[0] = br.ReadByte();

                    switch (buff[0] & 0x0F)
                    {
                    // from http://dvd.sourceforge.net/dvdinfo/sprm.html
                    case 1: subdesc[i] += " - (Caption/Normal Size Char)"; break;

                    case 2: subdesc[i] += " - (Caption/Large Size Char)"; break;

                    case 3: subdesc[i] += " - (Caption For Children)"; break;

                    case 5: subdesc[i] += " - (Closed Caption/Normal Size Char)"; break;

                    case 6: subdesc[i] += " - (Closed Caption/Large Size Char)"; break;

                    case 7: subdesc[i] += " - (Closed Caption For Children)"; break;

                    case 9: subdesc[i] += " - (Forced Caption)"; break;

                    case 13: subdesc[i] += " - (Director Comments/Normal Size Char)"; break;

                    case 14: subdesc[i] += " - (Director Comments/Large Size Char)"; break;

                    case 15: subdesc[i] += " - (Director Comments for Children)"; break;
                    }

                    if (buff[0] == 0)
                    {
                        buff[0] = 1;
                    }

                    // go to the next sub stream
                    sr.Seek(2, SeekOrigin.Current);
                }

                // find the PGC starting address of the requested PGC number
                sr.Seek(0x1000 + 0x0C + (iPGC - 1) * 0x08, SeekOrigin.Begin);
                br.Read(buff, 0, 4);

                // go to the starting address of the requested PGC number
                sr.Seek(0x1000 + buff[3] + buff[2] * 256 + buff[1] * 256 ^ 2 + buff[0] * 256 ^ 3, SeekOrigin.Begin);

                // go to the subtitle starting address
                sr.Seek(0x1B, SeekOrigin.Current);

                substreams = new string[32];
                for (int i = 0; i < 32; i++)
                {
                    if (i >= subdesc.Length)
                    {
                        break;
                    }

                    br.Read(buff, 0, 4);

                    if (buff[0] == 0)
                    {
                        continue;
                    }
                    buff[0] -= 128;

                    if (buff[0] > 0)
                    {
                        if (String.IsNullOrEmpty(substreams[buff[0]]))
                        {
                            substreams[buff[0]] = "[" + String.Format("{0:00}", buff[0]) + "] - " + subdesc[i];
                        }
                    }
                    if (buff[1] > 0)
                    {
                        if (String.IsNullOrEmpty(substreams[buff[1]]))
                        {
                            substreams[buff[1]] = "[" + String.Format("{0:00}", buff[1]) + "] - " + subdesc[i];
                        }
                    }
                    if (buff[2] > 0)
                    {
                        if (String.IsNullOrEmpty(substreams[buff[2]]))
                        {
                            substreams[buff[2]] = "[" + String.Format("{0:00}", buff[2]) + "] - " + subdesc[i];
                        }
                    }
                    if (buff[3] > 0)
                    {
                        if (String.IsNullOrEmpty(substreams[buff[3]]))
                        {
                            substreams[buff[3]] = "[" + String.Format("{0:00}", buff[3]) + "] - " + subdesc[i];
                        }
                    }
                    if (buff[0] == 0 && buff[1] == 0 && buff[2] == 0 && buff[3] == 0)
                    {
                        if (String.IsNullOrEmpty(substreams[buff[0]]))
                        {
                            substreams[buff[0]] = "[" + String.Format("{0:00}", buff[0]) + "] - " + subdesc[i];
                        }
                    }
                }

                if (bGetAllStreams)
                {
                    for (int i = 0; i < 32; i++)
                    {
                        if (String.IsNullOrEmpty(substreams[i]))
                        {
                            substreams[i] = "[" + String.Format("{0:00}", i) + "] - not detected";
                        }
                    }
                }
                else
                {
                    ArrayList arrList = new ArrayList();
                    foreach (string strItem in substreams)
                    {
                        if (!String.IsNullOrEmpty(strItem))
                        {
                            arrList.Add(strItem);
                        }
                    }
                    substreams = new string[arrList.Count];
                    for (int i = 0; i < arrList.Count; i++)
                    {
                        substreams[i] = arrList[i].ToString();
                    }
                }

                fs.Close();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
            return(substreams);
        }
Exemplo n.º 8
0
        /// <summary>
        /// get several Subtitles Informations from the IFO file
        /// </summary>
        /// <param name="fileName">name of the IFO file</param>
        /// <returns>several infos as String</returns>
        public static string[] GetSubtitlesStreamsInfos(string FileName, int iPGC, bool bGetAllStreams)
        {
            byte[]   buff       = new byte[4];
            string[] substreams = new string[32]; // according to the specs 32 is the max value for subtitles streams

            try
            {
                // get the number of subpicture streams in VTS_VOBS
                int iSubtitleCount = ToInt16(GetFileBlock(FileName, 0x254, 2));
                if (iSubtitleCount == 0 && !bGetAllStreams)
                {
                    return(new string[0]);
                }

                string[] subdesc = new string[32];

                FileStream   fs = new FileStream(FileName, FileMode.Open, FileAccess.Read);
                BinaryReader br = new BinaryReader(fs);
                Stream       sr = br.BaseStream;

                // go to the subpicture attributes of VTS_VOBS
                sr.Seek(0x256, SeekOrigin.Begin);
                for (int i = 0; i < 32; i++)
                {
                    // Presence (1 bit), Coding Mode (1bit), Short Language Code (2bits), Language Extension (1bit), Sub Picture Caption Type (1bit)

                    // ignore presence & coding mode and go to short language code
                    sr.Seek(0x2, SeekOrigin.Current);

                    // read short language code
                    br.Read(buff, 0, 2);

                    string ShortLangCode = String.Format("{0}{1}", (char)buff[0], (char)buff[1]);
                    subdesc[i] = LanguageSelectionContainer.LookupISOCode(ShortLangCode) + " - ";
                    if (String.IsNullOrEmpty(subdesc[i]))
                    {
                        subdesc[i] = "unknown - ";
                    }

                    // Go to Code Extension
                    sr.Seek(1, SeekOrigin.Current);
                    buff[0] = br.ReadByte();

                    switch (buff[0] & 0x0F)
                    {
                    // from http://dvd.sourceforge.net/dvdinfo/sprm.html
                    case 1: subdesc[i] += "Caption "; break;

                    case 2: subdesc[i] += "Caption (Large) "; break;

                    case 3: subdesc[i] += "Caption for Children "; break;

                    case 5: subdesc[i] += "Closed Caption "; break;

                    case 6: subdesc[i] += "Closed Caption (Large) "; break;

                    case 7: subdesc[i] += "Closed Caption for Children "; break;

                    case 9: subdesc[i] += "Forced Caption "; break;

                    case 13: subdesc[i] += "Director Comments "; break;

                    case 14: subdesc[i] += "Director Comments (Large) "; break;

                    case 15: subdesc[i] += "Director Comments for Children "; break;
                    }
                }

                // get VTS_PGCI
                long VTS_PGCI = GetPCGIP_Position(FileName);

                // find the VTS_PGC starting address of the requested PGC number in VTS_PGCI
                long VTS_PGC = VTS_PGCI + GetPGCOffset(FileName, VTS_PGCI, iPGC);

                // go to the Subpicture Stream Control (PGC_SPST_CTL) in VTS_PGC of the requested PGC number
                sr.Seek(VTS_PGC + 0x1C, SeekOrigin.Begin);

                byte[] iCountType = new byte[4];
                for (int i = 0; i < 32; i++)
                {
                    // read subtitle info of stream i
                    br.Read(buff, 0, 4);

                    // if bit 7 = 1 (true) the stream is available
                    if (!GetBit(buff[0], 7))
                    {
                        continue;
                    }

                    // remove bits 7, 6 and 5 as they are reserved
                    for (int j = 0; j < 4; j++)
                    {
                        if (GetBit(buff[j], 7))
                        {
                            buff[j] -= 128;
                        }
                        if (GetBit(buff[j], 6))
                        {
                            buff[j] -= 64;
                        }
                        if (GetBit(buff[j], 5))
                        {
                            buff[j] -= 32;
                        }
                    }

                    if (buff[0] > 0)
                    {
                        substreams[buff[0]] = "[" + String.Format("{0:00}", buff[0]) + "] - " + subdesc[i];
                        iCountType[0]++;
                    }
                    if (buff[1] > 0)
                    {
                        substreams[buff[1]] = "[" + String.Format("{0:00}", buff[1]) + "] - " + subdesc[i];
                        iCountType[1]++;
                    }
                    if (buff[2] > 0)
                    {
                        substreams[buff[2]] = "[" + String.Format("{0:00}", buff[2]) + "] - " + subdesc[i];
                        iCountType[2]++;
                    }
                    if (buff[3] > 0)
                    {
                        substreams[buff[3]] = "[" + String.Format("{0:00}", buff[3]) + "] - " + subdesc[i];
                        iCountType[3]++;
                    }

                    // as stream ID 0 is impossible to detect, we have to guess here
                    if (String.IsNullOrEmpty(substreams[0]))
                    {
                        if (buff[0] == 0 || buff[1] == 0 || buff[2] == 0 || buff[3] == 0)
                        {
                            substreams[0] = "[" + String.Format("{0:00}", 0) + "] - " + subdesc[i];
                        }
                    }
                }

                // check how many different types are there & if therefore the type description has to be added
                int iDifferentTypes = 0;
                if (iCountType[0] > 0)
                {
                    iDifferentTypes++;
                }
                if (iCountType[1] > 0)
                {
                    iDifferentTypes++;
                }
                if (iCountType[2] > 0)
                {
                    iDifferentTypes++;
                }
                if (iCountType[3] > 0)
                {
                    iDifferentTypes++;
                }
                bool bAddTypes = iDifferentTypes > 1;
                if (bAddTypes)
                {
                    for (int i = 0; i < subdesc.Length; i++)
                    {
                        if (!String.IsNullOrEmpty(subdesc[i]))
                        {
                            subdesc[i] += (subdesc[i].Substring(subdesc[i].Length - 1).Equals(" ") ? "(" : " (");
                        }
                    }

                    // go to the Subpicture Stream Control in VTS_PGC of the requested PGC number
                    sr.Seek(VTS_PGC + 0x1C, SeekOrigin.Begin);

                    int iCountStream = 0;
                    for (int i = 0; i < 32; i++)
                    {
                        // read subtitle info of stream i
                        br.Read(buff, 0, 4);

                        // if bit 7 = 1 (true) the stream is available
                        if (!GetBit(buff[0], 7))
                        {
                            continue;
                        }

                        iCountStream++;

                        // remove bits 7, 6 and 5 as they are reserved
                        for (int j = 0; j < 4; j++)
                        {
                            if (GetBit(buff[j], 7))
                            {
                                buff[j] -= 128;
                            }
                            if (GetBit(buff[j], 6))
                            {
                                buff[j] -= 64;
                            }
                            if (GetBit(buff[j], 5))
                            {
                                buff[j] -= 32;
                            }
                        }

                        if (buff[0] > 0)
                        {
                            if (substreams[buff[0]].Substring(substreams[buff[0]].Length - 1).Equals(")"))
                            {
                                substreams[buff[0]] = substreams[buff[0]].Substring(0, substreams[buff[0]].Length - 1) + "/4:3)";
                            }
                            else
                            {
                                substreams[buff[0]] += "(4:3)";
                            }
                        }
                        if (buff[1] > 0)
                        {
                            if (substreams[buff[1]].Substring(substreams[buff[1]].Length - 1).Equals(")"))
                            {
                                substreams[buff[1]] = substreams[buff[1]].Substring(0, substreams[buff[1]].Length - 1) + "/Wide)";
                            }
                            else
                            {
                                substreams[buff[1]] += "(Wide)";
                            }
                        }
                        if (buff[2] > 0)
                        {
                            if (substreams[buff[2]].Substring(substreams[buff[2]].Length - 1).Equals(")"))
                            {
                                substreams[buff[2]] = substreams[buff[2]].Substring(0, substreams[buff[2]].Length - 1) + "/Letterbox)";
                            }
                            else
                            {
                                substreams[buff[2]] += "(Letterbox)";
                            }
                        }
                        if (buff[3] > 0)
                        {
                            if (substreams[buff[3]].Substring(substreams[buff[3]].Length - 1).Equals(")"))
                            {
                                substreams[buff[3]] = substreams[buff[3]].Substring(0, substreams[buff[3]].Length - 1) + "/Pan&Scan)";
                            }
                            else
                            {
                                substreams[buff[3]] += "(Pan&Scan)";
                            }
                        }

                        if (bAddTypes && iCountStream == 2)
                        {
                            // only when the types should be added and the second track is in process
                            // first one is ignored because of the 0 stream ID which cannot be detected
                            int iID = 0;
                            if (buff[0] > 0)
                            {
                                iID = buff[0];
                                if (substreams[0].Substring(substreams[0].Length - 1).Equals(")"))
                                {
                                    substreams[0] = substreams[0].Substring(0, substreams[0].Length - 1) + "/4:3)";
                                }
                                else
                                {
                                    substreams[0] += "(4:3)";
                                }
                            }
                            if (buff[1] > 0 && (iID == 0 || iID == buff[1]))
                            {
                                iID = buff[1];
                                if (substreams[0].Substring(substreams[0].Length - 1).Equals(")"))
                                {
                                    substreams[0] = substreams[0].Substring(0, substreams[0].Length - 1) + "/Wide)";
                                }
                                else
                                {
                                    substreams[0] += "(Wide)";
                                }
                            }
                            if (buff[2] > 0 && (iID == 0 || iID == buff[2]))
                            {
                                iID = buff[2];
                                if (substreams[0].Substring(substreams[0].Length - 1).Equals(")"))
                                {
                                    substreams[0] = substreams[0].Substring(0, substreams[0].Length - 1) + "/Letterbox)";
                                }
                                else
                                {
                                    substreams[0] += "(Letterbox)";
                                }
                            }
                            if (buff[3] > 0 && (iID == 0 || iID == buff[3]))
                            {
                                iID = buff[3];
                                if (substreams[0].Substring(substreams[0].Length - 1).Equals(")"))
                                {
                                    substreams[0] = substreams[0].Substring(0, substreams[0].Length - 1) + "/Pan&Scan)";
                                }
                                else
                                {
                                    substreams[0] += "(Pan&Scan)";
                                }
                            }
                        }
                    }
                }

                if (bGetAllStreams)
                {
                    for (int i = 0; i < 32; i++)
                    {
                        if (String.IsNullOrEmpty(substreams[i]))
                        {
                            substreams[i] = "[" + String.Format("{0:00}", i) + "] - not detected";
                        }
                    }
                }
                else
                {
                    ArrayList arrList = new ArrayList();
                    foreach (string strItem in substreams)
                    {
                        if (!String.IsNullOrEmpty(strItem))
                        {
                            // remove trailing " - " if it exists
                            if (strItem.Substring(strItem.Length - 3).Equals(" - "))
                            {
                                arrList.Add(strItem.Substring(0, strItem.Length - 3).Trim());
                            }
                            else
                            {
                                arrList.Add(strItem.Trim());
                            }
                        }
                    }
                    substreams = new string[arrList.Count];
                    for (int i = 0; i < arrList.Count; i++)
                    {
                        substreams[i] = arrList[i].ToString();
                    }
                }

                fs.Close();
            }
            catch (Exception ex)
            {
                LogItem _oLog = MainForm.Instance.Log.Info("IFOparser");
                _oLog.LogValue("Error parsing ifo file " + FileName, ex.Message, ImageType.Error);
            }
            return(substreams);
        }