Frame.h 9.44 KB
Newer Older
1
/*
xiongziliang committed
2
 * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
3 4 5
 *
 * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
 *
xiongziliang committed
6 7 8
 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
9
 */
10 11 12 13

#ifndef ZLMEDIAKIT_FRAME_H
#define ZLMEDIAKIT_FRAME_H

14
#include <mutex>
15
#include <functional>
16
#include "Util/RingBuffer.h"
17
#include "Network/Socket.h"
18 19

using namespace std;
xiongziliang committed
20
using namespace toolkit;
21

xiongziliang committed
22
namespace mediakit{
23

24 25 26
typedef enum {
    CodecInvalid = -1,
    CodecH264 = 0,
27
    CodecH265,
28
    CodecAAC,
29 30
    CodecG711A,
    CodecG711U,
xiongziliang committed
31
    CodecOpus,
32
    CodecMax = 0x7FFF
33 34 35 36 37 38
} CodecId;

typedef enum {
    TrackInvalid = -1,
    TrackVideo = 0,
    TrackAudio,
39
    TrackTitle,
xiongziliang committed
40
    TrackMax = 3
41 42
} TrackType;

xiongziliang committed
43
/**
xiongziliang committed
44 45 46 47 48 49 50 51 52 53
 * 获取编码器名称
 */
const char *getCodecName(CodecId codecId);

/**
 * 获取音视频类型
 */
TrackType getTrackType(CodecId codecId);

/**
xiongziliang committed
54 55
 * 编码信息的抽象接口
 */
56 57
class CodecInfo {
public:
xiongziliang committed
58 59
    typedef std::shared_ptr<CodecInfo> Ptr;

60 61 62 63 64 65 66
    CodecInfo(){}
    virtual ~CodecInfo(){}

    /**
     * 获取编解码器类型
     */
    virtual CodecId getCodecId() const = 0;
67 68 69 70

    /**
     * 获取编码器名称
     */
xiongziliang committed
71
    const char *getCodecName();
xiongziliang committed
72 73 74 75 76

    /**
     * 获取音视频类型
     */
    TrackType getTrackType();
77 78
};

xiongziliang committed
79 80 81
/**
 * 帧类型的抽象接口
 */
82
class Frame : public Buffer, public CodecInfo {
83 84 85
public:
    typedef std::shared_ptr<Frame> Ptr;
    virtual ~Frame(){}
xiongziliang committed
86 87 88 89 90 91 92 93 94 95 96 97

    /**
     * 返回解码时间戳,单位毫秒
     */
    virtual uint32_t dts() const = 0;

    /**
     * 返回显示时间戳,单位毫秒
     */
    virtual uint32_t pts() const {
        return dts();
    }
98 99 100 101 102

    /**
     * 前缀长度,譬如264前缀为0x00 00 00 01,那么前缀长度就是4
     * aac前缀则为7个字节
     */
103 104 105 106 107 108
    virtual uint32_t prefixSize() const = 0;

    /**
     * 返回是否为关键帧
     */
    virtual bool keyFrame() const = 0;
109 110

    /**
xiongziliang committed
111 112 113 114 115
     * 是否为配置帧,譬如sps pps vps
     */
    virtual bool configFrame() const = 0;

    /**
116 117 118
     * 是否可以缓存
     */
    virtual bool cacheAble() const { return true; }
119 120 121 122 123

    /**
     * 返回可缓存的frame
     */
    static Ptr getCacheAbleFrame(const Ptr &frame);
124 125
};

xiongziliang committed
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
class FrameImp : public Frame {
public:
    typedef std::shared_ptr<FrameImp> Ptr;

    char *data() const override{
        return (char *)_buffer.data();
    }

    uint32_t size() const override {
        return _buffer.size();
    }

    uint32_t dts() const override {
        return _dts;
    }

    uint32_t pts() const override{
        return _pts ? _pts : _dts;
    }

    uint32_t prefixSize() const override{
        return _prefix_size;
    }

    CodecId getCodecId() const override{
151
        return _codec_id;
xiongziliang committed
152 153 154 155 156 157 158 159 160 161 162
    }

    bool keyFrame() const override {
        return false;
    }

