{$R 'res\movie.res'}

unit MainUnit;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  FlashPlayerControl, StdCtrls, ShellApi, ProgressFormUnit;

type
  TEncodingThread = class(TThread)
    constructor Create(SourceStream, DestStream: TStream; Size: Cardinal);
  private
    procedure Execute; override;
    procedure ChangeProgress;
    procedure CloseProgressForm;
    procedure SetupProgressForm;
  private
    FSourceStream, FDestStream: TStream;
    FSize: Cardinal;
  end;

  TContentProviderThread = class(TThread)
  public
    constructor Create(SourceStream, DestStream: TStream; Speed: Integer);
    destructor Destroy; override;
  private
    procedure Execute; override;
    procedure UpdateGUI;
    procedure DoWrite;
    procedure PrepareBuffer;
  private
    FSpeed, FDelay: Cardinal;
    FBufferSize: Cardinal;
    FStop: boolean;
    FLoadedBytes: Integer;
    FSourceStream, FDestStream: TStream;

    // prepared buffer
    FBuffer: TMemoryStream;
  end;

  TMainForm = class(TForm)
    FlashPlayerControl1: TFlashPlayerControl;
    OpenDialogFLV: TOpenDialog;
    OpenDialogSWF: TOpenDialog;
    ButtonSite: TButton;
    ButtonOrder: TButton;
    LabelStatus: TLabel;
    Label1: TLabel;
    ComboBoxSpeed: TComboBox;
    Label2: TLabel;
    ButtonEncode: TButton;
    ButtonPlayEncoded: TButton;
    OpenDialogFlashFiles: TOpenDialog;
    SaveDialogEncodedFlashFiles: TSaveDialog;
    OpenDialogEncodedFlashFiles: TOpenDialog;
    procedure FormCreate(Sender: TObject);
    procedure ButtonSiteClick(Sender: TObject);
    procedure ButtonOrderClick(Sender: TObject);
    procedure ButtonEncodeClick(Sender: TObject);
    procedure ButtonPlayEncodedClick(Sender: TObject);
  private
    FEncodedFLVStream: TStream;

    procedure ContentProvider(const URL: WideString; Stream: TStream; out bHandled: Boolean);
  public
    { Public declarations }
  end;

var
  MainForm: TMainForm;

implementation

const
   Mask = $43;

{$R *.DFM}

constructor TEncodingThread.Create(SourceStream, DestStream: TStream; Size: Cardinal);
begin
   inherited Create(True);

   FreeOnTerminate := True;

   FSourceStream := SourceStream;
   FDestStream := DestStream;

   FSize := Size;
end;

procedure TEncodingThread.Execute;
var
   b: Byte;
begin
   Synchronize(SetupProgressForm);

   while FSourceStream.Read(b, sizeof(b)) > 0 do
   begin
      b := b xor Mask;

      FDestStream.Write(b, sizeof(b));

      if ProgressForm.IsClosed then break;

      Synchronize(ChangeProgress);
   end;

   FSourceStream.Free;
   FDestStream.Free;

   Synchronize(CloseProgressForm);
end;

procedure TEncodingThread.SetupProgressForm;
begin
   ProgressForm.ProgressBar.Min := 1;
   ProgressForm.ProgressBar.Max := FSize;
   ProgressForm.ProgressBar.Step := 1;
   ProgressForm.ProgressBar.Position := 0;
end;

procedure TEncodingThread.ChangeProgress;
begin
   ProgressForm.ProgressBar.StepIt;
end;

procedure TEncodingThread.CloseProgressForm;
begin
   ProgressForm.Free;
   ProgressForm := nil;

   MainForm.Enabled := True;
end;

constructor TContentProviderThread.Create(SourceStream, DestStream: TStream; Speed: Integer);
begin
   inherited Create(False);

   FSourceStream := SourceStream;
   FDestStream := DestStream;

   FSpeed := Speed;
   FDelay := 100;

   FBufferSize := FSpeed * FDelay;
   FBufferSize := FBufferSize div 1000;

   FBuffer := TMemoryStream.Create;
end;

destructor TContentProviderThread.Destroy;
begin
   FSourceStream.Free;
   FDestStream.Free;

   FBuffer.Free;
end;

procedure TContentProviderThread.Execute;
begin
   FLoadedBytes := 0;

   while not FStop do
   begin
      PrepareBuffer;

      if FBuffer.Size > 0 then
      begin
         DoWrite;
         Sleep(FDelay);
      end;

      Synchronize(UpdateGUI);
   end;

   FreeOnTerminate := true;
end;

procedure TContentProviderThread.PrepareBuffer;
type
   PByte = ^Byte;
var
   nReadBytes: integer;
   Buffer: pointer; // buffer
   i: integer;
begin
   FBuffer.Clear;

   Buffer := pointer(LocalAlloc(LPTR, FBufferSize));

   nReadBytes := FSourceStream.Read(Buffer^, FBufferSize);

   if nReadBytes = 0 then
      FStop := true
   else
   begin
      for i := 0 to nReadBytes - 1 do
         PByte(Cardinal(Buffer) + i)^ := PByte(Cardinal(Buffer) + i)^ xor Mask;

      FBuffer.Write(Buffer^, nReadBytes);
      FBuffer.Position := 0;
   end;

   LocalFree(cardinal(Buffer));
