<commit_before>/****************************************************************************
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "mfvideorenderercontrol.h"
#include <mferror.h>
#include <qabstractvideosurface.h>
#include <qvideosurfaceformat.h>
#include <qtcore/qtimer.h>
#include <qtcore/qmutex.h>
#include <qtcore/qcoreevent.h>
#include <qtcore/qcoreapplication.h>
#include <qtcore/qthread.h>
#include "guiddef.h"
#include <qtcore/qdebug.h>

//#define DEBUG_MEDIAFOUNDATION
#define PAD_TO_DWORD(x)  (((x) + 3) & ~3)

namespace
{
    class MediaSampleVideoBuffer : public QAbstractVideoBuffer
    {
    public:
        MediaSampleVideoBuffer(IMFMediaBuffer *buffer, int bytesPerLine)
            : QAbstractVideoBuffer(NoHandle)
            , m_buffer(buffer)
            , m_bytesPerLine(bytesPerLine)
            , m_mapMode(NotMapped)
        {
            buffer->AddRef();
        }

        ~MediaSampleVideoBuffer()
        {
            m_buffer->Release();
        }

        uchar *map(MapMode mode, int *numBytes, int *bytesPerLine)
        {
            if (m_mapMode == NotMapped && mode != NotMapped) {
                BYTE *bytes;
                DWORD length;
                HRESULT hr = m_buffer->Lock(&bytes, NULL, &length);
                if (SUCCEEDED(hr)) {
                    if (numBytes)
                        *numBytes = int(length);

                    if (bytesPerLine)
                        *bytesPerLine = m_bytesPerLine;

                    m_mapMode = mode;
                    return reinterpret_cast<uchar *>(bytes);
                } else {
                    qWarning("Faild to lock mf buffer!");
                }
            }
            return 0;
        }

        void unmap()
        {
            if (m_mapMode == NotMapped)
                return;
            m_mapMode = NotMapped;
            m_buffer->Unlock();
        }

        MapMode mapMode() const
        {
            return m_mapMode;
        }

    private:
        IMFMediaBuffer *m_buffer;
        int m_bytesPerLine;
        MapMode m_mapMode;
    };

    template<class T>
    class AsyncCallback : public IMFAsyncCallback
    {
    public:
        typedef HRESULT (T::*InvokeFn)(IMFAsyncResult *pAsyncResult);

        AsyncCallback(T *pParent, InvokeFn fn) : m_pParent(pParent), m_pInvokeFn(fn)
        {
        }

        // IUnknown
        STDMETHODIMP QueryInterface(REFIID iid, void** ppv)
        {
            if (!ppv)
            {
                return E_POINTER;
            }
            if (iid == __uuidof(IUnknown))
            {
                *ppv = static_cast<IUnknown*>(static_cast<IMFAsyncCallback*>(this));
            }
            else if (iid == __uuidof(IMFAsyncCallback))
            {
                *ppv = static_cast<IMFAsyncCallback*>(this);
            }
            else
            {
                *ppv = NULL;
                return E_NOINTERFACE;
            }
            AddRef();
            return S_OK;
        }
        STDMETHODIMP_(ULONG) AddRef()
        {
            // Delegate to parent class.
            return m_pParent->AddRef();
        }
        STDMETHODIMP_(ULONG) Release()
        {
            // Delegate to parent class.
            return m_pParent->Release();
        }

        // IMFAsyncCallback methods
        STDMETHODIMP GetParameters(DWORD*, DWORD*)
        {
            // Implementation of this method is optional.
            return E_NOTIMPL;
        }

        STDMETHODIMP Invoke(IMFAsyncResult* pAsyncResult)
        {
            return (m_pParent->*m_pInvokeFn)(pAsyncResult);
        }

        T *m_pParent;
        InvokeFn m_pInvokeFn;
    };


    // Custom interface for handling IMFStreamSink::PlaceMarker calls asynchronously.
    MIDL_INTERFACE("a3ff32de-1031-438a-8b47-82f8acda59b7")
    IMarker : public IUnknown
    {
        virtual STDMETHODIMP GetMarkerType(MFSTREAMSINK_MARKER_TYPE *pType) = 0;
        virtual STDMETHODIMP GetMarkerValue(PROPVARIANT *pvar) = 0;
        virtual STDMETHODIMP GetContext(PROPVARIANT *pvar) = 0;
    };

    class Marker : public IMarker
    {
    public:
        static HRESULT Create(
            MFSTREAMSINK_MARKER_TYPE eMarkerType,
            const PROPVARIANT* pvarMarkerValue,  // Can be NULL.
            const PROPVARIANT* pvarContextValue, // Can be NULL.
            IMarker **ppMarker)
        {
            if (ppMarker == NULL)
                return E_POINTER;

            HRESULT hr = S_OK;
            Marker *pMarker = new Marker(eMarkerType);
            if (pMarker == NULL)
                hr = E_OUTOFMEMORY;

            // Copy the marker data.
            if (SUCCEEDED(hr) && pvarMarkerValue)
                hr = PropVariantCopy(&pMarker->m_varMarkerValue, pvarMarkerValue);

            if (SUCCEEDED(hr) && pvarContextValue)
                hr = PropVariantCopy(&pMarker->m_varContextValue, pvarContextValue);

            if (SUCCEEDED(hr)) {
                *ppMarker = pMarker;
                (*ppMarker)->AddRef();
            }

            if (pMarker)
                pMarker->Release();

            return hr;
        }

        // IUnknown methods.
        STDMETHODIMP QueryInterface(REFIID iid, void** ppv)
        {
            if (!ppv)
                return E_POINTER;
            if (iid == IID_IUnknown) {
                *ppv = static_cast<IUnknown*>(this);
            } else if (iid == __uuidof(IMarker)) {
                *ppv = static_cast<IMarker*>(this);
            } else {
                *ppv = NULL;
                return E_NOINTERFACE;
            }
            AddRef();
            return S_OK;
        }

        STDMETHODIMP_(ULONG) AddRef()
        {
            return InterlockedIncrement(&m_cRef);
        }

        STDMETHODIMP_(ULONG) Release()
        {
            LONG cRef = InterlockedDecrement(&m_cRef);
            if (cRef == 0)
                delete this;
            // For thread safety, return a temporary variable.
            return cRef;
        }

        STDMETHODIMP GetMarkerType(MFSTREAMSINK_MARKER_TYPE *pType)
        {
            if (pType == NULL)
                return E_POINTER;
            *pType = m_eMarkerType;
            return S_OK;
        }

        STDMETHODIMP GetMarkerValue(PROPVARIANT *pvar)
        {
            if (pvar == NULL)
                return E_POINTER;
            return PropVariantCopy(pvar, &m_varMarkerValue);
        }

        STDMETHODIMP GetContext(PROPVARIANT *pvar)
        {
            if (pvar == NULL)
                return E_POINTER;
            return PropVariantCopy(pvar, &m_varContextValue);
        }

    protected:
        MFSTREAMSINK_MARKER_TYPE m_eMarkerType;
        PROPVARIANT m_varMarkerValue;
        PROPVARIANT m_varContextValue;

    private:
        long    m_cRef;

        Marker(MFSTREAMSINK_MARKER_TYPE eMarkerType) : m_cRef(1), m_eMarkerType(eMarkerType)
        {
            PropVariantInit(&m_varMarkerValue);
            PropVariantInit(&m_varContextValue);
        }

        virtual ~Marker()
        {
            PropVariantClear(&m_varMarkerValue);
            PropVariantClear(&m_varContextValue);
        }
    };

    class MediaStream : public QObject, public IMFStreamSink, public IMFMediaTypeHandler
    {
        Q_OBJECT
        friend class MFVideoRendererControl;
    public:
        static const DWORD DEFAULT_MEDIA_STREAM_ID = 0x0;

        MediaStream(IMFMediaSink *parent, MFVideoRendererControl *rendererControl)
            : m_cRef(1)
            , m_eventQueue(0)
            , m_shutdown(false)
            , m_surface(0)
            , m_state(State_TypeNotSet)
            , m_currentFormatIndex(-1)
            , m_bytesPerLine(0)
            , m_workQueueId(0)
            , m_workQueueCB(this, &MediaStream::onDispatchWorkItem)
            , m_finalizeResult(0)
            , m_scheduledBuffer(0)
            , m_presentationClock(0)
            , m_currentMediaType(0)
            , m_prerolling(false)
            , m_prerollTargetTime(0)
            , m_startTime(0)
            , m_rendererControl(rendererControl)
        {
            m_sink = parent;

            if (FAILED(MFCreateEventQueue(&m_eventQueue)))
                qWarning("Failed to create mf event queue!");
            if (FAILED(MFAllocateWorkQueue(&m_workQueueId)))
                qWarning("Failed to allocated mf work queue!");
        }

        ~MediaStream()
        {
            Q_ASSERT(m_shutdown);
        }

        //from IUnknown
        STDMETHODIMP QueryInterface(REFIID riid, void** ppvObject)
        {<commit_msg>WMF: Fixed uninitialized member variable.<commit_after>/****************************************************************************
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "mfvideorenderercontrol.h"
#include <mferror.h>
#include <qabstractvideosurface.h>
#include <qvideosurfaceformat.h>
#include <qtcore/qtimer.h>
#include <qtcore/qmutex.h>
#include <qtcore/qcoreevent.h>
#include <qtcore/qcoreapplication.h>
#include <qtcore/qthread.h>
#include "guiddef.h"
#include <qtcore/qdebug.h>

//#define DEBUG_MEDIAFOUNDATION
#define PAD_TO_DWORD(x)  (((x) + 3) & ~3)

namespace
{
    class MediaSampleVideoBuffer : public QAbstractVideoBuffer
    {
    public:
        MediaSampleVideoBuffer(IMFMediaBuffer *buffer, int bytesPerLine)
            : QAbstractVideoBuffer(NoHandle)
            , m_buffer(buffer)
            , m_bytesPerLine(bytesPerLine)
            , m_mapMode(NotMapped)
        {
            buffer->AddRef();
        }

        ~MediaSampleVideoBuffer()
        {
            m_buffer->Release();
        }

        uchar *map(MapMode mode, int *numBytes, int *bytesPerLine)
        {
            if (m_mapMode == NotMapped && mode != NotMapped) {
                BYTE *bytes;
                DWORD length;
                HRESULT hr = m_buffer->Lock(&bytes, NULL, &length);
                if (SUCCEEDED(hr)) {
                    if (numBytes)
                        *numBytes = int(length);

                    if (bytesPerLine)
                        *bytesPerLine = m_bytesPerLine;

                    m_mapMode = mode;
                    return reinterpret_cast<uchar *>(bytes);
                } else {
                    qWarning("Faild to lock mf buffer!");
                }
            }
            return 0;
        }

        void unmap()
        {
            if (m_mapMode == NotMapped)
                return;
            m_mapMode = NotMapped;
            m_buffer->Unlock();
        }

        MapMode mapMode() const
        {
            return m_mapMode;
        }

    private:
        IMFMediaBuffer *m_buffer;
        int m_bytesPerLine;
        MapMode m_mapMode;
    };

    template<class T>
    class AsyncCallback : public IMFAsyncCallback
    {
    public:
        typedef HRESULT (T::*InvokeFn)(IMFAsyncResult *pAsyncResult);

        AsyncCallback(T *pParent, InvokeFn fn) : m_pParent(pParent), m_pInvokeFn(fn)
        {
        }

        // IUnknown
        STDMETHODIMP QueryInterface(REFIID iid, void** ppv)
        {
            if (!ppv)
            {
                return E_POINTER;
            }
            if (iid == __uuidof(IUnknown))
            {
                *ppv = static_cast<IUnknown*>(static_cast<IMFAsyncCallback*>(this));
            }
            else if (iid == __uuidof(IMFAsyncCallback))
            {
                *ppv = static_cast<IMFAsyncCallback*>(this);
            }
            else
            {
                *ppv = NULL;
                return E_NOINTERFACE;
            }
            AddRef();
            return S_OK;
        }
        STDMETHODIMP_(ULONG) AddRef()
        {
            // Delegate to parent class.
            return m_pParent->AddRef();
        }
        STDMETHODIMP_(ULONG) Release()
        {
            // Delegate to parent class.
            return m_pParent->Release();
        }

        // IMFAsyncCallback methods
        STDMETHODIMP GetParameters(DWORD*, DWORD*)
        {
            // Implementation of this method is optional.
            return E_NOTIMPL;
        }

        STDMETHODIMP Invoke(IMFAsyncResult* pAsyncResult)
        {
            return (m_pParent->*m_pInvokeFn)(pAsyncResult);
        }

        T *m_pParent;
        InvokeFn m_pInvokeFn;
    };


    // Custom interface for handling IMFStreamSink::PlaceMarker calls asynchronously.
    MIDL_INTERFACE("a3ff32de-1031-438a-8b47-82f8acda59b7")
    IMarker : public IUnknown
    {
        virtual STDMETHODIMP GetMarkerType(MFSTREAMSINK_MARKER_TYPE *pType) = 0;
        virtual STDMETHODIMP GetMarkerValue(PROPVARIANT *pvar) = 0;
        virtual STDMETHODIMP GetContext(PROPVARIANT *pvar) = 0;
    };

    class Marker : public IMarker
    {
    public:
        static HRESULT Create(
            MFSTREAMSINK_MARKER_TYPE eMarkerType,
            const PROPVARIANT* pvarMarkerValue,  // Can be NULL.
            const PROPVARIANT* pvarContextValue, // Can be NULL.
            IMarker **ppMarker)
        {
            if (ppMarker == NULL)
                return E_POINTER;

            HRESULT hr = S_OK;
            Marker *pMarker = new Marker(eMarkerType);
            if (pMarker == NULL)
                hr = E_OUTOFMEMORY;

            // Copy the marker data.
            if (SUCCEEDED(hr) && pvarMarkerValue)
                hr = PropVariantCopy(&pMarker->m_varMarkerValue, pvarMarkerValue);

            if (SUCCEEDED(hr) && pvarContextValue)
                hr = PropVariantCopy(&pMarker->m_varContextValue, pvarContextValue);

            if (SUCCEEDED(hr)) {
                *ppMarker = pMarker;
                (*ppMarker)->AddRef();
            }

            if (pMarker)
                pMarker->Release();

            return hr;
        }

        // IUnknown methods.
        STDMETHODIMP QueryInterface(REFIID iid, void** ppv)
        {
            if (!ppv)
                return E_POINTER;
            if (iid == IID_IUnknown) {
                *ppv = static_cast<IUnknown*>(this);
            } else if (iid == __uuidof(IMarker)) {
                *ppv = static_cast<IMarker*>(this);
            } else {
                *ppv = NULL;
                return E_NOINTERFACE;
            }
            AddRef();
            return S_OK;
        }

        STDMETHODIMP_(ULONG) AddRef()
        {
            return InterlockedIncrement(&m_cRef);
        }

        STDMETHODIMP_(ULONG) Release()
        {
            LONG cRef = InterlockedDecrement(&m_cRef);
            if (cRef == 0)
                delete this;
            // For thread safety, return a temporary variable.
            return cRef;
        }

        STDMETHODIMP GetMarkerType(MFSTREAMSINK_MARKER_TYPE *pType)
        {
            if (pType == NULL)
                return E_POINTER;
            *pType = m_eMarkerType;
            return S_OK;
        }

        STDMETHODIMP GetMarkerValue(PROPVARIANT *pvar)
        {
            if (pvar == NULL)
                return E_POINTER;
            return PropVariantCopy(pvar, &m_varMarkerValue);
        }

        STDMETHODIMP GetContext(PROPVARIANT *pvar)
        {
            if (pvar == NULL)
                return E_POINTER;
            return PropVariantCopy(pvar, &m_varContextValue);
        }

    protected:
        MFSTREAMSINK_MARKER_TYPE m_eMarkerType;
        PROPVARIANT m_varMarkerValue;
        PROPVARIANT m_varContextValue;

    private:
        long    m_cRef;

        Marker(MFSTREAMSINK_MARKER_TYPE eMarkerType) : m_cRef(1), m_eMarkerType(eMarkerType)
        {
            PropVariantInit(&m_varMarkerValue);
            PropVariantInit(&m_varContextValue);
        }

        virtual ~Marker()
        {
            PropVariantClear(&m_varMarkerValue);
            PropVariantClear(&m_varContextValue);
        }
    };

    class MediaStream : public QObject, public IMFStreamSink, public IMFMediaTypeHandler
    {
        Q_OBJECT
        friend class MFVideoRendererControl;
    public:
        static const DWORD DEFAULT_MEDIA_STREAM_ID = 0x0;

        MediaStream(IMFMediaSink *parent, MFVideoRendererControl *rendererControl)
            : m_cRef(1)
            , m_eventQueue(0)
            , m_shutdown(false)
            , m_surface(0)
            , m_state(State_TypeNotSet)
            , m_currentFormatIndex(-1)
            , m_bytesPerLine(0)
            , m_workQueueId(0)
            , m_workQueueCB(this, &MediaStream::onDispatchWorkItem)
            , m_finalizeResult(0)
            , m_scheduledBuffer(0)
            , m_presentationClock(0)
            , m_currentMediaType(0)
            , m_prerolling(false)
            , m_prerollTargetTime(0)
            , m_startTime(0)
            , m_rendererControl(rendererControl)
            , m_rate(1.f)
        {
            m_sink = parent;

            if (FAILED(MFCreateEventQueue(&m_eventQueue)))
                qWarning("Failed to create mf event queue!");
            if (FAILED(MFAllocateWorkQueue(&m_workQueueId)))
                qWarning("Failed to allocated mf work queue!");
        }

        ~MediaStream()
        {
            Q_ASSERT(m_shutdown);
        }

        //from IUnknown
        STDMETHODIMP QueryInterface(REFIID riid, void** ppvObject)
        {
{'fraction_non_alphanumeric': 0.10228686250119606, 'fraction_numerical': 0.00550186585015788, 'mean_word_length': 1.8843659445287706, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 57, 'https://': 0, 'lorem ipsum': 0, 'www.': 6, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2134800', 'n_tokens_mistral': 6132, 'n_tokens_neox': 5843, 'n_words': 1399}