    bool configFrame() const override{
        return false;
    }

public:
163
    CodecId _codec_id = CodecInvalid;
xiongziliang committed
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
    string _buffer;
    uint32_t _dts = 0;
    uint32_t _pts = 0;
    uint32_t _prefix_size = 0;
};

/**
 * 一个Frame类中可以有多个帧,他们通过 0x 00 00 01 分隔
 * ZLMediaKit会先把这种复合帧split成单个帧然后再处理
 * 一个复合帧可以通过无内存拷贝的方式切割成多个子Frame
 * 提供该类的目的是切割复合帧时防止内存拷贝,提高性能
 */
template<typename Parent>
class FrameInternal : public Parent{
public:
    typedef std::shared_ptr<FrameInternal> Ptr;
    FrameInternal(const Frame::Ptr &parent_frame, char *ptr, uint32_t size, int prefix_size)
            : Parent(ptr, size, parent_frame->dts(), parent_frame->pts(), prefix_size) {
        _parent_frame = parent_frame;
    }
    bool cacheAble() const override {
        return _parent_frame->cacheAble();
    }
private:
    Frame::Ptr _parent_frame;
};

xiongziliang committed
191 192 193
/**
 * 循环池辅助类
 */
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
template <typename T>
class ResourcePoolHelper{
public:
    ResourcePoolHelper(int size = 8){
        _pool.setSize(size);
    }
    virtual ~ResourcePoolHelper(){}

    std::shared_ptr<T> obtainObj(){
        return _pool.obtain();
    }
private:
    ResourcePool<T> _pool;
};

xiongziliang committed
209
/**
xiongziliang committed
210
 * 写帧接口的抽象接口类
xiongziliang committed
211
 */
212
class FrameWriterInterface {
213
public:
214 215 216
    typedef std::shared_ptr<FrameWriterInterface> Ptr;
    FrameWriterInterface(){}
    virtual ~FrameWriterInterface(){}
xiongziliang committed
217

218
    /**
xiongziliang committed
219 220
     * 写入帧数据
     */
221 222 223
    virtual void inputFrame(const Frame::Ptr &frame) = 0;
};

xiongziliang committed
224 225 226
/**
 * 写帧接口转function,辅助类
 */
227 228 229 230 231
class FrameWriterInterfaceHelper : public FrameWriterInterface {
public:
    typedef std::shared_ptr<FrameWriterInterfaceHelper> Ptr;
    typedef std::function<void(const Frame::Ptr &frame)> onWriteFrame;

xiongziliang committed
232 233 234
    /**
     * inputFrame后触发onWriteFrame回调
     */
235 236 237
    FrameWriterInterfaceHelper(const onWriteFrame& cb){
        _writeCallback = cb;
    }
xiongziliang committed
238

239
    virtual ~FrameWriterInterfaceHelper(){}
xiongziliang committed
240

241
    /**
xiongziliang committed
242 243
     * 写入帧数据
     */
244 245 246 247 248 249 250
    void inputFrame(const Frame::Ptr &frame) override {
        _writeCallback(frame);
    }
private:
    onWriteFrame _writeCallback;
};

251
/**
xiongziliang committed
252 253
 * 支持代理转发的帧环形缓存
 */
xiongziliang committed
254
class FrameDispatcher : public FrameWriterInterface {
255
public:
xiongziliang committed
256
    typedef std::shared_ptr<FrameDispatcher> Ptr;
257

xiongziliang committed
258 259
    FrameDispatcher(){}
    virtual ~FrameDispatcher(){}
260

xiongziliang committed
261 262 263
    /**
     * 添加代理
     */
264
    void addDelegate(const FrameWriterInterface::Ptr &delegate){
xiongziliang committed
265
        //_delegates_write可能多线程同时操作
266
        lock_guard<mutex> lck(_mtx);
267
        _delegates_write.emplace(delegate.get(),delegate);
xiongziliang committed
268
        _need_update = true;
269 270
    }

xiongziliang committed
271 272 273
    /**
     * 删除代理
     */
274
    void delDelegate(FrameWriterInterface *ptr){
xiongziliang committed
275
        //_delegates_write可能多线程同时操作
276
        lock_guard<mutex> lck(_mtx);
xiongziliang committed
277 278
        _delegates_write.erase(ptr);
        _need_update = true;
279 280 281
    }

