
Recherche avancée
Médias (91)
-
Head down (wav version)
26 septembre 2011, par
Mis à jour : Avril 2013
Langue : English
Type : Audio
-
Echoplex (wav version)
26 septembre 2011, par
Mis à jour : Avril 2013
Langue : English
Type : Audio
-
Discipline (wav version)
26 septembre 2011, par
Mis à jour : Avril 2013
Langue : English
Type : Audio
-
Letting you (wav version)
26 septembre 2011, par
Mis à jour : Avril 2013
Langue : English
Type : Audio
-
1 000 000 (wav version)
26 septembre 2011, par
Mis à jour : Avril 2013
Langue : English
Type : Audio
-
999 999 (wav version)
26 septembre 2011, par
Mis à jour : Avril 2013
Langue : English
Type : Audio
Autres articles (48)
-
MediaSPIP : Modification des droits de création d’objets et de publication définitive
11 novembre 2010, parPar défaut, MediaSPIP permet de créer 5 types d’objets.
Toujours par défaut les droits de création et de publication définitive de ces objets sont réservés aux administrateurs, mais ils sont bien entendu configurables par les webmestres.
Ces droits sont ainsi bloqués pour plusieurs raisons : parce que le fait d’autoriser à publier doit être la volonté du webmestre pas de l’ensemble de la plateforme et donc ne pas être un choix par défaut ; parce qu’avoir un compte peut servir à autre choses également, (...) -
HTML5 audio and video support
13 avril 2011, parMediaSPIP uses HTML5 video and audio tags to play multimedia files, taking advantage of the latest W3C innovations supported by modern browsers.
The MediaSPIP player used has been created specifically for MediaSPIP and can be easily adapted to fit in with a specific theme.
For older browsers the Flowplayer flash fallback is used.
MediaSPIP allows for media playback on major mobile platforms with the above (...) -
Support audio et vidéo HTML5
10 avril 2011MediaSPIP utilise les balises HTML5 video et audio pour la lecture de documents multimedia en profitant des dernières innovations du W3C supportées par les navigateurs modernes.
Pour les navigateurs plus anciens, le lecteur flash Flowplayer est utilisé.
Le lecteur HTML5 utilisé a été spécifiquement créé pour MediaSPIP : il est complètement modifiable graphiquement pour correspondre à un thème choisi.
Ces technologies permettent de distribuer vidéo et son à la fois sur des ordinateurs conventionnels (...)
Sur d’autres sites (8991)
-
Real-time Streaming of AI-Generated Video Frames in a Web Browser [closed]
5 décembre 2023, par MinKi JoI am attempting to display a real-time AI-generated video. My model produces video frame images sequentially, and my goal is to stream these generated images on a web browser. The audio for the video is already prepared.


I've been looking for tools such as OpenCV-Python, FFmpeg, OBS, and Gradio, but I haven't found the most suitable option for my needs yet. Can you recommend a good option for this ?


-
Why is there an audio delay on recording video stream with ffmpeg ?
25 décembre 2023, par mqwertyI am trying to record video and audio stream (Line in Microphone Analog Audio) which are streaming from broadcaster computer with those parameters in the recorder computer ;


ffmpeg record parameters :


/usr/bin/ffmpeg -y -buffer_size max -thread_queue_size 8192 -i udp://225.0.5.11:1026 -buffer_size max -thread_queue_size 8192 -i udp://225.0.5.11:1032 -map 0:v -map 1:a -metadata title=COMPUTER-01_metadata_file -metadata creation_time="2023-12-25 13:25:29" -threads 0 -c:v copy -c:a copy -movflags +faststart -f segment -segment_time 01:00:00 -segment_atclocktime 1 -reset_timestamps 1 -strftime 1 -segment_format mp4 -t 120 test_record_video_with_audio_%Y-%m-%d_%H-%M-%S.mp4



The ffmpeg started and finished successfully, but when I open the recorded video with mpv like (mpv test_record_video_with_audio.mp4), I realized that there is a 5-6 seconds delay in audio. How can I prevent the delay of audio in the recorded mp4 file without using offset ? My last option is setting offset but I think that it is not safe according to any changes in network or etc.


FFMPEG version on both computer :


ffmpeg version 4.2.9 Copyright (c) 2000-2023 the FFmpeg developers
built with gcc 8 (GCC)



BROADCASTER COMPUTER :


sysctl.conf :


No added configurations.



