⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 unaencoderapi.pas

📁 Voice Commnucation Components for Delphi
💻 PAS
📖 第 1 页 / 共 5 页
字号:
    //
    property libName: string read f_libName;
    property bassError: int read f_bassError;
    property bassStreamThread: unaBassStreamDecoder read f_bassStreamThread;
  end;


// ====================== Open H.323 plugins support ==================

type
  //
  popenH323pluginCodecs = ^openH323pluginCodecs;
  openH323pluginCodecs = array[word] of pluginCodec_definition;


  //
  // -- openH323plugin --
  //
  una_openH323plugin = class(unaAbstractEncoder)
  private
    f_libName: wideString;
    f_ilbcProc: plugin_proc;
    f_procOK: bool;
    //
    f_codecDefCnt: uint32;
    f_codecDefRoot: popenH323pluginCodecs;
    //
    f_codec: ppluginCodec_definition;	// selected codec
    f_context: pointer;			// codec instance
    f_codecIndex: int;
    //
    function getCodecDef(index: int): ppluginCodec_definition;
    procedure setCodecIndex(value: int);
  protected
    {DP:METHOD
      Loads plugin DLL into process memory.
    }
    function loadDLL(): int; virtual;
    {DP:METHOD
      Unloads plugin DLL from process memory.
    }
    function unloadDLL(): int; virtual;
    //
    {DP:METHOD
      Opens plugin codec
    }
    function doOpen(): UNA_ENCODER_ERR; override;
    {DP:METHOD
      Configures plugin codec
    }
    function doSetConfig(config: pointer): UNA_ENCODER_ERR; override;
    {DP:METHOD
      Closes plugin codec
    }
    function doClose(): UNA_ENCODER_ERR; override;
    {DP:METHOD
      Encodes a chunk of data.
    }
    function doEncode(data: pointer; nBytes: unsigned; out bytesUsed: unsigned): UNA_ENCODER_ERR; override;
  public
    {DP:METHOD
      Creates plugin codec class
    }
    constructor create(const dllPathAndName: wideString; priority: integer = THREAD_PRIORITY_NORMAL);
    //
    procedure AfterConstruction(); override;
    procedure BeforeDestruction(); override;
    //
    function selectCodec(index: int): UNA_ENCODER_ERR;
    //
    function isEncoder(index: int = -1): bool;
    //
    {DP:METHOD
      Returns version of loaded plugin
    }
    function getVersion(): int;
    //
    property codecDefCount: uint32 read f_codecDefCnt;
    property codecDef[index: int]: ppluginCodec_definition read getCodecDef;
    //
    property codecIndex: int read f_codecIndex write setCodecIndex;
  end;


// ====================== some well-known open H.323 plugin libraries ==================

const
  //
  c_openH323plugin_libraryName_g726	= 'g726codec_pwplugin.dll';
  c_openH323plugin_libraryName_GSM610	= 'gsm0610_pwplugin.dll';
  c_openH323plugin_libraryName_iLBC	= 'ilbccodec_pwplugin.dll';
  c_openH323plugin_libraryName_ADPCM	= 'IMA_ADPCM_pwplugin.dll';
  c_openH323plugin_libraryName_LPC	= 'LPC_10_pwplugin.dll';
  c_openH323plugin_libraryName_speeX	= 'speexcodec_pwplugin.dll';


implementation


uses
  unaUtils
{$IFDEF __SYSUTILS_H_ }
  , Math
{$ENDIF}
  ;

//============== una classes ===================

type

  //
  // -- unaBladeLazyWriteThread --
  //
  unaLazyWriteThread = class(unaThread)
  private
    f_encoder: unaAbstractEncoder;
    f_waitEvent: unaEvent;
    f_needToFlush: bool;
    //
    f_lazyStream: unaMemoryStream;
    f_lazyBuf: pointer;
  protected
    function execute(threadIndex: unsigned): int; override;
  public
    constructor create(encoder: unaAbstractEncoder);
    procedure BeforeDestruction(); override;
    //
    procedure write(buf: pointer; size: unsigned);
    procedure flush();
  end;


{ unaLazyWriteThread }

// --  --
procedure unaLazyWriteThread.BeforeDestruction();
begin
  inherited;
  //
  mrealloc(f_lazyBuf);
  freeAndNil(f_waitEvent);
  freeAndNil(f_lazyStream);
end;

