⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dvdsubber_kernel.cpp

📁 DVD工具dvdsynth的源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
   } else if (hard_lba >= disc_info->vmg_ifo_sector) {
      PatchVMGIFO(hard_lba - disc_info->vmg_ifo_sector, buffer);
   } else {
      if (check_udf_descriptor(buffer, 261) >= 0) {
         // file entry
         unsigned start_lba = GetICBStartLBA(buffer, hard_lba);
         if (start_lba) {
            if (start_lba < disc_info->titlesets[title].vts_vobs_sector) {
               // no action
            } else if (start_lba < disc_info->titlesets[title].vts_bup_sector) {
               // need to juggle the sizes: try to figure out which VTS_##_# file this is
               unsigned last_digit_minus_1 = (start_lba - disc_info->titlesets[title].vts_vobs_sector) / 0x7F000;   // round down
               if (last_digit_minus_1 > 8)
                  last_digit_minus_1 = 8;    // does this make sense?
               unsigned new_start_lba = disc_info->titlesets[title].vts_vobs_sector + last_digit_minus_1 * 0x7FFFF;
               unsigned length = 0x7FFFF;
               unsigned soft_end = Hard2Soft(disc_info->titlesets[title].vts_bup_sector);
               if (new_start_lba > soft_end) new_start_lba = soft_end;
               if (new_start_lba + length > soft_end) length = soft_end - new_start_lba;
               SetICBLengthInBlocks(buffer, length);
               SetICBStartLBA(buffer, hard_lba, new_start_lba);
            } else {
               start_lba += Hard2Soft(disc_info->titlesets[title].vts_bup_sector) - disc_info->titlesets[title].vts_bup_sector;
               SetICBStartLBA(buffer, hard_lba, start_lba);
            }
            RecalcCRC(buffer);
         }
      } else if (check_udf_descriptor(buffer, 5) >= 0) {
         // partition descriptor
         Put4(buffer+192, Hard2Soft(Get4(buffer+192)));
         RecalcCRC(buffer);
      }
   }
}


void DVDSubberKernel::TranslateRelativeSector(unsigned char* pos, unsigned hard_sector, bool and_size) {
   unsigned rel = Get4(pos);
   unsigned offset = rel & 0x7FFFFFFF;
   if (offset >= 0x3FFFFFFF)
      return;
   unsigned backward = rel & 0x80000000;
   unsigned hard_sector_2 = backward ? hard_sector-offset : hard_sector + offset;
   unsigned soft_sector_2 = Hard2Soft(hard_sector_2);
   int soft_rel = soft_sector_2 - Hard2Soft(hard_sector);
   Put4(pos, soft_rel >= 0 ? soft_rel : (0x80000000 - soft_rel));
   if (and_size) {
      unsigned size = pos[4]*256 + pos[5];
      if (size != 0 && size != 0xFFFF) {
         unsigned soft_size = Hard2Soft(hard_sector_2 + size) - soft_sector_2;
         pos[4] = soft_size >> 8;
         pos[5] = soft_size;
      }
   }
}


void DVDSubberKernel::UpdateSectorTable(unsigned offset, unsigned end_offset, unsigned record_min, unsigned record_size, unsigned base_lba, unsigned ifo_sector, unsigned char* buffer) {
   record_min *= 4;
   record_size *= 4;

   int buf_offset;
   unsigned record_pos;
   if (offset < ifo_sector*2048) {
      buf_offset = 0;
      record_pos = (ifo_sector*2048 - offset) % record_size;
   } else {
      buf_offset = (offset - ifo_sector*2048);
      record_pos = 0;
   }
   int buf_end_offset = end_offset - ifo_sector*2048;
   if (buf_end_offset > 2048) {
      buf_end_offset = 2048;
   }
   for (int i = buf_offset; i < buf_end_offset; i += 4) {
      if (record_pos >= record_min) {
         TranslateRelativeSector(&buffer[i], base_lba, false);
      }
      record_pos += 4;
      if (record_pos >= record_size)
         record_pos -= record_size;
   }
}


void DVDSubberKernel::PatchVMGIFO(unsigned ifo_sector, unsigned char* buffer) {
   UpdateSectorTable(disc_info->vmg_tt_srpt_offset, disc_info->vmg_tt_srpt_end_offset, 2, 3, disc_info->vmg_ifo_sector, ifo_sector, buffer);
   // FIXME: VMG copy of subpicture info
}

