Beispiel #1
0
  /**
   * Reads a single VTS file.
   *
   * @param vtsnTitles {@link DvdTitle} belonging to this VTS file. When this method returns, the
   *     {@link DvdTitle} will contain detailed data.
   * @param dvdDir Mount directory of the DVD
   * @param vtsFile actual VTS file to be read
   */
  private void readVtsFile(List<DvdTitle> vtsnTitles, File dvdDir, String vtsFile)
      throws IOException {
    try (IfoRandomAccessFile vts = new IfoRandomAccessFile(dvdDir, vtsFile)) {
      if (!"DVDVIDEO-VTS".equals(vts.readFixedString(12))) {
        throw new IfoException("No VTS file");
      }

      Map<Integer, Long> pgcOffsets = vts.readPgcOffsets();

      DvdTitleSet titleSet = vts.readTitleSet();

      for (int ix = 0; ix < vtsnTitles.size(); ix++) {
        DvdTitle title = vtsnTitles.get(ix);
        title.setTitleSet(titleSet);
        readVtsPgc(vts, title, titleSet, pgcOffsets.get(title.getVts()));
      }
    }
  }
Beispiel #2
0
  /**
   * Reads the given VMG file.
   *
   * @param dvdDir Mount directory of the DVD
   * @param vmgName Path and name of the VMG file
   */
  private void readVmgFile(File dvdDir, String vmgName) throws IOException {
    LOG.info("Reading VMG file %s", vmgName);
    try (IfoRandomAccessFile vmg = new IfoRandomAccessFile(dvdDir, vmgName)) {
      if (!"DVDVIDEO-VMG".equals(vmg.readFixedString(12))) {
        throw new IfoException("No VMG file");
      }

      long tt_srpt = vmg.at(0xC4).readOffset();
      LOG.debug("tt_srpt: 0x%08X", tt_srpt);
      vmg.at(tt_srpt);

      int titlesCount = vmg.readu16();
      LOG.debug("titlesCount: %d", titlesCount);

      long endAddress = vmg.skip(2).readu32();
      long computedTitles = endAddress / 12;
      LOG.debug("computedTitles: %d", computedTitles);
      if (computedTitles != titlesCount) {
        LOG.warn(
            "Different number of titles: %d != %d, using the latter one",
            titlesCount, computedTitles);
        titlesCount = (int) computedTitles;
      }

      int lastVtsn = -1;
      List<DvdTitle> vtsnTitles = new ArrayList<>();

      for (int ix = 0; ix < titlesCount; ix++) {
        DvdTitle title = new DvdTitle();

        title.setTitle(ix + 1);
        title.setAngles(vmg.skip(1).readu8());
        title.setChapters(vmg.readu16());
        title.setVtsn(vmg.skip(2).readu8());
        title.setVts(vmg.readu8());
        vmg.skip(4);

        titles.add(title);
        LOG.debug("Title %2d: vtsn=%d, vts=%d", title.getTitle(), title.getVtsn(), title.getVts());

        if (title.getVtsn() != lastVtsn) {
          if (!vtsnTitles.isEmpty()) {
            completeTitles(dvdDir, lastVtsn, vtsnTitles);
          }
          vtsnTitles.clear();
          lastVtsn = title.getVtsn();
        }

        vtsnTitles.add(title);
      }

      if (!vtsnTitles.isEmpty()) {
        completeTitles(dvdDir, lastVtsn, vtsnTitles);
      }
    }
  }
Beispiel #3
0
  /**
   * Reads a PGC structure and completes the {@link DvdTitle} with the data found there.
   *
   * @param vts random access to the VTS file
   * @param title {@link DvdTitle} to complete
   * @param offset Offset of the PGC structure to be read
   */
  private void readVtsPgc(
      IfoRandomAccessFile vts, DvdTitle title, DvdTitleSet titleSet, long offset)
      throws IOException {
    vts.at(offset).skip(2);

    int chapters = vts.readu8();
    int cellCount = vts.readu8();
    LOG.debug("  chapters: %d, cells: %d", chapters, cellCount);

    title.setTotalTimeMs(vts.readBcdTimeMs());

    vts.skip(4);

    for (int ix = 0; ix < 8; ix++) {
      int snr = vts.readu8();
      if ((snr & 0x80) != 0) {
        DvdAudio audio = titleSet.getAudios().get(ix);
        int streamId = snr & 0x07;
        if (streamId == 0) {
          streamId = ix;
        }
        streamId += audio.getMode().getBaseStreamId();
        audio.setStreamId(streamId);
      }
      vts.skip(1);
    }

    for (int ix = 0; ix < 32; ix++) {
      int snr = vts.readu8();
      int sWide = vts.readu8();
      int sLetterbox = vts.readu8();
      int sPanScan = vts.readu8();
      if ((snr & 0x80) != 0) {
        snr &= 0x1F;
        sWide &= 0x1F;
        sLetterbox &= 0x1F;
        sPanScan &= 0x1F;

        DvdSubtitle sub = titleSet.getSubs().get(ix);
        if (titleSet.getAspect() == Aspect.ASPECT_16_9) {
          sub.setStreamWideId((sWide > 0 ? sWide : ix) + 0x20);
        } else {
          sub.setStream43Id((snr > 0 ? snr : ix) + 0x20);
        }

        if (titleSet.isLetterboxEnabled()) {
          sub.setStreamLetterboxId((sLetterbox > 0 ? sLetterbox : ix) + 0x20);
        }

        if (titleSet.isPanScanEnabled()) {
          sub.setStreamPanScanId((sPanScan > 0 ? sPanScan : ix) + 0x20);
        }
      }
    }

    vts.skip(8);
    for (int ix = 0; ix < 16; ix++) {
      title.getColors()[ix] = (int) vts.readu32();
    }

    vts.skip(2);
    int programMapOffset = vts.readu16();
    int cellPlaybackOffset = vts.readu16();

    int[] cells = new int[chapters];
    vts.at(offset + programMapOffset);
    for (int ix = 0; ix < chapters; ix++) {
      cells[ix] = vts.readu8();
    }

    for (int ix = 0; ix < chapters; ix++) {
      int current = cells[ix];
      int next = (ix + 1 < chapters ? cells[ix + 1] : cellCount);
      long ms = 0;
      while (current < next) {
        vts.at(offset + cellPlaybackOffset + ((current - 1) * 0x18) + 4);
        ms += vts.readBcdTimeMs();
        current++;
      }
      if (ms > 0 || next != cellCount) {
        title.getChapterTimeMs().add(ms);
      }
    }
  }