// --  --
constructor unaLazyWriteThread.create(encoder: unaAbstractEncoder);
begin
  f_encoder := encoder;
  f_waitEvent := unaEvent.create();
  //
  f_lazyBuf := nil;
  f_lazyStream := unaMemoryStream.create();
  //
  inherited create(false, encoder.f_priority);
end;

// --  --
function unaLazyWriteThread.execute(threadIndex: unsigned): int;
var
  size: unsigned;
  avail: unsigned;
  used: unsigned;
begin
  size := f_encoder.f_inputChunkSize;
  mrealloc(f_lazyBuf, size);
  f_needToFlush := false;
  //
  while (not shouldStop and f_encoder.f_opened) do begin
    //
    if (f_waitEvent.waitFor(100)) then begin
      //
      if (enter(100)) then begin
	try
	  avail := f_lazyStream.getAvailableSize();
	  if ((size <= avail) or f_needToFlush) then begin
	    //
	    if (f_needToFlush) then
	      size := min(size, avail);
	    //
	    if (0 < size) then begin
	      //
	      avail := f_lazyStream.read(f_lazyBuf, size);
	      if (0 < avail) then begin
		//
		result := f_encoder.doEncode(f_lazyBuf, avail, used);
		//
		if (BE_ERR_SUCCESSFUL = result) then
		  f_encoder._write();
		//
		if (used < avail) then begin
		  //
		  // some bytes were left unused, need to re-use them later
		  // TODO:
		  used := avail;
		end;
	      end;
	      avail := f_lazyStream.getAvailableSize();
	      //
	      if (0 < avail) then
		f_waitEvent.setState();	// go read rest of the buffer
	    end;
	    //
	    if (f_needToFlush) then
	      // restore size value
	      size := f_encoder.f_inputChunkSize;
	  end;
	finally
	  leave();
	end
      end
      else
	f_waitEvent.setState();	// try one more time
    end;
    //
  end;
  //
  result := 0;
end;

// --  --
procedure unaLazyWriteThread.flush();
begin
  if (enter(30000)) then
    try
      //f_needToFlush := true;
    finally
      leave();
    end;
  //
  f_needToFlush := true;	// must be set anyway!
  //
  while (0 < f_lazyStream.getAvailableSize()) do begin
    //
    f_waitEvent.setState();
    //
    if ((unatsRunning <> getStatus()) or (Windows.getCurrentThreadId() = getThreadId())) then
      break	// no sence to wait any longer, since we are in the same thread as execute() method, or thread is not running
    else
      Windows.sleep(100);	// give encoder some CPU
  end;
end;

// --  --
procedure unaLazyWriteThread.write(buf: pointer; size: unsigned);
begin
  if ((nil <> buf) and (0 < size) and (unatsRunning = getStatus())) then begin
    //
    f_lazyStream.write(buf, size);
    f_waitEvent.setState();	// notify about new data
  end;
end;

{ unaAbstractEncoder }

// --  --
procedure unaAbstractEncoder.AfterConstruction();
begin
  inherited;
  //
  f_inBuf := nil;
  f_inBufSize := 0;
  //
  f_outBuf := nil;
  f_outBufSize := 0;
  f_outStream := unaMemoryStream.create();
  f_inStream := unaMemoryStream.create();
  f_gate := unaInProcessGate.create();
  //
  f_lazyThread := unaLazyWriteThread.create(self);
  //priority := f_priority;	- not required since thread will use our f_priority field
end;

// --  --
procedure unaAbstractEncoder.BeforeDestruction();
begin
  close();
  //
  inherited;
  //
  mrealloc(f_inBuf);
  mrealloc(f_outBuf);
  f_inBufSize := 0;
  f_outBufSize := 0;
  f_errorCode := BE_ERR_SUCCESSFUL;
  //
  freeAndNil(f_gate);
  freeAndNil(f_outStream);
  freeAndNil(f_inStream);
  freeAndNil(f_lazyThread);
end;

// --  --
function unaAbstractEncoder.close(): UNA_ENCODER_ERR;
begin
  if (f_opened) then begin
    //
    unaLazyWriteThread(f_lazyThread).flush();	// give thread a chance to flush the buffer
    f_lazyThread.stop();
  end;
  //
  if (f_configOK) then begin
    //
    result := doClose();
    //
    if (BE_ERR_SUCCESSFUL = result) then
      _write();	// do not forget to write the last chunk (if any)
    //
    f_opened := false;
    f_configOK := false;
  end
  else
    result := BE_ERR_SUCCESSFUL;
  //
  f_errorCode := result;
