private void SaveData(FileStream fs, byte[] data, int offset, int len, int id) { int skip = 0; if (fs.Name.EndsWith(".wav")) // swap bytes in wav data { if (bs == null) bs = new ByteSwapper(fs); for (int i = offset + skip; i < offset + skip + len; i++) bs.NextByte(data[i]); } else fs.Write(data, offset + skip, len); }
public ElementaryStreams ProcessVOB(IFOParse.ProgramChain pgc, string outputPath) { ElementaryStreams result = new ElementaryStreams(); result.AudioFile = null; result.VideoFile = null; List<IFOParse.VOB> vobs = pgc.Title.VOBs; List<IFOParse.Cell> cells = pgc.Cells; int audioOffset = 0; int videoOffset = 0; string audio = null; string video = null; try { byte[] buf = new byte[2048]; int totalSectors = 0; int 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; } for (int cellNum = 0; cellNum < cells.Count; cellNum++) { IFOParse.Cell cell = cells[cellNum]; for (int sector = cell.FirstSector; sector <= cell.LastSector; sector++) { ReadSector(vobs, buf, sector); // don't update progress every cell, otherwise it gets *really* slow if (currentSector % 3000 == 0 && Progress != null) Progress(currentSector, 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: #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(Path.Combine(outputPath, name)); writers[name] = w; if (name.EndsWith(".wav")) // leave room for wav header w.Seek(44, SeekOrigin.Begin); } SaveData(w, buf, i, (headerLength - 7 - b), t); #endregion break; case VID_DETECT_BYTES: #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(Path.Combine(outputPath, vname)); writers[vname] = vw; } SaveData(vw, buf, i, (headerLength - 3 - b), 1); #endregion break; case AUD_DETECT_BYTES: #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(Path.Combine(outputPath, aname)); writers[aname] = aw; } SaveData(aw, buf, i, (headerLength - 3 - b), 1); #endregion break; case NAV_DETECT_BYTES: #region find vobID and cellID int cellID = buf[0x422]; int vobID = (buf[0x41f] << 8) + buf[0x420]; #endregion break; default: break; } } } if (Progress != null) Progress(totalSectors, totalSectors); } finally { if (bs != null) bs.TRMSFinalize(); bs = null; foreach (string name in writers.Keys) { FileStream fs = (FileStream)writers[name]; fs.Close(); if (name.EndsWith(".m2v")) result.VideoFile = Path.Combine(outputPath, name); else if (name.EndsWith(".ac3") || name.EndsWith(".dts") || name.EndsWith(".wav") || name.EndsWith(".mp2")) result.AudioFile = Path.Combine(outputPath, 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(); } return (result); }