Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Звук, графика и видео > BASS_StreamCreateFileUser


Автор: GuManOiD 23.4.2009, 14:46
Доброго дня, форумчане.

IDE: Delphi 2007 update 3

Требуется написать sample программку, которая загружает MP3/WAV файл в TMemoryStream и 
воспроизводит с помощью библиотеки BASS - обязательно используя BASS_StreamCreateFileUser.
BASS_StreamCreateFile не предлагать smile

Вот собственно source:
Код

unit uPCore;

interface

uses
  Windows, Classes,
  Bass, uPDecodeStream;

type
  TBASSCorePlayer = class(TObject)
    public
      constructor Create(hwnd:HWND);
      procedure Free;

      function Play   :BOOL;
      function Stop   :BOOL;
      function Pause  :BOOL;

      function LastError :LongInt;
      function GetPlaybackLength :Double;
      function GetPlaybackPosition :Double;
      function SetPlaybackPosition(seconds:Double) :BOOL;

      procedure AssignStream(AStream:TPDecodeStream);
    private
      BASSCh: HSTREAM;
      BASSProcs: BASS_FILEPROCS;
  end;

  procedure proc_close(user : Pointer); stdcall;
  function proc_len(user: Pointer): QWORD; stdcall;
  function proc_seek(offset: QWORD; user: Pointer): BOOL; stdcall;
  function proc_read(buffer: Pointer; length: DWORD; user: Pointer): DWORD; stdcall;

implementation

constructor TBASSCorePlayer.Create(hwnd:HWND);
begin
  inherited Create;
  BASS_Init(-1, 44100, 0, hwnd, nil);
end;

procedure TBASSCorePlayer.Free;
begin
  BASS_Free;
  inherited Free;
end;

function TBASSCorePlayer.GetPlaybackLength :Double;
begin
  Result :=
    BASS_ChannelBytes2Seconds(BASSCh, BASS_ChannelGetLength(BASSCh, BASS_POS_BYTE));
end;

function TBASSCorePlayer.LastError :LongInt;
begin
  Result := BASS_ErrorGetCode;
end;

function TBASSCorePlayer.GetPlaybackPosition :Double;
begin
  Result :=
    BASS_ChannelBytes2Seconds(BASSCh, BASS_ChannelGetPosition(BASSCh, BASS_POS_BYTE));
end;

function TBASSCorePlayer.SetPlaybackPosition(seconds:Double) :BOOL;
begin
  Result :=
    BASS_ChannelSetPosition(BASSCh, BASS_ChannelSeconds2Bytes(BASSCh, seconds),BASS_POS_BYTE);
end;

procedure TBASSCorePlayer.AssignStream(AStream: TPDecodeStream);
begin
  //BASSCh := BASS_StreamCreateFile(True, AStream.Memory, 0, AStream.Size, 0);
  BASSProcs.close := proc_close;
  BASSProcs.length := proc_len;
  BASSProcs.read := proc_read;
  BASSProcs.seek := proc_seek;

  BASSCh := BASS_StreamCreateFileUser(STREAMFILE_NOBUFFER, 0, BASSProcs, @AStream)
end;
    //CALLBACKS HERE
    procedure proc_close(user: Pointer);
    var
      AStreamInstance: ^TPDecodeStream;
    begin
      AStreamInstance := user;
      //AStreamInstance.Position := 0;
      //AStreamInstance^.Free;
    end;

    function proc_len(user: Pointer): QWORD; stdcall;
    var
      AStreamInstance: ^TPDecodeStream;
    begin
      AStreamInstance := user;
      Result := AStreamInstance^.Size;
    end;

    function proc_seek(offset: QWORD; user: Pointer): BOOL; stdcall;
    var
      AStreamInstance: ^TPDecodeStream;
      NewPosition: Int64;
    begin
      AStreamInstance := user;
      NewPosition := AStreamInstance^.Seek(offset, soFromBeginning);
      Result := (NewPosition = AStreamInstance^.Position);
    end;

    function proc_read(buffer: Pointer; length: DWORD; user: Pointer): DWORD; stdcall;
    var
      AStreamInstance: ^TPDecodeStream;
      BytesReaded: DWORD;
    begin
      AStreamInstance := user;
      BytesReaded := 0;

      BytesReaded := AStreamInstance^.Read(buffer^, length);

      if BytesReaded = length then
        Result := BytesReaded
      else 
        Result := 0;
    end;

function TBASSCorePlayer.Play :BOOL;
begin
  Result := BASS_ChannelPlay(BASSCh, False);
end;

function TBASSCorePlayer.Stop :BOOL;
begin
  Result := BASS_ChannelStop(BASSCh);
end;

function TBASSCorePlayer.Pause :BOOL;
begin
  Result := BASS_ChannelPause(BASSCh)
end;

end.


Работает класс так:
Создаем TMemoryStream, делаем LoadFromFile mp3/wav файла.
Этот MemoryStream отправляем классу через AssignStream, далее Play (Stop/Pause/SetPlaybackPosition etc.)

Проблема в том, что при попытке воспроизведения mp3 файла - он играет первые полторы секунды, далее валиться 
Access Vialation на строку
Код

BytesReaded := AStreamInstance^.Read(buffer^, length);


