From 8c923b5b76bb17e00132a0b2b2b96de34265fc63 Mon Sep 17 00:00:00 2001 From: jaybinks Date: Tue, 16 Oct 2007 11:27:23 +0000 Subject: modified ffmpeg usage, to use interface same as bass... still needs some tidy up, but its working. :) git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@515 b956fd51-792f-4845-bead-9b4dfca2ff2c --- Game/Code/Classes/UAudio_FFMpeg.pas | 2 - Game/Code/Classes/UAudio_bass.pas | 27 +- Game/Code/Classes/UMedia_dummy.pas | 276 ++++++++++++++++ Game/Code/Classes/UMusic.pas | 142 +++++--- Game/Code/Classes/UVideo.pas | 625 +++++++++++++++++++++--------------- 5 files changed, 758 insertions(+), 314 deletions(-) create mode 100644 Game/Code/Classes/UMedia_dummy.pas (limited to 'Game/Code/Classes') diff --git a/Game/Code/Classes/UAudio_FFMpeg.pas b/Game/Code/Classes/UAudio_FFMpeg.pas index 2a3c5cb5..959d904a 100644 --- a/Game/Code/Classes/UAudio_FFMpeg.pas +++ b/Game/Code/Classes/UAudio_FFMpeg.pas @@ -16,8 +16,6 @@ uses Classes, {$IFNDEF FPC} Forms, {$ENDIF} - - bass, ULog, UMusic; diff --git a/Game/Code/Classes/UAudio_bass.pas b/Game/Code/Classes/UAudio_bass.pas index cbeadc47..5aecfc89 100644 --- a/Game/Code/Classes/UAudio_bass.pas +++ b/Game/Code/Classes/UAudio_bass.pas @@ -79,7 +79,7 @@ type procedure Close; function Finished: boolean; function Length: real; - function Position: real; + function getPosition: real; procedure PlayStart; procedure PlayBack; procedure PlaySwoosh; @@ -118,17 +118,22 @@ var Pet: integer; S: integer; begin - Log.BenchmarkStart(4); - Log.LogStatus('Initializing Playback Subsystem', 'Music Initialize'); + writeln( 'TAudio_bass.InitializePlayback' ); +// Log.BenchmarkStart(4); +// Log.LogStatus('Initializing Playback Subsystem', 'Music Initialize'); Loaded := false; Loop := false; + + writeln( 'TAudio_bass AllocateHWND' ); {$ifdef win32} // TODO : JB_Linux ... is this needed ? :) fHWND := AllocateHWND( nil); // TODO : JB_lazarus - can we do something different here ?? lazarus didnt like this function {$ENDIF} + + writeln( 'TAudio_bass BASS_Init' ); // TODO : jb_linux replace with something other than bass if not BASS_Init(1, 44100, 0, fHWND, nil) then begin @@ -139,15 +144,16 @@ begin Exit; end; - Log.BenchmarkEnd(4); Log.LogBenchmark('--> Bass Init', 4); +// Log.BenchmarkEnd(4); Log.LogBenchmark('--> Bass Init', 4); // config playing buffer // BASS_SetConfig(BASS_CONFIG_UPDATEPERIOD, 10); // BASS_SetConfig(BASS_CONFIG_BUFFER, 100); - Log.LogStatus('Loading Sounds', 'Music Initialize'); +// Log.LogStatus('Loading Sounds', 'Music Initialize'); - Log.BenchmarkStart(4); + writeln( 'TAudio_bass LoadSoundFromFile' ); +// Log.BenchmarkStart(4); LoadSoundFromFile(BassStart, SoundPath + 'Common Start.mp3'); LoadSoundFromFile(BassBack, SoundPath + 'Common Back.mp3'); LoadSoundFromFile(BassSwoosh, SoundPath + 'menu swoosh.mp3'); @@ -161,8 +167,8 @@ begin // LoadSoundFromFile(BassShuffle, SoundPath + 'Shuffle.mp3'); - Log.BenchmarkEnd(4); - Log.LogBenchmark('--> Loading Sounds', 4); +// Log.BenchmarkEnd(4); +// Log.LogBenchmark('--> Loading Sounds', 4); end; procedure TAudio_bass.InitializeRecord; @@ -347,7 +353,7 @@ begin Result := BASS_ChannelBytes2Seconds(Bass, bytes); end; -function TAudio_bass.Position: real; +function TAudio_bass.getPosition: real; var bytes: integer; begin @@ -631,7 +637,10 @@ initialization AudioManager.add( IAudioInput( singleton_MusicBass ) ); finalization + writeln( 'UAudio_Bass - UnRegister Playback' ); AudioManager.Remove( IAudioPlayback( singleton_MusicBass ) ); + + writeln( 'UAudio_Bass - UnRegister Input' ); AudioManager.Remove( IAudioInput( singleton_MusicBass ) ); end. diff --git a/Game/Code/Classes/UMedia_dummy.pas b/Game/Code/Classes/UMedia_dummy.pas new file mode 100644 index 00000000..0752ab64 --- /dev/null +++ b/Game/Code/Classes/UMedia_dummy.pas @@ -0,0 +1,276 @@ +unit UMedia_dummy; +{< ############################################################################# +# FFmpeg support for UltraStar deluxe # +# # +# Created by b1indy # +# based on 'An ffmpeg and SDL Tutorial' (http://www.dranger.com/ffmpeg/) # +# # +# http://www.mail-archive.com/fpc-pascal@lists.freepascal.org/msg09949.html # +# http://www.nabble.com/file/p11795857/mpegpas01.zip # +# # +############################################################################## } + +interface + +{$IFDEF FPC} + {$MODE DELPHI} +{$ENDIF} + + +implementation + +uses + SysUtils, + UMusic; + + +var + singleton_dummy : IVideoPlayback; + +type + Tmedia_dummy = class( TInterfacedObject, IVideoPlayback, IAudioPlayback, IAudioInput ) + private + public + constructor create(); + function GetName: String; + + procedure init(); + + function Open( aFileName : string): boolean; // true if succeed + procedure Close; + + procedure Play; + procedure Pause; + procedure Stop; + + procedure MoveTo(Time: real); + function getPosition: real; + + procedure FFmpegGetFrame(Time: Extended); + procedure FFmpegDrawGL(Screen: integer); + + // IAudioInput + procedure InitializeRecord; + procedure CaptureStart; + procedure CaptureStop; + procedure CaptureCard(RecordI, PlayerLeft, PlayerRight: byte); + procedure StopCard(Card: byte); + function GetFFTData: TFFTData; + + // IAudioPlayback + procedure InitializePlayback; + procedure SetVolume(Volume: integer); + procedure SetMusicVolume(Volume: integer); + procedure SetLoop(Enabled: boolean); + procedure Rewind; + + function Finished: boolean; + function Length: real; + + procedure PlayStart; + procedure PlayBack; + procedure PlaySwoosh; + procedure PlayChange; + procedure PlayOption; + procedure PlayClick; + procedure PlayDrum; + procedure PlayHihat; + procedure PlayClap; + procedure PlayShuffle; + procedure StopShuffle; + + function LoadSoundFromFile(var hStream: hStream; Name: string): boolean; + + function LoadCustomSound(const Filename: String): Cardinal; + procedure PlayCustomSound(const Index: Cardinal ); + + end; + + + +function Tmedia_dummy.GetName: String; +begin + result := 'dummy'; +end; + + +procedure Tmedia_dummy.FFmpegGetFrame(Time: Extended); +begin +end; + +procedure Tmedia_dummy.FFmpegDrawGL(Screen: integer); +begin +end; + +constructor Tmedia_dummy.create(); +begin +end; + +procedure Tmedia_dummy.init(); +begin +end; + + +function Tmedia_dummy.Open( aFileName : string): boolean; // true if succeed +begin + result := false; +end; + +procedure Tmedia_dummy.Close; +begin +end; + +procedure Tmedia_dummy.Play; +begin +end; + +procedure Tmedia_dummy.Pause; +begin +end; + +procedure Tmedia_dummy.Stop; +begin +end; + +procedure Tmedia_dummy.MoveTo(Time: real); +begin +end; + +function Tmedia_dummy.getPosition: real; +begin + result := 0; +end; + +// IAudioInput +procedure Tmedia_dummy.InitializeRecord; +begin +end; + +procedure Tmedia_dummy.CaptureStart; +begin +end; + +procedure Tmedia_dummy.CaptureStop; +begin +end; + +procedure Tmedia_dummy.CaptureCard(RecordI, PlayerLeft, PlayerRight: byte); +begin +end; + +procedure Tmedia_dummy.StopCard(Card: byte); +begin +end; + +function Tmedia_dummy.GetFFTData: TFFTData; +begin +end; + +// IAudioPlayback +procedure Tmedia_dummy.InitializePlayback; +begin +end; + +procedure Tmedia_dummy.SetVolume(Volume: integer); +begin +end; + +procedure Tmedia_dummy.SetMusicVolume(Volume: integer); +begin +end; + +procedure Tmedia_dummy.SetLoop(Enabled: boolean); +begin +end; + +procedure Tmedia_dummy.Rewind; +begin +end; + +function Tmedia_dummy.Finished: boolean; +begin +end; + +function Tmedia_dummy.Length: real; +begin +end; + +procedure Tmedia_dummy.PlayStart; +begin +end; + +procedure Tmedia_dummy.PlayBack; +begin +end; + +procedure Tmedia_dummy.PlaySwoosh; +begin +end; + +procedure Tmedia_dummy.PlayChange; +begin +end; + +procedure Tmedia_dummy.PlayOption; +begin +end; + +procedure Tmedia_dummy.PlayClick; +begin +end; + +procedure Tmedia_dummy.PlayDrum; +begin +end; + +procedure Tmedia_dummy.PlayHihat; +begin +end; + +procedure Tmedia_dummy.PlayClap; +begin +end; + +procedure Tmedia_dummy.PlayShuffle; +begin +end; + +procedure Tmedia_dummy.StopShuffle; +begin +end; + +function Tmedia_dummy.LoadSoundFromFile(var hStream: hStream; Name: string): boolean; +begin + result := false; +end; + +function Tmedia_dummy.LoadCustomSound(const Filename: String): Cardinal; +begin + result := 0; +end; + +procedure Tmedia_dummy.PlayCustomSound(const Index: Cardinal ); +begin +end; + + + +initialization + singleton_dummy := Tmedia_dummy.create(); + + writeln( 'UMedia_dummy - Register dummy Video_Playback' ); + AudioManager.add( IVideoPlayback( singleton_dummy ) ); + + writeln( 'UMedia_dummy - Register dummy Video_Playback' ); + AudioManager.add( IAudioPlayback( singleton_dummy ) ); + + writeln( 'UMedia_dummy - Register dummy Video_Playback' ); + AudioManager.add( IAudioInput( singleton_dummy ) ); + +finalization + AudioManager.Remove( IVideoPlayback( singleton_dummy ) ); + AudioManager.Remove( IAudioPlayback( singleton_dummy ) ); + AudioManager.Remove( IAudioInput( singleton_dummy ) ); + + +end. diff --git a/Game/Code/Classes/UMusic.pas b/Game/Code/Classes/UMusic.pas index 8aa59d41..88d845f7 100644 --- a/Game/Code/Classes/UMusic.pas +++ b/Game/Code/Classes/UMusic.pas @@ -8,8 +8,7 @@ interface {$MODE Delphi} {$ENDIF} -uses Classes // UCommon - ; +uses Classes ; type TMuzyka = record @@ -94,23 +93,58 @@ type end; type - IAudioPlayback = Interface + IGenericPlayback = Interface + ['{63A5EBC3-3F4D-4F23-8DFB-B5165FCE33DD}'] + function GetName: String; + + function Open(Name: string): boolean; // true if succeed + procedure Close; + + procedure Play; + procedure Pause; + procedure Stop; + + procedure MoveTo(Time: real); + function getPosition: real; + + property position : real READ getPosition WRITE MoveTo; + end; + + IVideoPlayback = Interface( IGenericPlayback ) + ['{3574C40C-28AE-4201-B3D1-3D1F0759B131}'] +(* + procedure FFmpegOpenFile(FileName: pAnsiChar); + procedure FFmpegClose; + + procedure FFmpegGetFrame(Time: Extended); + procedure FFmpegDrawGL(Screen: integer); + procedure FFmpegTogglePause; + procedure FFmpegSkip(Time: Single); +*) + procedure init(); + + procedure FFmpegGetFrame(Time: Extended); // WANT TO RENAME THESE TO BE MORE GENERIC + procedure FFmpegDrawGL(Screen: integer); // WANT TO RENAME THESE TO BE MORE GENERIC + + end; + + IAudioPlayback = Interface( IGenericPlayback ) ['{E4AE0B40-3C21-4DC5-847C-20A87E0DFB96}'] - function GetName: String; procedure InitializePlayback; procedure SetVolume(Volume: integer); procedure SetMusicVolume(Volume: integer); procedure SetLoop(Enabled: boolean); - function Open(Name: string): boolean; // true if succeed +// function Open(Name: string): boolean; // true if succeed procedure Rewind; - procedure MoveTo(Time: real); - procedure Play; - procedure Pause; //Pause Mod - procedure Stop; - procedure Close; +// procedure MoveTo(Time: real); +// procedure Play; +// procedure Pause; +// procedure Stop; +// procedure Close; function Finished: boolean; function Length: real; - function Position: real; +// function getPosition: real; + procedure PlayStart; procedure PlayBack; procedure PlaySwoosh; @@ -159,6 +193,7 @@ var // TODO : JB --- THESE SHOULD NOT BE GLOBAL procedure InitializeSound; +function VideoPlayback(): IVideoPlayback; function AudioPlayback(): IAudioPlayback; function AudioInput(): IAudioInput; @@ -168,21 +203,30 @@ function AudioManager: TInterfaceList; implementation uses - sysutils, - uLog; + sysutils; +// uLog; var - singleton_AudioPlayback : IAudioPlayback; - singleton_AudioInput : IAudioInput; - singleton_AudioManager : TInterfaceList; + singleton_VideoPlayback : IVideoPlayback = nil; + singleton_AudioPlayback : IAudioPlayback = nil; + singleton_AudioInput : IAudioInput = nil; + singleton_AudioManager : TInterfaceList = nil; function AudioManager: TInterfaceList; begin + if singleton_AudioManager = nil then + singleton_AudioManager := TInterfaceList.Create(); + Result := singleton_AudioManager; end; //CompressionPluginManager +function VideoPlayback(): IVideoPlayback; +begin + result := singleton_VideoPlayback; +end; + function AudioPlayback(): IAudioPlayback; begin result := singleton_AudioPlayback; @@ -195,45 +239,71 @@ end; procedure InitializeSound; var - lTmpPlayBack : IAudioPlayback; - lTmpInput : IAudioInput; - iCount : Integer; + lTmpInterface : IInterface; + iCount : Integer; begin - lTmpPlayBack := nil; - lTmpInput := nil; + lTmpInterface := nil; + + singleton_AudioPlayback := nil; + singleton_AudioInput := nil; + singleton_VideoPlayback := nil; writeln( 'InitializeSound , Enumerate Registered Audio Interfaces' ); - for iCount := 0 to singleton_AudioManager.Count - 1 do + for iCount := 0 to AudioManager.Count - 1 do begin if assigned( AudioManager[iCount] ) then begin // if this interface is a Playback, then set it as the default used - if ( AudioManager[iCount].QueryInterface( IAudioPlayback, lTmpPlayBack ) = 0 ) AND - ( not assigned( singleton_AudioPlayback ) ) then + + if ( AudioManager[iCount].QueryInterface( IAudioPlayback, lTmpInterface ) = 0 ) AND + ( true ) then +// ( not assigned( singleton_AudioPlayback ) ) then begin - singleton_AudioPlayback := lTmpPlayBack; + singleton_AudioPlayback := IAudioPlayback( lTmpInterface ); end; // if this interface is a Input, then set it as the default used - if ( AudioManager[iCount].QueryInterface( IAudioInput, lTmpInput ) = 0 ) AND - ( not assigned( singleton_AudioInput ) ) then + if ( AudioManager[iCount].QueryInterface( IAudioInput, lTmpInterface ) = 0 ) AND + ( true ) then +// ( not assigned( singleton_AudioInput ) ) then begin - singleton_AudioInput := lTmpInput; + singleton_AudioInput := IAudioInput( lTmpInterface ); end; + + // if this interface is a Input, then set it as the default used + if ( AudioManager[iCount].QueryInterface( IVideoPlayback, lTmpInterface ) = 0 ) AND + ( true ) then +// ( not assigned( singleton_VideoPlayback ) ) then + begin + singleton_VideoPlayback := IVideoPlayback( lTmpInterface ); + end; + end; end; - writeln( 'Registered Audio Playback Interface : ' + AudioPlayback.GetName ); - writeln( 'Registered Audio Input Interface : ' + AudioInput.GetName ); + if VideoPlayback <> nil then + begin + writeln( 'Registered Video Playback Interface : ' + VideoPlayback.GetName ); + end; + + if AudioPlayback <> nil then + begin + writeln( 'Registered Audio Playback Interface : ' + AudioPlayback.GetName ); + // Log.LogStatus('Initializing Playback ('+AudioPlayback.GetName+')', 'InitializeSound'); + AudioPlayback.InitializePlayback; + end; + + if AudioInput <> nil then + begin + writeln( 'Registered Audio Input Interface : ' + AudioInput.GetName ); + +// Log.LogStatus('Initializing Record ('+AudioPlayback.GetName+')', 'InitializeSound'); + AudioInput.InitializeRecord; + end; - // Initialize Playback - Log.LogStatus('Initializing Playback ('+AudioPlayback.GetName+')', 'InitializeSound'); - AudioPlayback.InitializePlayback; + writeln( 'InitializeSound DONE' ); - // Initialize Input - Log.LogStatus('Initializing Record ('+AudioPlayback.GetName+')', 'InitializeSound'); - AudioInput.InitializeRecord; end; initialization diff --git a/Game/Code/Classes/UVideo.pas b/Game/Code/Classes/UVideo.pas index ed1e5fe3..6e16a7a3 100644 --- a/Game/Code/Classes/UVideo.pas +++ b/Game/Code/Classes/UVideo.pas @@ -22,6 +22,14 @@ interface {$MODE DELPHI} {$ENDIF} +(* + + look into + av_read_play + +*) + +implementation uses SDL, UGraphicClasses, @@ -37,56 +45,69 @@ uses SDL, dialogs, {$endif} {$ENDIF} - UIni; + UIni, + UMusic; -procedure Init; -procedure FFmpegOpenFile(FileName: pAnsiChar); -procedure FFmpegClose; -procedure FFmpegGetFrame(Time: Extended); -procedure FFmpegDrawGL(Screen: integer); -procedure FFmpegTogglePause; -procedure FFmpegSkip(Time: Single); -{ - @author(Jay Binks ) - @created(2007-10-09) - @lastmod(2007-10-09) +var + singleton_VideoFFMpeg : IVideoPlayback; - @param(aFormatCtx is a PAVFormatContext returned from av_open_input_file ) - @param(aFirstVideoStream is an OUT value of type integer, this is the index of the video stream) - @param(aFirstAudioStream is an OUT value of type integer, this is the index of the audio stream) - @returns(@true on success, @false otherwise) +type + TVideoPlayback_ffmpeg = class( TInterfacedObject, IVideoPlayback ) + private + fVideoOpened , + fVideoPaused : Boolean; - translated from "Setting Up the Audio" section at - http://www.dranger.com/ffmpeg/ffmpegtutorial_all.html - } -function find_stream_ids( const aFormatCtx : PAVFormatContext; Out aFirstVideoStream, aFirstAudioStream : integer ): boolean; + fVideoTex : glUint; + fVideoSkipTime : Single; + + fTexData : array of Byte; + + VideoFormatContext: PAVFormatContext; + + VideoStreamIndex , + AudioStreamIndex : Integer; + VideoCodecContext: PAVCodecContext; + VideoCodec: PAVCodec; + AVFrame: PAVFrame; + AVFrameRGB: PAVFrame; + myBuffer: pByte; + + TexX, TexY, dataX, dataY: Cardinal; + + ScaledVideoWidth, ScaledVideoHeight: Real; + VideoAspect: Real; + VideoTextureU, VideoTextureV: Real; + VideoTimeBase, VideoTime, LastFrameTime, TimeDifference: Extended; + + + WantedAudioCodecContext, + AudioCodecContext : PSDL_AudioSpec; + aCodecCtx : PAVCodecContext; + + + function find_stream_ids( const aFormatCtx : PAVFormatContext; Out aFirstVideoStream, aFirstAudioStream : integer ): boolean; + public + constructor create(); + function GetName: String; + + procedure init(); + + function Open( aFileName : string): boolean; // true if succeed + procedure Close; + + procedure Play; + procedure Pause; + procedure Stop; + + procedure MoveTo(Time: real); + function getPosition: real; + + procedure FFmpegGetFrame(Time: Extended); // WANT TO RENAME THESE TO BE MORE GENERIC + procedure FFmpegDrawGL(Screen: integer); // WANT TO RENAME THESE TO BE MORE GENERIC + + end; -var - VideoOpened, VideoPaused: Boolean; - VideoFormatContext: PAVFormatContext; - VideoStreamIndex , - AudioStreamIndex : Integer; - VideoCodecContext: PAVCodecContext; - VideoCodec: PAVCodec; - AVFrame: PAVFrame; - AVFrameRGB: PAVFrame; - myBuffer: pByte; - VideoTex: glUint; - TexX, TexY, dataX, dataY: Cardinal; - TexData: array of Byte; - ScaledVideoWidth, ScaledVideoHeight: Real; - VideoAspect: Real; - VideoTextureU, VideoTextureV: Real; - VideoTimeBase, VideoTime, LastFrameTime, TimeDifference: Extended; - VideoSkipTime: Single; - - - WantedAudioCodecContext, - AudioCodecContext : PSDL_AudioSpec; - aCodecCtx : PAVCodecContext; - -implementation {$ifdef DebugDisplay} //{$ifNdef win32} @@ -102,15 +123,10 @@ end; { ------------------------------------------------------------------------------ asdf ------------------------------------------------------------------------------ } -procedure Init; -begin - av_register_all; - VideoOpened:=False; - VideoPaused:=False; - - glGenTextures(1, PglUint(@VideoTex)); - SetLength(TexData,0); +function TVideoPlayback_ffmpeg.GetName: String; +begin + result := 'FFMpeg'; end; { @@ -126,7 +142,7 @@ end; translated from "Setting Up the Audio" section at http://www.dranger.com/ffmpeg/ffmpegtutorial_all.html } -function find_stream_ids( const aFormatCtx : PAVFormatContext; Out aFirstVideoStream, aFirstAudioStream : integer ): boolean; +function TVideoPlayback_ffmpeg.find_stream_ids( const aFormatCtx : PAVFormatContext; Out aFirstVideoStream, aFirstAudioStream : integer ): boolean; var i : integer; st : pAVStream; @@ -164,202 +180,10 @@ begin (aFirstVideoStream > -1) ; // Didn't find a video stream end; -procedure FFmpegOpenFile(FileName: pAnsiChar); -var errnum, i, x,y: Integer; - lStreamsCount : Integer; - -begin - VideoOpened := False; - VideoPaused := False; - VideoTimeBase := 0; - VideoTime := 0; - LastFrameTime := 0; - TimeDifference := 0; - VideoFormatContext := 0; - - writeln( Filename ); - - errnum := av_open_input_file(VideoFormatContext, FileName, Nil, 0, Nil); - writeln( 'Errnum : ' +inttostr( errnum )); - if(errnum <> 0) then - begin -{$ifdef DebugDisplay} - case errnum of - AVERROR_UNKNOWN: showmessage('failed to open file '+Filename+#13#10+'AVERROR_UNKNOWN'); - AVERROR_IO: showmessage('failed to open file '+Filename+#13#10+'AVERROR_IO'); - AVERROR_NUMEXPECTED: showmessage('failed to open file '+Filename+#13#10+'AVERROR_NUMEXPECTED'); - AVERROR_INVALIDDATA: showmessage('failed to open file '+Filename+#13#10+'AVERROR_INVALIDDATA'); - AVERROR_NOMEM: showmessage('failed to open file '+Filename+#13#10+'AVERROR_NOMEM'); - AVERROR_NOFMT: showmessage('failed to open file '+Filename+#13#10+'AVERROR_NOFMT'); - AVERROR_NOTSUPP: showmessage('failed to open file '+Filename+#13#10+'AVERROR_NOTSUPP'); - else showmessage('failed to open file '+Filename+#13#10+'Error number: '+inttostr(Errnum)); - end; -{$ENDIF} - Exit; - end - else - begin - VideoStreamIndex := -1; - AudioStreamIndex := -1; - - // Find which stream contains the video - if( av_find_stream_info(VideoFormatContext) >= 0 ) then - begin - find_stream_ids( VideoFormatContext, VideoStreamIndex, AudioStreamIndex ); - - writeln( 'VideoStreamIndex : ' + inttostr(VideoStreamIndex) ); - writeln( 'AudioStreamIndex : ' + inttostr(AudioStreamIndex) ); - end; - aCodecCtx := VideoFormatContext.streams[ AudioStreamIndex ].codec; - - WantedAudioCodecContext.freq := aCodecCtx^.sample_rate; - WantedAudioCodecContext.format := AUDIO_S16SYS; - WantedAudioCodecContext.channels := aCodecCtx^.channels; - WantedAudioCodecContext.silence := 0; - WantedAudioCodecContext.samples := 1024;//SDL_AUDIO_BUFFER_SIZE; -// WantedAudioCodecContext.callback := audio_callback; - WantedAudioCodecContext.userdata := aCodecCtx; - - -(* - if(SDL_OpenAudio(WantedAudioCodecContext, AudioCodecContext) < 0) then - begin - writeln( 'Could not do SDL_OpenAudio' ); - exit; - end; -*) - - if(VideoStreamIndex >= 0) then - begin - VideoCodecContext:=VideoFormatContext^.streams[VideoStreamIndex]^.codec; - VideoCodec:=avcodec_find_decoder(VideoCodecContext^.codec_id); - end - else - begin -{$ifdef DebugDisplay} - showmessage('found no video stream'); -{$ENDIF} - av_close_input_file(VideoFormatContext); - Exit; - end; - - - if(VideoCodec<>Nil) then - begin - errnum:=avcodec_open(VideoCodecContext, VideoCodec); - end else begin -{$ifdef DebugDisplay} - showmessage('no matching codec found'); -{$ENDIF} - avcodec_close(VideoCodecContext); - av_close_input_file(VideoFormatContext); - Exit; - end; - if(errnum >=0) then - begin -{$ifdef DebugDisplay} - showmessage('Found a matching Codec: '+ VideoCodecContext^.Codec.Name +#13#10#13#10+ - ' Width = '+inttostr(VideoCodecContext^.width)+ ', Height='+inttostr(VideoCodecContext^.height)+#13#10+ - ' Aspect : '+inttostr(VideoCodecContext^.sample_aspect_ratio.num)+'/'+inttostr(VideoCodecContext^.sample_aspect_ratio.den)+#13#10+ - ' Framerate : '+inttostr(VideoCodecContext^.time_base.num)+'/'+inttostr(VideoCodecContext^.time_base.den)); -{$endif} - // allocate space for decoded frame and rgb frame - AVFrame:=avcodec_alloc_frame; - AVFrameRGB:=avcodec_alloc_frame; - end; - myBuffer:=Nil; - if(AVFrame <> Nil) and (AVFrameRGB <> Nil) then - begin - myBuffer:=av_malloc(avpicture_get_size(PIX_FMT_RGB24, VideoCodecContext^.width, - VideoCodecContext^.height)); - end; - if myBuffer <> Nil then errnum:=avpicture_fill(PAVPicture(AVFrameRGB), myBuffer, PIX_FMT_RGB24, - VideoCodecContext^.width, VideoCodecContext^.height) - else begin -{$ifdef DebugDisplay} - showmessage('failed to allocate video buffer'); -{$endif} - av_free(AVFrameRGB); - av_free(AVFrame); - avcodec_close(VideoCodecContext); - av_close_input_file(VideoFormatContext); - Exit; - end; - if errnum >=0 then - begin - VideoOpened:=True; - - TexX := VideoCodecContext^.width; - TexY := VideoCodecContext^.height; - dataX := Round(Power(2, Ceil(Log2(TexX)))); - dataY := Round(Power(2, Ceil(Log2(TexY)))); - SetLength(TexData,dataX*dataY*3); - // calculate some information for video display - VideoAspect:=VideoCodecContext^.sample_aspect_ratio.num/VideoCodecContext^.sample_aspect_ratio.den; - if (VideoAspect = 0) then - VideoAspect:=VideoCodecContext^.width/VideoCodecContext^.height - else - VideoAspect:=VideoAspect*VideoCodecContext^.width/VideoCodecContext^.height; - if VideoAspect >= 4/3 then - begin - ScaledVideoWidth:=800.0; - ScaledVideoHeight:=800.0/VideoAspect; - end else - begin - ScaledVideoHeight:=600.0; - ScaledVideoWidth:=600.0*VideoAspect; - end; - VideoTimeBase:=VideoCodecContext^.time_base.num/VideoCodecContext^.time_base.den; - // hack to get reasonable timebase for divx -{$ifdef DebugDisplay} - showmessage('framerate: '+inttostr(floor(1/videotimebase))+'fps'); -{$endif} - if VideoTimeBase < 0.02 then // 0.02 <-> 50 fps - begin - VideoTimeBase:=VideoCodecContext^.time_base.den/VideoCodecContext^.time_base.num; - while VideoTimeBase > 50 do VideoTimeBase:=VideoTimeBase/10; - VideoTimeBase:=1/VideoTimeBase; - end; -{$ifdef DebugDisplay} - showmessage('corrected framerate: '+inttostr(floor(1/videotimebase))+'fps'); - - if ((VideoAspect*VideoCodecContext^.width*VideoCodecContext^.height)>200000) then - showmessage('you are trying to play a rather large video'+#13#10+ - 'be prepared to experience some timing problems'); -{$endif} - end; - end; -end; - -procedure FFmpegClose; -begin - if VideoOpened then begin - av_free(myBuffer); - av_free(AVFrameRGB); - av_free(AVFrame); - avcodec_close(VideoCodecContext); - av_close_input_file(VideoFormatContext); - SetLength(TexData,0); - VideoOpened:=False; - end; -end; -procedure FFmpegTogglePause; -begin - if VideoPaused then VideoPaused:=False - else VideoPaused:=True; -end; -procedure FFmpegSkip(Time: Single); -begin - VideoSkiptime:=Time; - if VideoSkipTime > 0 then begin - av_seek_frame(VideoFormatContext,-1,Floor((VideoSkipTime)*1500000),0); - VideoTime:=VideoSkipTime; - end; -end; -procedure FFmpegGetFrame(Time: Extended); +procedure TVideoPlayback_ffmpeg.FFmpegGetFrame(Time: Extended); var FrameFinished: Integer; AVPacket: TAVPacket; @@ -372,13 +196,13 @@ var const FRAMEDROPCOUNT=3; begin - if not VideoOpened then Exit; + if not fVideoOpened then Exit; - if VideoPaused then Exit; - - myTime:=Time+VideoSkipTime; - TimeDifference:=myTime-VideoTime; - DropFrame:=False; + if fVideoPaused then Exit; + + myTime := Time + fVideoSkipTime; + TimeDifference := myTime - VideoTime; + DropFrame := False; {$IFDEF DebugDisplay} showmessage('Time: '+inttostr(floor(Time*1000))+#13#10+ @@ -404,7 +228,8 @@ begin Exit;// we don't need a new frame now end; - + + VideoTime:=VideoTime+VideoTimeBase; TimeDifference:=myTime-VideoTime; if TimeDifference >= (FRAMEDROPCOUNT-1)*VideoTimeBase then // skip frames @@ -415,37 +240,52 @@ begin {$endif} {$IFDEF DebugDisplay} + showmessage('skipping frames'+#13#10+ 'TimeBase: '+inttostr(floor(VideoTimeBase*1000))+#13#10+ 'TimeDiff: '+inttostr(floor(TimeDifference*1000))+#13#10+ 'Time2Skip: '+inttostr(floor((Time-LastFrameTime)*1000))); + {$endif} -// av_seek_frame(VideoFormatContext,VideoStreamIndex,Floor(Time*VideoTimeBase),0); +// av_seek_frame(VideoFormatContext.,VideoStreamIndex,Floor(Time*VideoTimeBase),0); { av_seek_frame(VideoFormatContext,-1,Floor((myTime+VideoTimeBase)*1500000),0); VideoTime:=floor(myTime/VideoTimeBase)*VideoTimeBase;} VideoTime:=VideoTime+FRAMEDROPCOUNT*VideoTimeBase; DropFrame:=True; end; + // av_init_packet(@AVPacket); + AVPacket.data := nil; av_init_packet( AVPacket ); // JB-ffmpeg - + + FrameFinished:=0; // read packets until we have a finished frame (or there are no more packets) // while (FrameFinished=0) and (av_read_frame(VideoFormatContext, @AVPacket)>=0) do while (FrameFinished=0) and (av_read_frame(VideoFormatContext, AVPacket)>=0) do // JB-ffmpeg begin + + // if we got a packet from the video stream, then decode it if (AVPacket.stream_index=VideoStreamIndex) then // errnum:=avcodec_decode_video(VideoCodecContext, AVFrame, @frameFinished , AVPacket.data, AVPacket.size); errnum := avcodec_decode_video(VideoCodecContext, AVFrame, frameFinished , AVPacket.data, AVPacket.size); // JB-ffmpeg - + // release internal packet structure created by av_read_frame // av_free_packet(PAVPacket(@AVPacket)); - av_free_packet( AVPacket ); // JB-ffmpeg + + try + if AVPacket.data <> nil then + av_free_packet( AVPacket ); // JB-ffmpeg + except + // TODO : JB_FFMpeg ... why does this now AV sometimes ( or always !! ) + end; + end; - + + if DropFrame then for droppedFrames:=1 to FRAMEDROPCOUNT do begin FrameFinished:=0; @@ -485,12 +325,12 @@ begin linesize := AVFrameRGB^.linesize[0]; for y:=0 to TexY-1 do begin - System.Move(FrameDataPtr[y*linesize],TexData[3*y*dataX],linesize); + System.Move(FrameDataPtr[y*linesize],fTexData[3*y*dataX],linesize); end; // generate opengl texture out of whatever we got - glBindTexture(GL_TEXTURE_2D, VideoTex); - glTexImage2D(GL_TEXTURE_2D, 0, 3, dataX, dataY, 0, GL_RGB, GL_UNSIGNED_BYTE, TexData); + glBindTexture(GL_TEXTURE_2D, fVideoTex); + glTexImage2D(GL_TEXTURE_2D, 0, 3, dataX, dataY, 0, GL_RGB, GL_UNSIGNED_BYTE, fTexData); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); {$ifdef DebugFrames} @@ -501,20 +341,21 @@ begin end; end; -procedure FFmpegDrawGL(Screen: integer); +procedure TVideoPlayback_ffmpeg.FFmpegDrawGL(Screen: integer); begin // have a nice black background to draw on (even if there were errors opening the vid) - if Screen=1 then begin + if Screen=1 then + begin 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 VideoOpened then Exit; + if not fVideoOpened then Exit; glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); glColor4f(1, 1, 1, 1); - glBindTexture(GL_TEXTURE_2D, VideoTex); + glBindTexture(GL_TEXTURE_2D, fVideoTex); glbegin(gl_quads); glTexCoord2f( 0, 0); glVertex2f(400-ScaledVideoWidth/2, 300-ScaledVideoHeight/2); glTexCoord2f( 0, TexY/dataY); glVertex2f(400-ScaledVideoWidth/2, 300+ScaledVideoHeight/2); @@ -525,7 +366,8 @@ begin glDisable(GL_BLEND); {$ifdef Info} - if VideoSkipTime+VideoTime+VideoTimeBase < 0 then begin + if VideoSkipTime+VideoTime+VideoTimeBase < 0 then + begin glColor4f(0.7, 1, 0.3, 1); SetFontStyle (1); SetFontItalic(False); @@ -558,4 +400,253 @@ begin {$endif} end; +constructor TVideoPlayback_ffmpeg.create(); +begin + writeln( 'UVideo_FFMpeg - TVideoPlayback_ffmpeg.create()' ); + + writeln( 'UVideo_FFMpeg - av_register_all' ); + av_register_all; + + fVideoOpened := False; + fVideoPaused := False; + +end; + +procedure TVideoPlayback_ffmpeg.init(); +begin + writeln( 'UVideo_FFMpeg - glGenTextures(1, PglUint(@fVideoTex))' ); + glGenTextures(1, PglUint(@fVideoTex)); + + writeln( 'UVideo_FFMpeg - SetLength(fTexData,0)' ); + SetLength(fTexData,0); +end; + + +function TVideoPlayback_ffmpeg.Open( aFileName : string): boolean; // true if succeed +var + errnum, i, x,y: Integer; + lStreamsCount : Integer; + +begin + fVideoOpened := False; + fVideoPaused := False; + VideoTimeBase := 0; + VideoTime := 0; + LastFrameTime := 0; + TimeDifference := 0; + VideoFormatContext := 0; + + writeln( aFileName ); + + errnum := av_open_input_file(VideoFormatContext, pchar( aFileName ), Nil, 0, Nil); + writeln( 'Errnum : ' +inttostr( errnum )); + if(errnum <> 0) then + begin +{$ifdef DebugDisplay} + case errnum of + AVERROR_UNKNOWN: showmessage('failed to open file '+aFileName+#13#10+'AVERROR_UNKNOWN'); + AVERROR_IO: showmessage('failed to open file '+aFileName+#13#10+'AVERROR_IO'); + AVERROR_NUMEXPECTED: showmessage('failed to open file '+aFileName+#13#10+'AVERROR_NUMEXPECTED'); + AVERROR_INVALIDDATA: showmessage('failed to open file '+aFileName+#13#10+'AVERROR_INVALIDDATA'); + AVERROR_NOMEM: showmessage('failed to open file '+aFileName+#13#10+'AVERROR_NOMEM'); + AVERROR_NOFMT: showmessage('failed to open file '+aFileName+#13#10+'AVERROR_NOFMT'); + AVERROR_NOTSUPP: showmessage('failed to open file '+aFileName+#13#10+'AVERROR_NOTSUPP'); + else showmessage('failed to open file '+aFileName+#13#10+'Error number: '+inttostr(Errnum)); + end; +{$ENDIF} + Exit; + end + else + begin + VideoStreamIndex := -1; + AudioStreamIndex := -1; + + // Find which stream contains the video + if( av_find_stream_info(VideoFormatContext) >= 0 ) then + begin + find_stream_ids( VideoFormatContext, VideoStreamIndex, AudioStreamIndex ); + + writeln( 'VideoStreamIndex : ' + inttostr(VideoStreamIndex) ); + writeln( 'AudioStreamIndex : ' + inttostr(AudioStreamIndex) ); + end; + aCodecCtx := VideoFormatContext.streams[ AudioStreamIndex ].codec; + +(* + WantedAudioCodecContext.freq := aCodecCtx^.sample_rate; + WantedAudioCodecContext.format := AUDIO_S16SYS; + WantedAudioCodecContext.channels := aCodecCtx^.channels; + WantedAudioCodecContext.silence := 0; + WantedAudioCodecContext.samples := 1024;//SDL_AUDIO_BUFFER_SIZE; +// WantedAudioCodecContext.callback := audio_callback; + WantedAudioCodecContext.userdata := aCodecCtx; +*) + +(* + if(SDL_OpenAudio(WantedAudioCodecContext, AudioCodecContext) < 0) then + begin + writeln( 'Could not do SDL_OpenAudio' ); + exit; + end; +*) + + if(VideoStreamIndex >= 0) then + begin + VideoCodecContext:=VideoFormatContext^.streams[VideoStreamIndex]^.codec; + VideoCodec:=avcodec_find_decoder(VideoCodecContext^.codec_id); + end + else + begin +{$ifdef DebugDisplay} + showmessage('found no video stream'); +{$ENDIF} + av_close_input_file(VideoFormatContext); + Exit; + end; + + + if(VideoCodec<>Nil) then + begin + errnum:=avcodec_open(VideoCodecContext, VideoCodec); + end else begin +{$ifdef DebugDisplay} + showmessage('no matching codec found'); +{$ENDIF} + avcodec_close(VideoCodecContext); + av_close_input_file(VideoFormatContext); + Exit; + end; + if(errnum >=0) then + begin +{$ifdef DebugDisplay} + showmessage('Found a matching Codec: '+ VideoCodecContext^.Codec.Name +#13#10#13#10+ + ' Width = '+inttostr(VideoCodecContext^.width)+ ', Height='+inttostr(VideoCodecContext^.height)+#13#10+ + ' Aspect : '+inttostr(VideoCodecContext^.sample_aspect_ratio.num)+'/'+inttostr(VideoCodecContext^.sample_aspect_ratio.den)+#13#10+ + ' Framerate : '+inttostr(VideoCodecContext^.time_base.num)+'/'+inttostr(VideoCodecContext^.time_base.den)); +{$endif} + // allocate space for decoded frame and rgb frame + AVFrame:=avcodec_alloc_frame; + AVFrameRGB:=avcodec_alloc_frame; + end; + myBuffer:=Nil; + if(AVFrame <> Nil) and (AVFrameRGB <> Nil) then + begin + myBuffer:=av_malloc(avpicture_get_size(PIX_FMT_RGB24, VideoCodecContext^.width, + VideoCodecContext^.height)); + end; + if myBuffer <> Nil then errnum:=avpicture_fill(PAVPicture(AVFrameRGB), myBuffer, PIX_FMT_RGB24, + VideoCodecContext^.width, VideoCodecContext^.height) + else begin +{$ifdef DebugDisplay} + showmessage('failed to allocate video buffer'); +{$endif} + av_free(AVFrameRGB); + av_free(AVFrame); + avcodec_close(VideoCodecContext); + av_close_input_file(VideoFormatContext); + Exit; + end; + if errnum >=0 then + begin + fVideoOpened:=True; + + TexX := VideoCodecContext^.width; + TexY := VideoCodecContext^.height; + dataX := Round(Power(2, Ceil(Log2(TexX)))); + dataY := Round(Power(2, Ceil(Log2(TexY)))); + SetLength(fTexData,dataX*dataY*3); + // calculate some information for video display + VideoAspect:=VideoCodecContext^.sample_aspect_ratio.num/VideoCodecContext^.sample_aspect_ratio.den; + if (VideoAspect = 0) then + VideoAspect:=VideoCodecContext^.width/VideoCodecContext^.height + else + VideoAspect:=VideoAspect*VideoCodecContext^.width/VideoCodecContext^.height; + if VideoAspect >= 4/3 then + begin + ScaledVideoWidth:=800.0; + ScaledVideoHeight:=800.0/VideoAspect; + end else + begin + ScaledVideoHeight:=600.0; + ScaledVideoWidth:=600.0*VideoAspect; + end; + VideoTimeBase:=VideoCodecContext^.time_base.num/VideoCodecContext^.time_base.den; + // hack to get reasonable timebase for divx +{$ifdef DebugDisplay} + showmessage('framerate: '+inttostr(floor(1/videotimebase))+'fps'); +{$endif} + if VideoTimeBase < 0.02 then // 0.02 <-> 50 fps + begin + VideoTimeBase:=VideoCodecContext^.time_base.den/VideoCodecContext^.time_base.num; + while VideoTimeBase > 50 do VideoTimeBase:=VideoTimeBase/10; + VideoTimeBase:=1/VideoTimeBase; + end; +{$ifdef DebugDisplay} + showmessage('corrected framerate: '+inttostr(floor(1/videotimebase))+'fps'); + + if ((VideoAspect*VideoCodecContext^.width*VideoCodecContext^.height)>200000) then + showmessage('you are trying to play a rather large video'+#13#10+ + 'be prepared to experience some timing problems'); +{$endif} + end; + end; +end; + +procedure TVideoPlayback_ffmpeg.Close; +begin + if fVideoOpened then + begin + av_free(myBuffer); + av_free(AVFrameRGB); + av_free(AVFrame); + + avcodec_close(VideoCodecContext); + av_close_input_file(VideoFormatContext); + + SetLength(fTexData,0); + + fVideoOpened:=False; + end; +end; + +procedure TVideoPlayback_ffmpeg.Play; +begin +end; + +procedure TVideoPlayback_ffmpeg.Pause; +begin + fVideoPaused := not fVideoPaused; +end; + +procedure TVideoPlayback_ffmpeg.Stop; +begin +end; + +procedure TVideoPlayback_ffmpeg.MoveTo(Time: real); +begin + fVideoSkipTime := Time; + + if fVideoSkipTime > 0 then + begin + av_seek_frame(VideoFormatContext,-1,Floor((fVideoSkipTime)*1500000),0); + + VideoTime := fVideoSkipTime; + end; +end; + +function TVideoPlayback_ffmpeg.getPosition: real; +begin + result := 0; +end; + +initialization + singleton_VideoFFMpeg := TVideoPlayback_ffmpeg.create(); + + writeln( 'UVideo_FFMpeg - Register Playback' ); + AudioManager.add( IVideoPlayback( singleton_VideoFFMpeg ) ); + + +finalization + AudioManager.Remove( IVideoPlayback( singleton_VideoFFMpeg ) ); + + end. -- cgit v1.2.3