ethtool output :


Supported ports: [ TP ]
Supported link modes: 100baseT/Full
 1000baseT/Full
 10000baseT/Full
 2500baseT/Full
 5000baseT/Full
Supported pause frame use: Symmetric
Supports auto-negotiation: Yes
Supported FEC modes: Not reported
Advertised link modes: 100baseT/Full
 1000baseT/Full
 10000baseT/Full
Advertised pause frame use: Symmetric
Advertised auto-negotiation: Yes
Advertised FEC modes: Not reported
Speed: 10000Mb/s
Duplex: Full
Auto-negotiation: on
Port: Twisted Pair
PHYAD: 0
Transceiver: internal
MDI-X: Unknown
Supports Wake-on: d
Wake-on: d
 Current message level: 0x00000007 (7)
 drv probe link
Link detected: yes



ffmpeg video stream :


ffmpeg -fflags +genpts -f x11grab -framerate 30 -video_size uhd2160 -i :0 -c:v hevc_nvenc -preset fast -pix_fmt bgr0 -b:v 3M -g 25 -an -f mpegts udp://225.0.5.11:1026



ffmpeg audio stream :


ffmpeg -f alsa -i hw:0,0 -c:a aac -ar 48000 -b:a 1024K -ab 512k -f rtp_mpegts rtp://225.0.5.11:1032



nvidia-smi :


| NVIDIA-SMI 535.129.03 Driver Version: 535.129.03 CUDA Version: 12.2 |
|-----------------------------------------+----------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+======================+======================|
| 0 NVIDIA T400 4GB Off | 00000000:5B:00.0 Off | N/A |
| 38% 38C P8 N/A / 31W | 207MiB / 4096MiB | 0% Default |
| | | N/A |
+-----------------------------------------+----------------------+----------------------+
| 1 NVIDIA RTX A4000 Off | 00000000:9E:00.0 Off | Off |
| 41% 59C P2 41W / 140W | 766MiB / 16376MiB | 17% Default |
| | | N/A |
+-----------------------------------------+----------------------+----------------------+
 
+---------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=======================================================================================|
| 0 N/A N/A 3227 G /usr/libexec/Xorg 114MiB |
| 0 N/A N/A 3423 G /usr/bin/gnome-shell 87MiB |
| 1 N/A N/A 3227 G /usr/libexec/Xorg 285MiB |
| 1 N/A N/A 3423 G /usr/bin/gnome-shell 91MiB |
| 1 N/A N/A 3762 C ffmpeg 372MiB |
+---------------------------------------------------------------------------------------+



lscpu output :




Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 96
On-line CPU(s) list: 0-95
Thread(s) per core: 2
Core(s) per socket: 24
Socket(s): 2
NUMA node(s): 2
Vendor ID: GenuineIntel
BIOS Vendor ID: Intel(R) Corporation
CPU family: 6
Model: 85
Model name: Intel(R) Xeon(R) Gold 5220R CPU @ 2.20GHz
BIOS Model name: Intel(R) Xeon(R) Gold 5220R CPU @ 2.20GHz
Stepping: 7
CPU MHz: 2200.000
CPU max MHz: 4000.0000
CPU min MHz: 1000.0000
BogoMIPS: 4400.00
Virtualization: VT-x
L1d cache: 32K
L1i cache: 32K
L2 cache: 1024K
L3 cache: 36608K
NUMA node0 CPU(s): 0-23,48-71
NUMA node1 CPU(s): 24-47,72-95



OS : CentOS Stream release 8



RECORDER COMPUTER :


sysctl.conf :


net.core.rmem_max=16777216
net.core.wmem_max=16777216
net.ipv4.tcp_rmem= 4096 87380 16777216
net.ipv4.tcp_wmem= 4096 65536 16777216
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_sack = 1
net.ipv4.tcp_no_metrics_save = 0
net.core.netdev_max_backlog = 50000
net.core.optmem_max=25165824



lscpu output :


Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 96
On-line CPU(s) list: 0-95
Thread(s) per core: 2
Core(s) per socket: 24
Socket(s): 2
NUMA node(s): 2
Vendor ID: GenuineIntel
BIOS Vendor ID: Intel
CPU family: 6
Model: 106
Model name: Intel(R) Xeon(R) Gold 5318Y CPU @ 2.10GHz
BIOS Model name: Intel(R) Xeon(R) Gold 5318Y CPU @ 2.10GHz
Stepping: 6
CPU MHz: 3400.000
CPU max MHz: 3400.0000
CPU min MHz: 800.0000
BogoMIPS: 4200.00
Virtualization: VT-x
L1d cache: 48K
L1i cache: 32K
L2 cache: 1280K
L3 cache: 36864K