void DVDSubberKernel::PatchVTSIFO(unsigned ts, const TitleSetInfo& tsi, unsigned ifo_sector, unsigned char* buffer) {
   if (ts != title) return;
   if (ifo_sector == 0) {
      TranslateRelativeSector(&buffer[4], tsi.vts_ifo_sector, false);
      // FIXME: hack
      unsigned tracks = tsi.number_of_existing_subpicture_tracks;
      buffer[0x255] = tracks + 1;
      g_callbacks->MemSet(buffer + 0x256 + tracks*6, 0, 6);
//      buffer[0x256+tracks*6] = 1;
//      buffer[0x256+tracks*6+2] = 'j';
//      buffer[0x256+tracks*6+3] = 'a';
   } else {
      for (unsigned pgc = 0; pgc < tsi.num_pgcs; ++pgc) {
         UpdateSectorTable(
            tsi.pgcs[pgc].cell_playback_info_table_offset,
            tsi.pgcs[pgc].cell_playback_info_table_end_offset,
            2, 6,
            tsi.vts_vobs_sector,
            ifo_sector, buffer);
         int ss_offset = (tsi.pgcs[pgc].subpicture_status_offset + 4 * tsi.number_of_existing_subpicture_tracks) - (ifo_sector * 2048);
         if (ss_offset >= 0 && ss_offset <= 2044) {
            Put4(&buffer[ss_offset], 0x80000000 + 0x01010101 * tsi.number_of_existing_subpicture_tracks);
         }
         for (int pal = 0; pal < palette_size; ++pal) {
            int pal_offset = tsi.pgcs[pgc].subpicture_status_offset - ifo_sector * 2048 + 0x88 + 4*15 - 4*pal;
            if (pal_offset >= 0 && pal_offset <= 2044) {
               Put4(&buffer[pal_offset], palette[pal]);
            }
         }
      }
      for (unsigned tmap = 0; tmap < tsi.num_tmaps; ++tmap) {
         UpdateSectorTable(
            tsi.tmaps[tmap].offset, tsi.tmaps[tmap].end_offset,
            0, 1, tsi.vts_vobs_sector,
            ifo_sector, buffer);
      }
      UpdateSectorTable(tsi.vts_c_adt_offset, tsi.vts_c_adt_end_offset, 1, 3, tsi.vts_vobs_sector, ifo_sector, buffer);
      UpdateSectorTable(tsi.vts_vobu_admap_offset, tsi.vts_vobu_admap_end_offset, 0, 1, tsi.vts_vobs_sector, ifo_sector, buffer);
   }
}

// returns true if hard sector range, false if subtitle
bool DVDSubberKernel::FindLBASource(unsigned soft_lba, unsigned num_blocks, unsigned* run_length, unsigned* hard_lba, SubpictureInfo** psi, unsigned* subpicture_rba) {
   unsigned earlier_soft_sectors = 0;
   SubpictureInfo* si = subpic_inf;
   for (int subpic = 0; subpic < num_subpics; ++subpic, si = si->next) {
      unsigned subpic_start = si->hard_lba + earlier_soft_sectors;
      if (subpic_start > soft_lba) {
         *run_length = Min(subpic_start-soft_lba, num_blocks);
         *hard_lba = soft_lba - earlier_soft_sectors;
         return true;
      }
      unsigned subpic_end = subpic_start + si->num_sectors;
      if (subpic_end > soft_lba) {
         *run_length = Min(subpic_end-soft_lba, num_blocks);
         *psi = si;
         *subpicture_rba = soft_lba - subpic_start;
         return false;
      }
      earlier_soft_sectors += si->num_sectors;
   }
   *run_length = num_blocks;
   *hard_lba = soft_lba - earlier_soft_sectors;
   return true;
}

