Recherche avancée

Médias (91)

Autres articles (111)

  • Script d’installation automatique de MediaSPIP

    25 avril 2011, par

    Afin de palier aux difficultés d’installation dues principalement aux dépendances logicielles coté serveur, un script d’installation "tout en un" en bash a été créé afin de faciliter cette étape sur un serveur doté d’une distribution Linux compatible.
    Vous devez bénéficier d’un accès SSH à votre serveur et d’un compte "root" afin de l’utiliser, ce qui permettra d’installer les dépendances. Contactez votre hébergeur si vous ne disposez pas de cela.
    La documentation de l’utilisation du script d’installation (...)

  • Automated installation script of MediaSPIP

    25 avril 2011, par

    To overcome the difficulties mainly due to the installation of server side software dependencies, an "all-in-one" installation script written in bash was created to facilitate this step on a server with a compatible Linux distribution.
    You must have access to your server via SSH and a root account to use it, which will install the dependencies. Contact your provider if you do not have that.
    The documentation of the use of this installation script is available here.
    The code of this (...)

  • Ajouter des informations spécifiques aux utilisateurs et autres modifications de comportement liées aux auteurs

    12 avril 2011, par

    La manière la plus simple d’ajouter des informations aux auteurs est d’installer le plugin Inscription3. Il permet également de modifier certains comportements liés aux utilisateurs (référez-vous à sa documentation pour plus d’informations).
    Il est également possible d’ajouter des champs aux auteurs en installant les plugins champs extras 2 et Interface pour champs extras.