ethtool output :


Supported ports: [ TP ]
 Supported link modes: 1000baseT/Full
 10000baseT/Full
 Supported pause frame use: Symmetric Receive-only
 Supports auto-negotiation: Yes
 Supported FEC modes: Not reported
 Advertised link modes: 1000baseT/Full
 10000baseT/Full
 Advertised pause frame use: Symmetric
 Advertised auto-negotiation: Yes
 Advertised FEC modes: Not reported
 Speed: 10000Mb/s
 Duplex: Full
 Auto-negotiation: on
 Port: Twisted Pair
 PHYAD: 12
 Transceiver: internal
 MDI-X: Unknown
 Supports Wake-on: d
 Wake-on: d
 Current message level: 0x00002081 (8321)
 drv tx_err hw
 Link detected: yes



No NVIDIA Graphic Driver


OS : CentOS Stream release 8



I tried audio encoding while recording like :


"-c:a", "aac", 
"-ar", "48000", 
"-b:a", "128k",



I also tried :


"aresample=async=1"




Unfortunately,these did not have any improvements on preventing latency in audio.


-
Decoding and playing audio with ffmpeg and XAudio2 - frequency ratio wrong
9 mars, par Brent de CarteretI'm using
ffmpeg
to decode audio and output it using the XAudio2 API, it works and plays synced with the video output using the pts. But it's high pitched (i.e. sounds like chipmunks).

Setting breakpoints I can see it has set the correct sample rate from the audio codec in CreateSourceVoice. I'm stumped.


Any help would be much appreciated.


CDVDAUDIO.cpp


#include "DVDAudioDevice.h"
 
HANDLE m_hBufferEndEvent;

CDVDAudio::CDVDAudio()
{
 m_pXAudio2 = NULL;
 m_pMasteringVoice = NULL;
 m_pSourceVoice = NULL;
 m_pWfx = NULL;
 m_VoiceCallback = NULL; 
 m_hBufferEndEvent = CreateEvent(NULL, false, false, "Buffer end event");
}
 
CDVDAudio::~CDVDAudio()
{
 m_pXAudio2 = NULL;
 m_pMasteringVoice = NULL;
 m_pSourceVoice = NULL;
 m_pWfx = NULL;
 m_VoiceCallback = NULL;
 CloseHandle(m_hBufferEndEvent);
 m_hBufferEndEvent = NULL;
}
 
bool CDVDAudio::Create(int iChannels, int iBitrate, int iBitsPerSample, bool bPasstrough)
{
 CoInitializeEx(NULL, COINIT_MULTITHREADED);
 HRESULT hr = XAudio2Create( &m_pXAudio2, 0, XAUDIO2_DEFAULT_PROCESSOR);
 
 if (SUCCEEDED(hr))
 {
 m_pXAudio2->CreateMasteringVoice( &m_pMasteringVoice );
 }
 
 // Create source voice
 WAVEFORMATEXTENSIBLE wfx;
 memset(&wfx, 0, sizeof(WAVEFORMATEXTENSIBLE));
 
 wfx.Format.wFormatTag = WAVE_FORMAT_PCM;
 wfx.Format.nSamplesPerSec = iBitrate;//pFFMpegData->pAudioCodecCtx->sample_rate;//48000 by default
 wfx.Format.nChannels = iChannels;//pFFMpegData->pAudioCodecCtx->channels;
 wfx.Format.wBitsPerSample = 16;
 wfx.Format.nBlockAlign = wfx.Format.nChannels*16/8;
 wfx.Format.nAvgBytesPerSec = wfx.Format.nSamplesPerSec * wfx.Format.nBlockAlign;
 wfx.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
 wfx.Samples.wValidBitsPerSample = wfx.Format.wBitsPerSample;
 
 if(wfx.Format.nChannels == 1)
 {
 wfx.dwChannelMask = SPEAKER_MONO;
 }
 else if(wfx.Format.nChannels == 2)
 {
 wfx.dwChannelMask = SPEAKER_STEREO;
 }
 else if(wfx.Format.nChannels == 5)
 {
 wfx.dwChannelMask = SPEAKER_5POINT1;
 }
 
 wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
 
 unsigned int flags = 0;//XAUDIO2_VOICE_NOSRC;// | XAUDIO2_VOICE_NOPITCH;
 
 //Source voice
 m_VoiceCallback = new StreamingVoiceCallback(this);
 hr = m_pXAudio2->CreateSourceVoice(&m_pSourceVoice,(WAVEFORMATEX*)&wfx, 0 , 1.0f, m_VoiceCallback);
 
 if (!SUCCEEDED(hr))
 return false;
 
 // Start sound
 hr = m_pSourceVoice->Start(0);
 
 if(!SUCCEEDED(hr))
 return false;
 
 return true;
}
 
