From 8cca9e3e6f591c35d35d132a9d3f93ffc7cdfee8 Mon Sep 17 00:00:00 2001 From: jaybinks Date: Sat, 27 Oct 2007 06:31:04 +0000 Subject: made some major progress with ffmpeg audio playback !!! YAY !!! still a little choppy, so I suspect incorrect buffer sizes or something like that. also made some mods to support Unicode song file iteration on windows, this is no worse than what we had before, but is not complete.. oh this code only supports win 2000 and up .. no Win 98... git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@533 b956fd51-792f-4845-bead-9b4dfca2ff2c --- Game/Code/Classes/UAudio_FFMpeg.pas | 153 ++++++++++++++++++++++++------------ Game/Code/Classes/UCommon.pas | 88 +++++++++++++++++++++ Game/Code/Classes/UFiles.pas | 20 +++-- Game/Code/Classes/USongs.pas | 65 +++++++-------- Game/Code/Classes/UVideo.pas | 85 ++++++++++++++------ Game/Code/Screens/UScreenSong.pas | 8 +- Game/Code/UltraStar.dpr | 13 +-- 7 files changed, 311 insertions(+), 121 deletions(-) diff --git a/Game/Code/Classes/UAudio_FFMpeg.pas b/Game/Code/Classes/UAudio_FFMpeg.pas index 548fb343..35822a3b 100644 --- a/Game/Code/Classes/UAudio_FFMpeg.pas +++ b/Game/Code/Classes/UAudio_FFMpeg.pas @@ -7,6 +7,8 @@ This unit is primarily based upon - and tutorial03.c + http://www.inb.uni-luebeck.de/~boehme/using_libavcodec.html + *******************************************************************************) interface @@ -25,10 +27,10 @@ uses Classes, {$IFNDEF FPC} Forms, {$ENDIF} + SDL, // Used for Audio output Interface avcodec, // FFMpeg Audio file decoding avformat, avutil, - SDL, // Used for Audio output Interface ULog, UMusic; @@ -47,19 +49,28 @@ type function packet_queue_get(var aPacketQueue : TPacketQueue; var AVPacket : TAVPacket; block : integer ): integer; procedure packet_queue_init( var aPacketQueue : TPacketQueue ); procedure audio_callback( userdata: Pointer; stream: PUInt8; len: Integer ); cdecl; - function audio_decode_frame(aCodecCtx : TAVCodecContext; audio_buf : PUInt8; buf_size: integer): integer; + function audio_decode_frame(aCodecCtx : TAVCodecContext; aAudio_buf : PUInt8; buf_size: integer): integer; var singleton_MusicFFMpeg : IAudioPlayback = nil; +var + audioq : TPacketQueue; + quit : integer = 0; +// faudio_buf : array[ 0 .. 0 ] of byte; //pUInt8{$ifndef fpc};{$else} = nil;{$endif} +// audio_buf : array[ 0 .. AVCODEC_MAX_AUDIO_FRAME_SIZE ] of byte; //pUInt8{$ifndef fpc};{$else} = nil;{$endif} + +type + Taudiobuff = array[ 0 .. AVCODEC_MAX_AUDIO_FRAME_SIZE ] of byte; + PAudioBuff = ^Taudiobuff; implementation uses {$IFDEF FPC} lclintf, - {$ENDIF} libc, + {$ENDIF} // URecord, UIni, UMain, @@ -82,9 +93,6 @@ type const ModeStr: array[TMPModes] of string = ('Not ready', 'Stopped', 'Playing', 'Recording', 'Seeking', 'Paused', 'Open'); -var - audioq : TPacketQueue; - quit : integer = 0; type @@ -154,7 +162,7 @@ end; constructor TAudio_ffMpeg.create(); begin - writeln( 'UVideo_FFMpeg - av_register_all' ); +// writeln( 'UVideo_FFMpeg - av_register_all' ); av_register_all; end; @@ -170,20 +178,20 @@ begin i := 0; while ( i < aFormatCtx.nb_streams ) do begin - writeln( ' aFormatCtx.streams[i] : ' + inttostr( i ) ); +// writeln( ' aFormatCtx.streams[i] : ' + inttostr( i ) ); st := aFormatCtx.streams[i]; if(st.codec.codec_type = CODEC_TYPE_VIDEO ) AND (aFirstVideoStream < 0) THEN begin - writeln( 'Found Video Stream' ); +// writeln( 'Found Video Stream' ); aFirstVideoStream := i; end; if ( st.codec.codec_type = CODEC_TYPE_AUDIO ) AND ( aFirstAudioStream < 0) THEN begin - writeln( 'Found Audio Stream' ); +// writeln( 'Found Audio Stream' ); aFirstAudioStream := i; end; @@ -206,8 +214,8 @@ var S: integer; begin - LoadSoundFromFile(BassStart, SoundPath + 'foo fighters - best of you.mp3'); - +// LoadSoundFromFile(BassStart, SoundPath + 'Green Day - American Idiot.mp3'); + (* LoadSoundFromFile(BassStart, SoundPath + 'Common start.mp3'); LoadSoundFromFile(BassBack, SoundPath + 'Common back.mp3'); @@ -438,12 +446,13 @@ end; procedure TAudio_ffMpeg.StopCard(Card: byte); begin + // TODO : jb_linux replace with something other than bass // BASS_RecordSetDevice(Card); // BASS_RecordFree; end; -function audio_decode_frame(aCodecCtx : TAVCodecContext; audio_buf : PUInt8; buf_size: integer): integer; +function audio_decode_frame(aCodecCtx : TAVCodecContext; aAudio_buf : PUInt8; buf_size: integer): integer; var pkt : TAVPacket; audio_pkt_data : pchar;//PUInt8 = nil; @@ -451,26 +460,44 @@ var len1 , data_size : integer; begin -// result := 1; -// exit; + {$ifdef win32} + FillChar(pkt, sizeof(pkt), #0); + {$else} + memset(@pkt, 0, sizeof(pkt)); // todo : jb memset + {$endif} + + audio_pkt_data := nil; + audio_pkt_size := 0; while true do begin while ( audio_pkt_size > 0 ) do begin - writeln( 'got audio packet' ); +// writeln( 'got audio packet' ); data_size := buf_size; - -// len1 := avcodec_decode_audio2(aCodecCtx, (int16_t )audio_buf, &data_size, audio_pkt_data, audio_pkt_size); - len1 := avcodec_decode_audio(@aCodecCtx, PWord( audio_buf ), data_size, audio_pkt_data, audio_pkt_size); // Todo.. should be avcodec_decode_audio2 but this wont link on my ubuntu box. + + len1 := -1; + + if aAudio_buf <> nil then + begin +// writeln( 'pre avcodec_decode_audio' ); + {$ifdef fpc} + len1 := avcodec_decode_audio(@aCodecCtx, PWord( aAudio_buf ), data_size, audio_pkt_data, audio_pkt_size); // Todo.. should be avcodec_decode_audio2 but this wont link on my ubuntu box. + {$else} + len1 := avcodec_decode_audio(@aCodecCtx, Pointer( aAudio_buf ), data_size, audio_pkt_data, audio_pkt_size); // Todo.. should be avcodec_decode_audio2 but this wont link on my ubuntu box. + {$endif} +// writeln( 'post avcodec_decode_audio' ); + + end; // writeln('avcodec_decode_audio'); if(len1 < 0) then begin //* if error, skip frame */ - audio_pkt_size := 0; +// writeln( 'Skip audio frame' ); + audio_pkt_size := 0; break; end; @@ -506,7 +533,7 @@ begin audio_pkt_data := pchar( pkt.data ); audio_pkt_size := pkt.size; - writeln( 'Audio Packet Size - ' + inttostr(audio_pkt_size) ); +// writeln( 'Audio Packet Size - ' + inttostr(audio_pkt_size) ); end; end; @@ -517,52 +544,69 @@ var audio_size , len1 : integer; aCodecCtx : TAVCodecContext; - audio_buf : pUInt8 = nil; + + lSrc : pointer; + + // this is used to emulate ...... static uint8_t audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2]; + lAudio_buf_data : Taudiobuff; // This created the memory we need + laudio_buf : PAudioBuff; // this makes it easy to work with.. since its the pointer to that memeory everywhere begin - aCodecCtx := pAVCodecContext(userdata)^; - audio_buf := UInt8( (AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) div 2); // todo : JB - audio_size := -1; + laudio_buf := @lAudio_buf_data ; -// writeln('----------- audio callback' ); + aCodecCtx := pAVCodecContext(userdata)^; + audio_size := -1; + audio_buf_index := 0; + audio_buf_size := 0; while (len > 0) do begin if(audio_buf_index >= audio_buf_size) then begin // We have already sent all our data; get more */ - audio_size := audio_decode_frame(aCodecCtx, audio_buf, sizeof(audio_buf)); + audio_size := audio_decode_frame(aCodecCtx, pUInt8( laudio_buf ), sizeof(laudio_buf)); if(audio_size < 0) then begin // If error, output silence */ audio_buf_size := 1024; // arbitrary? - memset(audio_buf, 0, audio_buf_size); // todo : jb memset + + {$ifdef win32} + FillChar(laudio_buf, audio_buf_size, #0); + {$else} + memset(laudio_buf, 0, audio_buf_size); // todo : jb memset + {$endif} end else begin audio_buf_size := audio_size; end; -// audio_buf_index := 0; // Todo : jb - SegFault ? + audio_buf_index := 0; // Todo : jb - SegFault ? end; len1 := audio_buf_size - audio_buf_index; if (len1 > len) then len1 := len; - - memcpy(stream, PUInt8( audio_buf ) + audio_buf_index , len1); - len := len - len1; - stream := stream + len1; + + {$ifdef win32} + lSrc := PUInt8( integer( laudio_buf ) + audio_buf_index ); + CopyMemory(stream, lSrc , len1); + {$else} + memcpy(stream, PUInt8( laudio_buf ) + audio_buf_index , len1); + {$endif} + + len := len - len1; + stream^ := stream^ + len1; audio_buf_index := audio_buf_index + len1; end; end; function TAudio_ffMpeg.LoadSoundFromFile(var hStream: hStream; Name: string): boolean; var - L: Integer; - pFormatCtx: PAVFormatContext; + L : Integer; + pFormatCtx : PAVFormatContext; lVidStreamID , lAudStreamID : Integer; aCodecCtx : pAVCodecContext; @@ -578,7 +622,7 @@ begin if FileExists(Name) then begin - writeln('Loading Sound: "' + Name + '"', 'LoadSoundFromFile'); +// writeln('Loading Sound: "' + Name + '"', 'LoadSoundFromFile'); // Open video file if (av_open_input_file(pFormatCtx, pchar(Name), nil, 0, nil) > 0) then @@ -593,11 +637,11 @@ begin if not find_stream_ids( pFormatCtx, lVidStreamID, lAudStreamID ) then exit; - writeln( 'done searching for stream ids' ); +// writeln( 'done searching for stream ids' ); if lAudStreamID > -1 then begin - writeln( 'Audio Stream ID is : '+ inttostr( lAudStreamID ) ); +// writeln( 'Audio Stream ID is : '+ inttostr( lAudStreamID ) ); lAudioStream := pFormatCtx.streams[lAudStreamID]; aCodecCtx := lAudioStream.codec; @@ -617,9 +661,9 @@ begin writeln('SDL_OpenAudio: '+SDL_GetError()); exit end; - - writeln( 'SDL opened audio device' ); - + +// writeln( 'SDL opened audio device' ); + aCodec := avcodec_find_decoder(aCodecCtx.codec_id); if (aCodec = nil) then begin @@ -629,27 +673,28 @@ begin avcodec_open(aCodecCtx, aCodec); - writeln( 'Opened the codec' ); +// writeln( 'Opened the codec' ); packet_queue_init( audioq ); SDL_PauseAudio(0); - writeln( 'SDL_PauseAudio' ); +// writeln( 'SDL_PauseAudio' ); i := 0; - while (av_read_frame(pFormatCtx, packet)>=0) do + while (av_read_frame(pFormatCtx, packet) >= 0) do begin - writeln( 'ffmpeg - av_read_frame' ); +// writeln( 'ffmpeg - av_read_frame' ); if (packet.stream_index = lAudStreamID ) then begin +// writeln( 'packet_queue_put' ); packet_queue_put(audioq, packet); end else begin av_free_packet(packet); end; - + // Free the packet that was allocated by av_read_frame SDL_PollEvent(@event); @@ -665,12 +710,14 @@ begin *) end; - + +// halt(0); + // Close the codec - avcodec_close(aCodecCtx); +// avcodec_close(aCodecCtx); // Close the video file - av_close_input_file(pFormatCtx); +// av_close_input_file(pFormatCtx); (* try @@ -698,7 +745,11 @@ end; procedure packet_queue_init(var aPacketQueue : TPacketQueue ); begin - memset(@aPacketQueue, 0, sizeof(TPacketQueue)); + {$ifdef win32} + FillChar(aPacketQueue, sizeof(TPacketQueue), #0); + {$else} + memset(@aPacketQueue, 0, sizeof(TPacketQueue)); + {$endif} aPacketQueue.mutex := SDL_CreateMutex(); aPacketQueue.cond := SDL_CreateCond(); @@ -710,7 +761,7 @@ var begin result := -1; - writeln( 'TAudio_ffMpeg.packet_queue_put' ); +// writeln( 'TAudio_ffMpeg.packet_queue_put' ); if av_dup_packet(@AVPacket) < 0 then exit; diff --git a/Game/Code/Classes/UCommon.pas b/Game/Code/Classes/UCommon.pas index af9ae82d..44ec6bb3 100644 --- a/Game/Code/Classes/UCommon.pas +++ b/Game/Code/Classes/UCommon.pas @@ -58,6 +58,26 @@ function AdaptFilePaths( const aPath : widestring ): widestring; procedure ZeroMemory( Destination: Pointer; Length: DWORD ); {$ENDIF} +{$IFDEF Win32} + +type + TSearchRecW = record + Time: Integer; + Size: Integer; + Attr: Integer; + Name: WideString; + ExcludeAttr: Integer; + FindHandle: THandle; + FindData: TWin32FindDataW; + end; + + function FindFirstW(const Path: WideString; Attr: Integer; var F: TSearchRecW): Integer; + function FindNextW(var F: TSearchRecW): Integer; + procedure FindCloseW(var F: TSearchRecW); + function FindMatchingFileW(var F: TSearchRecW): Integer; + function DirectoryExistsW(const Directory: widestring): Boolean; +{$endif} + implementation function StringReplaceW(text : WideString; search, rep: WideChar):WideString; @@ -190,7 +210,75 @@ begin end; {$ENDIF} + + + {$ENDIF} +{$ifdef win32} +function FindFirstW(const Path: widestring; Attr: Integer; var F: TSearchRecW): Integer; +const + faSpecial = faHidden or faSysFile or faVolumeID or faDirectory; +begin + F.ExcludeAttr := not Attr and faSpecial; + F.FindHandle := FindFirstFileW(PWideChar(Path), F.FindData); + if F.FindHandle <> INVALID_HANDLE_VALUE then + begin + Result := FindMatchingFileW(F); + if Result <> 0 then FindCloseW(F); + end else + Result := GetLastError; +end; + +function FindNextW(var F: TSearchRecW): Integer; +begin + if FindNextFileW(F.FindHandle, F.FindData) then + Result := FindMatchingFileW(F) + else + Result := GetLastError; +end; + +procedure FindCloseW(var F: TSearchRecW); +begin + if F.FindHandle <> INVALID_HANDLE_VALUE then + begin + Windows.FindClose(F.FindHandle); + F.FindHandle := INVALID_HANDLE_VALUE; + end; +end; + +function FindMatchingFileW(var F: TSearchRecW): Integer; +var + LocalFileTime: TFileTime; +begin + with F do + begin + while FindData.dwFileAttributes and ExcludeAttr <> 0 do + if not FindNextFileW(FindHandle, FindData) then + begin + Result := GetLastError; + Exit; + end; + FileTimeToLocalFileTime(FindData.ftLastWriteTime, LocalFileTime); + FileTimeToDosDateTime(LocalFileTime, LongRec(Time).Hi, LongRec(Time).Lo); + Size := FindData.nFileSizeLow; + Attr := FindData.dwFileAttributes; + Name := FindData.cFileName; + end; + Result := 0; +end; + +function DirectoryExistsW(const Directory: widestring): Boolean; +var + Code: Integer; +begin + Code := GetFileAttributesW(PWideChar(Directory)); + Result := (Code <> -1) and (FILE_ATTRIBUTE_DIRECTORY and Code <> 0); +end; +{$endif} + + + + end. diff --git a/Game/Code/Classes/UFiles.pas b/Game/Code/Classes/UFiles.pas index 7e23b42f..717d20e2 100644 --- a/Game/Code/Classes/UFiles.pas +++ b/Game/Code/Classes/UFiles.pas @@ -333,16 +333,22 @@ Result := False; //Open File and set File Pointer to the beginning AssignFile(SongFile, Song.Path + Song.FileName); - Reset(SongFile); +// if assinged( SongFile ) then + begin + try + Reset(SongFile); - //Clear old Song Header - ClearSong(Song); + //Clear old Song Header + ClearSong(Song); - //Read Header - Result := ReadTxTHeader(Song); + //Read Header + Result := ReadTxTHeader(Song); - //And Close File - CloseFile(SongFile); + //And Close File + finally + CloseFile(SongFile); + end; + end; {except CloseFile(SongFile); diff --git a/Game/Code/Classes/USongs.pas b/Game/Code/Classes/USongs.pas index 99474961..e3c54ac4 100644 --- a/Game/Code/Classes/USongs.pas +++ b/Game/Code/Classes/USongs.pas @@ -13,6 +13,7 @@ uses SysUtils, {$endif} ULog, UTexture, + UCommon, UCatCovers; type @@ -23,33 +24,33 @@ type end; TScore = record - Name: string; + Name: widestring; Score: integer; Length: string; end; TSong = record - Path: string; - Folder: string; // for sorting by folder - FileName: string; + Path: widestring; + Folder: widestring; // for sorting by folder + FileName: widestring; // sorting methods - Category: array of string; // I think I won't need this - Genre: string; - Edition: string; - Language: string; // 0.5.0: new + Category: array of widestring; // I think I won't need this + Genre: widestring; + Edition: widestring; + Language: widestring; // 0.5.0: new - Title: string; - Artist: string; + Title: widestring; + Artist: widestring; - Text: string; - Creator: string; + Text: widestring; + Creator: widestring; - Cover: string; + Cover: widestring; CoverTex: TTexture; - Mp3: string; - Background: string; - Video: string; + Mp3: widestring; + Background: widestring; + Video: widestring; VideoGAP: real; VideoLoaded: boolean; // 0.5.0: true if the video has been loaded NotesGAP: integer; @@ -79,7 +80,7 @@ type procedure LoadSongList; // load all songs procedure BrowseDir(Dir: widestring); // should return number of songs in the future procedure Sort(Order: integer); - function FindSongFile(Dir, Mask: string): string; + function FindSongFile(Dir, Mask: widestring): widestring; end; TCatSongs = class @@ -133,7 +134,7 @@ end; procedure TSongs.BrowseDir(Dir: widestring); var - SR: TSearchRec; // for parsing Songs Directory + SR: TSearchRecW; // for parsing Songs Directory SLen: integer; {$ifndef win32} @@ -144,16 +145,16 @@ var {$endif} begin {$ifdef win32} - if FindFirst(Dir + '*', faDirectory, SR) = 0 then // JB_Unicode - windows + if FindFirstW(Dir + '*', faDirectory, SR) = 0 then // JB_Unicode - windows begin repeat if (SR.Name <> '.') and (SR.Name <> '..') then begin BrowseDir(Dir + Sr.Name + PathDelim); end - until FindNext(SR) <> 0; + until FindNextw(SR) <> 0; end; // if - FindClose(SR); + FindClosew(SR); {$else} // Itterate the Songs Directory... ( With unicode capable functions for linux ) TheDir := opendir( Dir ); // JB_Unicode - linux @@ -178,7 +179,7 @@ begin // Log.LogStatus('Parsing directory: ' + Dir + SR.Name, 'LoadSongList'); - if FindFirst(Dir + '*.txt', 0, SR) = 0 then + if FindFirstW(Dir + '*.txt', 0, SR) = 0 then begin repeat SLen := BrowsePos; @@ -204,9 +205,9 @@ begin SetLength(Song, Length(Song) + 50); end; - until FindNext(SR) <> 0; + until FindNextW(SR) <> 0; end; // if FindFirst - FindClose(SR); + FindCloseW(SR); end; procedure TSongs.Sort(Order: integer); @@ -309,7 +310,7 @@ begin end; // case end; -function TSongs.FindSongFile(Dir, Mask: string): string; +function TSongs.FindSongFile(Dir, Mask: widestring): widestring; var SR: TSearchRec; // for parsing song directory begin @@ -463,10 +464,12 @@ case Ini.Sorting of CatSongs.Song[CatLen].Visible := true; end - else if (Ini.Sorting = sTitle) and (Length(Songs.Song[S].Title)>=1) and (Letter <> UpCase(Songs.Song[S].Title[1])) then begin + else if (Ini.Sorting = sTitle) and + (Length(Songs.Song[S].Title)>=1) and + (Letter <> UpperCase(Songs.Song[S].Title)[1]) then begin // add a letter Category Button Inc(Order); - Letter := UpCase(Songs.Song[S].Title[1]); + Letter := Uppercase(Songs.Song[S].Title)[1]; CatLen := Length(CatSongs.Song); SetLength(CatSongs.Song, CatLen+1); CatSongs.Song[CatLen].Artist := '[' + Letter + ']'; @@ -491,10 +494,10 @@ case Ini.Sorting of CatSongs.Song[CatLen].Visible := true; end - else if (Ini.Sorting = sArtist) and (Length(Songs.Song[S].Artist)>=1) and (Letter <> UpCase(Songs.Song[S].Artist[1])) then begin + else if (Ini.Sorting = sArtist) and (Length(Songs.Song[S].Artist)>=1) and (Letter <> UpperCase(Songs.Song[S].Artist)[1]) then begin // add a letter Category Button Inc(Order); - Letter := UpCase(Songs.Song[S].Artist[1]); + Letter := UpperCase(Songs.Song[S].Artist)[1]; CatLen := Length(CatSongs.Song); SetLength(CatSongs.Song, CatLen+1); CatSongs.Song[CatLen].Artist := '[' + Letter + ']'; @@ -545,7 +548,7 @@ case Ini.Sorting of end else if (Ini.Sorting = sTitle2) AND (Length(Songs.Song[S].Title)>=1) then begin - if (ord(Songs.Song[S].Title[1]) > 47) and (ord(Songs.Song[S].Title[1]) < 58) then Letter2 := '#' else Letter2 := UpCase(Songs.Song[S].Title[1]); + if (ord(Songs.Song[S].Title[1]) > 47) and (ord(Songs.Song[S].Title[1]) < 58) then Letter2 := '#' else Letter2 := UpperCase(Songs.Song[S].Title)[1]; if (Letter <> Letter2) then begin // add a letter Category Button Inc(Order); @@ -575,7 +578,7 @@ case Ini.Sorting of end else if (Ini.Sorting = sArtist2) AND (Length(Songs.Song[S].Artist)>=1) then begin - if (ord(Songs.Song[S].Artist[1]) > 47) and (ord(Songs.Song[S].Artist[1]) < 58) then Letter2 := '#' else Letter2 := UpCase(Songs.Song[S].Artist[1]); + if (ord(Songs.Song[S].Artist[1]) > 47) and (ord(Songs.Song[S].Artist[1]) < 58) then Letter2 := '#' else Letter2 := UpperCase(Songs.Song[S].Artist)[1]; if (Letter <> Letter2) then begin // add a letter Category Button Inc(Order); diff --git a/Game/Code/Classes/UVideo.pas b/Game/Code/Classes/UVideo.pas index 4c27867d..154cd04c 100644 --- a/Game/Code/Classes/UVideo.pas +++ b/Game/Code/Classes/UVideo.pas @@ -10,9 +10,11 @@ unit UVideo; # # ############################################################################## } -{$define DebugDisplay} // uncomment if u want to see the debug stuff +//{$define DebugDisplay} // uncomment if u want to see the debug stuff //{$define DebugFrames} //{$define Info} + +//{$define FFMpegAudio} {} @@ -45,6 +47,9 @@ uses SDL, dialogs, {$endif} {$ENDIF} + {$ifdef FFMpegAudio} + UAudio_FFMpeg, + {$endif} UIni, UMusic; @@ -108,7 +113,9 @@ type end; - + const + SDL_AUDIO_BUFFER_SIZE = 1024; + {$ifdef DebugDisplay} //{$ifNdef win32} @@ -262,19 +269,23 @@ begin 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 + 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); + begin 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)); + {$ifdef FFMpegAudio} + end + else + if (AVPacket.stream_index = AudioStreamIndex ) then + begin + UAudio_FFMpeg.packet_queue_put(UAudio_FFMpeg.audioq, AVPacket); + {$endif} + end; try if AVPacket.data <> nil then @@ -427,6 +438,10 @@ var errnum, i, x,y: Integer; lStreamsCount : Integer; + wanted_spec , + spec : TSDL_AudioSpec; + aCodec : pAVCodec; + begin fVideoOpened := False; fVideoPaused := False; @@ -471,27 +486,47 @@ begin end; aCodecCtx := VideoFormatContext.streams[ AudioStreamIndex ].codec; + {$ifdef FFMpegAudio} + // This is the audio ffmpeg audio support Jay is working on. if aCodecCtx <> nil then begin + wanted_spec.freq := aCodecCtx.sample_rate; + wanted_spec.format := AUDIO_S16SYS; + wanted_spec.channels := aCodecCtx.channels; + wanted_spec.silence := 0; + wanted_spec.samples := SDL_AUDIO_BUFFER_SIZE; + wanted_spec.callback := UAudio_FFMpeg.audio_callback; + wanted_spec.userdata := aCodecCtx; -// 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(@wanted_spec, @spec) < 0) then + begin + writeln('SDL_OpenAudio: '+SDL_GetError()); + exit; + end; + + writeln( 'SDL opened audio device' ); + + aCodec := avcodec_find_decoder(aCodecCtx.codec_id); + if (aCodec = nil) then + begin + writeln('Unsupported codec!'); + exit; + end; + + avcodec_open(aCodecCtx, aCodec); + + writeln( 'Opened the codec' ); + + packet_queue_init( audioq ); + SDL_PauseAudio(0); + + writeln( 'SDL_PauseAudio' ); + end; -(* - if(SDL_OpenAudio(WantedAudioCodecContext, AudioCodecContext) < 0) then - begin - writeln( 'Could not do SDL_OpenAudio' ); - exit; - end; -*) - + {$endif} + if(VideoStreamIndex >= 0) then begin VideoCodecContext:=VideoFormatContext^.streams[VideoStreamIndex]^.codec; diff --git a/Game/Code/Screens/UScreenSong.pas b/Game/Code/Screens/UScreenSong.pas index ea1dd8a5..4d146283 100644 --- a/Game/Code/Screens/UScreenSong.pas +++ b/Game/Code/Screens/UScreenSong.pas @@ -261,7 +261,9 @@ begin begin For I := 1 to high(CatSongs.Song) do begin - if (CatSongs.Song[(I + Interaction) mod I2].Visible) AND (Length(CatSongs.Song[(I + Interaction) mod I2].Title)>0) AND (UpCase(CatSongs.Song[(I + Interaction) mod I2].Title[1]) = Letter) then + if (CatSongs.Song[(I + Interaction) mod I2].Visible) AND + (Length(CatSongs.Song[(I + Interaction) mod I2].Title)>0) AND + (widechar(UpperCase(CatSongs.Song[(I + Interaction) mod I2].Title)[1]) = widechar(Letter)) then begin SkipTo(CatSongs.VisibleIndex((I + Interaction) mod I2)); @@ -280,7 +282,9 @@ begin begin For I := 1 to high(CatSongs.Song) do begin - if (CatSongs.Song[(I + Interaction) mod I2].Visible) AND (Length(CatSongs.Song[(I + Interaction) mod I2].Artist)>0) AND (UpCase(CatSongs.Song[(I + Interaction) mod I2].Artist[1]) = Letter) then + if (CatSongs.Song[(I + Interaction) mod I2].Visible) AND + (Length(CatSongs.Song[(I + Interaction) mod I2].Artist)>0) AND + (widechar(uppercase(CatSongs.Song[(I + Interaction) mod I2].Artist)[1]) = widechar(Letter)) then begin SkipTo(CatSongs.VisibleIndex((I + Interaction) mod I2)); diff --git a/Game/Code/UltraStar.dpr b/Game/Code/UltraStar.dpr index 1e418a49..0b7e8449 100644 --- a/Game/Code/UltraStar.dpr +++ b/Game/Code/UltraStar.dpr @@ -59,8 +59,6 @@ uses UCommon in 'Classes\UCommon.pas', UGraphic in 'Classes\UGraphic.pas', UTexture in 'Classes\UTexture.pas', - UMusic in 'Classes\UMusic.pas', - UAudio_Bass in 'Classes\UAudio_Bass.pas', ULanguage in 'Classes\ULanguage.pas', UMain in 'Classes\UMain.pas', UDraw in 'Classes\UDraw.pas', @@ -100,10 +98,14 @@ uses UParty in 'Classes\UParty.pas', // to - do : rewrite Party Manager as Module, reomplent ability to offer party Mody by Plugin //------------------------------ - //Includes - Video Support + //Includes - Media support classes.... + // Make sure UMedia always first, then UMedia_dummy //------------------------------ - UMedia_dummy in 'Classes\UMedia_dummy.pas', - UVideo in 'Classes\UVideo.pas', + UMusic in 'Classes\UMusic.pas', + UMedia_dummy in 'Classes\UMedia_dummy.pas', + UVideo in 'Classes\UVideo.pas', +// UAudio_FFMpeg in 'Classes\UAudio_FFMpeg.pas', // this is NEARLY to a working point :P + UAudio_Bass in 'Classes\UAudio_Bass.pas', //------------------------------ //Includes - Screens @@ -330,6 +332,7 @@ begin Log.BenchmarkEnd(1); Log.LogBenchmark('Initializing Sound', 1); +// exit; // Graphics Log.BenchmarkStart(1); -- cgit v1.2.3