(*************************************************************************
  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