From d5cf0ceae7fbbdb0ed21685e05c18541fb71675b Mon Sep 17 00:00:00 2001 From: brunzelchen Date: Mon, 7 Feb 2011 23:05:43 +0000 Subject: - 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 --- Game/Code/Classes/UVideo.pas | 698 +++++++++++++++++++++----------- Game/Code/UltraStar.bdsproj | 4 +- Game/Code/UltraStar.dpr | 2 +- Game/Code/lib/acinerella/acinerella.c | 44 +- Game/Code/lib/acinerella/acinerella.h | 1 + Game/Code/lib/acinerella/acinerella.pas | 1 + Game/Output/acinerella.dll | Bin 6093312 -> 5602304 bytes Installer/settings/variables.nsh | 2 +- 8 files changed, 517 insertions(+), 235 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 (mmfpsMAX) 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 @@ 1.0.0.0 - - - + Borland InterBase Express Components Intraweb 8.0 Design Package for Borland Development Studio 2006 Indy 10 Core Design Time 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. diff --git a/Game/Output/acinerella.dll b/Game/Output/acinerella.dll index dc16271d..62cc0444 100644 Binary files a/Game/Output/acinerella.dll and b/Game/Output/acinerella.dll differ diff --git a/Installer/settings/variables.nsh b/Installer/settings/variables.nsh index f634076f..7f064b01 100644 --- a/Installer/settings/variables.nsh +++ b/Installer/settings/variables.nsh @@ -1,7 +1,7 @@ ; These are the common used variables ; for the USdx Challenge, Medley & Duet Edition Installation Wizard -!define version "r9.7" ; Current version of UltraStar Deluxe Challenge, Medley & Duet Edition +!define version "r9.9" ; Current version of UltraStar Deluxe Challenge, Medley & Duet Edition !define p_name "UltraStar Deluxe CMD Edition" ; Just the name of the program !define publisher "USDX Team" ; Publisher !define homepage "http://www.ultrastardeluxe.org/" ; Project Homepage -- cgit v1.2.3