DWORD CDVDAudio::AddPackets(unsigned char* data, DWORD len)
{ 
 memset(&m_SoundBuffer,0,sizeof(XAUDIO2_BUFFER));
 m_SoundBuffer.AudioBytes = len;
 m_SoundBuffer.pAudioData = data;
 m_SoundBuffer.pContext = NULL;//(VOID*)data;
 XAUDIO2_VOICE_STATE state;
 
 while (m_pSourceVoice->GetState( &state ), state.BuffersQueued > 60)
 {
 WaitForSingleObject( m_hBufferEndEvent, INFINITE );
 }
 
 m_pSourceVoice->SubmitSourceBuffer( &m_SoundBuffer );
 return 0;
}
 
void CDVDAudio::Destroy()
{
 m_pMasteringVoice->DestroyVoice();
 m_pXAudio2->Release();
 m_pSourceVoice->DestroyVoice();
 delete m_VoiceCallback;
 m_VoiceCallback = NULL;
}



CDVDAUdioCodecFFmpeg.cpp


#include "DVDAudioCodecFFmpeg.h"
#include "Log.h"
 
CDVDAudioCodecFFmpeg::CDVDAudioCodecFFmpeg() : CDVDAudioCodec()
{
 m_iBufferSize = 0;
 m_pCodecContext = NULL;
 m_bOpenedCodec = false;
}
 
CDVDAudioCodecFFmpeg::~CDVDAudioCodecFFmpeg()
{
 Dispose();
}
 
bool CDVDAudioCodecFFmpeg::Open(AVCodecID codecID, int iChannels, int iSampleRate)
{
 AVCodec* pCodec;
 m_bOpenedCodec = false;
 av_register_all();
 pCodec = avcodec_find_decoder(codecID);
 m_pCodecContext = avcodec_alloc_context3(pCodec);//avcodec_alloc_context();
 avcodec_get_context_defaults3(m_pCodecContext, pCodec);
 
 if (!pCodec)
 {
 CLog::Log(LOGERROR, "CDVDAudioCodecFFmpeg::Open() Unable to find codec");
 return false;
 }
 
 m_pCodecContext->debug_mv = 0;
 m_pCodecContext->debug = 0;
 m_pCodecContext->workaround_bugs = 1;
 
 if (pCodec->capabilities & CODEC_CAP_TRUNCATED)
 m_pCodecContext->flags |= CODEC_FLAG_TRUNCATED;
 
 m_pCodecContext->channels = iChannels;
 m_pCodecContext->sample_rate = iSampleRate;
 //m_pCodecContext->bits_per_sample = 24;
 
 /* //FIXME BRENT
 if( ExtraData && ExtraSize > 0 )
 {
 m_pCodecContext->extradata_size = ExtraSize;
 m_pCodecContext->extradata = m_dllAvCodec.av_mallocz(ExtraSize + FF_INPUT_BUFFER_PADDING_SIZE);
 memcpy(m_pCodecContext->extradata, ExtraData, ExtraSize);
 }
 */
 
 // set acceleration
 //m_pCodecContext->dsp_mask = FF_MM_FORCE | FF_MM_MMX | FF_MM_MMXEXT | FF_MM_SSE; //BRENT
 
 if (avcodec_open2(m_pCodecContext, pCodec, NULL) < 0)
 {
 CLog::Log(LOGERROR, "CDVDAudioCodecFFmpeg::Open() Unable to open codec");
 Dispose();
 return false;
 }
 
 m_bOpenedCodec = true;
 return true;
}
 
