xtool/precompressor/PrecompMedia.pas

1006 lines
28 KiB
ObjectPascal

unit PrecompMedia;
{$POINTERMATH ON}
interface
uses
BrunsliDLL, FLACDLL, PackJPGDLL, JoJpegDLL, XDeltaDLL,
Utils,
PrecompUtils,
System.SysUtils, System.Classes, System.Math;
var
Codec: TPrecompressor;
implementation
const
MediaCodecs: array of PChar = ['flac', 'packjpg', 'brunsli', 'jojpeg'];
CODEC_COUNT = 4;
FLAC_CODEC = 0;
PACKJPG_CODEC = 1;
BRUNSLI_CODEC = 2;
JOJPEG_CODEC = 3;
const
FLAC_LEVEL = 5;
J_WORKMEM = 262144;
type
PFlacEncCD = ^TFlacEncCD;
TFlacEncCD = record
Output: TMemoryStreamEx;
Error: Boolean;
end;
PFlacDecCD = ^TFlacDecCD;
TFlacDecCD = record
Input, Output: TMemoryStreamEx;
end;
var
cctx, dctx: array of Pointer;
ccd: array of TFlacEncCD;
dcd: array of TFlacDecCD;
JJInst: TArray<Pointer>;
FlacLevel: Integer = FLAC_LEVEL;
CodecAvailable, CodecEnabled: TArray<Boolean>;
RestoreOut: TArray<_PrecompOutput>;
RestoreSize: TArray<Integer>;
const
RIFF_SIGN = $46464952;
WAVE_SIGN = $45564157;
fmt_SIGN = $20746D66;
data_SIGN = $61746164;
WAVE_FORMAT_PCM = 1;
WAVE_FORMAT_EXTENSIBLE = $FFFE;
type
PRIFF_hdr = ^TRIFF_hdr;
TRIFF_hdr = packed record
chunk_id, chunk_size, form_type: Cardinal;
end;
PWAVE_hdr = ^TWAVE_hdr;
TWAVE_hdr = packed record
audio_format, num_channels: Word;
sample_rate, byte_rate: Cardinal;
block_align, bits_per_sample: Word;
end;
PWAVE_subchunk_hdr = ^TWAVE_subchunk_hdr;
TWAVE_subchunk_hdr = packed record
subchunk_id, subchunk_size: Cardinal;
end;
PWAVE_subformat = ^TWAVE_subformat;
TWAVE_subformat = packed record
f1: Cardinal;
f2, f3: Word;
f4: array [0 .. 7] of Byte;
end;
PWAVE_ext_hdr = ^TWAVE_ext_hdr;
TWAVE_ext_hdr = packed record
cb_size, valid_bits: Word;
ch_mask: Cardinal;
est: TWAVE_subformat;
end;
function GetWAVEInfo(InBuff: PByte; InSize: NativeInt; wave_hdr: PWAVE_hdr;
chunk_size, header_size: PCardinal): Boolean;
var
Pos, LastPos: NativeInt;
riffhdr: TRIFF_hdr;
subchunk_hdr: TWAVE_subchunk_hdr;
wave_hdr_ex: TWAVE_ext_hdr;
begin
Result := False;
Pos := 0;
if InSize - Pos < SizeOf(TRIFF_hdr) then
exit;
Move((InBuff + Pos)^, riffhdr, SizeOf(TRIFF_hdr));
Inc(Pos, SizeOf(TRIFF_hdr));
if (riffhdr.chunk_id <> RIFF_SIGN) or (riffhdr.form_type <> WAVE_SIGN) then
exit;
while True do
begin
if InSize - Pos < SizeOf(TWAVE_subchunk_hdr) then
exit;
Move((InBuff + Pos)^, subchunk_hdr, SizeOf(TWAVE_subchunk_hdr));
Inc(Pos, SizeOf(TWAVE_subchunk_hdr));
if subchunk_hdr.subchunk_id = fmt_SIGN then
begin
LastPos := Pos;
if InSize - Pos < SizeOf(TWAVE_hdr) then
exit;
Move((InBuff + Pos)^, wave_hdr^, SizeOf(TWAVE_hdr));
Inc(Pos, SizeOf(TWAVE_hdr));
if wave_hdr^.audio_format = WAVE_FORMAT_EXTENSIBLE then
begin
if InSize - Pos < SizeOf(TWAVE_ext_hdr) then
exit;
Move((InBuff + Pos)^, wave_hdr_ex, SizeOf(TWAVE_ext_hdr));
Inc(Pos, SizeOf(TWAVE_ext_hdr));
wave_hdr^.audio_format := wave_hdr_ex.est.f1;
end
else if wave_hdr^.audio_format <> WAVE_FORMAT_PCM then
exit;
Pos := LastPos + subchunk_hdr.subchunk_size;
end
else if subchunk_hdr.subchunk_id = data_SIGN then
begin
chunk_size^ := Min(subchunk_hdr.subchunk_size,
(riffhdr.chunk_size + 8 - Pos));
header_size^ := Pos;
Result := chunk_size^ + header_size^ <= InSize;
exit;
end
else
Inc(Pos, subchunk_hdr.subchunk_size);
end;
end;
function FlacEncoderWriteCB(encoder: Pointer; const Buffer; bytes: NativeUInt;
samples, current_frame: Cardinal; client_data: PFlacEncCD): Integer cdecl;
begin
try
client_data^.Output.WriteBuffer(Buffer, bytes);
except
client_data^.Error := True;
end;
Result := 0;
end;
function FlacDecoderReadCB(decoder: Pointer; var Buffer; bytes: PNativeUInt;
client_data: PFlacDecCD): Integer cdecl;
begin
bytes^ := client_data^.Input.Read(Buffer, bytes^);
if bytes^ > 0 then
Result := 0
else
Result := 1;
end;
function FlacDecoderWriteCB(decoder: Pointer; frame: PFLAC__Frame;
Buffer: Pointer; client_data: PFlacDecCD): Integer cdecl;
var
I, J, X: Integer;
begin
for I := 0 to frame^.header.blocksize - 1 do
for J := 0 to frame^.header.channels - 1 do
begin
X := PInteger(PNativeInt(Buffer)[J])[I];
client_data^.Output.WriteBuffer(X, frame^.header.bits_per_sample div 8);
end;
Result := 0;
end;
procedure FlacDecoderErrorCB(decoder: Pointer; Status: Integer;
client_data: Pointer)cdecl;
begin
end;
function FlacEncode(ctx: Pointer; cd: PFlacEncCD; InBuff: PByte;
InSize: Integer; OutBuff: PByte; OutSize: Integer;
Level: Integer = 5): Integer;
const
READSIZE = 1000;
var
I, J, X: Integer;
Ptr: PByte;
wave_hdr: TWAVE_hdr;
byte_per_sample: Word;
data_size, hdr_size, smp_size: Cardinal;
ok: Boolean;
pcm: TArray<Integer>;
begin
Result := 0;
ok := False;
if GetWAVEInfo(InBuff, InSize, @wave_hdr, @data_size, @hdr_size) then
begin
ok := True;
byte_per_sample := (wave_hdr.bits_per_sample + 7) div 8;
smp_size := wave_hdr.num_channels * byte_per_sample;
ok := ok and FLAC__stream_encoder_set_verify(ctx, True);
ok := ok and FLAC__stream_encoder_set_compression_level(ctx, Level);
ok := ok and FLAC__stream_encoder_set_channels(ctx, wave_hdr.num_channels);
ok := ok and FLAC__stream_encoder_set_bits_per_sample(ctx,
wave_hdr.bits_per_sample);
ok := ok and FLAC__stream_encoder_set_sample_rate(ctx,
wave_hdr.sample_rate);
end;
if ok then
try
cd^.Error := False;
cd^.Output.Update(OutBuff, OutSize);
cd^.Output.Size := 0;
if FLAC__stream_encoder_init_stream(ctx, @FlacEncoderWriteCB, nil, nil,
nil, cd) = 0 then
begin
Ptr := InBuff + hdr_size;
SetLength(pcm, READSIZE * wave_hdr.num_channels);
while True do
begin
X := 0;
for I := 0 to READSIZE - 1 do
begin
if NativeInt(Ptr + smp_size - InBuff) > hdr_size + data_size then
break;
Inc(X);
for J := 0 to wave_hdr.num_channels - 1 do
begin
if NativeInt(Ptr - InBuff) > hdr_size + data_size then
break;
pcm[I * wave_hdr.num_channels + J] :=
GetBits(PInteger(Ptr)^, 0, Pred(wave_hdr.bits_per_sample)) -
IfThen(GetBits(PInteger(Ptr)^, Pred(wave_hdr.bits_per_sample),
1) = 0, 0, 1 shl Pred(wave_hdr.bits_per_sample));
Inc(Ptr, byte_per_sample);
end;
end;
ok := ok and FLAC__stream_encoder_process_interleaved(ctx, pcm[0], X);
if (NativeInt(Ptr + smp_size - InBuff) > hdr_size + data_size) or
(ok = False) then
break;
end;
end;
finally
FLAC__stream_encoder_finish(ctx);
if ok and (cd^.Error = False) then
Result := cd^.Output.Size;
end;
end;
function FlacDecode(ctx: Pointer; cd: PFlacDecCD; InBuff: PByte;
InSize: Integer; OutBuff: PByte; OutSize: Integer): Integer;
var
ok: Boolean;
begin
Result := 0;
ok := False;
cd^.Input.Update(InBuff, InSize);
cd^.Input.Position := 0;
cd^.Input.Size := InSize;
cd^.Output.Update(OutBuff, OutSize);
cd^.Output.Size := 0;
try
if FLAC__stream_decoder_init_stream(ctx, @FlacDecoderReadCB, nil, nil, nil,
nil, @FlacDecoderWriteCB, nil, @FlacDecoderErrorCB, cd) = 0 then
begin
ok := True;
ok := ok and FLAC__stream_decoder_process_until_end_of_stream(ctx);
end;
finally
FLAC__stream_decoder_finish(ctx);
if ok then
Result := cd^.Output.Size;
end;
end;
const
JPG_HEADER = $D8FF;
JPG_FOOTER = $D9FF;
function GetJPEGInfo(InBuff: PByte; InSize: NativeInt; ImageSize: PCardinal;
IsProgressive: PBoolean): Boolean;
// https://github.com/schnaader/precomp-cpp/blob/master/precomp.cpp
var
Pos: NativeInt;
hasQuantTable: Boolean;
done, found: Boolean;
length: Integer;
isMarker: Boolean;
bytesRead: Cardinal;
begin
Result := False;
Pos := 0;
done := False;
found := False;
if (PWord(InBuff)^ = JPG_HEADER) and ((InBuff + 2)^ = $FF) then
begin
Pos := 3;
if (InBuff + Pos)^ in [$C0, $C2, $C4, $DB .. $FE] then
begin
hasQuantTable := (InBuff + Pos)^ = $DB;
IsProgressive^ := (InBuff + Pos)^ = $C2;
Pos := 2;
repeat
if (Pos + 5 > InSize) or ((InBuff + Pos)[0] <> $FF) then
break;
length := Integer((InBuff + Pos)[2]) * 256 + Integer((InBuff + Pos)[3]);
case (InBuff + Pos)[1] of
$DB:
begin
if (length <= 262) and (((length - 2) mod 65) = 0) and
((InBuff + Pos)[4] <= 3) then
begin
hasQuantTable := True;
Inc(Pos, length + 2);
end
else
done := True;
end;
$C4:
begin
done := (((InBuff + Pos)[4] and $F) > 3) or
(((InBuff + Pos)[4] shr 4) > 1);
Inc(Pos, length + 2);
end;
$DA:
begin
found := hasQuantTable;
Inc(Pos, length + 2);
end;
$D9:
done := True;
$C2:
begin
IsProgressive^ := True;
Inc(Pos, length + 2);
end;
$C0:
begin
done := (InBuff + Pos)[4] <> $08;
Inc(Pos, length + 2);
end;
else
Inc(Pos, length + 2);
end;
until done;
if found then
while Pos < InSize - 1 do
begin
if PWord(InBuff + Pos)^ = JPG_FOOTER then
begin
ImageSize^ := Pos + 2;
Result := True;
break;
end;
Inc(Pos);
end;
end;
end;
end;
function BrunsliWriter(cd: Pointer; data: Pointer; Size: NativeUInt)
: Integer cdecl;
begin
RestoreOut[PInteger(cd)^](PInteger(cd)^, data, Size);
Inc(RestoreSize[PInteger(cd)^], Size);
Result := Size;
end;
function MediaInit(Command: PChar; Count: Integer;
Funcs: PPrecompFuncs): Boolean;
var
I: Integer;
Options: TArray<Integer>;
S: String;
X, Y: Integer;
begin
Result := True;
SetLength(RestoreOut, Count);
SetLength(RestoreSize, Count);
for X := Low(CodecAvailable) to High(CodecAvailable) do
begin
CodecAvailable[X] := False;
CodecEnabled[X] := False;
end;
CodecAvailable[FLAC_CODEC] := FLACDLL.DLLLoaded;
CodecAvailable[PACKJPG_CODEC] := PackJPGDLL.DLLLoaded;
CodecAvailable[BRUNSLI_CODEC] := BrunsliDLL.DLLLoaded;
CodecAvailable[JOJPEG_CODEC] := JoJpegDLL.DLLLoaded;
X := 0;
while Funcs^.GetCodec(Command, X, False) <> '' do
begin
S := Funcs^.GetCodec(Command, X, False);
if (CompareText(S, MediaCodecs[FLAC_CODEC]) = 0) and FLACDLL.DLLLoaded then
begin
CodecEnabled[FLAC_CODEC] := True;
if Funcs^.GetParam(Command, X, 'l') <> '' then
FlacLevel := StrToInt(Funcs^.GetParam(Command, X, 'l'));
end
else if (CompareText(S, MediaCodecs[PACKJPG_CODEC]) = 0) and PackJPGDLL.DLLLoaded
then
CodecEnabled[PACKJPG_CODEC] := True
else if (CompareText(S, MediaCodecs[BRUNSLI_CODEC]) = 0) and BrunsliDLL.DLLLoaded
then
CodecEnabled[BRUNSLI_CODEC] := True
else if (CompareText(S, MediaCodecs[JOJPEG_CODEC]) = 0) and JoJpegDLL.DLLLoaded
then
CodecEnabled[JOJPEG_CODEC] := True;;
Inc(X);
end;
if CodecAvailable[FLAC_CODEC] then
begin
SetLength(cctx, Count);
SetLength(dctx, Count);
SetLength(ccd, Count);
SetLength(dcd, Count);
for X := Low(cctx) to High(cctx) do
begin
cctx[X] := FLAC__stream_encoder_new;
dctx[X] := FLAC__stream_decoder_new;
ccd[X].Output := TMemoryStreamEx.Create(False);
dcd[X].Input := TMemoryStreamEx.Create(False);
dcd[X].Output := TMemoryStreamEx.Create(False);
end;
end;
if CodecAvailable[JOJPEG_CODEC] then
begin
SetLength(JJInst, Count);
for X := Low(JJInst) to High(JJInst) do
JJInst[X] := GetMemory(jojpeg_Size);
end;
end;
procedure MediaFree(Funcs: PPrecompFuncs);
var
X: Integer;
begin
if CodecAvailable[FLAC_CODEC] then
begin
for X := Low(cctx) to High(cctx) do
begin
FLAC__stream_encoder_delete(cctx[X]);
FLAC__stream_decoder_delete(dctx[X]);
ccd[X].Output.Free;
dcd[X].Input.Free;
dcd[X].Output.Free;
end;
end;
if CodecAvailable[JOJPEG_CODEC] then
for X := Low(JJInst) to High(JJInst) do
FreeMemory(JJInst[X]);
end;
function MediaParse(Command: PChar; Option: PInteger;
Funcs: PPrecompFuncs): Boolean;
var
S: String;
I: Integer;
begin
Result := False;
Option^ := 0;
I := 0;
while Funcs^.GetCodec(Command, I, False) <> '' do
begin
S := Funcs^.GetCodec(Command, I, False);
if (CompareText(S, MediaCodecs[FLAC_CODEC]) = 0) and FLACDLL.DLLLoaded then
begin
SetBits(Option^, FLAC_CODEC, 0, 5);
Result := True;
end
else if (CompareText(S, MediaCodecs[PACKJPG_CODEC]) = 0) and PackJPGDLL.DLLLoaded
then
begin
SetBits(Option^, PACKJPG_CODEC, 0, 5);
Result := True;
end
else if (CompareText(S, MediaCodecs[BRUNSLI_CODEC]) = 0) and BrunsliDLL.DLLLoaded
then
begin
SetBits(Option^, BRUNSLI_CODEC, 0, 5);
Result := True;
end
else if (CompareText(S, MediaCodecs[JOJPEG_CODEC]) = 0) and JoJpegDLL.DLLLoaded
then
begin
SetBits(Option^, JOJPEG_CODEC, 0, 5);
Result := True;
end;
Inc(I);
end;
end;
procedure MediaScan1(Instance, Depth: Integer; Input: PByte;
Size, SizeEx: NativeInt; Output: _PrecompOutput; Add: _PrecompAdd;
Funcs: PPrecompFuncs);
var
Buffer: PByte;
Pos: NativeInt;
X, Y, Z: Integer;
SI: _StrInfo1;
DI1, DI2: TDepthInfo;
DS: TPrecompStr;
wave_hdr: TWAVE_hdr;
data_size, hdr_size: Cardinal;
progressive: Boolean;
begin
DI1 := Funcs^.GetDepthInfo(Instance);
DS := Funcs^.GetCodec(DI1.Codec, 0, False);
if DS <> '' then
begin
X := IndexTextW(@DS[0], MediaCodecs);
if (X < 0) or (DI1.OldSize <> SizeEx) then
exit;
if not CodecAvailable[X] then
exit;
Y := DI1.OldSize;
case X of
FLAC_CODEC:
begin
if GetWAVEInfo(Input, Y, @wave_hdr, @data_size, @hdr_size) then
Y := data_size + hdr_size
else
Y := 0;
end;
PACKJPG_CODEC, BRUNSLI_CODEC, JOJPEG_CODEC:
begin
if GetJPEGInfo(Input, Y, @data_size, @progressive) then
Y := data_size
else
Y := 0;
end;
else
Y := 0;
end;
if Y > 0 then
begin
Z := data_size;
if X = FLAC_CODEC then
begin
Buffer := Funcs^.Allocator(Instance, hdr_size);
Move(Input^, Buffer^, hdr_size);
Inc(PInteger(Buffer)^);
Output(Instance, @hdr_size, hdr_size.Size);
Output(Instance, Buffer, hdr_size);
Output(Instance, Input + hdr_size, Z);
Inc(Z, hdr_size.Size);
Inc(Z, hdr_size);
end
else
Output(Instance, Input, Z);
SI.Position := 0;
SI.OldSize := Y;
SI.NewSize := Z;
SI.Option := 0;
SetBits(SI.Option, X, 0, 5);
if System.Pos(SPrecompSep2, DI1.Codec) > 0 then
SI.Status := TStreamStatus.Predicted
else
SI.Status := TStreamStatus.None;
DS := Funcs^.GetDepthCodec(DI1.Codec);
Move(DS[0], DI2.Codec, SizeOf(DI2.Codec));
DI2.OldSize := SI.NewSize;
DI2.NewSize := SI.NewSize;
Funcs^.LogScan1(MediaCodecs[GetBits(SI.Option, 0, 5)], SI.Position,
SI.OldSize, -1);
Add(Instance, @SI, DI1.Codec, @DI2);
end;
exit;
end;
if BoolArray(CodecEnabled, False) then
exit;
Pos := 0;
while Pos < Size do
begin
if CodecEnabled[FLAC_CODEC] and (PCardinal(Input + Pos)^ = RIFF_SIGN) then
begin
Y := SizeEx - Pos;
if GetWAVEInfo(Input + Pos, Y, @wave_hdr, @data_size, @hdr_size) then
Y := data_size + hdr_size
else
Y := 0;
if Y > 0 then
begin
Z := data_size;
Buffer := Funcs^.Allocator(Instance, hdr_size);
Move((Input + Pos)^, Buffer^, hdr_size);
Inc(PInteger(Buffer)^);
Output(Instance, @hdr_size, hdr_size.Size);
Output(Instance, Buffer, hdr_size);
Output(Instance, Input + Pos + hdr_size, Z);
Inc(Z, hdr_size.Size);
Inc(Z, hdr_size);
SI.Position := Pos;
SI.OldSize := Y;
SI.NewSize := Z;
SI.Option := 0;
SetBits(SI.Option, FLAC_CODEC, 0, 5);
SI.Status := TStreamStatus.None;
Funcs^.LogScan1(MediaCodecs[GetBits(SI.Option, 0, 5)], SI.Position,
SI.OldSize, -1);
Add(Instance, @SI, nil, nil);
Inc(Pos, SI.OldSize);
continue;
end;
end;
if (CodecEnabled[PACKJPG_CODEC] or CodecEnabled[BRUNSLI_CODEC] or
CodecEnabled[JOJPEG_CODEC]) and (PWord(Input + Pos)^ = JPG_HEADER) then
begin
Y := SizeEx - Pos;
if GetJPEGInfo(Input + Pos, Y, @data_size, @progressive) then
Y := data_size
else
Y := 0;
if Y > 0 then
begin
Z := data_size;
Output(Instance, Input + Pos, Z);
SI.Position := Pos;
SI.OldSize := Y;
SI.NewSize := Z;
SI.Option := 0;
if CodecEnabled[BRUNSLI_CODEC] then
SetBits(SI.Option, BRUNSLI_CODEC, 0, 5)
else if CodecEnabled[JOJPEG_CODEC] then
SetBits(SI.Option, JOJPEG_CODEC, 0, 5)
else if CodecEnabled[PACKJPG_CODEC] then
SetBits(SI.Option, PACKJPG_CODEC, 0, 5);
SI.Status := TStreamStatus.None;
Funcs^.LogScan1(MediaCodecs[GetBits(SI.Option, 0, 5)], SI.Position,
SI.OldSize, -1);
Add(Instance, @SI, nil, nil);
Inc(Pos, SI.OldSize);
continue;
end;
end;
Inc(Pos);
end;
end;
function MediaScan2(Instance, Depth: Integer; Input: Pointer; Size: NativeInt;
StreamInfo: PStrInfo2; Offset: PInteger; Output: _PrecompOutput;
Funcs: PPrecompFuncs): Boolean;
var
Buffer: PByte;
X, Y, Z: Integer;
wave_hdr: TWAVE_hdr;
data_size, hdr_size: Cardinal;
progressive: Boolean;
begin
Result := False;
X := GetBits(StreamInfo^.Option, 0, 5);
if StreamInfo^.OldSize <= 0 then
exit;
Y := StreamInfo^.OldSize;
case X of
FLAC_CODEC:
begin
if GetWAVEInfo(Input, Y, @wave_hdr, @data_size, @hdr_size) then
Y := data_size + hdr_size
else
Y := 0;
end;
PACKJPG_CODEC, BRUNSLI_CODEC, JOJPEG_CODEC:
begin
if GetJPEGInfo(Input, Y, @data_size, @progressive) then
Y := data_size
else
Y := 0;
end;
else
Y := 0;
end;
if Y > 0 then
begin
Z := data_size;
if X = FLAC_CODEC then
begin
Buffer := Funcs^.Allocator(Instance, hdr_size);
Move(Input^, Buffer^, hdr_size);
Inc(PInteger(Buffer)^);
Output(Instance, @hdr_size, hdr_size.Size);
Output(Instance, Buffer, hdr_size);
Output(Instance, PByte(Input) + hdr_size, Z);
Inc(Z, hdr_size.Size);
Inc(Z, hdr_size);
end
else
Output(Instance, Input, Z);
StreamInfo^.NewSize := Z;
Funcs^.LogScan2(MediaCodecs[GetBits(StreamInfo^.Option, 0, 5)],
StreamInfo^.OldSize, -1);
Result := True;
end;
end;
function MediaProcess(Instance, Depth: Integer; OldInput, NewInput: Pointer;
StreamInfo: PStrInfo2; Output: _PrecompOutput; Funcs: PPrecompFuncs): Boolean;
var
Buffer, Ptr: PByte;
Params: String;
ctx: Pointer;
I, J: Integer;
X, Y: Integer;
Res: Cardinal;
Res1, Res2: Integer;
begin
Result := False;
X := GetBits(StreamInfo^.Option, 0, 5);
if BoolArray(CodecAvailable, False) or (CodecAvailable[X] = False) then
exit;
Params := '';
case X of
FLAC_CODEC:
begin
Params := 'l' + FlacLevel.ToString;
Y := Integer.Size + PInteger(NewInput)^;
Res := StreamInfo.NewSize - Y;
Res := FlacEncode(cctx[Instance], @ccd[Instance], OldInput,
StreamInfo^.OldSize, PByte(NewInput) + Y, Res, FlacLevel);
if (Res > 0) and (Res + Y < StreamInfo^.NewSize) then
begin
StreamInfo^.NewSize := Res + Y;
Result := True;
end;
end;
PACKJPG_CODEC:
begin
Buffer := nil;
Res := StreamInfo.OldSize;
pjglib_init_streams(OldInput, pjglib_memory, StreamInfo^.OldSize,
Buffer, pjglib_memory);
if pjglib_convert_stream2mem(@Buffer, @Res, nil) and
(Res < StreamInfo^.NewSize) then
begin
Move(Buffer^, NewInput^, Res);
StreamInfo^.NewSize := Res;
Result := True;
end;
end;
BRUNSLI_CODEC:
begin
ctx := brunsli_alloc_JPEGData;
try
if brunsli_ReadJpeg(ctx, OldInput, StreamInfo^.OldSize) = Integer(True)
then
begin
Res := brunsli_GetMaximumEncodedSize(ctx);
Buffer := Funcs^.Allocator(Instance, Res);
Res := brunsli_EncodeJpeg(ctx, Buffer, Res);
if Res < StreamInfo^.NewSize then
begin
Move(Buffer^, NewInput^, Res);
StreamInfo^.NewSize := Res;
Result := True;
end;
end;
finally
brunsli_free_JPEGData(ctx);
end;
end;
JOJPEG_CODEC:
begin
ctx := JJInst[Instance];
Buffer := Funcs^.Allocator(Instance, J_WORKMEM * 2);
I := 0;
J := 0;
Y := 0;
jojpeg_Init(ctx, jojpeg_Compress);
try
jojpeg_Addbuf(ctx, jojpeg_Compress, Buffer, J_WORKMEM,
jojpeg_enc_Output1);
jojpeg_Addbuf(ctx, jojpeg_Compress, Buffer + J_WORKMEM, J_WORKMEM,
jojpeg_enc_Output2);
while True do
begin
Res1 := jojpeg_Loop(ctx, jojpeg_Compress);
if (Res1 = jojpeg_enc_Input) then
begin
Res2 := Min(StreamInfo^.OldSize - I, J_WORKMEM);
jojpeg_Addbuf(ctx, jojpeg_Compress, PByte(OldInput) + I, Res2,
jojpeg_enc_Input);
Inc(I, Res2);
end;
if (Res1 in [0, jojpeg_enc_Output1]) then
begin
Res2 := jojpeg_Getvalue(ctx, jojpeg_Compress, jojpeg_enc_Output1);
Move(Buffer^, (PByte(NewInput) + J)^, Res2);
Inc(J, Res2);
jojpeg_Addbuf(ctx, jojpeg_Compress, Buffer, J_WORKMEM,
jojpeg_enc_Output1);
end;
if (Res1 = jojpeg_enc_Output2) or (Res1 = 0) then
begin
Res2 := jojpeg_Getvalue(ctx, jojpeg_Compress, jojpeg_enc_Output2);
Output(Instance, Buffer + J_WORKMEM, Res2);
Inc(Y, Res2);
jojpeg_Addbuf(ctx, jojpeg_Compress, Buffer + J_WORKMEM, J_WORKMEM,
jojpeg_enc_Output2);
if Res1 = 0 then
break;
end;
end;
if I = StreamInfo^.OldSize then
begin
StreamInfo^.NewSize := J;
Result := True;
end;
finally
jojpeg_Quit(ctx, jojpeg_Compress);
end;
end;
end;
Funcs^.LogProcess(MediaCodecs[GetBits(StreamInfo^.Option, 0, 5)],
PChar(Params), StreamInfo^.OldSize, StreamInfo^.NewSize, -1, Result);
end;
function MediaRestore(Instance, Depth: Integer; Input, InputExt: Pointer;
StreamInfo: _StrInfo3; Output: _PrecompOutput; Funcs: PPrecompFuncs): Boolean;
var
Buffer: PByte;
Params: String;
ctx, writer: Pointer;
I, J: Integer;
X, Y: Integer;
Res: Cardinal;
Res1, Res2: Integer;
begin
Result := False;
X := GetBits(StreamInfo.Option, 0, 5);
if BoolArray(CodecAvailable, False) or (CodecAvailable[X] = False) then
exit;
Params := '';
case X of
FLAC_CODEC:
begin
Buffer := Funcs^.Allocator(Instance, StreamInfo.OldSize);
Y := Integer.Size + PInteger(Input)^;
Res := StreamInfo.OldSize;
Res := FlacDecode(dctx[Instance], @dcd[Instance], PByte(Input) + Y,
StreamInfo.NewSize - Y, Buffer + PInteger(Input)^, Res);
if Res > 0 then
begin
Move((PByte(Input) + Integer.Size)^, Buffer^, PInteger(Input)^);
Inc(Res, PInteger(Input)^);
Dec(PInteger(Buffer)^);
Result := True;
end;
if Result then
Output(Instance, Buffer, Res);
end;
PACKJPG_CODEC:
begin
Buffer := nil;
pjglib_init_streams(Input, pjglib_memory, StreamInfo.NewSize, Buffer,
pjglib_memory);
Res := StreamInfo.OldSize;
Result := pjglib_convert_stream2mem(@Buffer, @Res, nil);
if Result then
Output(Instance, Buffer, Res);
end;
BRUNSLI_CODEC:
begin
RestoreOut[Instance] := Output;
RestoreSize[Instance] := 0;
Res := RestoreSize[Instance];
ctx := brunsli_alloc_JPEGData;
try
if brunsli_DecodeJpeg(ctx, Input, StreamInfo.NewSize) = BRUNSLI_OK
then
begin
writer := brunsli_alloc_JPEGOutput(BrunsliWriter, @Instance);
try
Result := Boolean(brunsli_WriteJpeg(ctx, writer));
finally
brunsli_free_JPEGOutput(writer);
end;
end;
finally
brunsli_free_JPEGData(ctx);
end;
Res := RestoreSize[Instance];
end;
JOJPEG_CODEC:
begin
ctx := JJInst[Instance];
Buffer := Funcs^.Allocator(Instance, J_WORKMEM);
I := 0;
J := 0;
Y := 0;
jojpeg_Init(ctx, jojpeg_Decompress);
try
jojpeg_Addbuf(ctx, jojpeg_Decompress, Buffer, J_WORKMEM,
jojpeg_dec_Output);
while True do
begin
Res1 := jojpeg_Loop(ctx, jojpeg_Decompress);
if (Res1 = jojpeg_dec_Input1) then
begin
Res2 := Min(StreamInfo.NewSize - I, J_WORKMEM);
jojpeg_Addbuf(ctx, jojpeg_Decompress, PByte(Input) + I, Res2,
jojpeg_dec_Input1);
Inc(I, Res2);
end;
if (Res1 = jojpeg_dec_Input2) then
begin
Res2 := Min(StreamInfo.ExtSize - J, J_WORKMEM);
jojpeg_Addbuf(ctx, jojpeg_Decompress, PByte(InputExt) + J, Res2,
jojpeg_dec_Input2);
Inc(J, Res2);
end;
if (Res1 in [0, jojpeg_dec_Output]) then
begin
Res2 := jojpeg_Getvalue(ctx, jojpeg_Decompress,
jojpeg_dec_Output);
Output(Instance, Buffer, Res2);
Inc(Y, Res2);
jojpeg_Addbuf(ctx, jojpeg_Decompress, Buffer, J_WORKMEM,
jojpeg_dec_Output);
if Res1 = 0 then
break;
end;
end;
{ while True do
begin
Res1 := jojpeg_Loop(ctx, jojpeg_Decompress);
if Res1 = 0 then
break;
if (Res1 = jojpeg_dec_Input1) then
begin
Res2 := Min(StreamInfo.NewSize - I, J_WORKMEM);
jojpeg_Addbuf(ctx, jojpeg_Decompress, PByte(Input) + I, Res2,
jojpeg_dec_Input1);
Inc(I, Res2);
end;
if (Res1 = jojpeg_dec_Input2) then
begin
Res2 := Min(StreamInfo.ExtSize - J, J_WORKMEM);
jojpeg_Addbuf(ctx, jojpeg_Decompress, PByte(InputExt) + J, Res2,
jojpeg_dec_Input2);
Inc(J, Res2);
end;
if (Res1 = jojpeg_dec_Output) then
begin
Output(Instance, Buffer, J_WORKMEM);
Inc(Y, J_WORKMEM);
jojpeg_Addbuf(ctx, jojpeg_Decompress, Buffer, J_WORKMEM,
jojpeg_dec_Output);
end;
end;
if (Y <> StreamInfo.OldSize) and (StreamInfo.OldSize - Y < J_WORKMEM)
then
begin
Res2 := StreamInfo.OldSize - Y;
Output(Instance, Buffer, Res2);
Inc(Y, Res2);
end; }
Res := Y;
Result := Y = StreamInfo.OldSize;
finally
jojpeg_Quit(ctx, jojpeg_Decompress);
end;
end;
end;
Funcs^.LogRestore(MediaCodecs[GetBits(StreamInfo.Option, 0, 5)],
PChar(Params), StreamInfo.NewSize, Res, -1, Result);
end;
var
I: Integer;
initialization
Codec.Names := [];
for I := Low(MediaCodecs) to High(MediaCodecs) do
begin
Codec.Names := Codec.Names + [MediaCodecs[I]];
StockMethods.Add(MediaCodecs[I]);
end;
Codec.Initialised := False;
Codec.Init := @MediaInit;
Codec.Free := @MediaFree;
Codec.Parse := @MediaParse;
Codec.Scan1 := @MediaScan1;
Codec.Scan2 := @MediaScan2;
Codec.Process := @MediaProcess;
Codec.Restore := @MediaRestore;
SetLength(CodecAvailable, length(Codec.Names));
SetLength(CodecEnabled, length(Codec.Names));
end.