/*
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * \file DSCaptureDevice.h
 * \brief DirectShow capture device.
 * \author Sebastien Vincent
 * \date 2010
 */

#ifndef _ORG_JITSI_IMPL_NEOMEDIA_JMFEXT_MEDIA_PROTOCOL_DIRECTSHOW_DSCAPTUREDEVICE_H_
#define _ORG_JITSI_IMPL_NEOMEDIA_JMFEXT_MEDIA_PROTOCOL_DIRECTSHOW_DSCAPTUREDEVICE_H_

#include <list>

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <dshow.h>

#include "BasicSampleGrabberCB.h"
#include "DSFormat.h"

/**
 * \class DSCaptureDevice
 * \brief DirectShow capture device.
 *
 * Once a DSCapture has been obtained by DSManager, do not
 * forget to build the graph and optionally set a format.
 */
class DSCaptureDevice
{
public:
    /**
     * \brief Constructor.
     * \param name name of the capture device
     */
    DSCaptureDevice(const WCHAR* name);

    /**
     * \brief Destructor.
     */
    ~DSCaptureDevice();

    /**
     * \brief Get name of the capture device.
     * \return name of the capture device
     */
    const WCHAR* getName() const;

    /**
     * \brief Initialize the device.
     * \param moniker moniker of the capture device
     * \return S_OK or S_FALSE on success or an HRESULT value describing a
     * failure
     */
    HRESULT initDevice(IMoniker* moniker);

    /**
     * \brief Set video format.
     * \param format video format
     * \return S_OK or S_FALSE on success or an HRESULT value describing a
     * failure
     */
    HRESULT setFormat(const DSFormat& format);

    /**
     * \brief Get list of supported formats.
     * \return list of supported formats.
     */
    std::list<DSFormat> getSupportedFormats() const;

    /**
     * \brief Build the filter graph for this capture device.
     * \return true if success, false otherwise
     * \note Call this method before start().
     */
    HRESULT buildGraph();

    /**
     * \brief get callback object.
     * \return callback
     */
    BasicSampleGrabberCB* getCallback() { return m_callback; }

    /**
     * \brief Set callback object when receiving new frames.
     * \param callback callback object to set
     */
    void setCallback(BasicSampleGrabberCB *callback);

    /**
     * \brief Start capture device.
     * \return S_OK or S_FALSE on success or an HRESULT value describing a
     * failure
     */
    HRESULT start();

    /**
     * \brief Stop capture device.
     * \return S_OK or S_FALSE on success or an HRESULT value describing a
     * failure
     */
    HRESULT stop();

    /**
     * \brief Get current format.
     * \return current format
     */
    DSFormat getFormat() const;

    /**
     * \brief Get current bit per pixel.
     * \return bit per pixel of images
     */
    size_t getBitPerPixel();

private:
    // see https://msdn.microsoft.com/en-us/library/windows/desktop/dd390650(v=vs.85).aspx
    void RemoveFromRot();
    HRESULT AddToRot();
    DWORD m_dwRotRegister;

    /**
     * \brief Initialize list of supported size.
     */
    void initSupportedFormats();

    /**
    * \brief Set video format on a specific stream config object.
    * \param format video format
    * \param streamConfig the stream config to set the format on
    * \return S_OK or S_FALSE on success or an HRESULT value describing a
    * failure
    */
    HRESULT setFormat(const DSFormat& format, IAMStreamConfig* streamConfig);
    
    /**
     * \brief Name of the capture device.
     */
    WCHAR* m_name;

    /**
     * \brief Callback.
     */
    BasicSampleGrabberCB* m_callback;

    /**
     * \brief List of DSFormat.
     */
    std::list<DSFormat> m_formats;
    
    /**
     * \brief Reference of the filter graph.
     */
    IFilterGraph2* m_filterGraph;

    /**
     * \brief Reference of the capture graph builder.
     */
    ICaptureGraphBuilder2* m_captureGraphBuilder;

    /**
     * \brief Controller of the graph.
     */
    IMediaControl* m_graphController;

    /**
     * \brief Source filter.
     */
    IBaseFilter* m_srcFilter;
    
    /**
     * \brief Sample grabber filter.
     */
    IBaseFilter* m_sampleGrabberFilter;

    /**
     * \brief The null renderer.
     */
    IBaseFilter* m_renderer;

    /**
     * \brief The sample grabber.
     */
    ISampleGrabber* m_sampleGrabber;

    /**
     * \brief Current format.
     */
    DSFormat m_format;

    /**
     * \brief Current bit per pixel.
     */
    size_t m_bitPerPixel;
};

#endif /* _ORG_JITSI_IMPL_NEOMEDIA_JMFEXT_MEDIA_PROTOCOL_DIRECTSHOW_DSCAPTUREDEVICE_H_ */
