Correct AvPlayer handle, avoid dangling pointers + Refactor code (#71)

* Correct avplayer handle, avoid dangling pointers

* Uses TMemChunk in sys_types unit instead

* Minor

* Minor

* SceAvPlayerHandle should be 8 bytes in size

* Minor

* Minor

* Minor

* Moved from TDictionary to HAMT it's faster

* Added lock of Hamt and individual lock of Handle

* Using AllocMem instead of New (New doesn't guarantee an initial value) and fixing an endless loop of zero lastVideoTimeStamp

* Added callback helpers

* +

* +

Co-authored-by: Pavel <68122101+red-prig@users.noreply.github.com>
Co-authored-by: red-prig <vdpasha@mail.ru>
This commit is contained in:
Kagamma 2023-01-24 23:00:20 +07:00 committed by GitHub
parent 6771f25d42
commit f2d4f52331
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 368 additions and 149 deletions

View File

@ -11,13 +11,13 @@ uses
libavutil,
libswscale,
libswresample,
windows,
hamt,
ps4_program,
spinlock,
sys_types,
sys_signal,
sys_path,
sys_time,
sys_pthread,
Classes,
SysUtils,
Generics.Collections,
@ -47,15 +47,15 @@ const
type
TAVPacketQueue=specialize TQueue<PAVPacket>;
SceAvPlayerAllocate=function(argP:Pointer;argAlignment:DWord;argSize:DWord):Pointer; SysV_ABI_CDecl;
SceAvPlayerDeallocate=procedure(argP:Pointer;argMemory:Pointer); SysV_ABI_CDecl;
SceAvPlayerAllocateTexture=function(argP:Pointer;argAlignment:DWord;argSize:DWord):Pointer; SysV_ABI_CDecl;
SceAvPlayerAllocate =function(argP:Pointer;argAlignment:DWord;argSize:DWord):Pointer; SysV_ABI_CDecl;
SceAvPlayerDeallocate =procedure(argP:Pointer;argMemory:Pointer); SysV_ABI_CDecl;
SceAvPlayerAllocateTexture =function(argP:Pointer;argAlignment:DWord;argSize:DWord):Pointer; SysV_ABI_CDecl;
SceAvPlayerDeallocateTexture=procedure(argP:Pointer;argMemory:Pointer); SysV_ABI_CDecl;
SceAvPlayerOpenFile=function(argP:Pointer;argFilename:PChar):Integer; SysV_ABI_CDecl;
SceAvPlayerCloseFile=function(argP:Pointer):Integer; SysV_ABI_CDecl;
SceAvPlayerOpenFile =function(argP:Pointer;argFilename:PChar):Integer; SysV_ABI_CDecl;
SceAvPlayerCloseFile =function(argP:Pointer):Integer; SysV_ABI_CDecl;
SceAvPlayerReadOffsetFile=function(argP:Pointer;argBuffer:PByte;argPosition:QWord;argLength:DWord):Integer; SysV_ABI_CDecl;
SceAvPlayerSizeFile=function(argP:Pointer):QWord; SysV_ABI_CDecl;
SceAvPlayerSizeFile =function(argP:Pointer):QWord; SysV_ABI_CDecl;
SceAvPlayerEventCallback=procedure(p:Pointer;argEventId:Integer;argSourceId:Integer;argEventData:Pointer); SysV_ABI_CDecl;
SceAvPlayerLogCallback=Pointer;
@ -233,11 +233,6 @@ type
end;
PSceAvPlayerSourceDetails=^SceAvPlayerSourceDetails;
TMemChunk=packed record
pData:Pointer;
fSize:Ptruint;
end;
TAvPlayerState=class
formatContext :PAVFormatContext;
audioCodecContext :PAVCodecContext;
@ -267,7 +262,14 @@ type
function Buffer(const aType:DWord;const chunk:TMemChunk):Pointer;
end;
TAvPlayerInfo=record
SceAvPlayerHandle=QWord;
PSceAvPlayerHandle=^SceAvPlayerHandle;
PAvPlayerInfo=^TAvPlayerInfo;
TAvPlayerInfo=object
handle :SceAvPlayerHandle;
lock :Pointer;
//
playerState :TAvPlayerState;
//
isLooped :Boolean;
@ -276,26 +278,181 @@ type
memoryReplacement:SceAvPlayerMemAllocator;
fileReplacement :SceAvPlayerFileReplacement;
eventReplacement :SceAvPlayerEventReplacement;
//
function Allocate (argAlignment:DWord;argSize:DWord):Pointer;
procedure Deallocate (argMemory:Pointer);
function AllocateTexture (argAlignment:DWord;argSize:DWord):Pointer;
procedure DeallocateTexture(argMemory:Pointer);
//
procedure EventCallback (argEventId:Integer;argSourceId:Integer;argEventData:Pointer);
//
Function FileReplacementProvided:Boolean;
function open (argFilename:PChar):Integer;
function close ():Integer;
function readOffset (argBuffer:PByte;argPosition:QWord;argLength:DWord):Integer;
function size ():QWord;
end;
PAvPlayerInfo=^TAvPlayerInfo;
// For now AvPlayer handle is pointer that points directly to player struct
SceAvPlayerHandle=PAvPlayerInfo;
PSceAvPlayerHandle=^SceAvPlayerHandle;
var
lock:Pointer;
hamt_lock :Pointer;
handleCount :QWord=0;
AvHandleHamt:TSTUB_HAMT64;
function GetTimeInUs:QWord; inline;
function _GetTimeInUs:QWord; inline;
begin
Result:=SwGetTimeUsec;
end;
procedure _AvPlayerEventCallback(const handle:SceAvPlayerHandle;const event:Integer;const eventData:Pointer);
function _GetPlayer(const handle:SceAvPlayerHandle):PAvPlayerInfo;
var
data:PPointer;
begin
if (handle<>nil) and (handle^.eventReplacement.eventCallback<>nil) then
Result:=nil;
spin_lock(hamt_lock);
data:=HAMT_search64(@AvHandleHamt,handle);
if (data<>nil) then
begin
Result:=data^;
spin_lock(Result^.lock); //acqure
end;
spin_unlock(hamt_lock);
end;
function _AddPlayer(const player:PAvPlayerInfo):SceAvPlayerHandle;
var
data:PPointer;
begin
spin_lock(hamt_lock);
Inc(handleCount);
data:=HAMT_insert64(@AvHandleHamt,handleCount,player);
Assert(data<>nil,'unexpected err');
//force reuse
data^:=player;
//save handle
player^.handle:=handleCount;
Result:=handleCount;
spin_unlock(hamt_lock);
end;
procedure _DeletePlayer(const handle:SceAvPlayerHandle);
var
data:PAvPlayerInfo;
begin
spin_lock(hamt_lock);
data:=HAMT_delete64(@AvHandleHamt,handle);
spin_unlock(hamt_lock);
if (data<>nil) then
begin
FreeMem(data);
end;
end;
procedure AvHandleClean(data,userdata:Pointer);
var
handle:SceAvPlayerHandle;
player:PAvPlayerInfo;
begin
if (data=nil) then Exit;
player:=data;
handle:=player^.handle;
Writeln('WARNING: Leftover AvPlayer handle, let me clean it up: ', handle);
FreeMem(player);
end;
function TAvPlayerInfo.Allocate(argAlignment:DWord;argSize:DWord):Pointer;
begin
Result:=memoryReplacement.allocate(memoryReplacement.objectPointer,argAlignment,argSize);
end;
procedure TAvPlayerInfo.Deallocate(argMemory:Pointer);
begin
memoryReplacement.Deallocate(memoryReplacement.objectPointer,argMemory);
end;
function TAvPlayerInfo.AllocateTexture(argAlignment:DWord;argSize:DWord):Pointer;
begin
Result:=memoryReplacement.AllocateTexture(memoryReplacement.objectPointer,argAlignment,argSize);
end;
procedure TAvPlayerInfo.DeallocateTexture(argMemory:Pointer);
begin
memoryReplacement.DeallocateTexture(memoryReplacement.objectPointer,argMemory);
end;
//
procedure TAvPlayerInfo.EventCallback(argEventId:Integer;argSourceId:Integer;argEventData:Pointer);
begin
if (eventReplacement.eventCallback<>nil) then
begin
eventReplacement.eventCallback(eventReplacement.objectPointer,argEventId,argSourceId,argEventData);
end;
end;
//
function _test_file_cbs(var m:SceAvPlayerFileReplacement):Boolean; inline;
begin
Result:=False;
if (m.open =nil) then Exit;
if (m.close =nil) then Exit;
if (m.readOffset=nil) then Exit;
if (m.size =nil) then Exit;
Result:=True;
end;
Function TAvPlayerInfo.FileReplacementProvided:Boolean;
begin
Result:=_test_file_cbs(fileReplacement);
end;
function TAvPlayerInfo.open(argFilename:PChar):Integer;
begin
Result:=0;
if (fileReplacement.open<>nil) then
begin
Result:=fileReplacement.open(fileReplacement.objectPointer,argFilename);
end;
end;
function TAvPlayerInfo.close():Integer;
begin
Result:=0;
if (fileReplacement.close<>nil) then
begin
Result:=fileReplacement.close(fileReplacement.objectPointer);
end;
end;
function TAvPlayerInfo.readOffset(argBuffer:PByte;argPosition:QWord;argLength:DWord):Integer;
begin
Result:=0;
if (fileReplacement.readOffset<>nil) then
begin
Result:=fileReplacement.readOffset(fileReplacement.objectPointer,argBuffer,argPosition,argLength);
end;
end;
function TAvPlayerInfo.size():QWord;
begin
Result:=0;
if (fileReplacement.size<>nil) then
begin
Result:=fileReplacement.size(fileReplacement.objectPointer);
end;
end;
procedure _AvPlayerEventCallback(const handle:SceAvPlayerHandle;const event:Integer;const eventData:Pointer);
var
player:PAvPlayerInfo;
begin
player:=_GetPlayer(handle);
if (player<>nil) then
begin
Writeln(SysLogPrefix,'AvPlayerEventCallback,event=',event);
handle^.eventReplacement.eventCallback(handle^.eventReplacement.objectPointer,0,event,eventData);
player^.EventCallback(handle,event,eventData);
spin_unlock(player^.lock); //release
end;
end;
@ -398,7 +555,7 @@ begin
FreeMem(audioBuffer[I]);
end;
if videoBuffer[I]<>nil then
playerInfo^.memoryReplacement.deallocateTexture(playerInfo^.memoryReplacement.objectPointer,videoBuffer[I]);
playerInfo^.DeallocateTexture(videoBuffer[I]);
end;
source:='';
formatContext:=nil;
@ -460,7 +617,7 @@ begin
Result:=Default(TMemChunk);
if (audioStreamId<0) or (not IsPlaying) then Exit;
frame:=av_frame_alloc;
Result.pData:=nil;
Result.pAddr:=nil;
while True do
begin
err:=avcodec_receive_frame(audioCodecContext,frame);
@ -473,19 +630,19 @@ begin
end;
//
if frame^.format<>Integer(AV_SAMPLE_FMT_FLTP) then
Writeln('Unknown audio format: ',frame^.format);
Writeln('ERROR: Unknown audio format: ',frame^.format);
lastAudioTimeStamp:=av_rescale_q(frame^.best_effort_timestamp,formatContext^.streams[audioStreamId]^.time_base,AV_TIME_BASE_Q);
channelCount:=frame^.channels;
sampleCount:=frame^.nb_samples;
sampleRate:=frame^.sample_rate;
Result.fSize:=sampleCount*channelCount*SizeOf(SmallInt);
GetMem(Result.pData,Result.fSize);
Result.nSize:=sampleCount*channelCount*SizeOf(SmallInt);
GetMem(Result.pAddr,Result.nSize);
for i:=0 to sampleCount-1 do
for j:=0 to channelCount-1 do
begin
fdata:=PSingle(frame^.data[j]);
pcmSample:=Floor(fdata[i]*High(SmallInt));
PSmallInt(Result.pData)[i*channelCount+j]:=pcmSample;
PSmallInt(Result.pAddr)[i*channelCount+j]:=pcmSample;
end;
break;
end;
@ -506,7 +663,7 @@ begin
Result:=Default(TMemChunk);
if (videoStreamId<0) or (not IsPlaying) then Exit;
frame:=av_frame_alloc;
Result.pData:=nil;
Result.pAddr:=nil;
while True do
begin
err:=avcodec_receive_frame(videoCodecContext,frame);
@ -519,12 +676,12 @@ begin
end;
//
if frame^.format<>Integer(AV_PIX_FMT_YUV420P) then
Writeln('Unknown video format: ',frame^.format);
Writeln('ERROR: Unknown video format: ',frame^.format);
lastVideoTimeStamp:=av_rescale_q(frame^.best_effort_timestamp,formatContext^.streams[videoStreamId]^.time_base,AV_TIME_BASE_Q);
Result.fSize:=videoCodecContext^.width*videoCodecContext^.height*3 div 2;
GetMem(Result.pData,Result.fSize);
Result.nSize:=videoCodecContext^.width*videoCodecContext^.height*3 div 2;
GetMem(Result.pAddr,Result.nSize);
p:=Result.pData;
p:=Result.pAddr;
for i:=0 to frame^.height-1 do
begin
Move(frame^.data[0][frame^.linesize[0]*i],p[0],frame^.width);
@ -564,25 +721,25 @@ begin
playerInfo:=info;
if aType=0 then
begin
if (chunk.pData<>nil) then
if (chunk.pAddr<>nil) then
begin
if (audioBuffer[0]<>nil) then
begin
FreeMem(audioBuffer[0]);
end;
audioBuffer[0]:=chunk.pData;
audioBuffer[0]:=chunk.pAddr;
end;
Exit(audioBuffer[0]);
end else
begin
if (chunk.pData<>nil) then
if (chunk.pAddr<>nil) then
begin
if videoBuffer[0]=nil then
begin
videoBuffer[0]:=playerInfo^.memoryReplacement.allocateTexture(playerInfo^.memoryReplacement.objectPointer,0,chunk.fSize);
videoBuffer[0]:=playerInfo^.AllocateTexture(0,chunk.nSize);
end;
Move(chunk.pData^,videoBuffer[0]^,chunk.fSize);
FreeMem(chunk.pData);
Move(chunk.pAddr^,videoBuffer[0]^,chunk.nSize);
FreeMem(chunk.pAddr);
end;
Exit(videoBuffer[0]);
end;
@ -599,27 +756,31 @@ begin
end;
function _sceAvPlayerInit(pInit:PSceAvPlayerInitData):SceAvPlayerHandle;
var
player:PAvPlayerInfo;
begin
Result:=nil;
Result:=0;
if (pInit=nil) then Exit;
if not _test_mem_alloc(pInit^.memoryReplacement) then
begin
Writeln(SysLogPrefix,'All allocators are required for AVPlayer Initialisation.');
Writeln(SysLogPrefix,'ERROR: All allocators are required for AVPlayer Initialisation.');
Exit;
end;
Writeln(SysLogPrefix,'sceAvPlayerInit');
New(Result);
Result^.playerState:=TAvPlayerState.Create;
Result^.playerState.info :=Result;
player:=AllocMem(SizeOf(TAvPlayerInfo)); //alloc and fill zero
Result^.memoryReplacement:=pInit^.memoryReplacement;
Result^.eventReplacement :=pInit^.eventReplacement;
Result^.fileReplacement :=pInit^.fileReplacement;
player^.playerState:=TAvPlayerState.Create;
player^.playerState.info :=player;
Result^.lastFrameTime :=GetTimeInUs;
player^.memoryReplacement:=pInit^.memoryReplacement;
player^.eventReplacement :=pInit^.eventReplacement;
player^.fileReplacement :=pInit^.fileReplacement;
player^.lastFrameTime :=_GetTimeInUs;
Result:=_AddPlayer(player);
end;
function ps4_sceAvPlayerInit(pInit:PSceAvPlayerInitData):SceAvPlayerHandle; SysV_ABI_CDecl;
@ -632,30 +793,31 @@ end;
function _sceAvPlayerInitEx(pInit:PSceAvPlayerInitDataEx;pHandle:PSceAvPlayerHandle):Integer;
var
handle:SceAvPlayerHandle;
player:PAvPlayerInfo;
begin
Result:=-1;
if (pInit=nil) or (pHandle=nil) then Exit;
if not _test_mem_alloc(pInit^.memoryReplacement) then
begin
Writeln(SysLogPrefix,'All allocators are required for AVPlayer Initialisation.');
Writeln(SysLogPrefix,'ERROR: All allocators are required for AVPlayer Initialisation.');
Exit;
end;
Writeln(SysLogPrefix,'sceAvPlayerInitEx');
New(handle);
handle^.playerState:=TAvPlayerState.Create;
handle^.playerState.info :=handle;
player:=AllocMem(SizeOf(TAvPlayerInfo)); //alloc and fill zero
handle^.memoryReplacement:=pInit^.memoryReplacement;
handle^.eventReplacement :=pInit^.eventReplacement;
handle^.fileReplacement :=pInit^.fileReplacement;
player^.playerState:=TAvPlayerState.Create;
player^.playerState.info :=player;
handle^.lastFrameTime :=GetTimeInUs;
player^.memoryReplacement:=pInit^.memoryReplacement;
player^.eventReplacement :=pInit^.eventReplacement;
player^.fileReplacement :=pInit^.fileReplacement;
pHandle^:=handle;
player^.lastFrameTime :=_GetTimeInUs;
pHandle^:=_AddPlayer(player);
Result:=0;
end;
@ -668,10 +830,19 @@ begin
end;
function ps4_sceAvPlayerPostInit(handle:SceAvPlayerHandle;pPostInit:PSceAvPlayerPostInitData):Integer; SysV_ABI_CDecl;
var
player:PAvPlayerInfo;
begin
player:=_GetPlayer(handle);
Result:=-1;
if (handle=nil) or (pPostInit=nil) then Exit;
if (player=nil) or (pPostInit=nil) then Exit;
Writeln(SysLogPrefix,'sceAvPlayerPostInit');
if (player<>nil) then
begin
spin_unlock(player^.lock); //release
end;
Result:=0;
end;
@ -679,79 +850,81 @@ function _sceAvPlayerAddSource(handle:SceAvPlayerHandle;argFilename:PChar):Integ
const
BUF_SIZE=512*1024;
var
player :PAvPlayerInfo;
fileSize,
bytesRemaining,
offset :QWord;
bytesRead :Integer;
actualBufSize :QWord;
buf :array[0..BUF_SIZE-1] of Byte;
p :Pointer;
f :THandle;
source :RawByteString;
begin
if DISABLE_FMV_HACK then
Exit(-1);
spin_lock(lock);
player:=_GetPlayer(handle);
// With file functions provided by client
if (handle<>nil) and (handle^.fileReplacement.open<>nil) and (handle^.fileReplacement.close<>nil)
and (handle^.fileReplacement.readOffset<>nil) and (handle^.fileReplacement.size<>nil) then
if (player<>nil) then
begin
p:=handle^.fileReplacement.objectPointer;
if handle^.fileReplacement.open(p,argFilename)<0 then
if player^.FileReplacementProvided then
begin
spin_unlock(lock);
Exit(-1);
end;
fileSize:=handle^.fileReplacement.size(p);
if (fileSize=0) then //result is uint64
begin
spin_unlock(lock);
Exit(-1);
end;
// Read data and write to dump directory
// TODO: Should cache the file so it can be reused later
Writeln('TODO: Should cache media file so it can be reused later: ',argFilename);
CreateDir(DIRECTORY_AVPLAYER_DUMP);
//
source:=DIRECTORY_AVPLAYER_DUMP+'/'+ExtractFileName(argFilename);
f:=FileCreate(source,fmOpenWrite);
//
bytesRemaining:=fileSize;
offset:=0;
while bytesRemaining>0 do
begin
actualBufSize:=Min(QWORD(BUF_SIZE),bytesRemaining);
bytesRead:=handle^.fileReplacement.readOffset(p,@buf[0],offset,actualBufSize);
if bytesRead<0 then
if player^.open(argFilename)<0 then
begin
handle^.fileReplacement.close(p);
spin_unlock(lock);
spin_unlock(player^.lock); //release
Exit(-1);
end;
FileWrite(f,buf,actualBufSize);
Dec(bytesRemaining,actualBufSize);
Inc(offset,actualBufSize);
end;
FileClose(f);
handle^.fileReplacement.close(p);
// Init player
handle^.playerState.CreateMedia(source);
Result:=0;
end else
// Without client-side file functions
begin
source:='';
Result:=parse_filename(argFilename,source);
if (Result=PT_FILE) then //only real files
begin
handle^.playerState.CreateMedia(source);
fileSize:=player^.size();
if (fileSize=0) then //result is uint64
begin
spin_unlock(player^.lock); //release
Exit(-1);
end;
// Read data and write to dump directory
// TODO: Should cache the file so it can be reused later
Writeln('TODO: Should cache media file so it can be reused later: ',argFilename);
CreateDir(DIRECTORY_AVPLAYER_DUMP);
//
source:=DIRECTORY_AVPLAYER_DUMP+'/'+ExtractFileName(argFilename);
f:=FileCreate(source,fmOpenWrite);
//
bytesRemaining:=fileSize;
offset:=0;
while bytesRemaining>0 do
begin
actualBufSize:=Min(QWORD(BUF_SIZE),bytesRemaining);
bytesRead:=player^.readOffset(@buf[0],offset,actualBufSize);
if bytesRead<0 then
begin
player^.close();
spin_unlock(player^.lock); //release
Exit(-1);
end;
FileWrite(f,buf,actualBufSize);
Dec(bytesRemaining,actualBufSize);
Inc(offset,actualBufSize);
end;
FileClose(f);
player^.close();
// Init player
player^.playerState.CreateMedia(source);
Result:=0;
end else
// Without client-side file functions
begin
Result:=-1;
source:='';
Result:=parse_filename(argFilename,source);
if (Result=PT_FILE) then //only real files
begin
player^.playerState.CreateMedia(source);
Result:=0;
end else
begin
Result:=-1;
end;
end;
spin_unlock(player^.lock); //release
end;
spin_unlock(lock);
end;
function ps4_sceAvPlayerAddSource(handle:SceAvPlayerHandle;argFilename:PChar):Integer; SysV_ABI_CDecl;
@ -771,7 +944,7 @@ begin
if sourceDetails^.sourceType=1 then
Writeln('Source type: MP4')
else
Writeln('Source type: Unknown ',sourceDetails^.sourceType);
Writeln('ERROR: Source type: Unknown ',sourceDetails^.sourceType);
Result:=_sceAvPlayerAddSource(handle,sourceDetails^.uri.name)
end else
begin
@ -782,50 +955,73 @@ begin
end;
function ps4_sceAvPlayerIsActive(handle:SceAvPlayerHandle): LongBool; SysV_ABI_CDecl;
var
player:PAvPlayerInfo;
begin
if DISABLE_FMV_HACK then
Exit(False);
Result:=True;
player:=_GetPlayer(handle);
//Writeln(SysLogPrefix,'sceAvPlayerIsActive');
if (handle=nil) or (not handle^.playerState.IsPlaying) then
Exit(False);
Exit(True);
if (player=nil) or (not player^.playerState.IsPlaying) then
Result:=False;
if (player<>nil) then
begin
spin_unlock(player^.lock); //release
end;
end;
function ps4_sceAvPlayerSetLooping(handle:SceAvPlayerHandle;loopFlag:LongBool):DWord; SysV_ABI_CDecl;
var
player:PAvPlayerInfo;
begin
if DISABLE_FMV_HACK then
Exit(0);
player:=_GetPlayer(handle);
Writeln(SysLogPrefix,'sceAvPlayerSetLooping');
Result:=0;
handle^.isLooped:=loopFlag;
if (player<>nil) then
begin
player^.isLooped:=loopFlag;
spin_unlock(player^.lock); //release
Result:=0;
end else
begin
Result:=-1;
end;
end;
function _sceAvPlayerGetAudioData(handle:SceAvPlayerHandle;frameInfo:PSceAvPlayerFrameInfo):LongBool;
var
audioData:TMemChunk;
player :PAvPlayerInfo;
begin
if DISABLE_FMV_HACK then
Exit(False);
player:=_GetPlayer(handle);
//Writeln(SysLogPrefix,'sceAvPlayerGetAudioData');
Result:=False;
if (frameInfo<>nil) and (handle<>nil) and (handle^.playerState.IsPlaying) and (not handle^.isPaused) then
if (frameInfo<>nil) and (player<>nil) and (player^.playerState.IsPlaying) and (not player^.isPaused) then
begin
audioData:=Default(TMemChunk);
spin_lock(lock);
audioData:=handle^.playerState.ReceiveAudio;
if (audioData.pData=nil) then
audioData:=player^.playerState.ReceiveAudio;
if (audioData.pAddr=nil) then
begin
spin_unlock(lock);
spin_unlock(player^.lock); //release
Exit(False);
end;
frameInfo^.timeStamp:=_usec2msec(handle^.playerState.lastAudioTimeStamp);
frameInfo^.details.audio.channelCount:=handle^.playerState.channelCount;
frameInfo^.details.audio.sampleRate:=handle^.playerState.sampleRate;
frameInfo^.details.audio.size:=handle^.playerState.channelCount*handle^.playerState.sampleCount*SizeOf(SmallInt);
frameInfo^.pData:=handle^.playerState.Buffer(0,audioData);
spin_unlock(lock);
frameInfo^.timeStamp:=_usec2msec(player^.playerState.lastAudioTimeStamp);
frameInfo^.details.audio.channelCount:=player^.playerState.channelCount;
frameInfo^.details.audio.sampleRate:=player^.playerState.sampleRate;
frameInfo^.details.audio.size:=player^.playerState.channelCount*player^.playerState.sampleCount*SizeOf(SmallInt);
frameInfo^.pData:=player^.playerState.Buffer(0,audioData);
Result:=True;
end;
if (player<>nil) then
begin
spin_unlock(player^.lock); //release
end;
end;
function ps4_sceAvPlayerGetAudioData(handle:SceAvPlayerHandle;frameInfo:PSceAvPlayerFrameInfo):LongBool; SysV_ABI_CDecl;
@ -838,35 +1034,40 @@ end;
function _sceAvPlayerGetVideoDataEx(handle:SceAvPlayerHandle;frameInfo:PSceAvPlayerFrameInfoEx):LongBool;
var
videoData:TMemChunk;
player :PAvPlayerInfo;
begin
if DISABLE_FMV_HACK then
Exit(False);
//Writeln(SysLogPrefix,'sceAvPlayerGetVideoDataEx');
player:=_GetPlayer(handle);
Result:=False;
if (frameInfo<>nil) and (handle<>nil) and (handle^.playerState.IsPlaying) then
if (frameInfo<>nil) and (player<>nil) and (player^.playerState.IsPlaying) then
begin
videoData:=Default(TMemChunk);
spin_lock(lock);
if handle^.playerState.lastVideoTimeStamp<handle^.playerState.lastAudioTimestamp then
if player^.playerState.lastVideoTimeStamp<=player^.playerState.lastAudioTimestamp then
repeat
handle^.lastFrameTime:=GetTimeInUs;
videoData:=handle^.playerState.ReceiveVideo;
until (videoData.pData=nil) or (handle^.playerState.lastVideoTimeStamp>=handle^.playerState.lastAudioTimeStamp); // Check to see if video catch up with current timestamp
if (videoData.pData=nil) then
player^.lastFrameTime:=_GetTimeInUs;
videoData:=player^.playerState.ReceiveVideo;
until (videoData.pAddr=nil) or (player^.playerState.lastVideoTimeStamp>=player^.playerState.lastAudioTimeStamp); // Check to see if video catch up with current timestamp
if (videoData.pAddr=nil) then
begin
spin_unlock(lock);
spin_unlock(player^.lock); //release
Exit(False);
end;
frameInfo^.timeStamp:=_usec2msec(handle^.playerState.lastVideoTimeStamp);
frameInfo^.details.video.width:=handle^.playerState.videoCodecContext^.width;
frameInfo^.details.video.height:=handle^.playerState.videoCodecContext^.height;
frameInfo^.details.video.aspectRatio:=handle^.playerState.videoCodecContext^.width/handle^.playerState.videoCodecContext^.height;
frameInfo^.timeStamp:=_usec2msec(player^.playerState.lastVideoTimeStamp);
frameInfo^.details.video.width:=player^.playerState.videoCodecContext^.width;
frameInfo^.details.video.height:=player^.playerState.videoCodecContext^.height;
frameInfo^.details.video.aspectRatio:=player^.playerState.videoCodecContext^.width/player^.playerState.videoCodecContext^.height;
frameInfo^.details.video.framerate:=0;
frameInfo^.details.video.languageCode:=LANGUAGE_CODE_ENG;
frameInfo^.pData:=handle^.playerState.Buffer(1,videoData);
spin_unlock(lock);
frameInfo^.pData:=player^.playerState.Buffer(1,videoData);
Result:=True;
end;
if (player<>nil) then
begin
spin_unlock(player^.lock); //release
end;
end;
function ps4_sceAvPlayerGetVideoDataEx(handle:SceAvPlayerHandle;frameInfo:PSceAvPlayerFrameInfoEx):LongBool; SysV_ABI_CDecl;
@ -884,24 +1085,36 @@ begin
end;
function ps4_sceAvPlayerCurrentTime(handle:SceAvPlayerHandle):QWord; SysV_ABI_CDecl;
var
player:PAvPlayerInfo;
begin
if DISABLE_FMV_HACK then
Exit(0);
if (handle=nil) or (not handle^.playerState.IsPlaying) then
player:=_GetPlayer(handle);
if (player=nil) or (not player^.playerState.IsPlaying) then
Result:=0
else
Result:=_usec2msec(handle^.playerState.lastVideoTimeStamp);
Result:=_usec2msec(player^.playerState.lastVideoTimeStamp);
if (player<>nil) then
begin
spin_unlock(player^.lock); //release
end;
end;
function _sceAvPlayerStop(handle:SceAvPlayerHandle):Integer;
var
player:PAvPlayerInfo;
begin
player:=_GetPlayer(handle);
Result:=-1;
if (handle<>nil) then
if (player<>nil) then
begin
handle^.playerState.FreeMedia;
player^.playerState.FreeMedia;
spin_unlock(player^.lock); //release
Result:=0;
end;
_AvPlayerEventCallback(handle,SCE_AVPLAYER_STATE_STOP,nil);
Result:=0;
end;
function ps4_sceAvPlayerStop(handle:SceAvPlayerHandle):Integer; SysV_ABI_CDecl;
@ -923,10 +1136,9 @@ end;
function _sceAvPlayerClose(handle:SceAvPlayerHandle):Integer;
begin
Result:=-1;
if (handle=nil) then Exit;
_sceAvPlayerStop(handle);
Dispose(handle);
_DeletePlayer(handle);
Result:=0;
end;
@ -934,6 +1146,7 @@ end;
function ps4_sceAvPlayerClose(handle:SceAvPlayerHandle):Integer; SysV_ABI_CDecl;
begin
_sig_lock;
Writeln(SysLogPrefix,'sceAvPlayerClose');
Result:=_sceAvPlayerClose(handle);
_sig_unlock;
end;
@ -963,6 +1176,11 @@ begin
end;
initialization
FillChar(AvHandleHamt,SizeOf(AvHandleHamt),0);
ps4_app.RegistredPreLoad('libSceAvPlayer.prx',@Load_libSceAvPlayer);
finalization
// Cleanup leftover handle. This should not happen, unless the game quit halfway or get memory leak somehow
HAMT_clear32(@AvHandleHamt,@AvHandleClean,nil);
end.

View File

@ -507,6 +507,7 @@ type
time_t=QWORD;
ptime_t=^time_t;
psize_t=^size_t;
TMemChunk=packed record
pAddr:Pointer;