end;

// --  --
constructor unaAbstractEncoder.create(priority: integer);
begin
  inherited create();
  //
  f_priority := priority;
end;

// --  --
function unaAbstractEncoder.doDAEvent(data: pointer; size: unsigned): bool;
begin
  if (assigned(f_onDA)) then begin
    //
    result := false;
    f_onDA(self, data, size, result);
  end
  else
    result := true;
end;

// --  --
function unaAbstractEncoder.encodeChunk(data: pointer; size: unsigned; lastOne: bool): unsigned;
var
  dataSize: unsigned;
  used: unsigned;
begin
  if (f_opened) then begin
    //
    if (lastOne or ((nil <> data) and (0 < size))) then begin
      //
      f_inStream.write(data, size);
      result := UNA_ENCODER_ERR_FEED_MORE_DATA;
      //
      while (lastOne or (f_inStream.getAvailableSize() >= f_inputChunkSize)) do begin
	//
	dataSize := min(f_inStream.getAvailableSize(), f_inputChunkSize);
	if (dataSize > f_inBufSize) then begin
	  //
	  // increase size of input buffer
	  f_inBufSize := dataSize;
	  mrealloc(f_inBuf, f_inBufSize);
	end;
	//
	if ({f_sampleSize}2 <= dataSize) then begin
	  //
	  f_inStream.read(f_inBuf, dataSize);
	  result := doEncode(f_inBuf, dataSize, used);
	  //
	  if (BE_ERR_SUCCESSFUL = result) then begin
	    //
	    _write();
	    //
	    if (used < dataSize) then begin
	      //
	      // some bytes were left unused, need to re-use them later
	      // TODO:
	      used := dataSize;
	    end;
	  end
	  else begin
	    //assert(false, 'encode fails');
	    break;
	  end;
	end
	else
	  break;
      end;
      //
    end
    else
      result := BE_ERR_SUCCESSFUL;
  end
  else
    result := UNA_ENCODER_ERR_CONFIG_REQUIRED
end;

// --  --
function unaAbstractEncoder.encodeChunkInPlace(data: pointer; var size: unsigned; outBuf: pointer; outBufSize: unsigned): unsigned;
var
  res: UNA_ENCODER_ERR;
  sz: int;
  used: unsigned;
begin
  if (outBufSize <> f_outBufSize) then begin
    //
    // need to adjust output buffer size, so doEncode() will not exceed supplied outBuf
    f_outBufSize := outBufSize;
    mrealloc(f_outBuf, f_outBufSize);
  end;
  //
  res := doEncode(data, size, used);
  if (BE_ERR_SUCCESSFUL = res) then begin
    //
    sz := min(f_outBufUsed, outBufSize);
    //
    if (0 < sz) then
      move(f_outBuf^, outBuf^, sz);
    //
    inc(f_encodedDataSize, f_outBufUsed);
    result := f_outBufUsed;
    f_outBufUsed := 0;
    //
    size := used;
  end
  else
    result := 0;	// check error code  
end;

// --  --
function unaAbstractEncoder.enter(timeout: unsigned): bool;
begin
  result := f_gate.enter(timeout);
end;

// --  --
function unaAbstractEncoder.get_availableDataSize(index: integer): unsigned;
begin
  case (index) of

    0: result := f_outStream.getAvailableSize();
    1: result := f_inStream.getAvailableSize();
    2: result := unaLazyWriteThread(f_lazyThread).f_lazyStream.getAvailableSize();
    
    else
       result := 0;
  end;
end;

// --  --
function unaAbstractEncoder.get_priority(): integer;
begin
  result := f_lazyThread.priority;
end;

// --  --
procedure unaAbstractEncoder.lazyWrite(buf: pointer; size: unsigned);
begin
  unaLazyWriteThread(f_lazyThread).write(buf, size);
end;

// --  --
function unaAbstractEncoder.leave(): bool;
begin
  f_gate.leave();
  result := true;
end;

// --  --
function unaAbstractEncoder.open(): UNA_ENCODER_ERR;
begin
  if (f_configOK) then begin
    //
    if (not f_opened) then begin
      //
      f_inStream.clear();
      f_outStream.clear();
      f_encodedDataSize := 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -