/* General-purpose video encoding "glue library". */

#ifndef _ENCODE_H_
#define _ENCODE_H_

typedef enum _encoder_type {
    ENCTYPE_AUTO = 0,       /* auto-detect by file name */
    ENCTYPE_RAW_YUV,        /* raw YUV 4:2:0 */
    ENCTYPE_YUV4MPEG,       /* raw YUV 4:2:0 with YUV4MPEG2 headers */
    ENCTYPE_X264,           /* MPEG-4 AVC (H.264) via libx264 */
    ENCTYPE_XVID,           /* MPEG-4 ASP via xvid_encore */
    ENCTYPE_FFMPEG_MPEG2,   /* MPEG-2 via FFmpeg's libavcodec */
    ENCTYPE_FFMPEG_MPEG4,   /* MPEG-4 ASP via FFmpeg's libavcodec */
    ENCTYPE_DUMMY           /* dummy encoder (discards frames) */
} encoder_type_t;

/* rate control mode flags */
#define ENC_BITRATE      (1 <<  0)  /* 0: quality specifies a quantizer value,
                                     * 1: quality specifies a bitrate (in kbps) */
#define ENC_FIXED_TARGET (1 <<  1)  /* 0: deviations of the target quality allowed,
                                     * 1: target quality must be kept */

/* color and frame rate flags */
#define ENC_SAR           0         /* 0: aspect specifies a sample aspect ratio, */
#define ENC_DAR          (1 <<  2)  /* 1: aspect specified a display aspect ratio */
#define ENC_BT709        (1 <<  3)  /* 0: use BT.470 (SD) color space,
                                     * 1: use BT.709 (HD) color space */
#define ENC_INTERLACE    (1 <<  4)  /* 0: progressive video,
                                     * 1: interlaced video */

/* encoding quality flags */
#define ENC_RD           (1 <<  5)  /* 1: enable RD-optimal encoding */
#define ENC_TRELLIS      (1 <<  6)  /* 1: enable trellis-searched RD optimization */
#define ENC_PSYCHO       (1 <<  7)  /* 1: enable psycho-visual optimizations */
#define ENC_HQ_ME        (1 <<  8)  /* 1: enable high-quality motion estimation */
#define ENC_CHROMA_ME    (1 <<  9)  /* 1: enable chroma motion estimation */
#define ENC_MV0          (1 << 10)  /* 1: always try MV (0,0) */

/* MPEG-4 ASP specific flags */
#define ENC_4MV          (1 << 11)  /* 1: enable 4 MVs per macroblock */
#define ENC_QPEL         (1 << 12)  /* 1: enable quarter-pel motion compensation */
#define ENC_MPEG_QUANT   (1 << 13)  /* 1: enable MPEG-style quantizers */
#define ENC_GMC          (1 << 14)  /* 1: enable global motion compensation */

/* H.264 specific flags */
#define ENC_CABAC        (1 << 15)  /* 1: enable CABAC, 0: use CAVLC */
#define ENC_B_PYRAMID    (1 << 16)  /* 1: enable reference B frames */
#define ENC_NO_DEBLOCK   (1 << 17)  /* 1: disable in-loop deblocking filter */
#define ENC_8X8          (1 << 18)  /* 1: enable 8x8 transform (High Profile) */
#define ENC_WEIGHTED     (1 << 19)  /* 1: enable weighted prediction */
#define ENC_MIXED_REFS   (1 << 20)  /* 1: enable mixed references per partition */
#define ENC_MAIN         (1 << 21)  /* 1: enforce Main Profile */
#define ENC_BASELINE     (1 << 22)  /* 1: enforce Baseline Profile */

#define ENC_VERBOSE      (1 << 31)  /* 1: do some debugging printf()s */

/* some short-hands for the rate control modes */
#define ENC_CBR  (ENC_BITRATE | ENC_FIXED_TARGET)  /* constant bitrate */
#define ENC_ABR  (ENC_BITRATE)                     /* average bitrate */
#define ENC_QUANTIZER   (0)                        /* average target quantizer (= x264 --crf) */
#define ENC_FIXED_QUANT (ENC_FIXED_TARGET)         /* fixed quantizer */

/* encoding setting presets */
#define ENC_OPTIMAL_SPEED 0
#define ENC_OPTIMAL_QUALITY \
        ( ENC_RD | ENC_TRELLIS | ENC_PSYCHO | ENC_HQ_ME | ENC_CHROMA_ME | ENC_MV0 \
        | ENC_4MV | ENC_QPEL \
        | ENC_CABAC | ENC_B_PYRAMID | ENC_8X8 | ENC_WEIGHTED | ENC_MIXED_REFS )

/* frame flags */
#define ENC_FRAME_KEYFRAME    (1 <<  0)  /* 1: force encoding of an I frame */
#define ENC_FRAME_PROGRESSIVE (1 <<  1)  /* 1: encode as progressive frame */
#define ENC_FRAME_BFF         (1 <<  2)  /* 1: bottom field first, */
#define ENC_FRAME_TFF          0         /* 0: top field first */
#define ENC_FRAME_RFF         (1 <<  3)  /* 1: repeat first field */

typedef enum _encode_init_result {
    ENC_INIT_OK = 0,    /* no error */
    ENC_INIT_NO_ENC,    /* encoder type unavailable */
    ENC_INIT_NO_ARG,    /* required argument missing */
    ENC_INIT_ERR_MEM,   /* out of memory */
    ENC_INIT_ERR_IO,    /* could not create output file */
    ENC_INIT_ERR_CFG,   /* invalid parameter in configuration */
    ENC_INIT_ERR_LIB    /* unspecified error reported from encoder library */
} encode_init_result_t;

typedef struct _encoder_config {
    const char *filename;        /* output filename */
    encoder_type_t encoder_type; /* type of encoder to use */
    int width, height;           /* frame dimensions */
    int flags;                   /* encoding flags */
    /* note: the following fields can be filled in automatically by
     *       encode_get_config() */
    int quality;                 /* quantizer or bitrate in kbps (see the rate control mode flags) */
    int keyint;                  /* key frame interval */
    int bframes;                 /* number of B frames between I/P frames;
                                  * special case: -1 means no B frames */
    int refs;                    /* number of reference frames (H.264 only) */
    int fps_num, fps_den;        /* frames per second */
    int aspect_num, aspect_den;  /* aspect ratio (PAR or DAR -- see ENC_PAR/ENC_DAR) */
} encoder_config_t;

typedef struct _encoder_plane {
    unsigned char *pixels;
    int stride;
} encoder_plane_t;

typedef struct _encoder_frame {
    encoder_plane_t y, cb, cr;
    int flags;
} encoder_frame_t;

typedef void* encoder_handle_t;

extern encoder_type_t encoder_detect_type(const char *filename);
extern int encoder_type_is_available(encoder_type_t encoder_type);
extern encode_init_result_t encode_init(encoder_handle_t* encoder, const encoder_config_t* cfg);
extern const encoder_config_t* encode_get_config(encoder_handle_t encoder);
extern void encode_frame(encoder_handle_t encoder, encoder_frame_t* frame);
extern int encode_get_bitrate(encoder_handle_t encoder);
extern int encode_done(encoder_handle_t encoder);

#endif//_ENCODE_H_