void CDVDAudioCodecFFmpeg::Dispose()
{
 if (m_pCodecContext)
 {
 if (m_bOpenedCodec)
 avcodec_close(m_pCodecContext);
 m_bOpenedCodec = false;
 av_free(m_pCodecContext);
 m_pCodecContext = NULL;
 }
 m_iBufferSize = 0;
}

int CDVDAudioCodecFFmpeg::Decode(BYTE* pData, int iSize)
{
 int iBytesUsed;
 if (!m_pCodecContext) return -1;
 
 //Copy into a FFMpeg AVPAcket again
 AVPacket packet;
 av_init_packet(&packet);
 
 packet.data=pData;
 packet.size=iSize;
 
 int iOutputSize = AVCODEC_MAX_AUDIO_FRAME_SIZE; //BRENT
 
 iBytesUsed = avcodec_decode_audio3(m_pCodecContext, (int16_t *)m_buffer, &iOutputSize/*m_iBufferSize*/, &packet);

 m_iBufferSize = iOutputSize;//BRENT

 return iBytesUsed;
}

int CDVDAudioCodecFFmpeg::GetData(BYTE** dst)
{
 *dst = m_buffer;
 return m_iBufferSize;
}

void CDVDAudioCodecFFmpeg::Reset()
{
 if (m_pCodecContext)
 avcodec_flush_buffers(m_pCodecContext);
}

int CDVDAudioCodecFFmpeg::GetChannels()
{
 if (m_pCodecContext)
 return m_pCodecContext->channels;
 return 0;
}

int CDVDAudioCodecFFmpeg::GetSampleRate()
{
 if (m_pCodecContext)
 return m_pCodecContext->sample_rate;
 return 0;
}
 
int CDVDAudioCodecFFmpeg::GetBitsPerSample()
{
 if (m_pCodecContext)
 return 16;
 return 0;
}



CDVDPlayerAudio.cpp


#include "DVDPlayerAudio.h"
#include "DVDDemuxUtils.h"
#include "Log.h"
 
#include 
#include "DVDAudioCodecFFmpeg.h" //FIXME Move to a codec factory!!
 
CDVDPlayerAudio::CDVDPlayerAudio(CDVDClock* pClock) : CThread()
{
 m_pClock = pClock;
 m_pAudioCodec = NULL;
 m_bInitializedOutputDevice = false;
 m_iSourceChannels = 0;
 m_audioClock = 0;
 
 // m_currentPTSItem.pts = DVD_NOPTS_VALUE;
 // m_currentPTSItem.timestamp = 0;
 
 SetSpeed(DVD_PLAYSPEED_NORMAL);
 
 InitializeCriticalSection(&m_critCodecSection);
 m_messageQueue.SetMaxDataSize(10 * 16 * 1024);
 // g_dvdPerformanceCounter.EnableAudioQueue(&m_packetQueue);
}

CDVDPlayerAudio::~CDVDPlayerAudio()
{
 // g_dvdPerformanceCounter.DisableAudioQueue();

 // close the stream, and don't wait for the audio to be finished
 CloseStream(true);
 DeleteCriticalSection(&m_critCodecSection);
}

bool CDVDPlayerAudio::OpenStream( CDemuxStreamAudio *pDemuxStream )
{
 // should always be NULL!!!!, it will probably crash anyway when deleting m_pAudioCodec here.
 if (m_pAudioCodec)
 {
 CLog::Log(LOGFATAL, "CDVDPlayerAudio::OpenStream() m_pAudioCodec != NULL");
 return false;
 }
 
 AVCodecID codecID = pDemuxStream->codec;
 
 CLog::Log(LOGNOTICE, "Finding audio codec for: %i", codecID);
 //m_pAudioCodec = CDVDFactoryCodec::CreateAudioCodec( pDemuxStream ); 
 m_pAudioCodec = new CDVDAudioCodecFFmpeg; //FIXME BRENT Codec Factory needed!
 
 if (!m_pAudioCodec->Open(pDemuxStream->codec, pDemuxStream->iChannels, pDemuxStream->iSampleRate))
 {
 m_pAudioCodec->Dispose();
 delete m_pAudioCodec;
 m_pAudioCodec = NULL;
 return false;
 }
 
 if ( !m_pAudioCodec )
 {
 CLog::Log(LOGERROR, "Unsupported audio codec");
 return false;
 }
 
 m_codec = pDemuxStream->codec;
 m_iSourceChannels = pDemuxStream->iChannels;
 m_messageQueue.Init();
 
 CLog::Log(LOGNOTICE, "Creating audio thread");
 Create();
 
 return true;
}

