/*---------------------------------------------------------------------------*/
/* video_encoder.h                                                           */
/* copyright (c) innovaphone 2017                                            */
/*                                                                           */
/*---------------------------------------------------------------------------*/

class VideoEncoderSample {
public:
    dword timestamp;
    int length;
    byte *data;
};

class VideoEncoderH264 : public IMediaEncoder, public UMediaTranscoder
{
    class IIoMux * const iomux;
    class UMediaEncoder * const user;
    class IInstanceLog * const log;

    unsigned fullIntraRequest;
    unsigned fullIntraAck;

    void TranscodeResult(class IMediaTranscoder * transcoder, const void * buf, int len, dword timestamp, dword duration, short sequenceDiff, int width, int height, int stride, dword flags);
    void MediaTranscoderCloseResult(class IMediaTranscoder * transcoder);
    IMediaTranscoder * transcoder;

    bool shutDown;
    int execCnt;

public:
    VideoEncoderH264(class IIoMux * const iomux, class UMediaEncoder * const user, class IInstanceLog * log);
    ~VideoEncoderH264();

    // IVideoEncoder
    bool Initialize(const struct VideoFrameFormat * const format) override;
    void Encode(const void * buf, int len, dword timestamp, dword duration, const struct VideoFrameFormat * format) override;
    bool FullIntraRequest() override;
    enum VideoCoder GetVideoCoder() override { return VideoCoder::H264; };
    void Close() override;
};

#define BITRATE_SLOTS  200

class VideoEncoderKeyFrameTimer : public ITimer {
public:
    VideoEncoderKeyFrameTimer(IIoMux * ioMux, UTimerSubclass<VideoEncoderKeyFrameTimer> * owner) : ITimer(ioMux, owner) {};
};

class VideoEncoderQualityTimer : public ITimer {
public:
    VideoEncoderQualityTimer(IIoMux * ioMux, UTimerSubclass<VideoEncoderQualityTimer> * owner) : ITimer(ioMux, owner) {};
};

class VideoEncoderVPX : public IMediaEncoder, public UMediaTranscoder,
    public UTimerSubclass<VideoEncoderKeyFrameTimer>,
    public UTimerSubclass<VideoEncoderQualityTimer>
{
    class IIoMux * const iomux;
    class UMediaEncoder * const user;
    class IInstanceLog * const log;

    void TranscodeResult(class IMediaTranscoder * transcoder, const void * buf, int len, dword timestamp, dword duration, short sequenceDiff, int width, int height, int stride, dword flags);
    void MediaTranscoderCloseResult(class IMediaTranscoder * transcoder);
    IMediaTranscoder * transcoder;

    bool appSharing;

    bool vp9;
    bool shutDown;
    int execCnt;

    VideoEncoderKeyFrameTimer keyFrameTimer;
    bool sendKeyFrame;
    VideoEncoderQualityTimer qualityTimer;
    int qualityTimerTimeout;
    unsigned int nextRcMinQuantizer;
    unsigned int nextRcMaxQuantizer;
    bool activeMap;
    int forceKeyFrame;

    int maxSendBytes;
    int bitrateSlots[BITRATE_SLOTS];
    int indexBitrate;
    dword durationSlots[BITRATE_SLOTS];
    dword lastTimestamp;
    word startKeyFrameSeq;
    word endKeyFrameSeq;
    int lastKeyFrameSize;

    bool CalculateBitrate();

public:
    VideoEncoderVPX(class IIoMux * const iomux, class UMediaEncoder * const user, class IInstanceLog * log, bool vp9);
    ~VideoEncoderVPX();

    // IVideoEncoder
    bool Initialize(const struct VideoFrameFormat * const format) override;
    void Encode(const void * buf, int len, dword timestamp, dword duration, const struct VideoFrameFormat * format) override;
    bool FullIntraRequest() override;
    void PacketLostIndication() override;
    void RtpNackMessage(void* ctx) override;
    void KeyFrameSequences(void* ctx) override;
    enum VideoCoder GetVideoCoder() override { return vp9 ? VideoCoder::VP9 : VideoCoder::VP8; };
    void Close() override;

    void TimerOnTimeout(VideoEncoderKeyFrameTimer * timer);
    void TimerOnTimeout(VideoEncoderQualityTimer * timer);
};
