video_base.h 6.62 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
/*
 *  Copyright (C) 2013 Savoir-Faire Linux Inc.
 *  Author: Guillaume Roguez <Guillaume.Roguez@savoirfairelinux.com>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *  MA  02110-1301 USA.
 *
 *  Additional permission under GNU GPL version 3 section 7:
 *
 *  If you modify this program, or any covered work, by linking or
 *  combining it with the OpenSSL project's OpenSSL library (or a
 *  modified version of that library), containing parts covered by the
 *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
 *  grants you additional permission to convey the resulting work.
 *  Corresponding Source for a non-source form of such a combination
 *  shall include the source code for the parts of OpenSSL used as well
 *  as that of the covered work.
 */

32 33
#ifndef __VIDEO_FRAME_H__
#define __VIDEO_FRAME_H__
34 35 36

#include "noncopyable.h"

37 38
#include <cstdlib>
#include <cstdint>
39
#include <memory>
40 41
#include <set>
#include <mutex>
42

43 44 45 46 47
// std::this_thread::sleep_for is by default supported since 4.8.1
#define GCC_VERSION (__GNUC__ * 10000 \
                     + __GNUC_MINOR__ * 100             \
                     + __GNUC_PATCHLEVEL__)
#if GCC_VERSION >= 40801
48 49 50 51 52 53 54
#include <chrono>
#include <thread>
#define MYSLEEP(x) std::this_thread::sleep_for(std::chrono::seconds(x))
#else
#include <unistd.h>
#define MYSLEEP(x) sleep(x)
#endif
55

56
class AVFrame;
57 58 59
class AVPacket;
class AVDictionary;

60 61 62 63 64 65
#ifndef AVFORMAT_AVIO_H
class AVIOContext;
#endif

enum VideoPixelFormat {
    VIDEO_PIXFMT_BGRA = -1,
66
    VIDEO_PIXFMT_YUV420P = -2,
67 68
};

69
namespace sfl_video {
70

71
template <typename T> class Observer;
72 73 74
template <typename T> class Observable;
class VideoFrame;

75 76 77 78
typedef int(*io_readcallback)(void *opaque, uint8_t *buf, int buf_size);
typedef int(*io_writecallback)(void *opaque, uint8_t *buf, int buf_size);
typedef int64_t(*io_seekcallback)(void *opaque, int64_t offset, int whence);

79 80 81 82 83 84 85 86 87
typedef std::shared_ptr<VideoFrame> VideoFrameUP;
typedef std::shared_ptr<VideoFrame> VideoFrameSP;

/*=== Observable =============================================================*/

template <typename T>
class Observable
{
public:
88
    Observable() : observers_(), mutex_() {}
89 90
    virtual ~Observable() {};

91
    bool attach(Observer<T>* o) {
92
        std::unique_lock<std::mutex> lk(mutex_);
93 94 95 96 97
        if (o and observers_.insert(o).second) {
            o->attached(this);
            return true;
        }
        return false;
98 99
    }

100
    bool detach(Observer<T>* o) {
101
        std::unique_lock<std::mutex> lk(mutex_);
102 103 104 105 106
        if (o and observers_.erase(o)) {
            o->detached(this);
            return true;
        }
        return false;
107 108 109 110
    }

    void notify(T& data) {
        std::unique_lock<std::mutex> lk(mutex_);
111 112
        for (auto observer : observers_)
            observer->update(this, data);
113 114
    }

115 116 117 118 119
    int getObserversCount() {
        std::unique_lock<std::mutex> lk(mutex_);
        return observers_.size();
    }

120 121 122
private:
    NON_COPYABLE(Observable<T>);

123 124
	std::set<Observer<T>*> observers_;
    std::mutex mutex_; // lock observers_
125 126
};

127
/*=== Observer =============================================================*/
128 129

template <typename T>
130
class Observer
131 132
{
public:
133
    virtual ~Observer() {};
134
	virtual void update(Observable<T>*, T&) = 0;
135 136
    virtual void attached(Observable<T>*) {};
    virtual void detached(Observable<T>*) {};
137 138
};

139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
/*=== VideoPacket  ===========================================================*/

class VideoPacket {

public:
    VideoPacket();
    ~VideoPacket();
    AVPacket* get() { return packet_; };

private:
    NON_COPYABLE(VideoPacket);
    AVPacket *packet_;
};

/*=== VideoIOHandle  =========================================================*/

class VideoIOHandle {
public:
    VideoIOHandle(ssize_t buffer_size,
                  bool writeable,
                  io_readcallback read_cb,
                  io_writecallback write_cb,
                  io_seekcallback seek_cb,
                  void *opaque);
    ~VideoIOHandle();

    AVIOContext* get() { return ctx_; }

private:
    NON_COPYABLE(VideoIOHandle);
    AVIOContext *ctx_;
    unsigned char *buf_;
};

class VideoCodec {
public:
    VideoCodec();
    virtual ~VideoCodec() {}

    void setOption(const char *name, const char *value);

private:
    NON_COPYABLE(VideoCodec);

protected:
    AVDictionary *options_;
};

/*=== VideoFrame =============================================================*/

class VideoFrame {
public:
    VideoFrame();
    ~VideoFrame();

    AVFrame* get() { return frame_; };
195
    int getPixelFormat() const;
196 197
    int getWidth() const;
    int getHeight() const;
198 199 200
    void setGeometry(int width, int height, int pix_fmt);
    void setDestination(void *data);
    size_t getSize();
201
    static size_t getSize(int width, int height, int format);
202
    void setdefaults();
203 204 205
    bool allocBuffer(int width, int height, int pix_fmt);
    int blit(VideoFrame& src, int xoff, int yoff);
    void copy(VideoFrame &src);
206
    void clear();
207
    void test();
208 209 210 211

private:
    NON_COPYABLE(VideoFrame);
    AVFrame *frame_;
212
    bool allocated_;
213 214
};

215
/*=== VideoNode ============================================================*/
216

217 218 219 220 221 222 223 224 225
class VideoNode { public: virtual ~VideoNode() {}; };
typedef VideoNode VideoSource;

class VideoFrameActiveWriter :
        public Observable<VideoFrameSP>,
        public VideoNode
{};

class VideoFramePassiveReader :
226
        public Observer<VideoFrameSP>,
227 228
        public VideoNode
{};
229

230
/*=== VideoGenerator =========================================================*/
231

232 233
class VideoGenerator : public VideoFrameActiveWriter
{
234
public:
235
    VideoGenerator() : writableFrame_(), lastFrame_(), mutex_() {}
236 237 238 239

    virtual int getWidth() const = 0;
    virtual int getHeight() const = 0;
    virtual int getPixelFormat() const = 0;
240

241
    VideoFrameSP obtainLastFrame();
242 243

protected:
244
    // getNewFrame and publishFrame must be called by the same thread only
245
    VideoFrame& getNewFrame();
246
    void publishFrame();
247 248

private:
249 250
    VideoFrameUP writableFrame_;
    VideoFrameSP lastFrame_;
251
    std::mutex mutex_; // lock writableFrame_/lastFrame_ access
252 253
};

254 255
}

256
#endif // __VIDEO_BASE_H__