    /**
xiongziliang committed
282
     * 写入帧并派发
283 284
     */
    void inputFrame(const Frame::Ptr &frame) override{
xiongziliang committed
285 286 287 288 289 290
        if(_need_update){
            //发现代理列表发生变化了,这里同步一次
            lock_guard<mutex> lck(_mtx);
            _delegates_read = _delegates_write;
            _need_update = false;
        }
xiongziliang committed
291 292 293 294 295

        //_delegates_read能确保是单线程操作的
        for(auto &pr : _delegates_read){
            pr.second->inputFrame(frame);
        }
xiongziliang committed
296
    }
xiongziliang committed
297

xiongziliang committed
298 299 300 301 302
    /**
     * 返回代理个数
     */
    int size() const {
        return _delegates_write.size();
303 304
    }
private:
305
    mutex _mtx;
xiongziliang committed
306 307 308
    map<void *,FrameWriterInterface::Ptr>  _delegates_read;
    map<void *,FrameWriterInterface::Ptr>  _delegates_write;
    bool _need_update = false;
309 310
};

311 312 313 314
/**
 * 通过Frame接口包装指针,方便使用者把自己的数据快速接入ZLMediaKit
 */
class FrameFromPtr : public Frame{
315
public:
316
    typedef std::shared_ptr<FrameFromPtr> Ptr;
317 318 319

    FrameFromPtr(CodecId codec_id, char *ptr, uint32_t size, uint32_t dts, uint32_t pts = 0, int prefix_size = 0)
            : FrameFromPtr(ptr, size, dts, pts, prefix_size) {
320
        _codec_id = codec_id;
321 322 323
    }

    FrameFromPtr(char *ptr, uint32_t size, uint32_t dts, uint32_t pts = 0, int prefix_size = 0){
324 325 326 327 328 329 330
        _ptr = ptr;
        _size = size;
        _dts = dts;
        _pts = pts;
        _prefix_size = prefix_size;
    }

331
    char *data() const override{
xiongziliang committed
332
        return _ptr;
333
    }
334

335
    uint32_t size() const override {
xiongziliang committed
336
        return _size;
337
    }
xiongziliang committed
338

xiongziliang committed
339
    uint32_t dts() const override {
xiongziliang committed
340 341 342 343
        return _dts;
    }

    uint32_t pts() const override{
xiongziliang committed
344
        return _pts ? _pts : dts();
345
    }
xiongziliang committed
346

347
    uint32_t prefixSize() const override{
xiongziliang committed
348 349 350 351 352
        return _prefix_size;
    }

    bool cacheAble() const override {
        return false;
353
    }
354

355 356 357 358
    CodecId getCodecId() const override {
        if (_codec_id == CodecInvalid) {
            throw std::invalid_argument("FrameFromPtr对象未设置codec类型");
        }
359 360 361
        return _codec_id;
    }

362 363 364 365
    void setCodecId(CodecId codec_id) {
        _codec_id = codec_id;
    }

366 367 368 369 370 371 372 373 374 375 376
    bool keyFrame() const override {
        return false;
    }

    bool configFrame() const override{
        return false;
    }

protected:
    FrameFromPtr() {}

377 378 379 380 381
protected:
    char *_ptr;
    uint32_t _size;
    uint32_t _dts;
    uint32_t _pts = 0;
xiongziliang committed
382
    uint32_t _prefix_size;
383
    CodecId _codec_id = CodecInvalid;
384 385
};

386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429
/**
 * 该对象可以把Buffer对象转换成可缓存的Frame对象
 */
template <typename Parent>
class FrameWrapper : public Parent{
public:
    ~FrameWrapper() = default;

    /**
     * 构造frame
     * @param buf 数据缓存
     * @param dts 解码时间戳
     * @param pts 显示时间戳
     * @param prefix 帧前缀长度
     * @param offset buffer有效数据偏移量
     */
    FrameWrapper(const Buffer::Ptr &buf, int64_t dts, int64_t pts, int prefix, int offset) : Parent(buf->data() + offset, buf->size() - offset, dts, pts, prefix){
        _buf = buf;
    }

    /**
     * 构造frame
     * @param buf 数据缓存
     * @param dts 解码时间戳
     * @param pts 显示时间戳
     * @param prefix 帧前缀长度
     * @param offset buffer有效数据偏移量
     * @param codec 帧类型
     */
    FrameWrapper(const Buffer::Ptr &buf, int64_t dts, int64_t pts, int prefix, int offset, CodecId codec) : Parent(codec, buf->data() + offset, buf->size() - offset, dts, pts, prefix){
        _buf = buf;
    }

    /**
     * 该帧可缓存
     */
    bool cacheAble() const override {
        return true;
    }

private:
    Buffer::Ptr _buf;
};

xiongziliang committed
430
}//namespace mediakit
xiongziliang committed
431
#endif //ZLMEDIAKIT_FRAME_H