📄 unaencoderapi.pas
字号:
//
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 + -