end;

procedure TContentProviderThread.DoWrite;
var
   nWrittenBytes: integer;
begin
   nWrittenBytes := FDestStream.Write(FBuffer.Memory^, FBuffer.Size);

   if nWrittenBytes = 0 then
      // Write returns 0, if loading was cancelled by some reason
      FStop := true
   else
      Inc(FLoadedBytes, nWrittenBytes);
end;

procedure TContentProviderThread.UpdateGUI;
begin
   // Update GUI
   MainForm.LabelStatus.Caption := 'Status: ' + IntToStr(FLoadedBytes) + ' bytes loaded...';

   if FStop then
      MainForm.LabelStatus.Caption := MainForm.LabelStatus.Caption + ' (finished)';
end;

procedure TMainForm.FormCreate(Sender: TObject);
begin
  if Not IsFlashInstalled then
  begin
    ShowMessage('The application needs Flash'#13#10'Flash is not installed');
    Application.Terminate;
  end;

  FlashPlayerControl.SetGlobalOnLoadExternalResourceHandlerEx(ContentProvider);

  OpenDialogFLV.InitialDir := ExtractFileDir(Application.ExeName);
  OpenDialogSWF.InitialDir := ExtractFileDir(Application.ExeName);
  OpenDialogFlashFiles.InitialDir := ExtractFileDir(Application.ExeName);
end;

procedure TMainForm.ContentProvider(const URL: WideString; Stream: TStream; out bHandled: Boolean);
var
   ContentProviderThread: TContentProviderThread;
   Speed: Integer;
   SourceStream: TStream;
begin
  if URL = 'http://FLV/FlashVideo.flv' then
  begin
    if MainForm.ComboBoxSpeed.Text = '<unlimited>' then
       Speed := 1024 * 1024 // big speed
    else
       Speed := StrToInt(MainForm.ComboBoxSpeed.Text);

    ContentProviderThread := TContentProviderThread.Create(FEncodedFLVStream, Stream, Speed);

    bHandled := true;
  end;
end;

procedure TMainForm.ButtonSiteClick(Sender: TObject);
begin
  ShellExecute(0, nil, 'http://www.f-in-box.com/delphi/?from_program=1', nil, nil, SW_SHOW);
end;

procedure TMainForm.ButtonOrderClick(Sender: TObject);
begin
  ShellExecute(0, nil, 'http://www.f-in-box.com/delphi/order.html?from_program=1', nil, nil, SW_SHOW);
end;

procedure TMainForm.ButtonEncodeClick(Sender: TObject);
var
   SourceStream: TFileStream;
   DestStream: TStream;
   IsSWF: boolean;
   EncodingThread: TEncodingThread;
begin
   if OpenDialogFlashFiles.Execute then
      if SaveDialogEncodedFlashFiles.Execute then
      begin
         SourceStream := TFileStream.Create(OpenDialogFlashFiles.FileName, fmOpenRead or fmShareDenyWrite);
         DestStream := TFileStream.Create(SaveDialogEncodedFlashFiles.FileName, fmCreate or fmOpenWrite);

         if AnsiLowerCase(ExtractFileExt(OpenDialogFlashFiles.FileName)) = '.swf' then
            IsSWF := true
         else
            IsSWF := false;

         // Encoding (very simple)

         DestStream.Write(IsSWF, sizeof(IsSWF));

         EncodingThread := TEncodingThread.Create(SourceStream, DestStream, SourceStream.Size);

         MainForm.Enabled := False;

         ProgressForm := TProgressForm.Create(Self, EncodingThread);
      end;
end;

procedure TMainForm.ButtonPlayEncodedClick(Sender: TObject);
var
   SourceStream, MovieStream: TStream;
   ContentProviderThread: TContentProviderThread;
   Speed: Integer;
   IsSWF: Boolean;
   ResourceStream: TStream;
begin
   if OpenDialogEncodedFlashFiles.Execute then
   begin
      if MainForm.ComboBoxSpeed.Text = '<unlimited>' then
         Speed := 1024 * 1024 // big speed
      else
         Speed := StrToInt(MainForm.ComboBoxSpeed.Text);

      SourceStream := TFileStream.Create(OpenDialogEncodedFlashFiles.FileName, fmOpenRead or fmShareDenyWrite);

      SourceStream.Read(IsSWF, sizeof(IsSWF));

      if IsSWF then
      begin
         FlashPlayerControl1.LoadMovieUsingStream(0, MovieStream);
         ContentProviderThread := TContentProviderThread.Create(SourceStream, MovieStream, Speed);
      end
      else
      begin
         FEncodedFLVStream := SourceStream;

         FlashPlayerControl1.FlashVars := 'FLVPath=http://FLV/FlashVideo.flv';

         ResourceStream := TResourceStream.Create(0, 'FLVPlayer', 'FLASH');

         FlashPlayerControl1.PutMovieFromStream(ResourceStream);

         ResourceStream.Free;
      end
   end;
end;

end.

