// -*- c++ -*-

/***************************************************************************
                           v4l2dev.h
                           ---------
    begin                : Sat Oct 24 2004
    copyright            : (C) 2004 by Dirk Ziegelmeier
    email                : dziegel@gmx.de
***************************************************************************/

/*
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#ifndef __V4L2DEV_H
#define __V4L2DEV_H

#include <qstring.h>
#include <qstringlist.h>
#include <qsize.h>
#include <qmap.h>
#include <qvariant.h>

#include "qvideo.h"
#include <kdemacros.h>
class QImage;

#define V4L2_MAX_STREAMING_BUFFERS 10

struct v4l2_queryctrl;

/*
 * Abstract interface to Video4Linux2 devices.
 */
class QVIDEO_EXPORT V4L2Dev : public QVideo
{
public:
    virtual ~V4L2Dev();

    static V4L2Dev* getDevice(const QString& dev);

    const QString& name();
    bool isTuner() const { return _isTuner; }

    /*
     * Read/write v4l2 controls
     */
    enum ControlType {ControlType_Int, ControlType_Boolean, ControlType_Menu, ControlType_Button};
    const QStringList controls() const { return _controls.keys(); }
    QVariant control(const QString& name) const;
    bool setControl(const QString& name, const QVariant& value) const;
    const ControlType controlType(const QString& name) const { return _controls[name]->type; }
    const int controlMinimum(const QString& name) const { return _controls[name]->minVal; }
    const int controlMaximum(const QString& name) const { return _controls[name]->maxVal; }
    const int controlStep(const QString& name) const { return _controls[name]->step; }
    const int controlDefault(const QString& name) const { return _controls[name]->defaultVal; }
    const bool controlAdvanced(const QString& name) const { return _controls[name]->advanced; }
    const QStringList& controlMenuChoices(const QString& name) const { return _controls[name]->choices; }
    bool hasControl(const QString& name) const { return _controls.contains(name); } 

    /*
     * Source (input)
     */
    const QStringList sources() const { return _videoInputs.keys(); }
    bool setSource(const QString& name);
    const QString& source() const;

    /*
     * Encoding
     */
    const QStringList encodings() const { return _videoStandarts.keys(); }
    bool setEncoding(const QString& name);
    const QString& encoding() const;

    /*
     * Tuning
     */
    double frequency() const;
    double setFrequency(double frequency);
    int signal() const;

    /*
     * Audio
     */
    const QStringList& audioModes() { return _audioModes; };
    bool setAudioMode(const QString& mode);
    const QStringList& broadcastedAudioModes();

    /*
     * Grab properties
     */
    QSize setInputProperties(ImageFormat fmt, const QSize& size);
    QVideo::ImageFormat inputFormat() const;
    QSize inputSize() const;
    bool canGrabFormat(ImageFormat f) const { return (_grabFormats & f) != 0; }
    
    /*
     * Video stream
     */
    bool startStreaming(unsigned int numBuffers = 2);
    bool stopStreaming();
    int setupStreaming(unsigned int numBuffers = 2);
    int streamingBufferCount() const { return _streamingBufferCount; }
    const unsigned char* getStreamingBuffer(unsigned int id) const;
    bool enqueueBuffer(unsigned int id);
    bool waitBuffer(unsigned int* id);

    /*
     * Snapshot
     * This call always stops streaming and 
     * corrupts streaming format and size
     */
    QSize snapshot(unsigned char* buf, const QSize& desiredSize, QVideo::ImageFormat format);


protected:
    V4L2Dev(int fd, const QString& name, bool supportsReadWrite);

    static unsigned int qvideoformat2v4l2format(ImageFormat f);
    static ImageFormat v4l2format2qvideoformat(unsigned int f);

    int _fd;

    typedef struct controlDescriptor_s {
        int id;
        QString name;
        ControlType type;
        int minVal;
        int maxVal;
        int step;
        int defaultVal;
        QStringList choices;
        bool advanced;
    } controlDescriptor;

    typedef struct streamingBufferDescriptor_s {
        void*  start;
        size_t length;
        bool   mmapped;
        bool   queued;
    } streamingBufferDescriptor;

    bool xioctl(int cmd, void* buf, int mayFail = 0) const;
    controlDescriptor* parseControl(const v4l2_queryctrl& desc);

    int setupStreamingMMAP(unsigned int numBuffers);
    int setupStreamingUser(unsigned int numBuffers);
    void cleanup();

    unsigned int _streamingBufferCount;
    bool _streaming;
    streamingBufferDescriptor _streamingBuffers[V4L2_MAX_STREAMING_BUFFERS];
    int _streamtype;

    ImageFormat _grabFormats;

    QMap<QString, int> _videoInputs;
    QMap<QString, int> _tunerForInput;
    int _currentTuner;
    int _currentTunerType;
    double _frequencyScale;

    QMap<QString, Q_ULLONG> _videoStandarts;

    QMap<QString, controlDescriptor*> _controls;

    QMap<QString, int> _audioMap;
    QStringList _audioModes;
    QStringList _broadcastedAudioModes;

    QString _name;

    bool _isTuner;
    bool _supportsReadWrite;

    static ControlType translateV4L2ControlType(int t);
};

#endif