scsi_result_t DVDSubberKernel::ReadHardSectors(unsigned lba, unsigned count, unsigned char* buffer, SenseData* sense) {
   static unsigned char cdb[10] = { 0x28, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
   Put4(&cdb[5], count);   // order matters here...
   Put4(&cdb[2], lba);
   unsigned long buflen = count * 2048;
   return child->ScsiCommand(child, cdb, 10, buffer, &buflen, 1, sense);
}

scsi_result_t DVDSubberKernel::ReadSectors(unsigned soft_lba, unsigned num_soft_sectors, unsigned char* buffer, SenseData* sense) {
//printf("\nrange: %06X - %06X\n", soft_lba, soft_lba + num_soft_sectors);
   // first find the range of hard sectors to read
   unsigned pos = 0;
   unsigned first_hard_sector = 0, num_hard_sectors = 0;
   while (pos < num_soft_sectors) {
      unsigned run_length, hard_lba, subpic_rba;
      SubpictureInfo* si;
      if (FindLBASource(soft_lba + pos, num_soft_sectors - pos, &run_length, &hard_lba, &si, &subpic_rba)) {
         // hard
         if (num_hard_sectors == 0) {
            first_hard_sector = hard_lba;
         }
         num_hard_sectors += run_length;
      }
      pos += run_length;
   }
//printf(" hard: %06X - %06X\n", first_hard_sector, first_hard_sector + num_hard_sectors);

   // now read them
   unsigned char* hardp = buffer + (num_soft_sectors - num_hard_sectors) * 2048;
   scsi_result_t result = ReadHardSectors(first_hard_sector, num_hard_sectors, hardp, sense);
   if (result != SCSIRESULT_SUCCESS) return result;

   // now go back and put everything into place
   pos = 0;
   unsigned char* p = buffer;
   while (pos < num_soft_sectors) {
      unsigned run_length, hard_lba, subpic_rba;
      SubpictureInfo* si;
      bool hard = FindLBASource(soft_lba + pos, num_soft_sectors - pos, &run_length, &hard_lba, &si, &subpic_rba);
      for (unsigned i=0; i<run_length; ++i) {
         if (hard) {
            if (p != hardp) {
               g_callbacks->MemCpy(p, hardp, 2048);
            }
            PatchHardSector(hard_lba, p);
            hardp += 2048;
            ++hard_lba;
         } else {
            GenerateSubpictureSector(si, subpic_rba, p);
            ++subpic_rba;
         }
         p += 2048;
      }
      pos += run_length;
   }

   return SCSIRESULT_SUCCESS;
}


scsi_result_t ScsiCommand(DvsDeviceKernel* _self, const unsigned char* cdb, int cdblen, unsigned char* buffer, unsigned long* pbuflen, int inout, SenseData* sense) {
   DVDSubberKernel* self = (DVDSubberKernel*)_self;
   if (self->state == stateActive || cdb[0] == 0x12) {
      unsigned char newcdb[16];
      if (self->num_subpics > 0) {
         switch (cdb[0]) {
         case SCSIOP_READ:
            {
               unsigned first_sector = Get4(&cdb[2]);
               unsigned num_sectors = cdb[7]*256+cdb[8];
               return self->ReadSectors(first_sector, num_sectors, buffer, sense);
            }
         case SCSIOP_READ_CAPACITY:
            {
               scsi_result_t result = self->child->ScsiCommand(self->child, cdb, cdblen, buffer, pbuflen, inout, sense);
               if (result == SCSIRESULT_SUCCESS && *pbuflen >= 4) {
                  Put4(buffer, self->Hard2Soft(Get4(buffer)));
               }
               return result;
            }
         case SCSIOP_REPORT_KEY:
            g_callbacks->MemCpy(newcdb, cdb, cdblen);
            Put4(newcdb+2, self->Soft2Hard(Get4(newcdb+2)));
            cdb = newcdb;
            break;
         }
      }
      return self->child->ScsiCommand(self->child, cdb, cdblen, buffer, pbuflen, inout, sense);
   } else if (self->state == stateUpdating) {
      return MAKE_SCSIRESULT_ERROR(0x23A00); // MEDIUM NOT PRESENT
   } else /*if (self->state == stateUpdated)*/ {
      self->state = stateActive;
      return MAKE_SCSIRESULT_ERROR(0x62800); // NOT READY TO READY CHANGE, MEDIUM MAY HAVE CHANGED
   }
}

extern "C"
dvs_scsi_func* __cdecl GetDispatchFunc() { return ScsiCommand; }

extern "C"
void* __cdecl SetState(DVDSubberKernel* self, int state) { self->state = state; return 0; }

extern "C"
void __cdecl DvdsynthDriverInit(DvsDockingBayKernelGlobal* callbacks) {
   g_callbacks = callbacks;
}

extern "C"
unsigned __stdcall DLLEntry(void*, unsigned, void*) { return 1; }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -