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__