void CDVDPlayerAudio::CloseStream(bool bWaitForBuffers)
{
 // wait until buffers are empty
 if (bWaitForBuffers)
 m_messageQueue.WaitUntilEmpty();
 
 // send abort message to the audio queue
 m_messageQueue.Abort();
 
 CLog::Log(LOGNOTICE, "waiting for audio thread to exit");
 
 // shut down the audio_decode thread and wait for it
 StopThread(); // will set this->m_bStop to true
 this->WaitForThreadExit(INFINITE);
 
 // uninit queue
 m_messageQueue.End();
 
 CLog::Log(LOGNOTICE, "Deleting audio codec");
 if (m_pAudioCodec)
 {
 m_pAudioCodec->Dispose();
 delete m_pAudioCodec;
 m_pAudioCodec = NULL;
 }
 
 // flush any remaining pts values
 //FlushPTSQueue(); //FIXME BRENT
}

void CDVDPlayerAudio::OnStartup()
{
 CThread::SetName("CDVDPlayerAudio");
 pAudioPacket = NULL;
 m_audioClock = 0;
 audio_pkt_data = NULL;
 audio_pkt_size = 0;
 
 // g_dvdPerformanceCounter.EnableAudioDecodePerformance(ThreadHandle());
}

void CDVDPlayerAudio::Process()
{
 CLog::Log(LOGNOTICE, "running thread: CDVDPlayerAudio::Process()");

 int result;
 
 // silence data
 BYTE silence[1024];
 memset(silence, 0, 1024);
 
 DVDAudioFrame audioframe;
 
 __int64 iClockDiff=0;
 while (!m_bStop)
 {
 //Don't let anybody mess with our global variables
 EnterCriticalSection(&m_critCodecSection);
 result = DecodeFrame(audioframe, m_speed != DVD_PLAYSPEED_NORMAL); // blocks if no audio is available, but leaves critical section before doing so
 LeaveCriticalSection(&m_critCodecSection);
 
 if ( result & DECODE_FLAG_ERROR ) 
 { 
 CLog::Log(LOGERROR, "CDVDPlayerAudio::Process - Decode Error. Skipping audio frame");
 continue;
 }
 
 if ( result & DECODE_FLAG_ABORT )
 {
 CLog::Log(LOGDEBUG, "CDVDPlayerAudio::Process - Abort received, exiting thread");
 break;
 }
 
 if ( result & DECODE_FLAG_DROP ) //FIXME BRENT
 {
 /* //frame should be dropped. Don't let audio move ahead of the current time thou
 //we need to be able to start playing at any time
 //when playing backwards, we try to keep as small buffers as possible
 
 // set the time at this delay
 AddPTSQueue(audioframe.pts, m_dvdAudio.GetDelay());
 */
 if (m_speed > 0)
 {
 __int64 timestamp = m_pClock->GetAbsoluteClock() + (audioframe.duration * DVD_PLAYSPEED_NORMAL) / m_speed;
 while ( !m_bStop && timestamp > m_pClock->GetAbsoluteClock() )
 Sleep(1);
 }
 continue;
 }
 
 if ( audioframe.size > 0 ) 
 {
 // we have successfully decoded an audio frame, open up the audio device if not already done
 if (!m_bInitializedOutputDevice)
 {
 m_bInitializedOutputDevice = InitializeOutputDevice();
 }
 
 //Add any packets play
 m_dvdAudio.AddPackets(audioframe.data, audioframe.size);
 
 // store the delay for this pts value so we can calculate the current playing
 //AddPTSQueue(audioframe.pts, m_dvdAudio.GetDelay() - audioframe.duration);//BRENT
 }
 
 // if we where asked to resync on this packet, do so here
 if ( result & DECODE_FLAG_RESYNC )
 {
 CLog::Log(LOGDEBUG, "CDVDPlayerAudio::Process - Resync recieved.");
 //while (!m_bStop && (unsigned int)m_dvdAudio.GetDelay() > audioframe.duration ) Sleep(5); //BRENT
 m_pClock->Discontinuity(CLOCK_DISC_NORMAL, audioframe.pts);
 }
 
 #ifdef USEOLDSYNC
 //Clock should be calculated after packets have been added as m_audioClock points to the 
 //time after they have been played
 
 const __int64 iCurrDiff = (m_audioClock - m_dvdAudio.GetDelay()) - m_pClock->GetClock();
 const __int64 iAvDiff = (iClockDiff + iCurrDiff)/2;
 
 //Check for discontinuity in the stream, use a moving average to
 //eliminate highfreq fluctuations of large packet sizes
 if ( ABS(iAvDiff) > 5000 ) // sync clock if average diff is bigger than 5 msec 
 {
 //Wait until only the new audio frame which triggered the discontinuity is left
 //then set disc state
 while (!m_bStop && (unsigned int)m_dvdAudio.GetBytesInBuffer() > audioframe.size )
 Sleep(5);
 
 m_pClock->Discontinuity(CLOCK_DISC_NORMAL, m_audioClock - m_dvdAudio.GetDelay());
 CLog::("CDVDPlayer:: Detected Audio Discontinuity, syncing clock. diff was: %I64d, %I64d, av: %I64d", iClockDiff, iCurrDiff, iAvDiff);
 iClockDiff = 0;
 }
 else
 {
 //Do gradual adjustments (not working yet)
 //m_pClock->AdjustSpeedToMatch(iClock + iAvDiff);
 iClockDiff = iCurrDiff;
 }
 #endif
 }
}

