diff options
author | tobigun <tobigun@b956fd51-792f-4845-bead-9b4dfca2ff2c> | 2009-03-14 21:18:50 +0000 |
---|---|---|
committer | tobigun <tobigun@b956fd51-792f-4845-bead-9b4dfca2ff2c> | 2009-03-14 21:18:50 +0000 |
commit | a92d9807237a024106b67f045822679f7ee4df54 (patch) | |
tree | 5f2c2501be7da18d2b82216fe60e645d1a2caaac /unicode/src/media | |
parent | c61a339ad465ecb43897975538a77c3eb87110be (diff) | |
download | usdx-a92d9807237a024106b67f045822679f7ee4df54.tar.gz usdx-a92d9807237a024106b67f045822679f7ee4df54.tar.xz usdx-a92d9807237a024106b67f045822679f7ee4df54.zip |
merge with current trunk (just update)
git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/branches/experimental@1634 b956fd51-792f-4845-bead-9b4dfca2ff2c
Diffstat (limited to 'unicode/src/media')
-rw-r--r-- | unicode/src/media/UAudioConverter.pas | 14 | ||||
-rw-r--r-- | unicode/src/media/UAudioDecoder_Bass.pas | 6 | ||||
-rw-r--r-- | unicode/src/media/UAudioDecoder_FFmpeg.pas | 26 | ||||
-rw-r--r-- | unicode/src/media/UAudioPlayback_Bass.pas | 18 | ||||
-rw-r--r-- | unicode/src/media/UAudioPlayback_SDL.pas | 14 | ||||
-rw-r--r-- | unicode/src/media/UAudioPlayback_SoftMixer.pas | 38 | ||||
-rw-r--r-- | unicode/src/media/UVideo.pas | 160 | ||||
-rw-r--r-- | unicode/src/media/UVisualizer.pas | 15 |
8 files changed, 174 insertions, 117 deletions
diff --git a/unicode/src/media/UAudioConverter.pas b/unicode/src/media/UAudioConverter.pas index 24131b16..657b80dd 100644 --- a/unicode/src/media/UAudioConverter.pas +++ b/unicode/src/media/UAudioConverter.pas @@ -70,7 +70,7 @@ type function Init(SrcFormatInfo: TAudioFormatInfo; DstFormatInfo: TAudioFormatInfo): boolean; override; destructor Destroy(); override; - function Convert(InputBuffer: PChar; OutputBuffer: PChar; var InputSize: integer): integer; override; + function Convert(InputBuffer: PByteArray; OutputBuffer: PByteArray; var InputSize: integer): integer; override; function GetOutputBufferSize(InputSize: integer): integer; override; function GetRatio(): double; override; end; @@ -87,7 +87,7 @@ type function Init(SrcFormatInfo: TAudioFormatInfo; DstFormatInfo: TAudioFormatInfo): boolean; override; destructor Destroy(); override; - function Convert(InputBuffer: PChar; OutputBuffer: PChar; var InputSize: integer): integer; override; + function Convert(InputBuffer: PByteArray; OutputBuffer: PByteArray; var InputSize: integer): integer; override; function GetOutputBufferSize(InputSize: integer): integer; override; function GetRatio(): double; override; end; @@ -103,7 +103,7 @@ type function Init(SrcFormatInfo: TAudioFormatInfo; DstFormatInfo: TAudioFormatInfo): boolean; override; destructor Destroy(); override; - function Convert(InputBuffer: PChar; OutputBuffer: PChar; var InputSize: integer): integer; override; + function Convert(InputBuffer: PByteArray; OutputBuffer: PByteArray; var InputSize: integer): integer; override; function GetOutputBufferSize(InputSize: integer): integer; override; function GetRatio(): double; override; end; @@ -173,7 +173,7 @@ begin Result := cvt.len_ratio; end; -function TAudioConverter_SDL.Convert(InputBuffer: PChar; OutputBuffer: PChar; var InputSize: integer): integer; +function TAudioConverter_SDL.Convert(InputBuffer: PByteArray; OutputBuffer: PByteArray; var InputSize: integer): integer; begin Result := -1; @@ -242,7 +242,7 @@ begin inherited; end; -function TAudioConverter_FFmpeg.Convert(InputBuffer: PChar; OutputBuffer: PChar; var InputSize: integer): integer; +function TAudioConverter_FFmpeg.Convert(InputBuffer: PByteArray; OutputBuffer: PByteArray; var InputSize: integer): integer; var InputSampleCount: integer; OutputSampleCount: integer; @@ -360,11 +360,11 @@ begin inherited; end; -function TAudioConverter_SRC.Convert(InputBuffer: PChar; OutputBuffer: PChar; var InputSize: integer): integer; +function TAudioConverter_SRC.Convert(InputBuffer: PByteArray; OutputBuffer: PByteArray; var InputSize: integer): integer; var FloatInputBuffer: PSingle; FloatOutputBuffer: PSingle; - TempBuffer: PChar; + TempBuffer: PByteArray; TempSize: integer; NumSamples: integer; OutputSize: integer; diff --git a/unicode/src/media/UAudioDecoder_Bass.pas b/unicode/src/media/UAudioDecoder_Bass.pas index 3c31175d..6bbdaeaa 100644 --- a/unicode/src/media/UAudioDecoder_Bass.pas +++ b/unicode/src/media/UAudioDecoder_Bass.pas @@ -65,7 +65,7 @@ type function IsEOF(): boolean; override; function IsError(): boolean; override; - function ReadData(Buffer: PChar; BufSize: integer): integer; override; + function ReadData(Buffer: PByteArray; BufSize: integer): integer; override; end; type @@ -193,7 +193,7 @@ begin Result := Error; end; -function TBassDecodeStream.ReadData(Buffer: PChar; BufSize: integer): integer; +function TBassDecodeStream.ReadData(Buffer: PByteArray; BufSize: integer): integer; begin Result := BASS_ChannelGetData(Handle, Buffer, BufSize); // check error state (do not handle EOF as error) @@ -237,7 +237,7 @@ begin // TODO: use BASS_STREAM_PRESCAN for accurate seeking in VBR-files? // disadvantage: seeking will slow down. - Stream := BASS_StreamCreateFile(False, PChar(Filename), 0, 0, BASS_STREAM_DECODE); + Stream := BASS_StreamCreateFile(False, PAnsiChar(Filename), 0, 0, BASS_STREAM_DECODE); if (Stream = 0) then begin //Log.LogError(BassCore.ErrorGetString(), 'TAudioDecoder_Bass.Open'); diff --git a/unicode/src/media/UAudioDecoder_FFmpeg.pas b/unicode/src/media/UAudioDecoder_FFmpeg.pas index 399c2f52..2d221f40 100644 --- a/unicode/src/media/UAudioDecoder_FFmpeg.pas +++ b/unicode/src/media/UAudioDecoder_FFmpeg.pas @@ -57,7 +57,6 @@ implementation uses Classes, - SysUtils, Math, UMusic, UIni, @@ -68,8 +67,9 @@ uses avio, mathematics, // used for av_rescale_q rational, - UMediaCore_FFmpeg, SDL, + SysUtils, + UMediaCore_FFmpeg, ULog, UCommon, UConfig; @@ -129,14 +129,14 @@ type // state-vars for DecodeFrame (locked by DecoderLock) AudioPaket: TAVPacket; - AudioPaketData: PChar; + AudioPaketData: PByteArray; AudioPaketSize: integer; AudioPaketSilence: integer; // number of bytes of silence to return // state-vars for AudioCallback (locked by DecoderLock) AudioBufferPos: integer; AudioBufferSize: integer; - AudioBuffer: PChar; + AudioBuffer: PByteArray; Filename: string; @@ -153,7 +153,7 @@ type procedure PauseParser(); procedure ResumeParser(); - function DecodeFrame(Buffer: PChar; BufferSize: integer): integer; + function DecodeFrame(Buffer: PByteArray; BufferSize: integer): integer; procedure FlushCodecBuffers(); procedure PauseDecoder(); procedure ResumeDecoder(); @@ -173,11 +173,11 @@ type function IsEOF(): boolean; override; function IsError(): boolean; override; - function ReadData(Buffer: PChar; BufferSize: integer): integer; override; + function ReadData(Buffer: PByteArray; BufferSize: integer): integer; override; end; type - TAudioDecoder_FFmpeg = class( TInterfacedObject, IAudioDecoder ) + TAudioDecoder_FFmpeg = class(TInterfacedObject, IAudioDecoder) public function GetName: string; @@ -289,7 +289,7 @@ begin Self.Filename := Filename; // open audio file - if (av_open_input_file(FormatCtx, PChar(Filename), nil, 0, nil) <> 0) then + if (av_open_input_file(FormatCtx, PAnsiChar(Filename), nil, 0, nil) <> 0) then begin Log.LogError('av_open_input_file failed: "' + Filename + '"', 'UAudio_FFmpeg'); Exit; @@ -310,7 +310,7 @@ begin FormatCtx^.pb.eof_reached := 0; {$IFDEF DebugFFmpegDecode} - dump_format(FormatCtx, 0, pchar(Filename), 0); + dump_format(FormatCtx, 0, PAnsiChar(Filename), 0); {$ENDIF} AudioStreamIndex := FFmpegCore.FindAudioStreamIndex(FormatCtx); @@ -862,7 +862,7 @@ begin end; end; -function TFFmpegDecodeStream.DecodeFrame(Buffer: PChar; BufferSize: integer): integer; +function TFFmpegDecodeStream.DecodeFrame(Buffer: PByteArray; BufferSize: integer): integer; var PaketDecodedSize: integer; // size of packet data used for decoding DataSize: integer; // size of output data decoded by FFmpeg @@ -945,7 +945,7 @@ begin Exit; // handle Status-packet - if (PChar(AudioPaket.data) = STATUS_PACKET) then + if (PAnsiChar(AudioPaket.data) = STATUS_PACKET) then begin AudioPaket.data := nil; AudioPaketData := nil; @@ -986,7 +986,7 @@ begin Continue; end; - AudioPaketData := PChar(AudioPaket.data); + AudioPaketData := AudioPaket.data; AudioPaketSize := AudioPaket.size; // if available, update the stream position to the presentation time of this package @@ -1005,7 +1005,7 @@ begin end; end; -function TFFmpegDecodeStream.ReadData(Buffer: PChar; BufferSize: integer): integer; +function TFFmpegDecodeStream.ReadData(Buffer: PByteArray; BufferSize: integer): integer; var CopyByteCount: integer; // number of bytes to copy RemainByteCount: integer; // number of bytes left (remain) to read diff --git a/unicode/src/media/UAudioPlayback_Bass.pas b/unicode/src/media/UAudioPlayback_Bass.pas index d68ac1d4..923c1d7b 100644 --- a/unicode/src/media/UAudioPlayback_Bass.pas +++ b/unicode/src/media/UAudioPlayback_Bass.pas @@ -37,7 +37,6 @@ implementation uses Classes, - SysUtils, Math, UIni, UMain, @@ -46,7 +45,8 @@ uses UAudioCore_Bass, ULog, sdl, - bass; + bass, + SysUtils; type PHDSP = ^HDSP; @@ -90,7 +90,7 @@ type function GetAudioFormatInfo(): TAudioFormatInfo; override; - function ReadData(Buffer: PChar; BufferSize: integer): integer; + function ReadData(Buffer: PByteArray; BufferSize: integer): integer; property EOF: boolean READ IsEOF; end; @@ -106,8 +106,8 @@ type function Open(ChannelMap: integer; FormatInfo: TAudioFormatInfo): boolean; override; procedure Close(); override; - procedure WriteData(Buffer: PChar; BufferSize: integer); override; - function ReadData(Buffer: PChar; BufferSize: integer): integer; override; + procedure WriteData(Buffer: PByteArray; BufferSize: integer); override; + function ReadData(Buffer: PByteArray; BufferSize: integer): integer; override; function IsEOF(): boolean; override; function IsError(): boolean; override; end; @@ -163,14 +163,14 @@ begin Result := BytesRead; end; -function TBassPlaybackStream.ReadData(Buffer: PChar; BufferSize: integer): integer; +function TBassPlaybackStream.ReadData(Buffer: PByteArray; BufferSize: integer): integer; var AdjustedSize: integer; RequestedSourceSize, SourceSize: integer; SkipCount: integer; SourceFormatInfo: TAudioFormatInfo; FrameSize: integer; - PadFrame: PChar; + PadFrame: PByteArray; //Info: BASS_INFO; //Latency: double; begin @@ -610,7 +610,7 @@ begin inherited Close(); end; -procedure TBassVoiceStream.WriteData(Buffer: PChar; BufferSize: integer); +procedure TBassVoiceStream.WriteData(Buffer: PByteArray; BufferSize: integer); var QueueSize: DWORD; begin if ((Handle <> 0) and (BufferSize > 0)) then @@ -626,7 +626,7 @@ begin end; // Note: we do not need the read-function for the BASS implementation -function TBassVoiceStream.ReadData(Buffer: PChar; BufferSize: integer): integer; +function TBassVoiceStream.ReadData(Buffer: PByteArray; BufferSize: integer): integer; begin Result := -1; end; diff --git a/unicode/src/media/UAudioPlayback_SDL.pas b/unicode/src/media/UAudioPlayback_SDL.pas index b0887676..8403ef03 100644 --- a/unicode/src/media/UAudioPlayback_SDL.pas +++ b/unicode/src/media/UAudioPlayback_SDL.pas @@ -33,16 +33,14 @@ interface {$I switches.inc} -uses - Classes, - SysUtils, - UMusic; - implementation uses + Classes, sdl, + SysUtils, UAudioPlayback_SoftMixer, + UMusic, ULog, UIni, UMain; @@ -60,13 +58,13 @@ type function GetLatency(): double; override; public function GetName: String; override; - procedure MixBuffers(dst, src: PChar; size: Cardinal; volume: Single); override; + procedure MixBuffers(dst, src: PByteArray; size: Cardinal; volume: Single); override; end; { TAudioPlayback_SDL } -procedure SDLAudioCallback(userdata: Pointer; stream: PChar; len: integer); cdecl; +procedure SDLAudioCallback(userdata: Pointer; stream: PByteArray; len: integer); cdecl; var Engine: TAudioPlayback_SDL; begin @@ -172,7 +170,7 @@ begin Result := Latency; end; -procedure TAudioPlayback_SDL.MixBuffers(dst, src: PChar; size: Cardinal; volume: Single); +procedure TAudioPlayback_SDL.MixBuffers(dst, src: PByteArray; size: Cardinal; volume: Single); begin SDL_MixAudio(PUInt8(dst), PUInt8(src), size, Round(volume * SDL_MIX_MAXVOLUME)); end; diff --git a/unicode/src/media/UAudioPlayback_SoftMixer.pas b/unicode/src/media/UAudioPlayback_SoftMixer.pas index f3797dd6..c8da6bcd 100644 --- a/unicode/src/media/UAudioPlayback_SoftMixer.pas +++ b/unicode/src/media/UAudioPlayback_SoftMixer.pas @@ -35,8 +35,8 @@ interface uses Classes, - SysUtils, sdl, + SysUtils, URingBuffer, UMusic, UAudioPlaybackBase; @@ -48,12 +48,12 @@ type private Engine: TAudioPlayback_SoftMixer; - SampleBuffer: PChar; + SampleBuffer: PByteArray; SampleBufferSize: integer; SampleBufferCount: integer; // number of available bytes in SampleBuffer SampleBufferPos: cardinal; - SourceBuffer: PChar; + SourceBuffer: PByteArray; SourceBufferSize: integer; SourceBufferCount: integer; // number of available bytes in SourceBuffer @@ -70,7 +70,7 @@ type procedure Reset(); - procedure ApplySoundEffects(Buffer: PChar; BufferSize: integer); + procedure ApplySoundEffects(Buffer: PByteArray; BufferSize: integer); function InitFormatConversion(): boolean; procedure FlushBuffers(); @@ -100,7 +100,7 @@ type function GetAudioFormatInfo(): TAudioFormatInfo; override; - function ReadData(Buffer: PChar; BufferSize: integer): integer; + function ReadData(Buffer: PByteArray; BufferSize: integer): integer; function GetPCMData(var Data: TPCMData): Cardinal; override; procedure GetFFTData(var Data: TFFTData); override; @@ -114,7 +114,7 @@ type Engine: TAudioPlayback_SoftMixer; ActiveStreams: TList; - MixerBuffer: PChar; + MixerBuffer: PByteArray; InternalLock: PSDL_Mutex; AppVolume: single; @@ -129,7 +129,7 @@ type destructor Destroy(); override; procedure AddStream(Stream: TAudioPlaybackStream); procedure RemoveStream(Stream: TAudioPlaybackStream); - function ReadData(Buffer: PChar; BufferSize: integer): integer; + function ReadData(Buffer: PByteArray; BufferSize: integer): integer; property Volume: single read GetVolume write SetVolume; end; @@ -144,7 +144,7 @@ type function StartAudioPlaybackEngine(): boolean; virtual; abstract; procedure StopAudioPlaybackEngine(); virtual; abstract; function FinalizeAudioPlaybackEngine(): boolean; virtual; abstract; - procedure AudioCallback(Buffer: PChar; Size: integer); {$IFDEF HasInline}inline;{$ENDIF} + procedure AudioCallback(Buffer: PByteArray; Size: integer); {$IFDEF HasInline}inline;{$ENDIF} function CreatePlaybackStream(): TAudioPlaybackStream; override; public @@ -159,7 +159,7 @@ type function GetMixer(): TAudioMixerStream; {$IFDEF HasInline}inline;{$ENDIF} function GetAudioFormatInfo(): TAudioFormatInfo; - procedure MixBuffers(DstBuffer, SrcBuffer: PChar; Size: Cardinal; Volume: Single); virtual; + procedure MixBuffers(DstBuffer, SrcBuffer: PByteArray; Size: Cardinal; Volume: Single); virtual; end; type @@ -174,8 +174,8 @@ type function Open(ChannelMap: integer; FormatInfo: TAudioFormatInfo): boolean; override; procedure Close(); override; - procedure WriteData(Buffer: PChar; BufferSize: integer); override; - function ReadData(Buffer: PChar; BufferSize: integer): integer; override; + procedure WriteData(Buffer: PByteArray; BufferSize: integer); override; + function ReadData(Buffer: PByteArray; BufferSize: integer): integer; override; function IsEOF(): boolean; override; function IsError(): boolean; override; end; @@ -276,7 +276,7 @@ begin Unlock(); end; -function TAudioMixerStream.ReadData(Buffer: PChar; BufferSize: integer): integer; +function TAudioMixerStream.ReadData(Buffer: PByteArray; BufferSize: integer): integer; var i: integer; Size: integer; @@ -545,7 +545,7 @@ begin SourceBufferCount := 0; end; -procedure TGenericPlaybackStream.ApplySoundEffects(Buffer: PChar; BufferSize: integer); +procedure TGenericPlaybackStream.ApplySoundEffects(Buffer: PByteArray; BufferSize: integer); var i: integer; begin @@ -558,7 +558,7 @@ begin end; end; -function TGenericPlaybackStream.ReadData(Buffer: PChar; BufferSize: integer): integer; +function TGenericPlaybackStream.ReadData(Buffer: PByteArray; BufferSize: integer): integer; var ConversionInputCount: integer; ConversionOutputSize: integer; // max. number of converted data (= buffer size) @@ -573,7 +573,7 @@ var SkipSourceCount: integer; // number of source-data bytes to skip FillCount: integer; // number of bytes to fill with padding data CopyCount: integer; - PadFrame: PChar; + PadFrame: PByteArray; i: integer; begin Result := -1; @@ -986,7 +986,7 @@ begin inherited Close(); end; -procedure TGenericVoiceStream.WriteData(Buffer: PChar; BufferSize: integer); +procedure TGenericVoiceStream.WriteData(Buffer: PByteArray; BufferSize: integer); begin // lock access to buffer SDL_mutexP(BufferLock); @@ -999,7 +999,7 @@ begin end; end; -function TGenericVoiceStream.ReadData(Buffer: PChar; BufferSize: integer): integer; +function TGenericVoiceStream.ReadData(Buffer: PByteArray; BufferSize: integer): integer; begin Result := -1; @@ -1059,7 +1059,7 @@ begin Result := true; end; -procedure TAudioPlayback_SoftMixer.AudioCallback(Buffer: PChar; Size: integer); +procedure TAudioPlayback_SoftMixer.AudioCallback(Buffer: PByteArray; Size: integer); begin MixerStream.ReadData(Buffer, Size); end; @@ -1102,7 +1102,7 @@ begin MixerStream.Volume := Volume; end; -procedure TAudioPlayback_SoftMixer.MixBuffers(DstBuffer, SrcBuffer: PChar; Size: Cardinal; Volume: Single); +procedure TAudioPlayback_SoftMixer.MixBuffers(DstBuffer, SrcBuffer: PByteArray; Size: Cardinal; Volume: Single); var SampleIndex: Cardinal; SampleInt: Integer; diff --git a/unicode/src/media/UVideo.pas b/unicode/src/media/UVideo.pas index 06577d9e..35f8ab4d 100644 --- a/unicode/src/media/UVideo.pas +++ b/unicode/src/media/UVideo.pas @@ -126,6 +126,7 @@ type fFrameBuffer: PByte; //**< stores a FFmpeg video frame fFrameTex: GLuint; //**< OpenGL texture for FrameBuffer + fFrameTexValid: boolean; //**< if true, fFrameTex contains the current frame fTexWidth, fTexHeight: cardinal; {$IFDEF UseSWScale} @@ -137,11 +138,11 @@ type fTimeBase: extended; //**< FFmpeg time base per time unit fTime: extended; //**< video time position (absolute) - fLoopTime: extended; //**< video time position (relative to current loop) + fLoopTime: extended; //**< start time of the current loop procedure Reset(); - function DecodeFrame(var AVPacket: TAVPacket; out pts: double): boolean; - procedure SynchronizeVideo(Frame: PAVFrame; var pts: double); + function DecodeFrame(): boolean; + procedure SynchronizeTime(Frame: PAVFrame; var pts: double); procedure GetVideoRect(var ScreenRect, TexRect: TRectCoords); @@ -240,6 +241,7 @@ begin fTime := 0; fStream := nil; fStreamIndex := -1; + fFrameTexValid := false; fEOF := false; @@ -453,7 +455,7 @@ begin fOpened := False; end; -procedure TVideoPlayback_FFmpeg.SynchronizeVideo(Frame: PAVFrame; var pts: double); +procedure TVideoPlayback_FFmpeg.SynchronizeTime(Frame: PAVFrame; var pts: double); var FrameDelay: double; begin @@ -473,12 +475,21 @@ begin fTime := fTime + FrameDelay; end; -function TVideoPlayback_FFmpeg.DecodeFrame(var AVPacket: TAVPacket; out pts: double): boolean; +{** + * Decode a new frame from the video stream. + * The decoded frame is stored in fAVFrame. fTime is updated to the new frame's + * time. + * @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; var FrameFinished: Integer; VideoPktPts: int64; pbIOCtx: PByteIOContext; errnum: integer; + AVPacket: TAVPacket; + pts: double; begin Result := false; FrameFinished := 0; @@ -521,8 +532,17 @@ begin end; // no error -> wait for user input - SDL_Delay(100); +{ + 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 + Exit; + end; // if we got a packet from the video stream, then decode it @@ -555,9 +575,9 @@ begin end; pts := pts * av_q2d(fStream^.time_base); - // synchronize on each complete frame + // synchronize time on each complete frame if (frameFinished <> 0) then - SynchronizeVideo(fAVFrame, pts); + SynchronizeTime(fAVFrame, pts); end; // free the packet from av_read_frame @@ -569,13 +589,12 @@ end; procedure TVideoPlayback_FFmpeg.GetFrame(Time: Extended); var - AVPacket: TAVPacket; errnum: Integer; - myTime: Extended; + NewTime: Extended; TimeDifference: Extended; DropFrameCount: Integer; - pts: double; i: Integer; + Success: boolean; const FRAME_DROPCOUNT = 3; begin @@ -585,41 +604,50 @@ begin if fPaused then Exit; - // current time, relative to last fLoop (if any) - myTime := Time - fLoopTime; - // time since the last frame was returned - TimeDifference := myTime - fTime; + // requested stream position (relative to the last loop's start) + NewTime := Time - fLoopTime; - {$IFDEF DebugDisplay} - DebugWriteln('Time: '+inttostr(floor(Time*1000)) + sLineBreak + - 'VideoTime: '+inttostr(floor(fTime*1000)) + sLineBreak + - 'TimeBase: '+inttostr(floor(fTimeBase*1000)) + sLineBreak + - 'TimeDiff: '+inttostr(floor(TimeDifference*1000))); - {$endif} - - // check if a new frame is needed - if (fTime <> 0) and (TimeDifference < fTimeBase) then + // check if current texture still contains the active frame + if (fFrameTexValid) then begin - {$ifdef DebugFrames} - // frame delay debug display - GoldenRec.Spawn(200,15,1,16,0,-1,ColoredStar,$00ff00); - {$endif} + // time since the last frame was returned + TimeDifference := NewTime - fTime; {$IFDEF DebugDisplay} - DebugWriteln('not getting new frame' + sLineBreak + - 'Time: '+inttostr(floor(Time*1000)) + sLineBreak + - 'VideoTime: '+inttostr(floor(fTime*1000)) + sLineBreak + - 'TimeBase: '+inttostr(floor(fTimeBase*1000)) + sLineBreak + - 'TimeDiff: '+inttostr(floor(TimeDifference*1000))); + DebugWriteln('Time: '+inttostr(floor(Time*1000)) + sLineBreak + + 'VideoTime: '+inttostr(floor(fTime*1000)) + sLineBreak + + 'TimeBase: '+inttostr(floor(fTimeBase*1000)) + sLineBreak + + 'TimeDiff: '+inttostr(floor(TimeDifference*1000))); {$endif} - // we do not need a new frame now - Exit; + // check if last time is more than one frame in the past + if (TimeDifference < fTimeBase) then + begin + {$ifdef DebugFrames} + // frame delay debug display + GoldenRec.Spawn(200,15,1,16,0,-1,ColoredStar,$00ff00); + {$endif} + + {$IFDEF DebugDisplay} + DebugWriteln('not getting new frame' + sLineBreak + + 'Time: '+inttostr(floor(Time*1000)) + sLineBreak + + 'VideoTime: '+inttostr(floor(fTime*1000)) + sLineBreak + + 'TimeBase: '+inttostr(floor(fTimeBase*1000)) + sLineBreak + + 'TimeDiff: '+inttostr(floor(TimeDifference*1000))); + {$endif} + + // we do not need a new frame now + Exit; + end; end; - // update video-time to the next frame - fTime := fTime + fTimeBase; - TimeDifference := myTime - fTime; + {$IFDEF VideoBenchmark} + Log.BenchmarkStart(15); + {$ENDIF} + + // fetch new frame (updates fTime) + Success := DecodeFrame(); + TimeDifference := NewTime - fTime; // check if we have to skip frames if (TimeDifference >= FRAME_DROPCOUNT*fTimeBase) then @@ -640,19 +668,18 @@ begin // skip half of the frames, this is much smoother than to skip all at once for i := 1 to DropFrameCount (*div 2*) do - DecodeFrame(AVPacket, pts); + Success := DecodeFrame(); end; - {$IFDEF VideoBenchmark} - Log.BenchmarkStart(15); - {$ENDIF} - - if (not DecodeFrame(AVPacket, pts)) then + // check if we got an EOF or error + if (not Success) then begin if fLoop then begin - // Record the time we looped. This is used to keep the loops in time. otherwise they speed + // we have to loop, so rewind SetPosition(0); + // record the start-time of the current loop, so we can + // determine the position in the stream (fTime-fLoopTime) later. fLoopTime := Time; end; Exit; @@ -695,6 +722,9 @@ begin fCodecContext^.width, fCodecContext^.height, PIXEL_FMT_OPENGL, GL_UNSIGNED_BYTE, fAVFrameRGB^.data[0]); + if (not fFrameTexValid) then + fFrameTexValid := true; + {$ifdef DebugFrames} //frame decode debug display GoldenRec.Spawn(200, 35, 1, 16, 0, -1, ColoredStar, $ffff00); @@ -738,7 +768,9 @@ begin acoLetterBox: begin ScaledVideoWidth := RenderW; ScaledVideoHeight := RenderH * ScreenAspect/fAspect; - end; + end + else + raise Exception.Create('Unhandled aspect correction!'); end; // center video @@ -762,8 +794,18 @@ var begin // have a nice black background to draw on // (even if there were errors opening the vid) - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); + // TODO: Philipp: IMO TVideoPlayback should not clear the screen at + // all, because clearing is already done by the background class + // at this moment. + if (Screen = 1) then + begin + // It is important that we just clear once before we start + // drawing the first screen otherwise the first screen + // would be cleared by the drawgl called when the second + // screen is drawn + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); + end; // exit if there's nothing to draw if (not fOpened) then @@ -858,6 +900,14 @@ procedure TVideoPlayback_FFmpeg.Stop; begin end; +{** + * Sets the stream's position. + * The stream is set to the first keyframe with timestamp <= Time. + * Note that fTime is set to Time no matter if the actual position seeked to is + * at Time or the time of a preceding keyframe. fTime will be updated to the + * actual frame time when GetFrame() is called the next time. + * @param Time new position in seconds + *} procedure TVideoPlayback_FFmpeg.SetPosition(Time: real); var SeekFlags: integer; @@ -871,13 +921,18 @@ begin // TODO: handle fLoop-times //Time := Time mod VideoDuration; - // backward seeking might fail without AVSEEK_FLAG_BACKWARD - SeekFlags := AVSEEK_FLAG_ANY; - if (Time < fTime) then - SeekFlags := SeekFlags or AVSEEK_FLAG_BACKWARD; + // Do not use the AVSEEK_FLAG_ANY here. It will seek to any frame, even + // non keyframes (P-/B-frames). It will produce corrupted video frames as + // FFmpeg does not use the information of the preceding I-frame. + // The picture might be gray or green until the next keyframe occurs. + // Instead seek the first keyframe smaller than the requested time + // (AVSEEK_FLAG_BACKWARD). As this can be some seconds earlier than the + // requested time, let the sync in GetFrame() do its job. + SeekFlags := AVSEEK_FLAG_BACKWARD; fTime := Time; fEOF := false; + fFrameTexValid := false; if (av_seek_frame(fFormatContext, fStreamIndex, Floor(Time/fTimeBase), SeekFlags) < 0) then begin @@ -890,7 +945,6 @@ end; function TVideoPlayback_FFmpeg.GetPosition: real; begin - // TODO: return video-position in seconds Result := fTime; end; diff --git a/unicode/src/media/UVisualizer.pas b/unicode/src/media/UVisualizer.pas index 9af6d8c2..37e0268a 100644 --- a/unicode/src/media/UVisualizer.pas +++ b/unicode/src/media/UVisualizer.pas @@ -484,7 +484,11 @@ begin glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); - gluOrtho2D(0, 1, 0, 1); + // Use count of screens instead of 1 for the right corner + // otherwise we would draw the visualization streched over both screens + // another point is that we draw over the at this time drawn first + // screen, if Screen = 2 + gluOrtho2D(0, Screens, 0, 1); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); @@ -496,11 +500,12 @@ begin glColor4f(1, 1, 1, 1); // draw projectM frame + // Screen is 1 to 2. So current screen is from (Screen - 1) to (Screen) glBegin(GL_QUADS); - glTexCoord2f(0, 0); glVertex2f(0, 0); - glTexCoord2f(1, 0); glVertex2f(1, 0); - glTexCoord2f(1, 1); glVertex2f(1, 1); - glTexCoord2f(0, 1); glVertex2f(0, 1); + glTexCoord2f(0, 0); glVertex2f((Screen - 1), 0); + glTexCoord2f(1, 0); glVertex2f(Screen, 0); + glTexCoord2f(1, 1); glVertex2f(Screen, 1); + glTexCoord2f(0, 1); glVertex2f((Screen - 1), 1); glEnd(); glDisable(GL_TEXTURE_2D); |