Here's the sample code. I'm using BASS_StreamCreateFileUser with custom procedures.
Crash happens at BASS_ChannelGetData. If I uncomment that sleep(100), crash is not happening.
I tried with mp3 files as well using the same approach and it worked fine.
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, bass;
type
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
type
TBassThread = class(TThread)
private
FFileName: string;
FFileStream: TFileStream;
FMemo: TMemo;
FInfo: string;
procedure CreateDecoder(var h: HSTREAM);
procedure Info;
public
constructor Create(const FileName: string; Memo: TMemo);
procedure Execute; override;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
TBassThread.Create('C:\converted\output\01.opus', Memo1);
TBassThread.Create('C:\converted\output\02.opus', Memo1);
//TBassThread.Create('C:\converted\output\01.mp3', Memo1);
//TBassThread.Create('C:\converted\output\02.mp3', Memo1);
//TBassThread.Create('C:\converted\output\01.mp3', Memo1);
//TBassThread.Create('C:\converted\output\02.mp3', Memo1);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
BASS_Init(-1, 44100, 0, Form1.handle, nil);
if BASS_PluginLoad(PWideChar(ExtractFilePath(ParamStr(0)) + 'bassopus.dll'), BASS_UNICODE) = 0 then begin
MessageDlg('BASS_PluginLoad failed.', mtError, [mbOK], 0);
end;
end;
{ TBassThread }
procedure FILECLOSEPROC(user: pointer); stdcall;
begin
end;
function FILELENPROC(user: pointer): QWORD; stdcall;
begin
Result := TFileStream(user).size;
end;
function FILEREADPROC(buffer: pointer; length: DWORD; user: pointer): DWORD; stdcall;
begin
Result := TFileStream(user).Read(buffer^, length);
end;
function FILESEEKPROC(offset: QWORD; user: pointer): BOOL; stdcall;
begin
Result := TFileStream(user).Seek(offset, soFromBeginning) = offset;
end;
constructor TBassThread.Create(const FileName: string; Memo: TMemo);
begin
FFileName := FileName;
FMemo := Memo;
FreeOnTerminate := True;
inherited Create(False);
end;
procedure TBassThread.CreateDecoder(var h: HSTREAM);
var
procs: BASS_FILEPROCS;
flags: DWORD;
begin
h := 0;
procs.close := FILECLOSEPROC;
procs.length := FILELENPROC;
procs.Read := FILEREADPROC;
procs.Seek := FILESEEKPROC;
flags := BASS_STREAM_DECODE;
FFileStream := TFileStream.Create(FFileName, fmOpenRead or fmShareDenyWrite);
h := BASS_StreamCreateFileUser(STREAMFILE_NOBUFFER, flags, procs, FFileStream);
if h = 0 then begin
Exit;
end;
end;
procedure TBassThread.Info;
begin
FMemo.Lines.Add(FInfo);
end;
procedure TBassThread.Execute;
var
h: HSTREAM;
buf: pointer;
i: DWORD;
begin
CreateDecoder(h);
if h = 0 then begin
Exit;
end;
GetMem(buf, 4 * 1024);
repeat
i := BASS_ChannelGetData(h, buf, 4 * 1024);
//Sleep(100);
until (i = 0) or (i = DWORD(-1));
FreeMem(buf);
Finfo := Format('Done %s', [FFilename]);
Synchronize(Info);
end;
end.