DeviceReader.pas
上传用户:wanyu_2000
上传日期:2021-02-21
资源大小:527k
文件大小:9k
源码类别:

DVD

开发平台:

Delphi

  1. {-----------------------------------------------------------------------------
  2.  Unit Name: DeviceReader
  3.  Author:    Dancemammal
  4.  Purpose:   Class to help with disk reading and ripping
  5.  History:
  6. -----------------------------------------------------------------------------}
  7. unit DeviceReader;
  8. interface
  9. uses
  10.   Windows, Messages, Forms, DeviceTypes, MMSystem, CovertFuncs, SCSIDefs,
  11.     SysUtils, SCSITypes, SCSIUnit, Classes, Resources;
  12. const
  13.   WaveHeaderSize = 44;
  14.   MAX_DATABLOCKS = 16;
  15. type
  16.   TWaveHeader = record
  17.     { RIFF file header }
  18.     RIFFHeader: array[1..4] of Char; { Must be "RIFF" }
  19.     FileSize: Integer; { Must be "RealFileSize - 8" }
  20.     WAVEHeader: array[1..4] of Char; { Must be "WAVE" }
  21.     { Format information }
  22.     FormatHeader: array[1..4] of Char; { Must be "fmt " }
  23.     FormatSize: Integer; { Must be 16 (decimal) }
  24.     FormatCode: Word; { Must be 1 }
  25.     ChannelNumber: Word; { Number of channels }
  26.     SampleRate: Integer; { Sample rate (hz) }
  27.     BytesPerSecond: Integer; { Bytes per second }
  28.     BytesPerSample: Word; { Bytes per Sample }
  29.     BitsPerSample: Word; { Bits per sample }
  30.     { Data area }
  31.     DataHeader: array[1..4] of Char; { Must be "data" }
  32.     DataSize: Integer; { Data size }
  33.   end;
  34. type
  35.   TCDStatusEvent = procedure(CurrentStatus: string) of object;
  36.   TCopyStatusEvent = procedure(CurrentSector, PercentDone: Integer) of object;
  37. type
  38.   TDeviceReader = class
  39.   private
  40.     FInfoRecord: PCDBurnerInfo;
  41.     FLastError: TScsiError;
  42.     FDefaults: TScsiDefaults;
  43.     FOnCDStatus: TCDStatusEvent;
  44.     FOnCopyStatus: TCopyStatusEvent;
  45.     FBytesWritten: Longint;
  46.     FsectorWrite: LongInt;
  47.     FWaveHeader: TWaveHeader;
  48.     function GetBurnerInfo: TCDBurnerInfo;
  49.     function GetTOC: TScsiTOC;
  50.     function CreateWaveHeader: TWaveHeader;
  51.   protected
  52.     procedure Log(Status: string);
  53.     property BurnerInfo: TCDBurnerInfo read GetBurnerInfo;
  54.   public
  55.     constructor Create(InfoRecord: PCDBurnerInfo);
  56.     destructor Destroy; override;
  57.     function Seek(GLBA: DWORD): Boolean;
  58.     function ReadData(GLBA, SectorCount: DWORD; BUF: Pointer; BUFLen: DWORD):
  59.       Boolean;
  60.     function ReadAudio(GLBA, SectorCount: DWORD; BUF: Pointer; BUFLen: DWORD):
  61.       Boolean;
  62.     function RipDiskToISOImage(ISOFilename: string): boolean;
  63.     function RipAllAudioTracks(TracksFilename: string): boolean;
  64.     function RipAudioTrack(TrackNo: Integer; TracksFilename: string): boolean;
  65.   published
  66.     property TOC: TScsiTOC read GetTOC;
  67.     property OnCDStatus: TCDStatusEvent read FOnCDStatus write FOnCDStatus;
  68.     property OnCopyStatus: TCopyStatusEvent read FOnCopyStatus write
  69.       FOnCopyStatus;
  70.   end; {DeviceReader}
  71. implementation
  72. constructor TDeviceReader.Create(InfoRecord: PCDBurnerInfo);
  73. begin
  74.   FinfoRecord := InfoRecord;
  75.   FDefaults := SCSI_DEF;
  76. end;
  77. destructor TDeviceReader.Destroy;
  78. begin
  79.   inherited;
  80. end;
  81. procedure TDeviceReader.Log(Status: string);
  82. begin
  83.   if Assigned(FOnCDStatus) then
  84.     FOnCDStatus(Status);
  85. end;
  86. function TDeviceReader.GetBurnerInfo: TCDBurnerInfo;
  87. begin
  88.   Result := FInfoRecord^;
  89. end;
  90. function TDeviceReader.GetTOC: TScsiTOC;
  91. begin
  92.   FLastError := SCSIgetTOC(BurnerInfo, Result, fDefaults);
  93. end;
  94. function TDeviceReader.Seek(GLBA: DWORD): Boolean;
  95. begin
  96.   FLastError := SCSIseek10(BurnerInfo, GLBA, FDefaults);
  97.   Result := FLastError = Err_None;
  98. end;
  99. function TDeviceReader.ReadData(GLBA, SectorCount: DWORD; BUF: Pointer; BUFLen:
  100.   DWORD): Boolean;
  101. begin
  102.   fLastError := SCSIread10(BurnerInfo, GLBA, SectorCount, Buf, BufLen,
  103.     fDefaults);
  104.   Result := fLastError = Err_None;
  105. end;
  106. function TDeviceReader.ReadAudio(GLBA, SectorCount: DWORD; BUF: Pointer; BUFLen:
  107.   DWORD): Boolean;
  108. begin
  109.   fLastError := SCSIreadCdEx(BurnerInfo, GLBA, SectorCount, csfAudio,
  110.     [cffUserData], BUF, BUFLen, fDefaults);
  111.   Result := fLastError = Err_None;
  112. end;
  113. function TDeviceReader.RipDiskToISOImage(ISOFilename: string): boolean;
  114. var
  115.   ISOStream: TFileStream;
  116.   Buf: pointer;
  117.   BufLen: integer;
  118.   DataBlocks, SectorSize: Integer;
  119.   IndexBlock: integer;
  120.   LastBlock: integer;
  121. begin
  122.   SectorSize := ConvertDataBlock(MODE_1);
  123.   BufLen := MAX_DATABLOCKS * SectorSize;
  124.   Result := True;
  125.   LastBlock := TOC.Tracks[TOC.TrackCount - 1].AbsAddress;
  126.   Log(resGetLastLBA + inttostr(LastBlock));
  127.   ISOStream := TFileStream.Create(ISOFilename, fmCreate);
  128.   try
  129.     if LastBlock < 1 then exit;
  130.     Log(resMemAlloc);
  131.     Buf := nil;
  132.     ReAllocMem(Buf, BufLen);
  133.     Log(resStreamStart);
  134.     IndexBlock := 0;
  135.     DataBlocks := MAX_DATABLOCKS;
  136.     while IndexBlock < LastBlock - 1 do
  137.     begin
  138.       if ((LastBlock - IndexBlock) < DataBlocks) then
  139.       begin
  140.         DataBlocks := (LastBlock - IndexBlock);
  141.         BufLen := DataBlocks * SectorSize;
  142.       end;
  143.       if ReadData(IndexBlock, DataBlocks, Buf, BufLen) then
  144.             FBytesWritten := ISOStream.Write(pchar(Buf)^, BufLen);
  145.       FsectorWrite := IndexBlock;
  146.       IndexBlock := IndexBlock + DataBlocks;
  147.       if Assigned(FOnCopyStatus) then
  148.         FOnCopyStatus(FsectorWrite, (FsectorWrite div ((LastBlock - 1) div
  149.           100)));
  150.       Forms.Application.ProcessMessages;    
  151.     end;
  152.     Log(resMemDeAlloc);
  153.     ReallocMem(Buf, 0);
  154.     Log(resCloseStream);
  155.   finally
  156.     ISOStream.Free;
  157.   end;
  158. end;
  159. function TDeviceReader.CreateWaveHeader: TWaveHeader;
  160. var
  161.   Waveheader: TWaveHeader;
  162. begin
  163.   FillChar(WaveHeader, Sizeof(TWaveHeader), 0);
  164.   Waveheader.RIFFHeader := 'RIFF'; { Must be "RIFF" }
  165.   Waveheader.FileSize := 0; { Must be "RealFileSize - 8" }
  166.   Waveheader.WAVEHeader := 'WAVE'; { Must be "WAVE" }
  167.   { Format information }
  168.   Waveheader.FormatHeader := 'fmt '; { Must be "fmt " }
  169.   Waveheader.FormatSize := 16; { Must be 16 (decimal) }
  170.   Waveheader.FormatCode := WAVE_FORMAT_PCM; { Must be 1 }
  171.   Waveheader.ChannelNumber := 2; { Number of channels }
  172.   Waveheader.SampleRate := 44100; { Sample rate (hz) }
  173.   Waveheader.BytesPerSample := MulDiv(Waveheader.ChannelNumber,
  174.     Waveheader.FormatSize, 8); { Bytes per Sample }
  175.   Waveheader.BytesPerSecond := (Waveheader.SampleRate *
  176.     Waveheader.BytesPerSample); { Bytes per second }
  177.   Waveheader.BitsPerSample := Waveheader.FormatSize; { Bits per sample }
  178.   { Data area }
  179.   Waveheader.DataHeader := 'data'; { Must be "data" }
  180.   Waveheader.DataSize := 0; { Data size }
  181.   Result := Waveheader;
  182. end;
  183. function TDeviceReader.RipAudioTrack(TrackNo: Integer; TracksFilename: string):
  184.   boolean;
  185. var
  186.   WaveStream: TFileStream;
  187.   WavDataStream: TMemoryStream;
  188.   Buf: Pointer;
  189.   BufLen: integer;
  190.   IndexBlock, SectorSize: integer;
  191.   LastBlock: integer;
  192.   DataBlocks: Integer;
  193.   WavPath, TrackFilename: string;
  194.   TrackIndex: integer;
  195. begin
  196.   FBytesWritten := 0;
  197.   Result := True;
  198.   SectorSize := ConvertDataBlock(RAW_DATA_BLOCK);
  199.   BufLen := MAX_DATABLOCKS * SectorSize;
  200.   WavPath := extractFilePath(TracksFilename);
  201.   TrackIndex := TrackNo;
  202.   IndexBlock := TOC.Tracks[TrackIndex - 1].AbsAddress;
  203.   LastBlock := TOC.Tracks[TrackIndex].AbsAddress;
  204.   Log(resLastAudioLBA + inttostr(LastBlock));
  205.   WavDataStream := TMemoryStream.Create;
  206.   try
  207.     Log(resMemAlloc);
  208.     Buf := nil;
  209.     ReAllocMem(Buf, BufLen);
  210.     Log(resTrackStreamStart + inttostr(TrackIndex));
  211.     DataBlocks := MAX_DATABLOCKS;
  212.     while IndexBlock < LastBlock do
  213.     begin
  214.       if ((LastBlock - IndexBlock) < DataBlocks) then
  215.       begin
  216.         DataBlocks := (LastBlock - IndexBlock);
  217.         BufLen := DataBlocks * SectorSize;
  218.       end;
  219.       if ReadAudio(IndexBlock, DataBlocks, Buf, BufLen) then
  220.         FBytesWritten := WavDataStream.Write(pchar(Buf)^, BufLen);
  221.           // read audio data
  222.       FsectorWrite := IndexBlock;
  223.       IndexBlock := IndexBlock + DataBlocks;
  224.       if Assigned(FOnCopyStatus) then
  225.         FOnCopyStatus(FsectorWrite, (FsectorWrite div ((LastBlock - 1) div
  226.           100)));
  227.       Forms.Application.ProcessMessages;
  228.     end; // finish ripping all data
  229.     // create PCM wave header
  230.     FWaveHeader := CreateWaveHeader;
  231.     FWaveHeader.FileSize := (WaveHeaderSize + WavDataStream.Size) - 8;
  232.     FWaveHeader.DataSize := WavDataStream.Size;
  233.     // save wave file
  234.     TrackFilename := IncludeTrailingBackslash(WavPath) + 'Track' +
  235.       inttostr(TrackIndex) + '.wav';
  236.     WaveStream := TFileStream.Create(TrackFilename, fmCreate);
  237.     try
  238.       WaveStream.Write(FWaveHeader, sizeof(FWaveHeader));
  239.       if Assigned(FOnCDStatus) then
  240.         FOnCDStatus(resSaveWaveToDisk);
  241.       WavDataStream.SaveToStream(WaveStream); // write header to stream
  242.     finally
  243.       WaveStream.Free;
  244.     end;
  245.   finally
  246.     Log(resMemDeAlloc);
  247.     ReallocMem(Buf, 0);
  248.     Log(resCloseStream);
  249.     WavDataStream.Free;
  250.   end;
  251.   Log(resFinishTrackRip);
  252. end;
  253. function TDeviceReader.RipAllAudioTracks(TracksFilename: string): boolean;
  254. var
  255.   WavPath: string;
  256.   TrackIndex: integer;
  257. begin
  258.   Result := True;
  259.   WavPath := extractFilePath(TracksFilename);
  260.   for TrackIndex := 1 to TOC.TrackCount do
  261.   begin
  262.     if not RipAudioTrack(TrackIndex, WavPath) then
  263.     begin
  264.       Result := False;
  265.       exit;
  266.     end;
  267.   end;
  268.   Log(resFinishCDRip);
  269. end;
  270. end.