private void button3_Click(object sender, System.EventArgs e) { try { lock (this) { List<IFOParse.VOB> vobs = null; IFOParse.ProgramChain pgc = null; List<IFOParse.Cell> cells = null; if (treeView1.SelectedNode == null) return; if (treeView1.SelectedNode.Tag.GetType() == typeof(FileInfo)) { // got single vob file FileInfo fi = (FileInfo)treeView1.SelectedNode.Tag; IFOParse.VOB v = new IFOParse.VOB(fi.FullName); vobs = new List<IFOParse.VOB>(); vobs.Add(v); // create dummy cell list cells = new List<IFOParse.Cell>(); IFOParse.Cell c = new IFOParse.Cell(); c.FirstSector = 0; c.LastSector = (int)v.LastSector; cells.Add(c); } else if (treeView1.SelectedNode.Tag.GetType() == typeof(IFOParse.ProgramChain)) { pgc = (IFOParse.ProgramChain)treeView1.SelectedNode.Tag; vobs = pgc.Title.VOBs; cells = pgc.Cells; } m_ds = new DSUtils(); ArrayList ranges = new ArrayList(); ArrayList vobNames = new ArrayList(); for (int c = 0; c < cells.Count; c++) { ranges.Add(cells[c].FirstSector); ranges.Add(cells[c].LastSector); } for (int v = 0; v < vobs.Count; v++) { vobNames.Add(vobs[v].FileInfo.FullName); vobNames.Add(vobs[v].Sectors); } m_ds.Preview(ranges, vobNames, panel1.Handle, trackBar1.Value); button3.Enabled = false; button4.Enabled = true; button5.Enabled = true; if (Settings.Default.AudioMode) { label9.Visible = true; label10.Visible = true; } m_videoThread = new Thread(new ThreadStart(PlaybackProgress)); m_videoThread.Start(); } } catch (Exception ex) { MessageBox.Show(String.Format("Error starting preview: {0}", ex.Message)); } }
private void ProcessVOB() { try { DisableForm(); List<IFOParse.VOB> vobs = null; IFOParse.ProgramChain pgc = null; List<IFOParse.Cell> cells = null; int selectedAudioTrack = 0; if (treeView1.SelectedNode.Tag.GetType() == typeof(FileInfo)) { // treat a single vob file with no ifo file as all data // got single vob file FileInfo fi = (FileInfo)treeView1.SelectedNode.Tag; IFOParse.VOB v = new IFOParse.VOB(fi.FullName); vobs = new List<IFOParse.VOB>(); vobs.Add(v); // create dummy cell list cells = new List<IFOParse.Cell>(); IFOParse.Cell c = new IFOParse.Cell(); c.FirstSector = 0; c.LastSector = (int)v.LastSector; cells.Add(c); } else if (treeView1.SelectedNode.Tag.GetType() == typeof(IFOParse.ProgramChain)) { pgc = (IFOParse.ProgramChain)treeView1.SelectedNode.Tag; vobs = pgc.Title.VOBs; cells = pgc.Cells; // if we have multiple audio streams, allow the user to select which one to use if (pgc.Title.AudioFormat.Count > 1) { SelectAudio audioSelector = new SelectAudio(pgc.Title.AudioFormat); if (audioSelector.ShowDialog() == DialogResult.Cancel) return; selectedAudioTrack = audioSelector.SelectedSubstreamID; } } //string outputDir = ""; #region Choose a file, default to last directory used string saveFile = ""; saveFileDialog1.FileName = textBox2.Text + "-" + textBox4.Text + "-" + textBox3.Text + ".mpg"; saveFileDialog1.FileName = new Utilities().MakeSafeFilename(saveFileDialog1.FileName); RegistryKey rk = Registry.LocalMachine.OpenSubKey(REGISTRY_KEY); if (rk != null) { string initialDir = rk.GetValue("DefaultDirectory").ToString(); if (initialDir != null && Directory.Exists(initialDir)) saveFileDialog1.InitialDirectory = initialDir; } DialogResult dr = saveFileDialog1.ShowDialog(); if (dr == DialogResult.OK && File.Exists(saveFileDialog1.FileName)) { dr = DialogResult.Cancel; // ask about overwriting if (MessageBox.Show(saveFileDialog1.FileName + " already exists.\nDo you want to replace it?", "Save As", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes) { dr = DialogResult.OK; File.Delete(saveFileDialog1.FileName); } } if (dr == DialogResult.OK) { saveFile = saveFileDialog1.FileName; FileInfo fi = new FileInfo(saveFile); try { RegistryKey saveKey = Registry.LocalMachine.CreateSubKey(REGISTRY_KEY); saveKey.SetValue("DefaultDirectory", fi.Directory.FullName); //outputDir = fi.Directory.FullName; } catch { } } else { SetProgress(0); SetStatusText(""); EnableForm(); thread = null; return; } #endregion int audioOffset = 0; int videoOffset = 0; string audio = null; string video = null; m_startTime = DateTime.Now; m_lastSecond = 0; try { SetProgress(0); byte[] buf = new byte[2048]; long totalSectors = 0; long currentSector = 0; // find total number of sectors for all cells for (int cellNum = 0; cellNum < cells.Count; cellNum++) { IFOParse.Cell cell = cells[cellNum]; totalSectors += cell.LastSector - cell.FirstSector; } SetStatusText("Reading from DVD..."); for (int cellNum = 0; cellNum < cells.Count; cellNum++) { IFOParse.Cell cell = cells[cellNum]; ulong updateInterval = 0; for (int sector = cell.FirstSector; sector <= cell.LastSector; sector++) { ReadSector(vobs, buf, sector); if (updateInterval++ % 10 == 0) { SetStatusText("Reading from DVD..." + Convert.ToInt32(100.0 * (Convert.ToDouble(currentSector) / Convert.ToDouble(totalSectors))) + "%"); SetProgress(Convert.ToInt32(m_demuxCount * (Convert.ToDouble(currentSector) / Convert.ToDouble(totalSectors)))); } currentSector++; uint code = ReadCode(buf, 0); if (code != BLOCK_START_CODE) continue; int i = 0x0e; ulong systemCode = ReadCode(buf, i); i += 4; UInt16 headerLength = ReadWord(buf, i); i += 2; switch (systemCode) { case AC3_DETECT_BYTES: //if (!inCell) // break; //audPacks++; #region write non-mpeg audio data to temp file UInt16 flags = ReadWord(buf, i); i += 2; byte b = buf[i++]; #region find ms offset if ((flags & 0xc000) == 0x8000 && (flags & 0xff) >= 0x80 && audioOffset == 0) { byte c = buf[i++]; int offset = (c & 0x0e) << 29; offset += (ReadWord(buf, i) & 0xfffe) << 14; i += 2; offset += (ReadWord(buf, i) >> 1) & 0x7fff; i += 2; offset /= 90; i += b - 5; audioOffset = offset; } else i += b; #endregion byte substream = buf[i++]; i++; // # frame headers UInt16 pointer = ReadWord(buf, i); i += 2; int t = substream; string name = t.ToString("000"); if (t >= 0xA8) // nothing continue; else if (t >= 0xA0) // PCM { // http://dvd.sourceforge.net/dvdinfo/index.html name += ".wav"; i++; // emph, mute, reserved, frame # byte details = buf[i++]; i++; // dynamic range; // these seem to be zeroed out in my tests, ignore them int bitsPerSample = (details & 0xC0) >> 6; int sampleRate = (details & 0x30) >> 4; int numChannels = details & 0x07; b += 3; } else if (t >= 0x88) // DTS name += ".dts"; // dts audio will be ignored (most dvds are ac3, or at least have an ac3 track) else if (t >= 0x80) // AC3 name += ".ac3"; else continue; FileStream w = null; if (writers.ContainsKey(name)) w = (FileStream)writers[name]; else { w = File.Create(TempPath + name); writers[name] = w; if (name.EndsWith(".wav")) // leave room for wav header w.Seek(44, SeekOrigin.Begin); } //SaveData(w, buf, i, 2048 - i, t); SaveData(w, buf, i, (headerLength - 7 - b), t); #endregion break; case VID_DETECT_BYTES: //if (!inCell) // break; //vidPacks++; #region write mpeg video to temp file flags = ReadWord(buf, i); i += 2; b = buf[i++]; #region find ms offset if ((flags & 0xc000) == 0x8000 && (flags & 0xff) >= 0x80 && videoOffset == 0) { byte c = buf[i++]; int offset = (c & 0x0e) << 29; offset += (ReadWord(buf, i) & 0xfffe) << 14; i += 2; offset += (ReadWord(buf, i) >> 1) & 0x7fff; i += 2; offset /= 90; i += b - 5; videoOffset = offset; } else i += b; #endregion string vname = "video.m2v"; video = vname; FileStream vw = null; if (writers.ContainsKey(vname)) vw = (FileStream)writers[vname]; else { vw = File.Create(TempPath + vname); writers[vname] = vw; } //SaveData(vw, buf, i, 2048 - i, 1); SaveData(vw, buf, i, (headerLength - 3 - b), 1); #endregion break; case AUD_DETECT_BYTES: //if (!inCell) // break; //audPacks++; #region write mpeg audio to temp file flags = ReadWord(buf, i); i += 2; b = buf[i++]; #region find ms offset if ((flags & 0xc000) == 0x8000 && (flags & 0xff) >= 0x80 && audioOffset == 0) { byte c = buf[i++]; int offset = (c & 0x0e) << 29; offset += (ReadWord(buf, i) & 0xfffe) << 14; i += 2; offset += (ReadWord(buf, i) >> 1) & 0x7fff; i += 2; offset /= 90; i += b - 5; audioOffset = offset; } else i += b; #endregion string aname = "vob.mp2"; if (audio == null) audio = aname; FileStream aw = null; if (writers.ContainsKey(aname)) aw = (FileStream)writers[aname]; else { aw = File.Create(TempPath + aname); writers[aname] = aw; } //SaveData(aw, buf, i, 2048 - i, 0); SaveData(aw, buf, i, (headerLength - 3 - b), 1); #endregion break; case NAV_DETECT_BYTES: //navPacks++; #region find vobID and cellID int cellID = buf[0x422]; int vobID = (buf[0x41f] << 8) + buf[0x420]; //if (cellID == cell.CellID && vobID == cell.VobID) // inCell = true; //else // inCell = false; #endregion break; default: break; } if (m_run == false) return; } } SetProgress(m_demuxCount); } finally { if (bs != null) bs.TRMSFinalize(); bs = null; foreach (string name in writers.Keys) { FileStream fs = (FileStream)writers[name]; fs.Close(); // determine the audio track to use by selecting the first one we encounter, // or the one the user selected if there is more than one // (if the audio is .mp2, it will already be set and we don't have to worry about the non-digit // name at this point) if (name.EndsWith(".m2v")) video = name; else if (audio == null && selectedAudioTrack == 0 && (name.EndsWith(".ac3") || name.EndsWith(".dts") || name.EndsWith(".wav") || name.EndsWith(".mp2"))) // select first audio track we encounter, unless otherwise directed audio = name; else if (audio == null && selectedAudioTrack == Convert.ToInt32(Path.GetFileNameWithoutExtension(name))) audio = name; // delete anything after the first audio and video streams in the file if (audio != null && name != video && name != audio) File.Delete(name); } writers.Clear(); foreach (FileStream fs in readers.Values) { fs.Close(); } readers.Clear(); } int duration = 0; if (pgc != null) duration = pgc.Duration; if (audio == null) // don't process empty audio (will screw things up) return; audio = ConvertAudio(TempPath + audio, duration); if (audio == null) return; SetProgress(m_audioCount); DisableCancel(); SetStatusText("Remuxing elementary mpeg streams..."); FileInfo appPath = new FileInfo(Application.ExecutablePath); string mplexCommand = appPath.Directory + "\\mplex.exe"; if (File.Exists(mplexCommand) == false) return; process = new Process(); process.StartInfo.UseShellExecute = false; process.StartInfo.WorkingDirectory = Environment.CurrentDirectory; //process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; process.StartInfo.FileName = mplexCommand; int AVOffset = Offset(cells, vobs); // format = MPEG2 (-f 3) // -V = VBR // -v 2 = verbose output // -O x = A/V offset // -S 0 = disable segment splitting // -o <file> = output to final output process.StartInfo.Arguments = String.Format("-f 3 -V -v 2 -O {0} -S 0 -o \"{1}\" \"{2}\" \"{3}\"", AVOffset, saveFile, TempPath + video, audio); process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; process.StartInfo.CreateNoWindow = true; process.Start(); string line; string muxBitrate = String.Empty; string muxStatus = String.Empty; int streams = 0; int overflowCount = 0; long lastSCR = 0; StreamReader sr = process.StandardError; DateTime lastMessage = DateTime.MinValue; while ((line = sr.ReadLine()) != null) { line = Regex.Replace(line, @"^[^\[]*\[[^\]]*\]\s+", ""); // get rid of process name at start of string if (m_run == false) return; else if(line.Contains("SCR=")) { if (DateTime.Now < lastMessage.AddMilliseconds(50)) continue; try { Match m = Regex.Match(line, @"\w\d:\s+SCR=(-?\d+)"); if (m.Success) { // workaround for printf in windows truncating 64-bit SCR data long scr = Convert.ToInt64(m.Groups[1].Value); if(scr < lastSCR) overflowCount++; lastSCR = scr; scr += overflowCount * UInt32.MaxValue; // divide it by the CLOCK value to get number of seconds scr /= m_mplexMpegClock; if (pgc == null) { SetStatusText("Remuxing elementary mpeg streams..."); } else { SetStatusText("Remuxing elementary mpeg streams..." + Convert.ToInt32(100.0 * (Convert.ToDouble(scr) / Convert.ToDouble(pgc.Duration))) + "%"); SetProgress(m_audioCount + Convert.ToInt32((m_remuxCount - m_audioCount) * (Convert.ToDouble(scr) / Convert.ToDouble(pgc.Duration)))); } lastMessage = DateTime.Now; } } catch { } } else if (line == "New sequence commences...") streams++; else if (line.StartsWith("MUX STATUS: ")) { line = line.Replace("MUX STATUS: ", ""); muxStatus = line; } else if (line.StartsWith("Average bit-rate")) { muxBitrate = line; } } process.WaitForExit(); process = null; SetProgress(m_remuxCount); if (String.IsNullOrEmpty(muxBitrate) == false) { SetStatusText(muxBitrate); Thread.Sleep(500); } if(AVOffset != 0) { if(String.IsNullOrEmpty(muxStatus)) muxStatus = ""; else muxStatus += " "; muxStatus += "used " + AVOffset + "ms AV offset"; } if (String.IsNullOrEmpty(muxStatus) == false) { SetStatusText(muxStatus); Thread.Sleep(500); } } catch (ThreadAbortException) { try { if (process != null && process.HasExited == false) process.Kill(); } catch { } } catch (Exception ex) { MessageBox.Show("Error: " + ex.Message); } finally { if (process != null && process.HasExited == false) process.Kill(); EnableForm(); thread = null; SetProgress(0); //SetStatusText(""); SetETAText(""); SetStatusText(""); try { Directory.Delete(TempPath, true); } catch { } } }
private void LoadTitles() { try { treeView1.Nodes.Clear(); button3.Enabled = false; button4.Enabled = false; button5.Enabled = false; string path = ""; if (tabControl1.SelectedIndex == 0) { string drive = comboBox1.Items[comboBox1.SelectedIndex].ToString(); path = drive + "VIDEO_TS"; } else path = textBox1.Text; if (!Directory.Exists(path)) return; //int index = 0; int maxLength = 0; TreeNode longestNode = null; int ifoIdx = 1; while (true) { FileInfo fi = new FileInfo(path + Path.DirectorySeparatorChar + "VTS_" + ifoIdx.ToString("00") + "_0.IFO"); if (fi.Exists == false) break; ifoIdx++; string name = fi.Name.ToUpper(); //if (name == "VIDEO_TS.IFO") // continue; try { int title = Convert.ToInt32(name.Replace("VTS_", "").Replace("_0.IFO", "")); IFOParse ifo = new IFOParse(fi.FullName); // add to tree view TreeNode titleNode = new TreeNode(); string audioTracks = "No audio"; if (ifo.AudioFormat.Count == 1) audioTracks = ifo.AudioFormat[0].ToString(); else if(ifo.AudioFormat.Count > 1) audioTracks = "Multiple audio streams"; titleNode.Text = "Title " + title + ": " + ifo.VideoMode + " video, " + audioTracks; titleNode.Tag = ifo; titleNode.Nodes.Clear(); titleNode.ToolTipText = ifo.ProgramChainCount + " programs"; for (int pgcNum = 0; pgcNum < ifo.ProgramChainCount; pgcNum++) { IFOParse.ProgramChain pgc = ifo.ProgramChains[pgcNum]; TreeNode n = new TreeNode(); n.Text = "PGC " + (pgcNum + 1) + ": " + Utilities.SecondsToLength(pgc.Duration); n.ToolTipText = pgc.Cells.Count + " cells"; n.Tag = pgc; titleNode.Nodes.Add(n); if (pgc.Duration > maxLength) { longestNode = n; maxLength = pgc.Duration; } } treeView1.Nodes.Add(titleNode); } catch (Exception ex) { MessageBox.Show(ex.Message); } } if (treeView1.Nodes.Count == 0) { // found no IFO files, load raw VOB list foreach (string file in Directory.GetFiles(path, "*.VOB")) { FileInfo fi = new FileInfo(file); string name = fi.Name.ToUpper(); TreeNode titleNode = new TreeNode(); List<IFOParse.VOB> vobs = new List<IFOParse.VOB>(); IFOParse.VOB v = new IFOParse.VOB(file); vobs = new List<IFOParse.VOB>(); vobs.Add(v); // create dummy cell list List<IFOParse.Cell> cells = new List<IFOParse.Cell>(); IFOParse.Cell c = new IFOParse.Cell(); c.FirstSector = 0; c.LastSector = (int)v.LastSector; cells.Add(c); titleNode.Text = name + ": " + Utilities.BytesToSize(fi.Length); titleNode.Tag = fi; treeView1.Nodes.Add(titleNode); } } if (longestNode != null) treeView1.SelectedNode = longestNode; treeView1.ExpandAll(); } catch (Exception ex) { MessageBox.Show("An error occurred reading DVD, it may be corrupt or a failed burn.\n\n" + ex.Message); } }