From 868ce765441473e7d1fec9b3ad22a707f121a637 Mon Sep 17 00:00:00 2001 From: tobigun Date: Wed, 21 Apr 2010 18:27:36 +0000 Subject: - add video loop option - allow multiple instances of a video git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@2260 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/media/UVideo.pas | 162 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 103 insertions(+), 59 deletions(-) (limited to 'src/media/UVideo.pas') diff --git a/src/media/UVideo.pas b/src/media/UVideo.pas index 27f29f7e..fd3c7e2a 100644 --- a/src/media/UVideo.pas +++ b/src/media/UVideo.pas @@ -107,11 +107,15 @@ type Upper, Lower: double; end; - TVideoPlayback_FFmpeg = class( TInterfacedObject, IVideoPlayback ) + IVideo_FFmpeg = interface (IVideo) + ['{E640E130-C8C0-4399-AF02-67A3569313AB}'] + function Open(const FileName: IPath): boolean; + end; + + TVideo_FFmpeg = class( TInterfacedObject, IVideo_FFmpeg ) private fOpened: boolean; //**< stream successfully opened fPaused: boolean; //**< stream paused - fInitialized: boolean; fEOF: boolean; //**< end-of-file state fLoop: boolean; //**< looping enabled @@ -150,23 +154,37 @@ type procedure ShowDebugInfo(); public - function GetName: String; + constructor Create; + destructor Destroy; override; + + function Open(const FileName: IPath): boolean; + procedure Close; - function Init(): boolean; - function Finalize: boolean; + procedure Play; + procedure Pause; + procedure Stop; + + procedure SetLoop(Enable: boolean); + function GetLoop(): boolean; + + procedure SetPosition(Time: real); + function GetPosition: real; + + procedure GetFrame(Time: Extended); + procedure DrawGL(Screen: integer); + end; - function Open(const FileName : IPath): boolean; // true if succeed - procedure Close; + TVideoPlayback_FFmpeg = class( TInterfacedObject, IVideoPlayback ) + private + fInitialized: boolean; - procedure Play; - procedure Pause; - procedure Stop; + public + function GetName: String; - procedure SetPosition(Time: real); - function GetPosition: real; + function Init(): boolean; + function Finalize: boolean; - procedure GetFrame(Time: Extended); - procedure DrawGL(Screen: integer); + function Open(const FileName : IPath): IVideo; end; var @@ -219,47 +237,46 @@ begin FFmpegCore := TMediaCore_FFmpeg.GetInstance(); - Reset(); av_register_all(); - glGenTextures(1, PGLuint(@fFrameTex)); end; function TVideoPlayback_FFmpeg.Finalize(): boolean; begin - Close(); - glDeleteTextures(1, PGLuint(@fFrameTex)); Result := true; end; -procedure TVideoPlayback_FFmpeg.Reset(); +function TVideoPlayback_FFmpeg.Open(const FileName : IPath): IVideo; +var + Video: IVideo_FFmpeg; begin - // close previously opened video - Close(); + Video := TVideo_FFmpeg.Create; + if Video.Open(FileName) then + Result := Video + else + Result := nil; +end; - fOpened := False; - fPaused := False; - fTimeBase := 0; - fTime := 0; - fStream := nil; - fStreamIndex := -1; - fFrameTexValid := false; - fEOF := false; +{* TVideo_FFmpeg *} - // TODO: do we really want this by default? - fLoop := true; - fLoopTime := 0; +constructor TVideo_FFmpeg.Create; +begin + glGenTextures(1, PGLuint(@fFrameTex)); + Reset(); +end; - fAspectCorrection := acoCrop; +destructor TVideo_FFmpeg.Destroy; +begin + Close(); + glDeleteTextures(1, PGLuint(@fFrameTex)); end; -function TVideoPlayback_FFmpeg.Open(const FileName : IPath): boolean; // true if succeed +function TVideo_FFmpeg.Open(const FileName : IPath): boolean; var errnum: Integer; AudioStreamIndex: integer; begin Result := false; - Reset(); // use custom 'ufile' protocol for UTF-8 support @@ -408,6 +425,7 @@ begin end; {$ENDIF} + fTexWidth := Round(Power(2, Ceil(Log2(fCodecContext^.width)))); fTexHeight := Round(Power(2, Ceil(Log2(fCodecContext^.height)))); @@ -420,11 +438,32 @@ begin glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - fOpened := True; + fOpened := true; Result := true; end; -procedure TVideoPlayback_FFmpeg.Close; +procedure TVideo_FFmpeg.Reset(); +begin + // close previously opened video + Close(); + + fOpened := False; + fPaused := False; + fTimeBase := 0; + fTime := 0; + fStream := nil; + fStreamIndex := -1; + fFrameTexValid := false; + + fEOF := false; + + fLoop := false; + fLoopTime := 0; + + fAspectCorrection := acoCrop; +end; + +procedure TVideo_FFmpeg.Close; begin if (fFrameBuffer <> nil) then av_free(fFrameBuffer); @@ -457,7 +496,7 @@ begin fOpened := False; end; -procedure TVideoPlayback_FFmpeg.SynchronizeTime(Frame: PAVFrame; var pts: double); +procedure TVideo_FFmpeg.SynchronizeTime(Frame: PAVFrame; var pts: double); var FrameDelay: double; begin @@ -484,7 +523,7 @@ end; * @param pts will be updated to the presentation time of the decoded frame. * returns true if a frame could be decoded. False if an error or EOF occured. *} -function TVideoPlayback_FFmpeg.DecodeFrame(): boolean; +function TVideo_FFmpeg.DecodeFrame(): boolean; var FrameFinished: Integer; VideoPktPts: int64; @@ -522,7 +561,10 @@ begin // check for errors if (url_ferror(pbIOCtx) <> 0) then + begin + Log.LogError('Video decoding file error', 'TVideoPlayback_FFmpeg.DecodeFrame'); Exit; + end; // url_feof() does not detect an EOF for some mov-files (e.g. deluxe.mov) // so we have to do it this way. @@ -533,18 +575,9 @@ begin Exit; end; - // no error -> wait for user input -{ - SDL_Delay(100); // initial version, left for documentation - continue; -} - - // Patch by Hawkear: - // Why should this function loop in an endless loop if there is an error? - // This runs in the main thread, so it halts the whole program - // Therefore, it is better to exit when an error occurs + // error occured, log and exit + Log.LogError('Video decoding error', 'TVideoPlayback_FFmpeg.DecodeFrame'); Exit; - end; // if we got a packet from the video stream, then decode it @@ -593,7 +626,7 @@ begin Result := true; end; -procedure TVideoPlayback_FFmpeg.GetFrame(Time: Extended); +procedure TVideo_FFmpeg.GetFrame(Time: Extended); var errnum: Integer; NewTime: Extended; @@ -749,7 +782,7 @@ begin {$ENDIF} end; -procedure TVideoPlayback_FFmpeg.GetVideoRect(var ScreenRect, TexRect: TRectCoords); +procedure TVideo_FFmpeg.GetVideoRect(var ScreenRect, TexRect: TRectCoords); var ScreenAspect: double; // aspect of screen resolution ScaledVideoWidth, ScaledVideoHeight: double; @@ -799,7 +832,7 @@ begin TexRect.Lower := fCodecContext^.height / fTexHeight; end; -procedure TVideoPlayback_FFmpeg.DrawGL(Screen: integer); +procedure TVideo_FFmpeg.DrawGL(Screen: integer); var ScreenRect: TRectCoords; TexRect: TRectCoords; @@ -862,7 +895,7 @@ begin {$IFEND} end; -procedure TVideoPlayback_FFmpeg.ShowDebugInfo(); +procedure TVideo_FFmpeg.ShowDebugInfo(); begin {$IFDEF Info} if (fTime+fTimeBase < 0) then @@ -899,17 +932,28 @@ begin {$ENDIF} end; -procedure TVideoPlayback_FFmpeg.Play; +procedure TVideo_FFmpeg.Play; begin end; -procedure TVideoPlayback_FFmpeg.Pause; +procedure TVideo_FFmpeg.Pause; begin fPaused := not fPaused; end; -procedure TVideoPlayback_FFmpeg.Stop; +procedure TVideo_FFmpeg.Stop; +begin +end; + +procedure TVideo_FFmpeg.SetLoop(Enable: boolean); +begin + fLoop := Enable; + fLoopTime := 0; +end; + +function TVideo_FFmpeg.GetLoop(): boolean; begin + Result := fLoop; end; {** @@ -920,7 +964,7 @@ end; * actual frame time when GetFrame() is called the next time. * @param Time new position in seconds *} -procedure TVideoPlayback_FFmpeg.SetPosition(Time: real); +procedure TVideo_FFmpeg.SetPosition(Time: real); var SeekFlags: integer; begin @@ -955,7 +999,7 @@ begin avcodec_flush_buffers(fCodecContext); end; -function TVideoPlayback_FFmpeg.GetPosition: real; +function TVideo_FFmpeg.GetPosition: real; begin Result := fTime; end; -- cgit v1.2.3