Recherche avancée

Médias (91)

Autres articles (48)

  • MediaSPIP : Modification des droits de création d’objets et de publication définitive

    11 novembre 2010, par

    Par 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, par

    MediaSPIP 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 2011

    MediaSPIP 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 Jo

    I 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 mqwerty

    I 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 Carteret

    I'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;
}