(*************************************************************************
vStrip_Thread: Unit for vStrip Thread (that's actually doing the work)
Copyright (C) 2001 [maven] (maven@maven.de)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*************************************************************************)
unit vStrip_Thread;
interface
uses
Windows, Classes, ComCtrls, StdCtrls, Forms, Dialogs, vStrip;
const
UpdateCounterAnd = 255;
ETAInterval = 4000; // ms
type
TVSUpdateRecord = record
lba: Cardinal;
vob_id: Cardinal;
cell_id: Cardinal; // stream-id (in low word) if vob_id = -1
key: Cardinal; // 0..3 of key if vob_id = $fffffffe
end;
TVSUpdate = record
ProgressBar: TProgressBar;
ListView: TListView;
EditETA, EditKS: TEdit;
OldForm1Caption: String;
Events: array[0..UpdateCounterAnd] of TVSUpdateRecord;
StreamsFound: array[0..511] of Boolean;
NumEvents: Integer;
old_vob_id, old_cell_id: Cardinal;
UpdateCounter: Cardinal;
TotalLBA: Cardinal;
LastLBA, LastTick: Cardinal;
OldPercent: Byte;
was_in_mainloop: Boolean;
{$IFDEF vs_DECRYPT}
old_key: array[0..4] of Byte;
{$ENDIF}
end;
TVSThread = class(TThread)
private
ec: t_vs_errorcode;
data: tp_vs_data;
streams, substreams: tpa_vs_streamflags;
cell_list: TPAVobCellID;
num_cell: Integer;
Update: TVSUpdate;
procedure InitAll();
procedure UpdateAll();
procedure CloseAll();
published
constructor CreateVS(vdata: tp_vs_data; vstreams, vsubstreams: tpa_vs_streamflags; total_lba: Cardinal;
vnum_cell: Integer; vcell_list: TPAVobCellID; ProgBarFile: TProgressBar; ListViewInfo, ListViewFiles: TListView);
destructor Destroy; override;
protected
procedure Execute; override;
end;
implementation
uses
MainForm, SysUtils, Math;
procedure TVSThread.InitAll();
var
i: Integer;
sw: Cardinal;
begin
Update.OldForm1Caption := vStripForm.Caption;
Update.EditETA := vStripForm.EditETA;
Update.EditKS := vStripForm.EditKS;
Update.ProgressBar.Min := 0;
Update.ProgressBar.Max := 10000;
Update.ProgressBar.Position := 0;
Update.ListView.Items.Clear();
Update.UpdateCounter := 0;
Update.NumEvents := 0;
Update.old_vob_id := $ffffffff;
Update.old_cell_id := $ffffffff;
Update.OldPercent := 255;
Update.was_in_mainloop := False;
for i := 0 to 511 do
Update.StreamsFound[i] := False;
{$IFDEF vs_DECRYPT}
for i := 0 to 4 do
Update.old_key[i] := data^.key[i];
{$ENDIF}
if (data^.end_lba <> $ffffffff) then begin
if (data^.end_lba < data^.start_lba) then begin
sw := data^.end_lba;
data^.end_lba := data^.start_lba;
data^.start_lba := sw;
end;
if (data^.end_lba > Update.TotalLBA) then
data^.end_lba := Update.TotalLBA - 1;
Update.TotalLBA := (data^.end_lba - data^.start_lba) + 1;
end;
if ((data^.flags and vs_NO_VOB) <> 0) then
Update.TotalLBA := Update.TotalLBA div 8;
Update.LastLBA := data^.start_lba;
Update.LastTick := GetTickCount();
ec := vs_init(data^, streams^, substreams^);
end;
procedure TVSThread.UpdateAll();
var
time, eta: Cardinal;
pc: Single;
b: Byte;
i: Integer;
itime, ilba: Int64;
s: String;
it: TListItem;
pts: double;
begin
time := GetTickCount();
if ((ec = vse_OK) and (Update.TotalLBA > 0) and (data^._in.buffer <> nil)) then begin
pc := (100.0 * (data^._in.buffer^.lba - data^.start_lba)) / Update.TotalLBA;
Update.ProgressBar.Position := Trunc(pc * 100.0);
b := Trunc(pc);
if (b <> Update.OldPercent) then begin // set form1.caption to %
vStripForm.Caption := '[' + Format('%.2d', [Trunc(pc)]) + '%] ' + Update.OldForm1Caption;
Application.Title := vStripForm.Caption;
Update.OldPercent := b;
end;
if (time - Update.LastTick >= ETAInterval) then begin
itime := time - Update.LastTick;
ilba := data^._in.buffer^.lba - Update.LastLBA;
Update.EditKS.Text := IntToStr((ilba * Int64(2 * 1000)) div itime) + ' k/s';
eta := (itime * (Update.TotalLBA - Int64(data^._in.buffer^.lba - data^.start_lba))) div ilba;
DateTimeToString(s, 'hh:mm:ss', EncodeTime(Min(23, eta div (1000 * 60 * 60)), (eta div (1000 * 60)) mod 60, (eta div 1000) mod 60, eta mod 1000));
Update.EditETA.Text := s;
Update.LastLBA := data^._in.buffer^.lba;
Update.LastTick := time;
end;
end;
if ((streams <> nil) and (substreams <> nil)) then begin
for i := 0 to Update.NumEvents - 1 do with Update.Events[i] do begin
case vob_id of
$ffffffff: begin
if (Boolean(cell_id and $ff)) then begin
s := '0xBD ' + vStripForm.GetStreamDescription(cell_id shr 8, True);
pts := substreams^[cell_id shr 8].pts;
if (pts > 0.0) then begin
s := s + ' PTS ' + vs_get_time(pts);
if (streams^[$e0].pts > 0.0) then
s := s + ' (-> delay ' + vs_get_time(pts - streams^[$e0].pts) + ')';
end;
end else begin
s := vStripForm.GetStreamDescription(cell_id shr 8, False);
pts := streams^[cell_id shr 8].pts;
if (pts > 0.0) then
s := s + ' PTS ' + vs_get_time(pts);
end;
end;
$fffffffe: s := Format('Key: 0x%.2x%.2x%.2x%.2x%.2x', [cell_id, key shr 24, (key shr 16) and $ff, (key shr 8) and $ff, key and $ff]);
else
s := Format('VOB-ID: %.2u/CELL-ID: %.2u', [vob_id, cell_id]);
end;
it := Update.ListView.Items.Add();
it.Caption := s;
it.SubItems.Add(Format('[@ LBA %u]', [lba]));
end;
end;
Update.NumEvents := 0;
end;
procedure TVSThread.CloseAll();
var
lba_string: String;
begin
lba_string := Format(' [@LBA %u]', [data^._in.sti.lba]);
case ec of
vse_DONE: if (Update.was_in_mainloop) then Update.ProgressBar.Position := Update.ProgressBar.Max;
vse_INIT_FAILED: MessageDlg('vStrip initialisation failed!', mtError, [mbOK], 0);
vse_CANT_OPEN_INPUT: MessageDlg('vStrip could not open input!', mtError, [mbOK], 0);
vse_CANT_CREATE_OUTPUT: MessageDlg('vStrip could not open output!', mtError, [mbOK], 0);
vse_CANT_WRITE_OUTPUT: MessageDlg('vStrip could not write to output (disk full?)' + lba_string, mtError, [mbOK], 0);
vse_CANT_CRACK: MessageDlg('vStrip could not decrypt' + lba_string, mtError, [mbOK], 0);
vse_LOST_SYNC: MessageDlg('vStrip lost sync (not authenticated?)' + lba_string, mtError, [mbOK], 0);
end;
vStripForm.Caption := Update.OldForm1Caption;
Application.Title := Update.OldForm1Caption;
end;
constructor TVSThread.CreateVS(vdata: tp_vs_data; vstreams, vsubstreams: tpa_vs_streamflags; total_lba: Cardinal;
vnum_cell: Integer; vcell_list: TPAVobCellID; ProgBarFile: TProgressBar; ListViewInfo, ListViewFiles: TListView);
begin
inherited Create(true);
Update.ProgressBar := ProgBarFile;
Update.ListView := ListViewInfo;
Update.TotalLBA := total_lba;
data := vdata;
streams := vstreams;
substreams := vsubstreams;
num_cell := vnum_cell;
cell_list := vcell_list;
Synchronize(InitAll);
FreeOnTerminate := True;
end;
destructor TVSThread.Destroy();
begin
Synchronize(CloseAll);
inherited destroy;
end;
procedure TVSThread.Execute();
begin
while ((ec = vse_OK) and not Terminated) do begin
Update.was_in_mainloop := True;
ec := vs_strip_one_block(data^, streams^, substreams^, num_cell, tp_vs_vobcellid(cell_list));
if ((ec = vse_OK) or (ec = vse_DONE)) then begin // look what's happened
if (data^._in.sti.stream_id <> 0) then begin
if (not Update.StreamsFound[data^._in.sti.stream_id and $ff]) then begin
Update.StreamsFound[data^._in.sti.stream_id and $ff] := True;
Update.Events[Update.NumEvents].lba := data^._in.sti.lba;
Update.Events[Update.NumEvents].vob_id := $ffffffff;
Update.Events[Update.NumEvents].cell_id := (data^._in.sti.stream_id and $ff) shl 8; // not substream
Inc(Update.NumEvents);
end;
if ((data^._in.sti.stream_id = $bd) and (data^._in.sti.substream_id <> $ffffffff)
and (not Update.StreamsFound[256 + (data^._in.sti.substream_id and $ff)])) then begin
Update.StreamsFound[256 + (data^._in.sti.substream_id and $ff)] := True;
Update.Events[Update.NumEvents].lba := data^._in.sti.lba;
Update.Events[Update.NumEvents].vob_id := $ffffffff;
Update.Events[Update.NumEvents].cell_id := ((data^._in.sti.substream_id and $ff) shl 8) + 1; // substream
Inc(Update.NumEvents);
end;
end;
if ((data^._in.sti.vob_id <> Update.old_vob_id) or (data^._in.sti.cell_id <> Update.old_cell_id)) then begin
Update.old_vob_id := data^._in.sti.vob_id;
Update.old_cell_id := data^._in.sti.cell_id;
Update.Events[Update.NumEvents].lba := data^._in.sti.lba;
Update.Events[Update.NumEvents].vob_id := data^._in.sti.vob_id;
Update.Events[Update.NumEvents].cell_id := data^._in.sti.cell_id;
Inc(Update.NumEvents);
end;
{$IFDEF vs_DECRYPT}
if ((data^.key[0] <> Update.old_key[0]) or (data^.key[1] <> Update.old_key[1]) or (data^.key[2] <> Update.old_key[2]) or (data^.key[3] <> Update.old_key[3]) or (data^.key[4] <> Update.old_key[4])) then begin
Update.old_key[0] := data^.key[0];
Update.old_key[1] := data^.key[1];
Update.old_key[2] := data^.key[2];
Update.old_key[3] := data^.key[3];
Update.old_key[4] := data^.key[4];
Update.Events[Update.NumEvents].lba := data^._in.sti.lba;
Update.Events[Update.NumEvents].vob_id := $fffffffe;
Update.Events[Update.NumEvents].cell_id := data^.key[0];
Update.Events[Update.NumEvents].key := (data^.key[1] shl 24) + (data^.key[2] shl 16) + (data^.key[3] shl 8) + data^.key[4];
Inc(Update.NumEvents);
end;
{$ENDIF}
end;
if ((Update.UpdateCounter and UpdateCounterAnd) = 0) then
Synchronize(UpdateAll);
Inc(Update.UpdateCounter);
end;
// end main loop
if (Update.NumEvents > 0) then
Synchronize(UpdateAll);
if (ec = vse_OK) then
ec := vs_done(data^, streams^, substreams^);
end;
end.
syntax highlighted by Code2HTML, v. 0.9.1