void CDVDPlayerAudio::OnExit()
{
 //g_dvdPerformanceCounter.DisableAudioDecodePerformance();
 
 // destroy audio device
 CLog::Log(LOGNOTICE, "Closing audio device");
 m_dvdAudio.Destroy();
 m_bInitializedOutputDevice = false;

 CLog::Log(LOGNOTICE, "thread end: CDVDPlayerAudio::OnExit()");
}

// decode one audio frame and returns its uncompressed size
int CDVDPlayerAudio::DecodeFrame(DVDAudioFrame &audioframe, bool bDropPacket)
{
 CDVDDemux::DemuxPacket* pPacket = pAudioPacket;
 int n=48000*2*16/8, len;
 
 //Store amount left at this point, and what last pts was
 unsigned __int64 first_pkt_pts = 0;
 int first_pkt_size = 0; 
 int first_pkt_used = 0;
 int result = 0;
 
 // make sure the sent frame is clean
 memset(&audioframe, 0, sizeof(DVDAudioFrame));
 
 if (pPacket)
 {
 first_pkt_pts = pPacket->pts;
 first_pkt_size = pPacket->iSize;
 first_pkt_used = first_pkt_size - audio_pkt_size;
 }
 
 for (;;)
 {
 /* NOTE: the audio packet can contain several frames */
 while (audio_pkt_size > 0)
 {
 len = m_pAudioCodec->Decode(audio_pkt_data, audio_pkt_size);
 if (len < 0)
 {
 /* if error, we skip the frame */
 audio_pkt_size=0;
 m_pAudioCodec->Reset();
 break;
 }
 
 // fix for fucked up decoders //FIXME BRENT
 if( len > audio_pkt_size )
 { 
 CLog::Log(LOGERROR, "CDVDPlayerAudio:DecodeFrame - Codec tried to consume more data than available. Potential memory corruption"); 
 audio_pkt_size=0;
 m_pAudioCodec->Reset();
 assert(0);
 }
 
 // get decoded data and the size of it
 audioframe.size = m_pAudioCodec->GetData(&audioframe.data);
 audio_pkt_data += len;
 audio_pkt_size -= len;
 
 if (audioframe.size <= 0)
 continue;
 
 audioframe.pts = m_audioClock;
 
 // compute duration.
 n = m_pAudioCodec->GetChannels() * m_pAudioCodec->GetBitsPerSample() / 8 * m_pAudioCodec->GetSampleRate();
 if (n > 0)
 {
 // safety check, if channels == 0, n will result in 0, and that will result in a nice divide exception
 audioframe.duration = (unsigned int)(((__int64)audioframe.size * DVD_TIME_BASE) / n);
 
 // increase audioclock to after the packet
 m_audioClock += audioframe.duration;
 }
 
 //If we are asked to drop this packet, return a size of zero. then it won't be played
 //we currently still decode the audio.. this is needed since we still need to know it's 
 //duration to make sure clock is updated correctly.
 if ( bDropPacket )
 {
 result |= DECODE_FLAG_DROP;
 }
 return result;
 }
 
 // free the current packet
 if (pPacket)
 {
 CDVDDemuxUtils::FreeDemuxPacket(pPacket); //BRENT FIXME
 pPacket = NULL;
 pAudioPacket = NULL;
 }
 
 if (m_messageQueue.RecievedAbortRequest())
 return DECODE_FLAG_ABORT;
 
 // read next packet and return -1 on error
 LeaveCriticalSection(&m_critCodecSection); //Leave here as this might stall a while
 
 CDVDMsg* pMsg;
 MsgQueueReturnCode ret = m_messageQueue.Get(&pMsg, INFINITE);
 EnterCriticalSection(&m_critCodecSection);
 
 if (MSGQ_IS_ERROR(ret) || ret == MSGQ_ABORT)
 return DECODE_FLAG_ABORT;
 
 if (pMsg->IsType(CDVDMsg::DEMUXER_PACKET))
 {
 CDVDMsgDemuxerPacket* pMsgDemuxerPacket = (CDVDMsgDemuxerPacket*)pMsg;
 pPacket = pMsgDemuxerPacket->GetPacket();
 pMsgDemuxerPacket->m_pPacket = NULL; // XXX, test
 pAudioPacket = pPacket;
 audio_pkt_data = pPacket->pData;
 audio_pkt_size = pPacket->iSize;
 }
 else
 {
 // other data is not used here, free if
 // msg itself will still be available
 pMsg->Release();
 }
 
 // if update the audio clock with the pts
 if (pMsg->IsType(CDVDMsg::DEMUXER_PACKET) || pMsg->IsType(CDVDMsg::GENERAL_RESYNC))
 {
 if (pMsg->IsType(CDVDMsg::GENERAL_RESYNC))
 { 
 //player asked us to sync on this package
 CDVDMsgGeneralResync* pMsgGeneralResync = (CDVDMsgGeneralResync*)pMsg;
 result |= DECODE_FLAG_RESYNC;
 m_audioClock = pMsgGeneralResync->GetPts();
 }
 else if (pPacket->pts != DVD_NOPTS_VALUE) // CDVDMsg::DEMUXER_PACKET, pPacket is already set above
 {
 if (first_pkt_size == 0) 
 { 
 //first package
 m_audioClock = pPacket->pts; 
 }
 else if (first_pkt_pts > pPacket->pts)
 { 
 //okey first packet in this continous stream, make sure we use the time here 
 m_audioClock = pPacket->pts; 
 }
 else if ((unsigned __int64)m_audioClock < pPacket->pts || (unsigned __int64)m_audioClock > pPacket->pts)
 {
 //crap, moved outsided correct pts
 //Use pts from current packet, untill we find a better value for it.
 //Should be ok after a couple of frames, as soon as it starts clean on a packet
 m_audioClock = pPacket->pts;
 }
 else if (first_pkt_size == first_pkt_used)
 {
 //Nice starting up freshly on the start of a packet, use pts from it
 m_audioClock = pPacket->pts;
 }
 }
 }
 pMsg->Release();
 }
}