Вроде по документации callback функции написаны как надо.
Кстати при попытке воспроизвести WAV проигрывание даже не начинается.

Есть догадки?

SOLVED

Починил smile
Изменил read и seek.
Но проблема была в указателе на AStreamInstance.
Теперь адрес передается В параметрах AssignStream, а не в теле процедуры как адрес локальной переменной.
Все ^TMemoryStream поменял на PMemoryStream.

Вот рабочий код (кстати, примером с использованием BASS_StreamCreateFileUser в Delphi нет, 
может стоит включить куда-нибудь? сам я блога не веду, кому охота поделиться в своем блоге - welcome):
Код

unit SamplePlayer;

interface

uses
  Windows, Classes,
  Bass;

type
  PMemoryStream = ^TMemoryStream;
  TBASSCorePlayer = class(TObject)
    public
      constructor Create(hwnd:HWND);
      procedure Free;

      function Play   :BOOL;
      function Stop   :BOOL;
      function Pause  :BOOL;

      function LastError :LongInt;
      function GetPlaybackLength :Double;
      function GetPlaybackPosition :Double;
      function SetPlaybackPosition(seconds:Double) :BOOL;

      procedure AssignStream(AStream:PMemoryStream);
    private
      BASSCh: HSTREAM;
      BASSProcs: BASS_FILEPROCS;
  end;

  procedure proc_close(user : Pointer); stdcall;
  function proc_len(user: Pointer): QWORD; stdcall;
  function proc_seek(offset: QWORD; user: Pointer): BOOL; stdcall;
  function proc_read(buffer: Pointer; length: DWORD; user: Pointer): DWORD; stdcall;

implementation

constructor TBASSCorePlayer.Create(hwnd:HWND);
begin
  inherited Create;
  BASS_Init(-1, 44100, 0, hwnd, nil);
end;

procedure TBASSCorePlayer.Free;
begin
  BASS_Free;
  inherited Free;
end;

function TBASSCorePlayer.GetPlaybackLength :Double;
begin
  Result :=
    BASS_ChannelBytes2Seconds(BASSCh, BASS_ChannelGetLength(BASSCh, BASS_POS_BYTE));
end;

function TBASSCorePlayer.LastError :LongInt;
begin
  Result := BASS_ErrorGetCode;
end;

function TBASSCorePlayer.GetPlaybackPosition :Double;
begin
  Result :=
    BASS_ChannelBytes2Seconds(BASSCh, BASS_ChannelGetPosition(BASSCh, BASS_POS_BYTE));
end;

function TBASSCorePlayer.SetPlaybackPosition(seconds:Double) :BOOL;
begin
  Result :=
    BASS_ChannelSetPosition(BASSCh, BASS_ChannelSeconds2Bytes(BASSCh, seconds),BASS_POS_BYTE);
end;

procedure TBASSCorePlayer.AssignStream(AStream: PMemoryStream);
begin
  //BASSCh := BASS_StreamCreateFile(True, AStream.Memory, 0, AStream.Size, 0);
  BASSProcs.close := proc_close;
  BASSProcs.length := proc_len;
  BASSProcs.read := proc_read;
  BASSProcs.seek := proc_seek;

  BASSCh := BASS_StreamCreateFileUser(STREAMFILE_NOBUFFER, 0, BASSProcs, @AStream)
end;
    //CALLBACKS HERE
    procedure proc_close(user: Pointer);
    var
      AStreamInstance: PMemoryStream;
    begin
      AStreamInstance := user;
      AStreamInstance.Position := 0;
      //AStreamInstance^.Free;
    end;

    function proc_len(user: Pointer): QWORD; stdcall;
    var
      AStreamInstance: ^TMemoryStream;
    begin
      AStreamInstance := user;
      Result := AStreamInstance^.Size;
    end;

    function proc_seek(offset: QWORD; user: Pointer): BOOL; stdcall;
    var
      AStreamInstance: ^TMemoryStream;
      NewPosition: Int64;
    begin
      AStreamInstance := user;
      NewPosition := AStreamInstance^.Seek(offset, soFromBeginning);
      Result := (NewPosition < AStreamInstance^.Size);
    end;

    function proc_read(buffer: Pointer; length: DWORD; user: Pointer): DWORD; stdcall;
    var
      AStreamInstance: ^TMemoryStream;
      BytesReaded: DWORD;
    begin
      AStreamInstance := user;

      Result := AStreamInstance^.Read(buffer^, length);
    end;

function TBASSCorePlayer.Play :BOOL;
begin
  Result := BASS_ChannelPlay(BASSCh, False);
end;

function TBASSCorePlayer.Stop :BOOL;
begin
  Result := BASS_ChannelStop(BASSCh);
end;

function TBASSCorePlayer.Pause :BOOL;
begin
  Result := BASS_ChannelPause(BASSCh)
end;

end.




Автор: dsoft 1.5.2013, 03:22
Поздновато увидел пример, но всё равно. Автор не исправил ошибки, а только больше напутал в коде, как следствие те же 1.5 секунды и  AccessViolation.
Цитата

Все ^TMemoryStream поменял на PMemoryStream.

исправить везде на TMemoryStream. После этого начинает играть без сбоев.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)