aboutsummaryrefslogtreecommitdiffstats
path: root/Game/Code
diff options
context:
space:
mode:
authorbrunzelchen <brunzelchen@b956fd51-792f-4845-bead-9b4dfca2ff2c>2011-02-07 23:05:43 +0000
committerbrunzelchen <brunzelchen@b956fd51-792f-4845-bead-9b4dfca2ff2c>2011-02-07 23:05:43 +0000
commitd5cf0ceae7fbbdb0ed21685e05c18541fb71675b (patch)
tree259d73f4418819a79901992eb9684c6134e147f0 /Game/Code
parent61be36a5af28943f27bd4a42f52fa4ca879adaa5 (diff)
downloadusdx-d5cf0ceae7fbbdb0ed21685e05c18541fb71675b.tar.gz
usdx-d5cf0ceae7fbbdb0ed21685e05c18541fb71675b.tar.xz
usdx-d5cf0ceae7fbbdb0ed21685e05c18541fb71675b.zip
- added "ac_drop_decode_video_package" - method to acinerella: decoding of a frame without scaling
- added threaded video decoding - added video frame buffer (50 frames) git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/branches/1.0.1 Challenge MOD@2803 b956fd51-792f-4845-bead-9b4dfca2ff2c
Diffstat (limited to 'Game/Code')
-rw-r--r--Game/Code/Classes/UVideo.pas698
-rw-r--r--Game/Code/UltraStar.bdsproj4
-rw-r--r--Game/Code/UltraStar.dpr2
-rw-r--r--Game/Code/lib/acinerella/acinerella.c44
-rw-r--r--Game/Code/lib/acinerella/acinerella.h1
-rw-r--r--Game/Code/lib/acinerella/acinerella.pas1
6 files changed, 516 insertions, 234 deletions
diff --git a/Game/Code/Classes/UVideo.pas b/Game/Code/Classes/UVideo.pas
index b89f5cc0..a93ee778 100644
--- a/Game/Code/Classes/UVideo.pas
+++ b/Game/Code/Classes/UVideo.pas
@@ -9,7 +9,6 @@
//{$define Info}
-
unit UVideo;
interface
@@ -29,13 +28,15 @@ uses SDL,
glu,
glext,
SysUtils,
+ SyncObjs,
{$ifdef DebugDisplay}
{$ifdef win32}
dialogs,
{$endif}
{$ENDIF}
UIni,
- UTime;
+ UTime,
+ windows;
type
TAspectCorrection = (acoStretch, acoCrop, acoLetterBox); //from 1.1
@@ -50,20 +51,43 @@ type
ZoomFaktor: real;
end;
+ TFrameBuffer = record
+ frame: Pointer;
+ time: Extended;
+ displayed: Boolean;
+ end;
+
+ TFrameThread = class(TThread)
+ private
+ Time: Extended;
+ Gap: Single;
+ Start: Single;
+
+ iSkip: Boolean;
+ waiting: Boolean;
+
+ procedure DoDecode;
+ procedure DoSkip;
+ procedure Copy;
+ procedure Update();
+ protected
+ constructor Create;
+ procedure Execute; override;
+ end;
+
procedure Init;
procedure acOpenFile(FileName: pAnsiChar);
procedure acClose;
procedure acGetFrame(Time: Extended);
-function acSearch(Time: Extended): integer;
procedure acDrawGL(Screen: integer; DoDraw: boolean);
procedure acDrawGLi(Screen: integer; Window: TRectCoords; Blend: real; DoDraw: boolean);
procedure acTogglePause;
-procedure acSkip(Gap: Single; Start: Single);
procedure acSkip2(Gap: Single; Start: Single);
procedure ToggleAspectCorrection;
procedure GetVideoRect(var ScreenRect, TexRect: TRectCoords; Window: TRectCoords);
procedure SetAspectCorrection(aspect: TAspectCorrection);
procedure ResetAspectCorrection;
+procedure UploadNewFrame;
Const
MIN_FPS = 40;
@@ -118,6 +142,19 @@ var
EnableVideoDraw: boolean;
+ FrameData: Pointer;
+ NewFrame: boolean;
+ SetTime: Extended;
+ SetGap: Single;
+ SetStart: Single;
+ SetSkip: boolean;
+
+ FrameThread: TFrameThread;
+
+ EventDecode: TEvent;
+ FrameBuffer: array [0..49] of TFrameBuffer;
+ MutexFramebuffer: PSDL_Mutex;
+ MutexSyncSignals: PSDL_Mutex;
implementation
@@ -133,10 +170,13 @@ end;
function seek_proc(sender: Pointer; pos: int64; whence: integer): int64; cdecl;
begin
- result := fs.Seek(pos, TSeekOrigin(whence))
+ result := fs.Seek(pos, TSeekOrigin(whence));
end;
procedure Init;
+var
+ i: integer;
+
begin
inst := nil;
videodecoder := nil;
@@ -161,6 +201,32 @@ begin
PIXEL_FORMAT := GL_RGBA;
EnableVideoDraw := true;
+
+ SetTime := 0;
+ if(FrameData<>nil) then
+ FreeMem(FrameData);
+ FrameData := nil;
+
+ for i := 0 to High(FrameBuffer) do
+ begin
+ if(FrameBuffer[i].frame <> nil) then
+ FreeMem(FrameBuffer[i].frame);
+ FrameBuffer[i].frame := nil;
+
+ FrameBuffer[i].time := -1;
+ FrameBuffer[i].displayed := true;
+ end;
+
+ if (FrameThread<>nil) then
+ begin
+ FrameThread.Terminate;
+ FrameThread.WaitFor;
+ FrameThread.Free;
+ FrameThread := nil;
+ end;
+
+ MutexFramebuffer := SDL_CreateMutex;
+ MutexSyncSignals := SDL_CreateMutex;
end;
procedure acOpenFile(FileName: pAnsiChar);
@@ -168,6 +234,7 @@ var
I: integer;
begin
+ acClose;
VideoPaused := False;
VideoTimeBase := 0;
@@ -175,7 +242,6 @@ begin
LastFrameTime := 0;
TimeDifference := 0;
Counter := 0;
- acClose;
if not FileExists(FileName) then
Exit; //TODO: error.log
@@ -234,6 +300,12 @@ begin
dataX := Round(Power(2, Ceil(Log2(TexX))));
dataY := Round(Power(2, Ceil(Log2(TexY))));
+ GetMem(FrameData, numBytes*TexX*TexY);
+ for I := 0 to high(FrameBuffer) do
+ begin
+ GetMem(FrameBuffer[I].frame, numBytes*TexX*TexY);
+ end;
+
// calculate some information for video display
VideoAspect:=videodecoder^.stream_info.additional_info.video_info.pixel_aspect;
if (VideoAspect = 0) then
@@ -268,11 +340,39 @@ begin
end;
mmfps := (MAX_FPS-MIN_FPS)/2;
+
+ SetTime := 0;
+ NewFrame := false;
+ SetSkip := false;
+
+ if (EventDecode = nil) then
+ EventDecode := TEvent.Create(nil, false, false, '');
+
+ if (FrameThread = nil) then
+ FrameThread := TFrameThread.Create();
+
+ FrameThread.Resume;
end;
procedure acClose;
+var
+ I: Integer;
+
begin
- if VideoOpened then begin
+ if VideoOpened then
+ begin
+ if (FrameThread<>nil) then
+ begin
+ FrameThread.Terminate;
+ FrameThread.WaitFor;
+ FrameThread.Free;
+ FrameThread := nil;
+ end;
+
+ FreeAndNil(EventDecode);
+
+ NewFrame := false;
+ SetSkip := false;
if videodecoder <> nil then
ac_free_decoder(videodecoder);
@@ -286,6 +386,20 @@ begin
VideoOpened:=False;
fName := '';
+
+ if(FrameData<>nil) then
+ FreeMem(FrameData);
+ FrameData := nil;
+
+ for I := 0 to High(FrameBuffer) do
+ begin
+ if(FrameBuffer[i].frame <> nil) then
+ FreeMem(FrameBuffer[i].frame);
+ FrameBuffer[i].frame := nil;
+
+ FrameBuffer[i].time := -1;
+ FrameBuffer[i].displayed := false;
+ end;
end;
end;
@@ -297,137 +411,46 @@ end;
procedure acSkip2(Gap: Single; Start: Single);
begin
- VideoSkiptime:=Gap;
- NegativeSkipTime:=Start+Gap;
- if Start+Gap > 0 then
- begin
- VideoTime:=Start+Gap;
- try
- ac_seek(videodecoder, -1, Floor((Start+Gap)*1000));
- except
- Log.LogError('Error seeking Video "acSkip2" on video ('+fName+')');
- acClose;
- end;
- end else
- begin
- try
- ac_seek(videodecoder, 0, 0);
- except
- Log.LogError('Error seeking Video "acSkip2" on video ('+fName+')');
- acClose;
- end;
- VideoTime:=0;
- end;
-end;
-
-procedure acSkip(Gap: Single; Start: Single);
-begin
- VideoSkiptime:=Gap;
- NegativeSkipTime:=Start+Gap;
- if Start+Gap > 0 then
- begin
- VideoTime:=0;
- ac_seek(videodecoder, -1, Floor((Start+Gap)*1000));
- if (acSearch(Gap+Start)=0) then
- begin
- ac_seek(videodecoder, 0, 0);
- VideoTime:=0;
- acSearch(Gap+Start);
- end;
- end else
- begin
- ac_seek(videodecoder, 0, 0);
- VideoTime:=0;
+ SDL_LockMutex(MutexSyncSignals);
+ try
+ SetGap := Gap;
+ SetStart := Start;
+ SetSkip := true;
+ finally
+ SDL_UnlockMutex(MutexSyncSignals);
end;
+ EventDecode.SetEvent;
end;
-function acSearch(Time: Extended): integer;
-var
- FrameFinished: Integer;
- errnum: Integer;
- FrameDataPtr: PByteArray;
- myTime: Extended;
-
+procedure acGetFrame(Time: Extended);
begin
- Result := 0;
- if not VideoOpened then Exit;
- if (NegativeSkipTime < 0)and(Time+NegativeSkipTime>=0) then
- NegativeSkipTime:=0;
-
- myTime:=Time+VideoSkipTime;
- TimeDifference:=myTime-VideoTime;
-
- if (VideoTime <> 0) and (TimeDifference <= VideoTimeBase) then begin
- Exit;// we don't need a new frame now
- end;
-
- pack := ac_read_package(inst);
- FrameFinished:=0;
- // read packets until we have a finished frame (or there are no more packets)
- while ((VideoTime < Time-VideoTimeBase)) and (pack <> nil) do
+ if (Time-SetTime>=0) or (SetTime>Time) then
begin
- // if we got a packet from the video stream, then decode it
- if (videodecoder^.stream_index = pack^.stream_index) then
- begin
- FrameFinished := ac_decode_package(pack, videodecoder);
- VideoTime := videodecoder^.timecode;
- ac_free_package(pack);
- if ((VideoTime < Time-VideoTimeBase)) then
- pack := ac_read_package(inst);
- end else
- begin
- ac_free_package(pack);
- pack := ac_read_package(inst);
- end;
- end;
- if (pack<>nil) then
- ac_free_package(pack);
-
- // if we did not get an new frame, there's nothing more to do
- if Framefinished=0 then
- begin
- Exit;
- end;
-
- errnum:=1; //TODO!!
- if errnum >=0 then begin
- FrameDataPtr:=Pointer(videodecoder^.buffer);
- Result := 1;
- glBindTexture(GL_TEXTURE_2D, VideoTex);
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, TexX, TexY, PIXEL_FORMAT, GL_UNSIGNED_BYTE, @FrameDataPtr[0]);
-
- if Ini.Debug = 1 then
- begin
- //frame decode debug display
- GoldenRec.Spawn(200,85,1,16,0,-1,ColoredStar,$ffff00,0);
+ SDL_LockMutex(MutexSyncSignals);
+ try
+ SetTime := Time;
+ finally
+ SDL_UnlockMutex(MutexSyncSignals);
end;
-
+ UploadNewFrame();
+ EventDecode.SetEvent;
end;
end;
-procedure acGetFrame(Time: Extended);
+procedure TFrameThread.DoDecode;
Const
MAX = 3000;
+ FRAMEDROPCOUNT=4;
var
FrameFinished: Integer;
- errnum: Integer;
- FrameDataPtr: PByteArray;
- FrameDataPtr2: PByteArray;
myTime: Extended;
DropFrame: Boolean;
droppedFrames: Integer;
I: Integer;
- glError: glEnum;
- glErrorStr: String;
-const
- FRAMEDROPCOUNT=3;
begin
- if not VideoOpened then Exit;
- if VideoPaused then Exit;
-
- mmfps := (Display.mFPS+mmfps)/2;
+ {mmfps := (Display.mFPS+mmfps)/2;
if(Ini.PerformanceMode=1) then
begin
if (mmfps<MIN_FPS) then
@@ -454,45 +477,31 @@ begin
end;
if (Counter>MAX) then
- Counter := MAX;
+ Counter := MAX;}
if (NegativeSkipTime < 0)and(Time+NegativeSkipTime>=0) then NegativeSkipTime:=0;
myTime:=Time+VideoSkipTime;
TimeDifference:=myTime-VideoTime;
- if Ini.Debug = 1 then
- begin
- timediff_str:= 't-diff: ' + FormatFloat('#0.00', TimeDifference);
- mtime_str:= 'mytime: ' + FormatFloat('#0.00', myTime);
- end;
-
DropFrame:=False;
- if (VideoTime <> 0) and (TimeDifference <= VideoTimeBase) then begin
- if Ini.Debug = 1 then
- begin
- // frame delay debug display
- GoldenRec.Spawn(200,65,1,16,0,-1,ColoredStar,$00ff00,0);
- end;
- Exit;// we don't need a new frame now
- end;
-
- if TimeDifference >= (FRAMEDROPCOUNT-1)*VideoTimeBase then begin // skip frames
- if Ini.Debug = 1 then
- begin
- //frame drop debug display
- GoldenRec.Spawn(200,105,1,16,0,-1,ColoredStar,$ff0000,0);
- end;
-
+ if TimeDifference >= (FRAMEDROPCOUNT-1)*VideoTimeBase then
+ begin // skip frames
DropFrame:=True;
end;
+ if terminated then
+ Exit;
+
pack := ac_read_package(inst);
FrameFinished:=0;
// read packets until we have a finished frame (or there are no more packets)
- while (FrameFinished=0) and (pack <> nil) do
+ while (FrameFinished=0) and (pack <> nil) and not DropFrame do
begin
+ if terminated then
+ Exit;
+
// if we got a packet from the video stream, then decode it
if (videodecoder^.stream_index = pack^.stream_index) then
begin
@@ -510,15 +519,51 @@ begin
if DropFrame then
begin
- //acSearch(Time);
- for droppedFrames:=1 to FRAMEDROPCOUNT do
+ for droppedFrames:=1 to FRAMEDROPCOUNT-1 do
begin
- pack := ac_read_package(inst);
+ if terminated then
+ Exit;
+
+ if (droppedFrames>1) then
+ pack := ac_read_package(inst);
FrameFinished:=0;
// read packets until we have a finished frame (or there are no more packets)
while (FrameFinished=0) and (pack <> nil) do
begin
- // if we got a packet from the video stream, then decode it
+ if terminated then
+ Exit;
+
+ // if we got a packet from the video stream, then decode it (without scaling)
+ if (videodecoder^.stream_index = pack^.stream_index) then
+ begin
+ FrameFinished := ac_drop_decode_package(pack, videodecoder);
+ ac_free_package(pack);
+ if (FrameFinished=0) then
+ pack := ac_read_package(inst);
+ end else
+ begin
+ ac_free_package(pack);
+ pack := ac_read_package(inst);
+ end;
+ end;
+ end;
+
+ for I:=droppedFrames to FRAMEDROPCOUNT do
+ begin
+ if terminated then
+ Exit;
+
+ if (droppedFrames>1) then
+ pack := ac_read_package(inst);
+
+ FrameFinished:=0;
+ // read packets until we have a finished frame (or there are no more packets)
+ while (FrameFinished=0) and (pack <> nil) do
+ begin
+ if terminated then
+ Exit;
+
+ // if we got a packet from the video stream, then decode it (with scaling)
if (videodecoder^.stream_index = pack^.stream_index) then
begin
FrameFinished := ac_decode_package(pack, videodecoder);
@@ -536,108 +581,160 @@ begin
// if we did not get an new frame, there's nothing more to do
if Framefinished=0 then
- begin
-// GoldenRec.Spawn(220,15,1,16,0,-1,ColoredStar,$0000ff);
- acClose;
Exit;
- end;
- errnum:=1; //TODO!!
- if errnum >=0 then
- begin
- if(not pbo_supported) then
- begin
- FrameDataPtr:=Pointer(videodecoder^.buffer);
+ //cope the decoded frame into buffer
+ Copy;
+end;
- glBindTexture(GL_TEXTURE_2D, VideoTex);
+procedure TFrameThread.Copy();
+var
+ num: Integer;
+ FrameDataPtr: PByteArray;
+ FrameDataPtr2: PByteArray;
+ I: Integer;
- if(SkipLines>0)then
- begin
- for I := 0 to TexY - 1 do
- begin
- if(I mod (SkipLines+1) = 0) then
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, (I div (SkipLines+1)), TexX, 1,
- PIXEL_FORMAT, GL_UNSIGNED_BYTE, @FrameDataPtr[I*numBytes*TexX]);
- end;
- end else
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, TexX, TexY,
- PIXEL_FORMAT, GL_UNSIGNED_BYTE, @FrameDataPtr[0]);
+begin
+ num := -1;
+ SDL_LockMutex(MutexFramebuffer);
+ try
+ for I := 0 to high(FrameBuffer) do
+ begin
+ if FrameBuffer[I].displayed then
+ begin
+ num := I;
+ break;
+ end;
+ end;
+
+ if (num = -1) then
+ begin
+ waiting := true;
end else
begin
- glGetError();
- glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo);
+ FrameDataPtr := FrameBuffer[num].frame;
+ FrameBuffer[num].time := VideoTime;
+ FrameBuffer[num].displayed := false;
- glError := glGetError;
- if glError <> GL_NO_ERROR then
- begin
- acClose;
- Log.LogError('Error drawing Video "glBindBuffer"');
- Exit;
- end;
+ FrameDataPtr2:=Pointer(videodecoder^.buffer);
- FrameDataPtr := glMapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY);
- glError := glGetError;
- if glError <> GL_NO_ERROR then
- begin
- acClose;
- Log.LogError('Error drawing Video pbo "glMapBuffer"');
- Exit;
- end;
+ if terminated then
+ Exit;
- FrameDataPtr2:=Pointer(videodecoder^.buffer);
move(FrameDataPtr2[0], FrameDataPtr[0], numBytes*TexX*TexY);
- glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB);
- glError := glGetError;
- if glError <> GL_NO_ERROR then
- begin
- acClose;
- Log.LogError('Error drawing Video pbo "glUnmapBuffer"');
- Exit;
- end;
+ VideoTime := videodecoder^.timecode;
+
+ waiting := false;
+ end;
+ finally
+ SDL_UnLockMutex(MutexFramebuffer);
+ end;
+end;
- glBindTexture(GL_TEXTURE_2D, VideoTex);
- glError := glGetError;
- if glError <> GL_NO_ERROR then
- begin
- acClose;
- Log.LogError('Error drawing Video pbo "glBindTexture"');
- Exit;
- end;
+procedure TFrameThread.DoSkip;
+var
+ SkipTime: Extended;
+ I: Integer;
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, TexX, TexY,
- PIXEL_FORMAT, GL_UNSIGNED_BYTE, nil);
+begin
+ SDL_LockMutex(MutexSyncSignals);
+ try
+ VideoSkiptime:=Gap;
+ NegativeSkipTime:=Start+Gap;
+ SkipTime := Start+Gap;
+ finally
+ SDL_UnlockMutex(MutexSyncSignals);
+ end;
- glError := glGetError;
- if glError <> GL_NO_ERROR then
- begin
- acClose;
- case glError of
- GL_INVALID_ENUM: glErrorStr:='INVALID_ENUM';
- GL_INVALID_VALUE: glErrorStr:='INVALID_VALUE';
- GL_INVALID_OPERATION: glErrorStr:='INVALID_OPERATION';
- GL_STACK_OVERFLOW: glErrorStr:='STACK_OVERFLOW';
- GL_STACK_UNDERFLOW: glErrorStr:='STACK_UNDERFLOW';
- GL_OUT_OF_MEMORY: glErrorStr:='OUT_OF_MEMORY';
- else glErrorStr:='unknown error';
- end;
- Log.LogError('Error drawing Video pbo "glTexSubImage2D" ('+glErrorStr+')');
- Exit;
- end;
- glBindTexture(GL_TEXTURE_2D, 0);
- glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
+ if SkipTime > 0 then
+ begin
+ VideoTime:=SkipTime;
+ try
+ ac_seek(videodecoder, -1, Floor((SkipTime)*1000));
+ except
+ Log.LogError('Error seeking Video "acSkip2" on video ('+fName+')');
end;
- VideoTime := videodecoder^.timecode;
-
- if Ini.Debug = 1 then
- begin
- //frame decode debug display
- GoldenRec.Spawn(200,85,1,16,0,-1,ColoredStar,$ffff00,0);
+ end else
+ begin
+ try
+ ac_seek(videodecoder, 0, 0);
+ except
+ Log.LogError('Error seeking Video "acSkip2" on video ('+fName+')');
end;
+ VideoTime:=0;
+ end;
+
+ waiting := false;
+ SDL_LockMutex(MutexFramebuffer);
+ try
+ for I := 0 to High(FrameBuffer) do
+ begin
+ FrameBuffer[i].time := -1;
+ FrameBuffer[i].displayed := true;
+ end;
+ finally
+ SDL_UnLockMutex(MutexFramebuffer);
end;
end;
+constructor TFrameThread.Create;
+begin
+ inherited Create(true);
+ Self.Priority := tpNormal;
+ Self.FreeOnTerminate := false;
+
+ Time := 0;
+ iSkip := false;
+ waiting := false;
+
+ Self.Resume;
+end;
+
+procedure TFrameThread.Execute;
+begin
+ while not terminated do
+ begin
+ if (EventDecode.WaitFor(1) = wrSignaled) or not waiting then
+ begin
+ try
+ if iSkip then
+ begin
+ DoSkip;
+ iSkip := false;
+ end;
+
+ if not waiting then
+ DoDecode();
+
+ if waiting then
+ Copy();
+ except
+
+ end;
+ end;
+ if not terminated then
+ Update;
+ end;
+end;
+
+procedure TFrameThread.Update;
+begin
+ SDL_LockMutex(MutexSyncSignals);
+ try
+ Time := SetTime;
+ if (SetSkip) then
+ iSkip := true;
+
+ SetSkip := false;
+ Gap := SetGap;
+ Start := SetStart;
+ finally
+ SDL_UnlockMutex(MutexSyncSignals);
+ end;
+ end;
+
procedure ToggleAspectCorrection();
begin
case fAspectCorrection of
@@ -770,6 +867,149 @@ begin
acDrawGLi(Screen, Window, 1, DoDraw);
end;
+procedure UploadNewFrame;
+var
+ FrameDataPtr: PByteArray;
+ FrameDataPtr2: PByteArray;
+ I: Integer;
+ glError: glEnum;
+ glErrorStr: String;
+ num: Integer;
+
+ function FindFrame(): Integer;
+ var
+ I: Integer;
+ diff, td: Extended;
+ begin
+ Result := -1;
+ diff := 10000000;
+
+ for I := 0 to high(FrameBuffer) do
+ begin
+ td := SetTime + VideoSkipTime - FrameBuffer[I].time;
+ if not FrameBuffer[I].displayed and (td < diff) and
+ (td > VideoTimeBase) then
+ begin
+ diff := Abs(FrameBuffer[I].time - SetTime - VideoSkipTime);
+ Result := I;
+ end;
+
+ if (td > VideoTimeBase*2) then
+ FrameBuffer[I].displayed := true;
+ end;
+
+ if (Result<>-1) then
+ FrameBuffer[Result].displayed := true
+ end;
+
+begin
+ if VideoOpened then
+ begin
+ if (not pbo_supported) then
+ begin
+ SDL_LockMutex(MutexFramebuffer);
+ try
+ num := FindFrame();
+
+ if (num>=0) then
+ begin
+ FrameDataPtr:=FrameBuffer[num].frame;
+
+ glBindTexture(GL_TEXTURE_2D, VideoTex);
+
+ if(SkipLines>0)then
+ begin
+ for I := 0 to TexY - 1 do
+ begin
+ if(I mod (SkipLines+1) = 0) then
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, (I div (SkipLines+1)), TexX, 1,
+ PIXEL_FORMAT, GL_UNSIGNED_BYTE, @FrameDataPtr[I*numBytes*TexX]);
+ end;
+ end else
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, TexX, TexY,
+ PIXEL_FORMAT, GL_UNSIGNED_BYTE, @FrameDataPtr[0]);
+ end;
+ finally
+ SDL_UnLockMutex(MutexFramebuffer);
+ end;
+ end else
+ begin
+ glGetError();
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo);
+
+ glError := glGetError;
+ if glError <> GL_NO_ERROR then
+ begin
+ acClose;
+ Log.LogError('Error drawing Video "glBindBuffer"');
+ Exit;
+ end;
+
+ FrameDataPtr := glMapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY);
+ glError := glGetError;
+ if glError <> GL_NO_ERROR then
+ begin
+ acClose;
+ Log.LogError('Error drawing Video pbo "glMapBuffer"');
+ Exit;
+ end;
+
+ SDL_LockMutex(MutexFramebuffer);
+ try
+ num := FindFrame();
+ if (num>=0) then
+ begin
+ FrameDataPtr2:=FrameBuffer[num].frame;
+ move(FrameDataPtr2[0], FrameDataPtr[0], numBytes*TexX*TexY);
+ end;
+ finally
+ SDL_UnLockMutex(MutexFramebuffer);
+ end;
+
+ glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB);
+ glError := glGetError;
+ if glError <> GL_NO_ERROR then
+ begin
+ acClose;
+ Log.LogError('Error drawing Video pbo "glUnmapBuffer"');
+ Exit;
+ end;
+
+ glBindTexture(GL_TEXTURE_2D, VideoTex);
+ glError := glGetError;
+ if glError <> GL_NO_ERROR then
+ begin
+ acClose;
+ Log.LogError('Error drawing Video pbo "glBindTexture"');
+ Exit;
+ end;
+
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, TexX, TexY,
+ PIXEL_FORMAT, GL_UNSIGNED_BYTE, nil);
+
+ glError := glGetError;
+ if glError <> GL_NO_ERROR then
+ begin
+ acClose;
+ case glError of
+ GL_INVALID_ENUM: glErrorStr:='INVALID_ENUM';
+ GL_INVALID_VALUE: glErrorStr:='INVALID_VALUE';
+ GL_INVALID_OPERATION: glErrorStr:='INVALID_OPERATION';
+ GL_STACK_OVERFLOW: glErrorStr:='STACK_OVERFLOW';
+ GL_STACK_UNDERFLOW: glErrorStr:='STACK_UNDERFLOW';
+ GL_OUT_OF_MEMORY: glErrorStr:='OUT_OF_MEMORY';
+ else glErrorStr:='unknown error';
+ end;
+ Log.LogError('Error drawing Video pbo "glTexSubImage2D" ('+glErrorStr+')');
+ Exit;
+ end;
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
+ end;
+ EventDecode.SetEvent;
+ end;
+end;
+
procedure acDrawGLi(Screen: integer; Window: TRectCoords; Blend: real; DoDraw: boolean);
var
ScreenRect, TexRect: TRectCoords;
@@ -947,7 +1187,7 @@ begin
SetFontItalic(False);
SetFontSize(7);
SetFontPos (5, 50);
- glPrint(PChar('vtime: ' + FormatFloat('#0.00', VideoTime)));
+ glPrint(PChar('tdiff: ' + FormatFloat('#0.00', TimeDifference)));
SetFontPos (5, 65);
glPrint(PChar(timediff_str));
diff --git a/Game/Code/UltraStar.bdsproj b/Game/Code/UltraStar.bdsproj
index 2f94b78a..36df4a05 100644
--- a/Game/Code/UltraStar.bdsproj
+++ b/Game/Code/UltraStar.bdsproj
@@ -170,9 +170,7 @@
<VersionInfoKeys Name="ProductName"></VersionInfoKeys>
<VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys>
<VersionInfoKeys Name="Comments"></VersionInfoKeys>
- </VersionInfoKeys>
-
- <Excluded_Packages>
+ </VersionInfoKeys> <Excluded_Packages>
<Excluded_Packages Name="c:\program files\borland\bds\4.0\Bin\dclib100.bpl">Borland InterBase Express Components</Excluded_Packages>
<Excluded_Packages Name="c:\program files\borland\bds\4.0\Bin\dclIntraweb_80_100.bpl">Intraweb 8.0 Design Package for Borland Development Studio 2006</Excluded_Packages>
<Excluded_Packages Name="c:\program files\borland\bds\4.0\Bin\dclIndyCore100.bpl">Indy 10 Core Design Time</Excluded_Packages>
diff --git a/Game/Code/UltraStar.dpr b/Game/Code/UltraStar.dpr
index ba63c085..efdb9017 100644
--- a/Game/Code/UltraStar.dpr
+++ b/Game/Code/UltraStar.dpr
@@ -123,7 +123,7 @@ uses
const
VersionName = 'UltraStar Deluxe Challenge, Medley & Duet Edition';
- VersionNumber = 'r9.7';
+ VersionNumber = 'r9.9';
var
WndTitle: string;
diff --git a/Game/Code/lib/acinerella/acinerella.c b/Game/Code/lib/acinerella/acinerella.c
index 5b0178e4..d807ec4f 100644
--- a/Game/Code/lib/acinerella/acinerella.c
+++ b/Game/Code/lib/acinerella/acinerella.c
@@ -680,7 +680,7 @@ int ac_decode_video_package(lp_ac_package pPackage, lp_ac_video_decoder pDecoder
pDecoder->pSwsCtx = sws_getCachedContext(pDecoder->pSwsCtx,
pDecoder->pCodecCtx->width, pDecoder->pCodecCtx->height, pDecoder->pCodecCtx->pix_fmt,
pDecoder->pCodecCtx->width, pDecoder->pCodecCtx->height, convert_pix_format(pDecoder->decoder.pacInstance->output_format),
- SWS_BICUBIC, NULL, NULL, NULL);
+ SWS_FAST_BILINEAR, NULL, NULL, NULL);
sws_scale(
pDecoder->pSwsCtx,
@@ -780,6 +780,48 @@ int CALL_CONVT ac_decode_package(lp_ac_package pPackage, lp_ac_decoder pDecoder)
return 0;
}
+int CALL_CONVT ac_drop_decode_package(lp_ac_package pPackage, lp_ac_decoder pDecoder) {
+ if (pDecoder->type == AC_DECODER_TYPE_VIDEO) {
+ return ac_drop_decode_video_package(pPackage, (lp_ac_video_decoder)pDecoder, pDecoder);
+ }
+ return 0;
+}
+
+int ac_drop_decode_video_package(lp_ac_package pPackage, lp_ac_video_decoder pDecoder, lp_ac_decoder pDec) {
+ int finished;
+ double pts;
+
+ avcodec_decode_video2(
+ pDecoder->pCodecCtx, pDecoder->pFrame, &finished,
+ &(((lp_ac_package_data)pPackage)->ffpackage));
+
+ if (finished) {
+ pts=0;
+ global_video_pkt_pts = ((lp_ac_package_data)pPackage)->ffpackage.pts;
+
+ if(((lp_ac_package_data)pPackage)->ffpackage.dts == AV_NOPTS_VALUE &&
+ *(uint64_t*)pDecoder->pFrame->opaque != AV_NOPTS_VALUE ){
+ pts = *(uint64_t*)pDecoder->pFrame->opaque;
+ } else if(((lp_ac_package_data)pPackage)->ffpackage.dts != AV_NOPTS_VALUE){
+ pts = ((lp_ac_package_data)pPackage)->ffpackage.dts;
+ } else {
+ pts = 0;
+ }
+
+ if(((lp_ac_data)pDec->pacInstance)->pFormatCtx->streams[pPackage->stream_index]->start_time != AV_NOPTS_VALUE){
+ pts -= ((lp_ac_data)pDec->pacInstance)->pFormatCtx->streams[pPackage->stream_index]->start_time;
+ }
+
+ pts *= av_q2d(((lp_ac_data)pDec->pacInstance)->pFormatCtx->streams[pPackage->stream_index]->time_base);
+
+ pts = ac_sync_video(pPackage, pDec, pDecoder->pFrame, pts);
+ pDec->timecode = pts;
+
+ return 1;
+ }
+ return 0;
+}
+
//Seek function
int CALL_CONVT ac_seek(lp_ac_decoder pDecoder, int dir, int64_t target_pos) {
AVRational timebase =
diff --git a/Game/Code/lib/acinerella/acinerella.h b/Game/Code/lib/acinerella/acinerella.h
index 9eded573..a568b84c 100644
--- a/Game/Code/lib/acinerella/acinerella.h
+++ b/Game/Code/lib/acinerella/acinerella.h
@@ -241,6 +241,7 @@ extern void CALL_CONVT ac_free_decoder(lp_ac_decoder pDecoder);
/*Decodes a package using the specified decoder. The decodec data is stored in the
"buffer" property of the decoder.*/
extern int CALL_CONVT ac_decode_package(lp_ac_package pPackage, lp_ac_decoder pDecoder);
+extern int CALL_CONVT ac_drop_decode_package(lp_ac_package pPackage, lp_ac_decoder pDecoder);
/*Seeks to the given target position in the file. The seek funtion is not able to seek a single audio/video stream
but seeks the whole file forward. The stream number paremter (nb) is only used for the timecode reference.
diff --git a/Game/Code/lib/acinerella/acinerella.pas b/Game/Code/lib/acinerella/acinerella.pas
index 2d267027..316204c2 100644
--- a/Game/Code/lib/acinerella/acinerella.pas
+++ b/Game/Code/lib/acinerella/acinerella.pas
@@ -237,6 +237,7 @@ procedure ac_free_decoder(pDecoder: PAc_decoder); cdecl; external ac_dll;
{Decodes a package using the specified decoder. The decodec data is stored in the
"buffer" property of the decoder.}
function ac_decode_package(pPackage: PAc_package; pDecoder: PAc_decoder): integer; cdecl; external ac_dll;
+function ac_drop_decode_package(pPackage: PAc_package; pDecoder: PAc_decoder): integer; cdecl; external ac_dll;
{Seeks to the given target position in the file. The seek funtion is not able to seek a single audio/video stream
but seeks the whole file forward. The deocder parameter is only used as an timecode reference.