Sur d’autres sites (17376)

  • avcodec/dvdsubenc : Add dvdsub workaround for some players

    9 juillet 2014, par Oliver Fromme
    avcodec/dvdsubenc : Add dvdsub workaround for some players
    

    The issue affects dvdsub subtitles (a.k.a. VOBSUB).

    Some players — in particular hardware players — cut off
    the lowest row of pixels if the number of rows in the subtitle
    is odd.

    The patch below implements a work-around for that. If the
    number of rows is odd, it is simply rounded up to an even
    number, adding an invisible (i.e. fully transparent) row.
    The work-around can be enabled or disabled with a new
    option -even_rows_fix. The default is disabled, so there
    is no change of behaviour for users who don’t care about it.

    The overhead for the fix is low, and in many cases even zero :
    For subtitles with an odd number of rows (i.e. in 50% of
    cases on average), the size increases by two bytes because
    a fully transparent row is encoded as 0x00 0x00. However,
    in the VOBSUB standard, all data packets are padded to 2KB
    anyway, so in most cases the additional bytes just use some
    part of the padding, so there is no overhead. Only in the
    rare case that the 2KB boundary is hit (0.1% chance), a full
    2KB block is added.

    Signed-off-by : Michael Niedermayer <michaelni@gmx.at>

    • [DH] libavcodec/dvdsubenc.c
  • FFmpeg player backporting to Android 2.1 - one more problem

    22 avril 2024, par tretdm

    I looked for a lot of information about how to build and use FFmpeg in early versions of Android, looked at the source codes of players from 2011-2014 and was able to easily build FFmpeg 4.0.4 and 3.1.4 on the NDKv5 platform. I have highlighted the main things for this purpose :

    &#xA;

      &#xA;
    • <android></android>bitmap.h> and <android></android>native_window.h> before Android 2.2 (API Level 8) such a thing did not exist
    • &#xA;

    • this requires some effort to implement buffer management for A/V streams, since in practice, when playing video, the application silently crashed after a few seconds due to overflow (below code example in C++ and Java)
    • &#xA;

    • FFmpeg - imho, the only way to support a sufficient number of codecs that are not officially included in Android 2.1 and above
    • &#xA;

    &#xA;

    void decodeVideoFromPacket(JNIEnv *env, jobject instance,&#xA;                           jclass mplayer_class, AVPacket avpkt, &#xA;                           int total_frames, int length) {&#xA;    AVFrame     *pFrame = NULL&#xA;    AVFrame     *pFrameRGB = NULL;&#xA;    pFrame = avcodec_alloc_frame();&#xA;    pFrameRGB = avcodec_alloc_frame();&#xA;    int frame_size = avpicture_get_size(PIX_FMT_RGB32, gVideoCodecCtx->width, gVideoCodecCtx->height);&#xA;    unsigned char* buffer = (unsigned char*)av_malloc((size_t)frame_size * 3);&#xA;    if (!buffer) {&#xA;        av_free(pFrame);&#xA;        av_free(pFrameRGB);&#xA;        return;&#xA;    }&#xA;    jbyteArray buffer2;&#xA;    jmethodID renderVideoFrames = env->GetMethodID(mplayer_class, "renderVideoFrames", "([BI)V");&#xA;    int frameDecoded;&#xA;    avpicture_fill((AVPicture*) pFrame,&#xA;                   buffer,&#xA;                   gVideoCodecCtx->pix_fmt,&#xA;                   gVideoCodecCtx->width,&#xA;                   gVideoCodecCtx->height&#xA;                  );&#xA;&#xA;    if (avpkt.stream_index == gVideoStreamIndex) { // If video stream found&#xA;        int size = avpkt.size;&#xA;        total_frames&#x2B;&#x2B;;&#xA;        struct SwsContext *img_convert_ctx = NULL;&#xA;        avcodec_decode_video2(gVideoCodecCtx, pFrame, &amp;frameDecoded, &amp;avpkt);&#xA;        if (!frameDecoded || pFrame == NULL) {&#xA;            return;&#xA;        }&#xA;&#xA;        try {&#xA;            PixelFormat pxf;&#xA;            // RGB565 by default for Android Canvas in pre-Gingerbread devices.&#xA;            if(android::get_android_api_version(env) >= ANDROID_API_CODENAME_GINGERBREAD) {&#xA;                pxf = PIX_FMT_BGR32;&#xA;            } else {&#xA;                pxf = PIX_FMT_RGB565;&#xA;            }&#xA;&#xA;            int rgbBytes = avpicture_get_size(pxf, gVideoCodecCtx->width,&#xA;                                            gVideoCodecCtx->height);&#xA;&#xA;            // Converting YUV to RGB frame &amp; RGB frame to char* buffer &#xA;            &#xA;            buffer = convertYuv2Rgb(pxf, pFrame, rgbBytes); // result of av_image_copy_to_buffer()&#xA;&#xA;            if(buffer == NULL) {&#xA;                return;&#xA;            }&#xA;&#xA;            buffer2 = env->NewByteArray((jsize) rgbBytes);&#xA;            env->SetByteArrayRegion(buffer2, 0, (jsize) rgbBytes,&#xA;                                    (jbyte *) buffer);&#xA;            env->CallVoidMethod(instance, renderVideoFrames, buffer2, rgbBytes);&#xA;            env->DeleteLocalRef(buffer2);&#xA;            free(buffer);&#xA;        } catch (...) {&#xA;            if (debug_mode) {&#xA;                LOGE(10, "[ERROR] Render video frames failed");&#xA;                return;&#xA;            }&#xA;        }&#xA;    }&#xA;}&#xA;

    &#xA;

    private void renderVideoFrames(final byte[] buffer, final int length) {&#xA;        new Thread(new Runnable() {&#xA;            @Override&#xA;            public void run() {&#xA;                Canvas c;&#xA;                VideoTrack track = null;&#xA;                for (int tracks_index = 0; tracks_index &lt; tracks.size(); tracks_index&#x2B;&#x2B;) {&#xA;                    if (tracks.get(tracks_index) instanceof VideoTrack) {&#xA;                        track = (VideoTrack) tracks.get(tracks_index);&#xA;                    }&#xA;                }&#xA;                if (track != null) {&#xA;                    int frame_width = track.frame_size[0];&#xA;                    int frame_height = track.frame_size[1];&#xA;                    if (frame_width > 0 &amp;&amp; frame_height > 0) {&#xA;                        try {&#xA;                            // RGB_565  == 65K colours (16 bit)&#xA;                            // RGB_8888 == 16.7M colours (24 bit w/ alpha ch.)&#xA;                            int bpp = Build.VERSION.SDK_INT > 9 ? 16 : 24;&#xA;                            Bitmap.Config bmp_config =&#xA;                                    bpp == 24 ? Bitmap.Config.RGB_565 : Bitmap.Config.ARGB_8888;&#xA;                            Paint paint = new Paint();&#xA;                            if(buffer != null &amp;&amp; holder != null) {&#xA;                                holder.setType(SurfaceHolder.SURFACE_TYPE_NORMAL);&#xA;                                if((c = holder.lockCanvas()) == null) {&#xA;                                    Log.d(MPLAY_TAG, "Lock canvas failed");&#xA;                                    return;&#xA;                                }&#xA;                                ByteBuffer bbuf =&#xA;                                        ByteBuffer.allocateDirect(minVideoBufferSize);&#xA;                                bbuf.rewind();&#xA;                                for(int i = 0; i &lt; buffer.length; i&#x2B;&#x2B;) {&#xA;                                    bbuf.put(i, buffer[i]);&#xA;                                }&#xA;                                bbuf.rewind();&#xA;&#xA;                                // The approximate location where the application crashed.&#xA;                                Bitmap bmp = Bitmap.createBitmap(frame_width, frame_height, bmp_config);&#xA;                                bmp.copyPixelsFromBuffer(bbuf);&#xA;                                &#xA;                                float aspect_ratio = (float) frame_width / (float) frame_height;&#xA;                                int scaled_width = (int)(aspect_ratio * (c.getHeight()));&#xA;                                c.drawBitmap(bmp,&#xA;                                        null,&#xA;                                        new RectF(&#xA;                                                ((c.getWidth() - scaled_width) / 2), 0,&#xA;                                                ((c.getWidth() - scaled_width) / 2) &#x2B; scaled_width,&#xA;                                                c.getHeight()),&#xA;                                        null);&#xA;                                holder.unlockCanvasAndPost(c);&#xA;                                bmp.recycle();&#xA;                                bbuf.clear();&#xA;                            } else {&#xA;                                Log.d(MPLAY_TAG, "Video frame buffer is null");&#xA;                            }&#xA;                        } catch (Exception ex) {&#xA;                            ex.printStackTrace();&#xA;                        } catch (OutOfMemoryError oom) {&#xA;                            oom.printStackTrace();&#xA;                            stop();&#xA;                        }&#xA;                    }&#xA;                }&#xA;            }&#xA;        }).start();&#xA;    }&#xA;

    &#xA;

    Exception (tested in Android 4.1.2 emulator) :

    &#xA;

    E/dalvikvm-heap: Out of memory on a 1228812-byte allocation&#xA;I/dalvikvm: "Thread-495" prio=5 tid=21 RUNNABLE&#xA;   ................................................&#xA;     at android.graphics.Bitmap.nativeCreate(Native Method)&#xA;     at android.graphics.Bitmap.createBitmap(Bitmap.java:640)&#xA;     at android.graphics.Bitmap.createBitmap(Bitmap.java:620)&#xA;     at [app_package_name].MediaPlayer$5.run(MediaPlayer.java:406)&#xA;     at java.lang.Thread.run(Thread.java:856)&#xA;

    &#xA;

    For clarification : I first compiled FFmpeg 0.11.x on a virtual machine with Ubuntu 12.04 LTS from my written build script, looked for player examples suitable for Android below 2.2 (there is little information about them, unfortunately) and opened the file on the player and after showing the first frames it crashed into a stack or buffer overflow, on I put off developing the player for some time.

    &#xA;

    Is there anything ready-made that, as a rule, fits into one C++ file and takes into account all the nuances of backporting ? Thanks in advance.

    &#xA;

  • 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).

    &#xA;

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

    &#xA;

    Any help would be much appreciated.

    &#xA;

    CDVDAUDIO.cpp

    &#xA;

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

    &#xA;

    CDVDAUdioCodecFFmpeg.cpp

    &#xA;

    #include "DVDAudioCodecFFmpeg.h"&#xA;#include "Log.h"&#xA;    &#xA;CDVDAudioCodecFFmpeg::CDVDAudioCodecFFmpeg() : CDVDAudioCodec()&#xA;{&#xA;    m_iBufferSize = 0;&#xA;    m_pCodecContext = NULL;&#xA;    m_bOpenedCodec = false;&#xA;}&#xA;    &#xA;CDVDAudioCodecFFmpeg::~CDVDAudioCodecFFmpeg()&#xA;{&#xA;    Dispose();&#xA;}&#xA;    &#xA;bool CDVDAudioCodecFFmpeg::Open(AVCodecID codecID, int iChannels, int iSampleRate)&#xA;{&#xA;    AVCodec* pCodec;&#xA;    m_bOpenedCodec = false;&#xA;    av_register_all();&#xA;    pCodec = avcodec_find_decoder(codecID);&#xA;    m_pCodecContext = avcodec_alloc_context3(pCodec);//avcodec_alloc_context();&#xA;    avcodec_get_context_defaults3(m_pCodecContext, pCodec);&#xA;    &#xA;    if (!pCodec)&#xA;    {&#xA;        CLog::Log(LOGERROR, "CDVDAudioCodecFFmpeg::Open() Unable to find codec");&#xA;        return false;&#xA;    }&#xA;    &#xA;    m_pCodecContext->debug_mv = 0;&#xA;    m_pCodecContext->debug = 0;&#xA;    m_pCodecContext->workaround_bugs = 1;&#xA;    &#xA;    if (pCodec->capabilities &amp; CODEC_CAP_TRUNCATED)&#xA;        m_pCodecContext->flags |= CODEC_FLAG_TRUNCATED;&#xA;    &#xA;    m_pCodecContext->channels = iChannels;&#xA;    m_pCodecContext->sample_rate = iSampleRate;&#xA;    //m_pCodecContext->bits_per_sample = 24;&#xA;     &#xA;    /* //FIXME BRENT&#xA;        if( ExtraData &amp;&amp; ExtraSize > 0 )&#xA;        {&#xA;            m_pCodecContext->extradata_size = ExtraSize;&#xA;            m_pCodecContext->extradata = m_dllAvCodec.av_mallocz(ExtraSize &#x2B; FF_INPUT_BUFFER_PADDING_SIZE);&#xA;            memcpy(m_pCodecContext->extradata, ExtraData, ExtraSize);&#xA;        }&#xA;    */&#xA;    &#xA;    // set acceleration&#xA;    //m_pCodecContext->dsp_mask = FF_MM_FORCE | FF_MM_MMX | FF_MM_MMXEXT | FF_MM_SSE; //BRENT&#xA;    &#xA;    if (avcodec_open2(m_pCodecContext, pCodec, NULL) &lt; 0)&#xA;    {&#xA;        CLog::Log(LOGERROR, "CDVDAudioCodecFFmpeg::Open() Unable to open codec");&#xA;        Dispose();&#xA;        return false;&#xA;    }&#xA;    &#xA;    m_bOpenedCodec = true;&#xA;    return true;&#xA;}&#xA;    &#xA;void CDVDAudioCodecFFmpeg::Dispose()&#xA;{&#xA;    if (m_pCodecContext)&#xA;    {&#xA;        if (m_bOpenedCodec)&#xA;            avcodec_close(m_pCodecContext);&#xA;        m_bOpenedCodec = false;&#xA;        av_free(m_pCodecContext);&#xA;        m_pCodecContext = NULL;&#xA;    }&#xA;    m_iBufferSize = 0;&#xA;}&#xA;&#xA;int CDVDAudioCodecFFmpeg::Decode(BYTE* pData, int iSize)&#xA;{&#xA;    int iBytesUsed;&#xA;    if (!m_pCodecContext) return -1;&#xA;    &#xA;    //Copy into a FFMpeg AVPAcket again&#xA;    AVPacket packet;&#xA;    av_init_packet(&amp;packet);&#xA;    &#xA;    packet.data=pData;&#xA;    packet.size=iSize;&#xA;    &#xA;    int iOutputSize = AVCODEC_MAX_AUDIO_FRAME_SIZE; //BRENT&#xA;    &#xA;    iBytesUsed = avcodec_decode_audio3(m_pCodecContext, (int16_t *)m_buffer, &amp;iOutputSize/*m_iBufferSize*/, &amp;packet);&#xA;&#xA;    m_iBufferSize = iOutputSize;//BRENT&#xA;&#xA;    return iBytesUsed;&#xA;}&#xA;&#xA;int CDVDAudioCodecFFmpeg::GetData(BYTE** dst)&#xA;{&#xA;    *dst = m_buffer;&#xA;    return m_iBufferSize;&#xA;}&#xA;&#xA;void CDVDAudioCodecFFmpeg::Reset()&#xA;{&#xA;    if (m_pCodecContext)&#xA;        avcodec_flush_buffers(m_pCodecContext);&#xA;}&#xA;&#xA;int CDVDAudioCodecFFmpeg::GetChannels()&#xA;{&#xA;    if (m_pCodecContext)&#xA;        return m_pCodecContext->channels;&#xA;    return 0;&#xA;}&#xA;&#xA;int CDVDAudioCodecFFmpeg::GetSampleRate()&#xA;{&#xA;    if (m_pCodecContext)&#xA;        return m_pCodecContext->sample_rate;&#xA;    return 0;&#xA;}&#xA;    &#xA;int CDVDAudioCodecFFmpeg::GetBitsPerSample()&#xA;{&#xA;    if (m_pCodecContext)&#xA;        return 16;&#xA;    return 0;&#xA;}&#xA;

    &#xA;

    CDVDPlayerAudio.cpp

    &#xA;

    #include "DVDPlayerAudio.h"&#xA;#include "DVDDemuxUtils.h"&#xA;#include "Log.h"&#xA;    &#xA;#include &#xA;#include "DVDAudioCodecFFmpeg.h" //FIXME Move to a codec factory!!&#xA;    &#xA;CDVDPlayerAudio::CDVDPlayerAudio(CDVDClock* pClock) : CThread()&#xA;{&#xA;    m_pClock = pClock;&#xA;    m_pAudioCodec = NULL;&#xA;    m_bInitializedOutputDevice = false;&#xA;    m_iSourceChannels = 0;&#xA;    m_audioClock = 0;&#xA;    &#xA;    //  m_currentPTSItem.pts = DVD_NOPTS_VALUE;&#xA;    //  m_currentPTSItem.timestamp = 0;&#xA;    &#xA;    SetSpeed(DVD_PLAYSPEED_NORMAL);&#xA;      &#xA;    InitializeCriticalSection(&amp;m_critCodecSection);&#xA;    m_messageQueue.SetMaxDataSize(10 * 16 * 1024);&#xA;    //  g_dvdPerformanceCounter.EnableAudioQueue(&amp;m_packetQueue);&#xA;}&#xA;&#xA;CDVDPlayerAudio::~CDVDPlayerAudio()&#xA;{&#xA;    //  g_dvdPerformanceCounter.DisableAudioQueue();&#xA;&#xA;    // close the stream, and don&#x27;t wait for the audio to be finished&#xA;    CloseStream(true);&#xA;    DeleteCriticalSection(&amp;m_critCodecSection);&#xA;}&#xA;&#xA;bool CDVDPlayerAudio::OpenStream( CDemuxStreamAudio *pDemuxStream )&#xA;{&#xA;    // should always be NULL!!!!, it will probably crash anyway when deleting m_pAudioCodec here.&#xA;    if (m_pAudioCodec)&#xA;    {&#xA;        CLog::Log(LOGFATAL, "CDVDPlayerAudio::OpenStream() m_pAudioCodec != NULL");&#xA;        return false;&#xA;    }&#xA;    &#xA;    AVCodecID codecID = pDemuxStream->codec;&#xA;    &#xA;    CLog::Log(LOGNOTICE, "Finding audio codec for: %i", codecID);&#xA;    //m_pAudioCodec = CDVDFactoryCodec::CreateAudioCodec( pDemuxStream ); &#xA;    m_pAudioCodec = new CDVDAudioCodecFFmpeg; //FIXME BRENT Codec Factory needed!&#xA;    &#xA;    if (!m_pAudioCodec->Open(pDemuxStream->codec, pDemuxStream->iChannels, pDemuxStream->iSampleRate))&#xA;    {&#xA;        m_pAudioCodec->Dispose();&#xA;        delete m_pAudioCodec;&#xA;        m_pAudioCodec = NULL;&#xA;        return false;&#xA;    }&#xA;    &#xA;    if ( !m_pAudioCodec )&#xA;    {&#xA;        CLog::Log(LOGERROR, "Unsupported audio codec");&#xA;        return false;&#xA;    }&#xA;    &#xA;    m_codec = pDemuxStream->codec;&#xA;    m_iSourceChannels = pDemuxStream->iChannels;&#xA;    m_messageQueue.Init();&#xA;    &#xA;    CLog::Log(LOGNOTICE, "Creating audio thread");&#xA;    Create();&#xA;    &#xA;    return true;&#xA;}&#xA;&#xA;void CDVDPlayerAudio::CloseStream(bool bWaitForBuffers)&#xA;{&#xA;    // wait until buffers are empty&#xA;    if (bWaitForBuffers)&#xA;        m_messageQueue.WaitUntilEmpty();&#xA;    &#xA;    // send abort message to the audio queue&#xA;    m_messageQueue.Abort();&#xA;    &#xA;    CLog::Log(LOGNOTICE, "waiting for audio thread to exit");&#xA;    &#xA;    // shut down the audio_decode thread and wait for it&#xA;    StopThread(); // will set this->m_bStop to true&#xA;    this->WaitForThreadExit(INFINITE);&#xA;    &#xA;    // uninit queue&#xA;    m_messageQueue.End();&#xA;    &#xA;    CLog::Log(LOGNOTICE, "Deleting audio codec");&#xA;    if (m_pAudioCodec)&#xA;    {&#xA;        m_pAudioCodec->Dispose();&#xA;        delete m_pAudioCodec;&#xA;        m_pAudioCodec = NULL;&#xA;    }&#xA;    &#xA;    // flush any remaining pts values&#xA;    //FlushPTSQueue(); //FIXME BRENT&#xA;}&#xA;&#xA;void CDVDPlayerAudio::OnStartup()&#xA;{&#xA;    CThread::SetName("CDVDPlayerAudio");&#xA;    pAudioPacket = NULL;&#xA;    m_audioClock = 0;&#xA;    audio_pkt_data = NULL;&#xA;    audio_pkt_size = 0;&#xA;  &#xA;    //  g_dvdPerformanceCounter.EnableAudioDecodePerformance(ThreadHandle());&#xA;}&#xA;&#xA;void CDVDPlayerAudio::Process()&#xA;{&#xA;    CLog::Log(LOGNOTICE, "running thread: CDVDPlayerAudio::Process()");&#xA;&#xA;    int result;&#xA;    &#xA;    // silence data&#xA;    BYTE silence[1024];&#xA;    memset(silence, 0, 1024);&#xA;    &#xA;    DVDAudioFrame audioframe;&#xA;    &#xA;    __int64 iClockDiff=0;&#xA;    while (!m_bStop)&#xA;    {&#xA;        //Don&#x27;t let anybody mess with our global variables&#xA;        EnterCriticalSection(&amp;m_critCodecSection);&#xA;        result = DecodeFrame(audioframe, m_speed != DVD_PLAYSPEED_NORMAL); // blocks if no audio is available, but leaves critical section before doing so&#xA;        LeaveCriticalSection(&amp;m_critCodecSection);&#xA;    &#xA;        if ( result &amp; DECODE_FLAG_ERROR ) &#xA;        {      &#xA;            CLog::Log(LOGERROR, "CDVDPlayerAudio::Process - Decode Error. Skipping audio frame");&#xA;            continue;&#xA;        }&#xA;    &#xA;        if ( result &amp; DECODE_FLAG_ABORT )&#xA;        {&#xA;            CLog::Log(LOGDEBUG, "CDVDPlayerAudio::Process - Abort received, exiting thread");&#xA;            break;&#xA;        }&#xA;    &#xA;        if ( result &amp; DECODE_FLAG_DROP ) //FIXME BRENT&#xA;        {&#xA;            /*  //frame should be dropped. Don&#x27;t let audio move ahead of the current time thou&#xA;                //we need to be able to start playing at any time&#xA;                //when playing backwards, we try to keep as small buffers as possible&#xA;    &#xA;                // set the time at this delay&#xA;                AddPTSQueue(audioframe.pts, m_dvdAudio.GetDelay());&#xA;            */&#xA;            if (m_speed > 0)&#xA;            {&#xA;                __int64 timestamp = m_pClock->GetAbsoluteClock() &#x2B; (audioframe.duration * DVD_PLAYSPEED_NORMAL) / m_speed;&#xA;                while ( !m_bStop &amp;&amp; timestamp > m_pClock->GetAbsoluteClock() )&#xA;                    Sleep(1);&#xA;            }&#xA;            continue;&#xA;        }&#xA;    &#xA;        if ( audioframe.size > 0 ) &#xA;        {&#xA;            // we have successfully decoded an audio frame, open up the audio device if not already done&#xA;            if (!m_bInitializedOutputDevice)&#xA;            {&#xA;                m_bInitializedOutputDevice = InitializeOutputDevice();&#xA;            }&#xA;    &#xA;            //Add any packets play&#xA;            m_dvdAudio.AddPackets(audioframe.data, audioframe.size);&#xA;    &#xA;            // store the delay for this pts value so we can calculate the current playing&#xA;            //AddPTSQueue(audioframe.pts, m_dvdAudio.GetDelay() - audioframe.duration);//BRENT&#xA;        }&#xA;    &#xA;        // if we where asked to resync on this packet, do so here&#xA;        if ( result &amp; DECODE_FLAG_RESYNC )&#xA;        {&#xA;            CLog::Log(LOGDEBUG, "CDVDPlayerAudio::Process - Resync recieved.");&#xA;            //while (!m_bStop &amp;&amp; (unsigned int)m_dvdAudio.GetDelay() > audioframe.duration ) Sleep(5); //BRENT&#xA;            m_pClock->Discontinuity(CLOCK_DISC_NORMAL, audioframe.pts);&#xA;        }&#xA;    &#xA;        #ifdef USEOLDSYNC&#xA;        //Clock should be calculated after packets have been added as m_audioClock points to the &#xA;        //time after they have been played&#xA;    &#xA;        const __int64 iCurrDiff = (m_audioClock - m_dvdAudio.GetDelay()) - m_pClock->GetClock();&#xA;        const __int64 iAvDiff = (iClockDiff &#x2B; iCurrDiff)/2;&#xA;    &#xA;        //Check for discontinuity in the stream, use a moving average to&#xA;        //eliminate highfreq fluctuations of large packet sizes&#xA;        if ( ABS(iAvDiff) > 5000 ) // sync clock if average diff is bigger than 5 msec &#xA;        {&#xA;            //Wait until only the new audio frame which triggered the discontinuity is left&#xA;            //then set disc state&#xA;            while (!m_bStop &amp;&amp; (unsigned int)m_dvdAudio.GetBytesInBuffer() > audioframe.size )&#xA;                Sleep(5);&#xA;    &#xA;            m_pClock->Discontinuity(CLOCK_DISC_NORMAL, m_audioClock - m_dvdAudio.GetDelay());&#xA;            CLog::("CDVDPlayer:: Detected Audio Discontinuity, syncing clock. diff was: %I64d, %I64d, av: %I64d", iClockDiff, iCurrDiff, iAvDiff);&#xA;            iClockDiff = 0;&#xA;        }&#xA;        else&#xA;        {&#xA;            //Do gradual adjustments (not working yet)&#xA;            //m_pClock->AdjustSpeedToMatch(iClock &#x2B; iAvDiff);&#xA;            iClockDiff = iCurrDiff;&#xA;        }&#xA;        #endif&#xA;    }&#xA;}&#xA;&#xA;void CDVDPlayerAudio::OnExit()&#xA;{&#xA;    //g_dvdPerformanceCounter.DisableAudioDecodePerformance();&#xA;  &#xA;    // destroy audio device&#xA;    CLog::Log(LOGNOTICE, "Closing audio device");&#xA;    m_dvdAudio.Destroy();&#xA;    m_bInitializedOutputDevice = false;&#xA;&#xA;    CLog::Log(LOGNOTICE, "thread end: CDVDPlayerAudio::OnExit()");&#xA;}&#xA;&#xA;// decode one audio frame and returns its uncompressed size&#xA;int CDVDPlayerAudio::DecodeFrame(DVDAudioFrame &amp;audioframe, bool bDropPacket)&#xA;{&#xA;    CDVDDemux::DemuxPacket* pPacket = pAudioPacket;&#xA;    int n=48000*2*16/8, len;&#xA;    &#xA;    //Store amount left at this point, and what last pts was&#xA;    unsigned __int64 first_pkt_pts = 0;&#xA;    int first_pkt_size = 0; &#xA;    int first_pkt_used = 0;&#xA;    int result = 0;&#xA;    &#xA;    // make sure the sent frame is clean&#xA;    memset(&amp;audioframe, 0, sizeof(DVDAudioFrame));&#xA;    &#xA;    if (pPacket)&#xA;    {&#xA;        first_pkt_pts = pPacket->pts;&#xA;        first_pkt_size = pPacket->iSize;&#xA;        first_pkt_used = first_pkt_size - audio_pkt_size;&#xA;    }&#xA;     &#xA;    for (;;)&#xA;    {&#xA;        /* NOTE: the audio packet can contain several frames */&#xA;        while (audio_pkt_size > 0)&#xA;        {&#xA;            len = m_pAudioCodec->Decode(audio_pkt_data, audio_pkt_size);&#xA;            if (len &lt; 0)&#xA;            {&#xA;                /* if error, we skip the frame */&#xA;                audio_pkt_size=0;&#xA;                m_pAudioCodec->Reset();&#xA;                break;&#xA;            }&#xA;    &#xA;            // fix for fucked up decoders //FIXME BRENT&#xA;            if( len > audio_pkt_size )&#xA;            {        &#xA;                CLog::Log(LOGERROR, "CDVDPlayerAudio:DecodeFrame - Codec tried to consume more data than available. Potential memory corruption");        &#xA;                audio_pkt_size=0;&#xA;                m_pAudioCodec->Reset();&#xA;                assert(0);&#xA;            }&#xA;    &#xA;            // get decoded data and the size of it&#xA;            audioframe.size = m_pAudioCodec->GetData(&amp;audioframe.data);&#xA;            audio_pkt_data &#x2B;= len;&#xA;            audio_pkt_size -= len;&#xA;    &#xA;            if (audioframe.size &lt;= 0)&#xA;                continue;&#xA;    &#xA;            audioframe.pts = m_audioClock;&#xA;    &#xA;            // compute duration.&#xA;            n = m_pAudioCodec->GetChannels() * m_pAudioCodec->GetBitsPerSample() / 8 * m_pAudioCodec->GetSampleRate();&#xA;            if (n > 0)&#xA;            {&#xA;                // safety check, if channels == 0, n will result in 0, and that will result in a nice divide exception&#xA;                audioframe.duration = (unsigned int)(((__int64)audioframe.size * DVD_TIME_BASE) / n);&#xA;    &#xA;                // increase audioclock to after the packet&#xA;                m_audioClock &#x2B;= audioframe.duration;&#xA;            }&#xA;    &#xA;            //If we are asked to drop this packet, return a size of zero. then it won&#x27;t be played&#xA;            //we currently still decode the audio.. this is needed since we still need to know it&#x27;s &#xA;            //duration to make sure clock is updated correctly.&#xA;            if ( bDropPacket )&#xA;            {&#xA;                result |= DECODE_FLAG_DROP;&#xA;            }&#xA;            return result;&#xA;        }&#xA;    &#xA;        // free the current packet&#xA;        if (pPacket)&#xA;        {&#xA;            CDVDDemuxUtils::FreeDemuxPacket(pPacket); //BRENT FIXME&#xA;            pPacket = NULL;&#xA;            pAudioPacket = NULL;&#xA;        }&#xA;    &#xA;        if (m_messageQueue.RecievedAbortRequest())&#xA;            return DECODE_FLAG_ABORT;&#xA;    &#xA;        // read next packet and return -1 on error&#xA;        LeaveCriticalSection(&amp;m_critCodecSection); //Leave here as this might stall a while&#xA;    &#xA;        CDVDMsg* pMsg;&#xA;        MsgQueueReturnCode ret = m_messageQueue.Get(&amp;pMsg, INFINITE);&#xA;        EnterCriticalSection(&amp;m_critCodecSection);&#xA;            &#xA;        if (MSGQ_IS_ERROR(ret) || ret == MSGQ_ABORT)&#xA;            return DECODE_FLAG_ABORT;&#xA;    &#xA;        if (pMsg->IsType(CDVDMsg::DEMUXER_PACKET))&#xA;        {&#xA;            CDVDMsgDemuxerPacket* pMsgDemuxerPacket = (CDVDMsgDemuxerPacket*)pMsg;&#xA;            pPacket = pMsgDemuxerPacket->GetPacket();&#xA;            pMsgDemuxerPacket->m_pPacket = NULL; // XXX, test&#xA;            pAudioPacket = pPacket;&#xA;            audio_pkt_data = pPacket->pData;&#xA;            audio_pkt_size = pPacket->iSize;&#xA;        }&#xA;        else&#xA;        {&#xA;            // other data is not used here, free if&#xA;            // msg itself will still be available&#xA;            pMsg->Release();&#xA;        }&#xA; &#xA;        // if update the audio clock with the pts&#xA;        if (pMsg->IsType(CDVDMsg::DEMUXER_PACKET) || pMsg->IsType(CDVDMsg::GENERAL_RESYNC))&#xA;        {&#xA;            if (pMsg->IsType(CDVDMsg::GENERAL_RESYNC))&#xA;            { &#xA;                //player asked us to sync on this package&#xA;                CDVDMsgGeneralResync* pMsgGeneralResync = (CDVDMsgGeneralResync*)pMsg;&#xA;                result |= DECODE_FLAG_RESYNC;&#xA;                m_audioClock = pMsgGeneralResync->GetPts();&#xA;            }&#xA;            else if (pPacket->pts != DVD_NOPTS_VALUE) // CDVDMsg::DEMUXER_PACKET, pPacket is already set above&#xA;            {&#xA;                if (first_pkt_size == 0) &#xA;                { &#xA;                    //first package&#xA;                    m_audioClock = pPacket->pts;        &#xA;                }&#xA;                else if (first_pkt_pts > pPacket->pts)&#xA;                { &#xA;                    //okey first packet in this continous stream, make sure we use the time here        &#xA;                    m_audioClock = pPacket->pts;        &#xA;                }&#xA;                else if ((unsigned __int64)m_audioClock &lt; pPacket->pts || (unsigned __int64)m_audioClock > pPacket->pts)&#xA;                {&#xA;                    //crap, moved outsided correct pts&#xA;                    //Use pts from current packet, untill we find a better value for it.&#xA;                    //Should be ok after a couple of frames, as soon as it starts clean on a packet&#xA;                    m_audioClock = pPacket->pts;&#xA;                }&#xA;                else if (first_pkt_size == first_pkt_used)&#xA;                {&#xA;                    //Nice starting up freshly on the start of a packet, use pts from it&#xA;                    m_audioClock = pPacket->pts;&#xA;                }&#xA;            }&#xA;        }&#xA;        pMsg->Release();&#xA;    }&#xA;}&#xA;&#xA;void CDVDPlayerAudio::SetSpeed(int speed)&#xA;{ &#xA;    m_speed = speed;&#xA;  &#xA;    //if (m_speed == DVD_PLAYSPEED_PAUSE) m_dvdAudio.Pause(); //BRENT FIXME&#xA;    //else m_dvdAudio.Resume();&#xA;}&#xA;    &#xA;bool CDVDPlayerAudio::InitializeOutputDevice()&#xA;{&#xA;    int iChannels = m_pAudioCodec->GetChannels();&#xA;    int iSampleRate = m_pAudioCodec->GetSampleRate();&#xA;    int iBitsPerSample = m_pAudioCodec->GetBitsPerSample();&#xA;    //bool bPasstrough = m_pAudioCodec->NeedPasstrough(); //BRENT&#xA;    &#xA;    if (iChannels == 0 || iSampleRate == 0 || iBitsPerSample == 0)&#xA;    {&#xA;        CLog::Log(LOGERROR, "Unable to create audio device, (iChannels == 0 || iSampleRate == 0 || iBitsPerSample == 0)");&#xA;        return false;&#xA;    }&#xA;    &#xA;    CLog::Log(LOGNOTICE, "Creating audio device with codec id: %i, channels: %i, sample rate: %i", m_codec, iChannels, iSampleRate);&#xA;    if (m_dvdAudio.Create(iChannels, iSampleRate, iBitsPerSample, /*bPasstrough*/0)) // always 16 bit with ffmpeg ? //BRENT Passthrough needed?&#xA;    {&#xA;        return true;&#xA;    }&#xA;    &#xA;    CLog::Log(LOGERROR, "Failed Creating audio device with codec id: %i, channels: %i, sample rate: %i", m_codec, iChannels, iSampleRate);&#xA;    return false;&#xA;}&#xA;

    &#xA;