void CDVDPlayerAudio::SetSpeed(int speed)
{ 
 m_speed = speed;
 
 //if (m_speed == DVD_PLAYSPEED_PAUSE) m_dvdAudio.Pause(); //BRENT FIXME
 //else m_dvdAudio.Resume();
}
 
bool CDVDPlayerAudio::InitializeOutputDevice()
{
 int iChannels = m_pAudioCodec->GetChannels();
 int iSampleRate = m_pAudioCodec->GetSampleRate();
 int iBitsPerSample = m_pAudioCodec->GetBitsPerSample();
 //bool bPasstrough = m_pAudioCodec->NeedPasstrough(); //BRENT
 
 if (iChannels == 0 || iSampleRate == 0 || iBitsPerSample == 0)
 {
 CLog::Log(LOGERROR, "Unable to create audio device, (iChannels == 0 || iSampleRate == 0 || iBitsPerSample == 0)");
 return false;
 }
 
 CLog::Log(LOGNOTICE, "Creating audio device with codec id: %i, channels: %i, sample rate: %i", m_codec, iChannels, iSampleRate);
 if (m_dvdAudio.Create(iChannels, iSampleRate, iBitsPerSample, /*bPasstrough*/0)) // always 16 bit with ffmpeg ? //BRENT Passthrough needed?
 {
 return true;
 }
 
 CLog::Log(LOGERROR, "Failed Creating audio device with codec id: %i, channels: %i, sample rate: %i", m_codec, iChannels, iSampleRate);
 return false;
}