blob: 17b1bd1c544d0b02636af5d8ba958f31849580de [file] [log] [blame]
#define LIBVA_UTILS_UPLOAD_DOWNLOAD_YUV_SURFACE 1
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <assert.h>
#include <pthread.h>
#include <errno.h>
#include <math.h>
#include <va/va.h>
#include "va_display.h"
#define ALIGN16(x) ((x+15)&~15)
#define CHECK_VASTATUS(va_status,func) \
if (va_status != VA_STATUS_SUCCESS) { \
fprintf(stderr,"%s:%s (%d) failed,exit\n", __func__, func, __LINE__); \
exit(1); \
}
#define MIN(a, b) ((a)>(b)?(b):(a))
#define MAX(a, b) ((a)>(b)?(a):(b))
#define CHECK_NULL(p) \
if(!(p)) \
{ \
fprintf(stderr, "Null pointer at:%s:%d\n", __func__, __LINE__); \
exit(1); \
}
#define CHECK_CONDITION(cod) \
if(!(cod)) \
{ \
fprintf(stderr, "Unexpected condition:%s:%d\n", __func__, __LINE__); \
exit(1); \
}
#define CHECK_BS_NULL(p) \
CHECK_NULL(p) \
CHECK_NULL(p->buffer)
#include "loadsurface.h"
/*****
*
* Bit stream management
*
*
* */
#define BITSTREAM_ALLOCATE_STEPPING 1024 // in byte
struct __bitstream {
uint8_t *buffer; // managed by u8 to avoid swap every 4byte
int bit_offset;
int max_size_in_byte;
};
typedef struct __bitstream bitstream;
static void
bitstream_start(bitstream *bs)
{
CHECK_NULL(bs);
bs->max_size_in_byte = BITSTREAM_ALLOCATE_STEPPING;
bs->buffer = calloc(bs->max_size_in_byte * sizeof(uint8_t), 1);
CHECK_NULL(bs->buffer);
bs->bit_offset = 0;
}
static void
put_ui(bitstream* bs, uint32_t val, int size_in_bits)
{
CHECK_BS_NULL(bs);
CHECK_CONDITION((size_in_bits + bs->bit_offset) <= (8 * bs->max_size_in_byte));
int remain_bits = 8 - (bs->bit_offset % 8);
// make sure val does not overflow size_in_bits
val &= (0xffffffff >> (32 - size_in_bits));
if(size_in_bits <= remain_bits)
{
bs->buffer[bs->bit_offset / 8] |= val << (remain_bits - size_in_bits);
bs->bit_offset += size_in_bits;
}
else
{
put_ui(bs, val >> (size_in_bits - remain_bits), remain_bits);
put_ui(bs, val & (~(0xffffffff << (size_in_bits - remain_bits))), size_in_bits - remain_bits);
}
}
static void
put_aligning_bits(bitstream* bs)
{
CHECK_BS_NULL(bs);
while (bs->bit_offset & 7)
put_ui(bs, 0, 1);; //trailing_zero_bit
}
static void
put_trailing_bits(bitstream* bs)
{
CHECK_BS_NULL(bs);
put_ui(bs, 1, 1); //trailing_one_bit
while (bs->bit_offset & 7)
put_ui(bs, 0, 1);; //trailing_zero_bit
}
static void
bitstream_free(bitstream* bs)
{
CHECK_BS_NULL(bs);
free(bs->buffer);
bs->bit_offset = 0;
bs->max_size_in_byte = 0;
}
static void
bitstream_cat(bitstream *bs1, bitstream *bs2)
{
CHECK_NULL(bs1);
CHECK_NULL(bs2);
CHECK_CONDITION(! (bs1->bit_offset & 7));
if(! (bs1->bit_offset & 7)) //byte aligned
{
memcpy(bs1->buffer + (bs1->bit_offset / 8), bs2->buffer, bs2->bit_offset/8);
bs1->bit_offset += bs2->bit_offset;
bitstream_free(bs2);
}
else
{
//when call this function to concat 2 bitstreams, the first bitstream should always be byte aligned
CHECK_CONDITION(0);
}
}
/******
* definition of para set structure
*
*
*
* */
#define PRIMARY_REF_BITS 3
#define PRIMARY_REF_NONE 7
#define REF_FRAMES_LOG2 3
#define NUM_REF_FRAMES (1 << REF_FRAMES_LOG2)
#define REFS_PER_FRAME 7
#define TOTAL_REFS_PER_FRAME 8
#define MAX_MODE_LF_DELTAS 2
#define MAX_MB_PLANE 3
#define CDEF_MAX_STRENGTHS 8
#define CDEF_STRENGTH_BITS 6
#define CDEF_STRENGTH_DIVISOR 4
#define AV1_MAX_NUM_TILE_COLS 64
#define AV1_MAX_NUM_TILE_ROWS 64
#define MAX_NUM_OPERATING_POINTS 32
#define SURFACE_NUM 16 /* 16 surfaces for source YUV */
enum {
SINGLE_REFERENCE = 0,
COMPOUND_REFERENCE = 1,
REFERENCE_MODE_SELECT = 2,
REFERENCE_MODES = 3,
} REFERENCE_MODE;
enum FRAME_TYPE
{
KEY_FRAME = 0,
INTER_FRAME = 1,
INTRA_ONLY_FRAME = 2,
SWITCH_FRAME = 3,
NUM_FRAME_TYPES,
};
enum INTERP_FILTER{
EIGHTTAP_REGULAR,
EIGHTTAP_SMOOTH,
EIGHTTAP_SHARP,
BILINEAR,
SWITCHABLE,
INTERP_FILTERS_ALL
};
enum AV1_OBU_TYPE
{
OBU_SEQUENCE_HEADER = 1,
OBU_TEMPORAL_DELIMITER = 2,
OBU_FRAME_HEADER = 3,
OBU_TILE_GROUP = 4,
OBU_METADATA = 5,
OBU_FRAME = 6,
OBU_REDUNDANT_FRAME_HEADER = 7,
OBU_PADDING = 15,
};
struct LoopFilterParams
{
int32_t loop_filter_level[4];
int32_t loop_filter_sharpness;
uint8_t loop_filter_delta_enabled;
uint8_t loop_filter_delta_update;
// 0 = Intra, Last, Last2, Last3, GF, BWD, ARF
int8_t loop_filter_ref_deltas[TOTAL_REFS_PER_FRAME];
// 0 = ZERO_MV, MV
int8_t loop_filter_mode_deltas[MAX_MODE_LF_DELTAS];
};
struct TileInfoAv1
{
uint32_t uniform_tile_spacing_flag;
uint32_t TileColsLog2;
uint32_t TileRowsLog2;
uint32_t TileCols;
uint32_t TileRows;
uint32_t TileWidthInSB[AV1_MAX_NUM_TILE_COLS]; // valid for 0 <= i < TileCols
uint32_t TileHeightInSB[AV1_MAX_NUM_TILE_ROWS]; // valid for 0 <= i < TileRows
uint32_t context_update_tile_id;
uint32_t TileSizeBytes;
};
struct QuantizationParams
{
uint32_t base_q_idx;
int32_t DeltaQYDc;
int32_t DeltaQUDc;
int32_t DeltaQUAc;
int32_t DeltaQVDc;
int32_t DeltaQVAc;
uint32_t using_qmatrix;
uint32_t qm_y;
uint32_t qm_u;
uint32_t qm_v;
};
struct CdefParams
{
uint32_t cdef_damping;
uint32_t cdef_bits;
uint32_t cdef_y_pri_strength[CDEF_MAX_STRENGTHS];
uint32_t cdef_y_sec_strength[CDEF_MAX_STRENGTHS];
uint32_t cdef_uv_pri_strength[CDEF_MAX_STRENGTHS];
uint32_t cdef_uv_sec_strength[CDEF_MAX_STRENGTHS];
};
enum RestorationType
{
RESTORE_NONE,
RESTORE_SWITCHABLE,
RESTORE_WIENER,
RESTORE_SGRPROJ,
RESTORE_TYPES = 4,
};
enum {
BITDEPTH_8 = 8,
BITDEPTH_10 = 10
};
enum {
INTRA_FRAME = 0,
LAST_FRAME = 1,
LAST2_FRAME = 2,
LAST3_FRAME = 3,
GOLDEN_FRAME = 4,
BWDREF_FRAME = 5,
ALTREF2_FRAME = 6,
ALTREF_FRAME = 7,
MAX_REF_FRAMES = 8
};
struct LRParams
{
enum RestorationType lr_type[MAX_MB_PLANE];
uint32_t lr_unit_shift;
uint32_t lr_uv_shift;
uint32_t lr_unit_extra_shift;
};
enum TX_MODE{
ONLY_4X4 = 0, // only 4x4 transform used
TX_MODE_LARGEST, // transform size is the largest possible for pu size
TX_MODE_SELECT, // transform specified for each block
TX_MODES,
};
struct ColorConfig
{
uint32_t BitDepth ;
uint32_t mono_chrome ;
uint32_t color_primaries ;
uint32_t transfer_characteristics ;
uint32_t matrix_coefficients ;
uint32_t color_description_present_flag;
uint32_t color_range ;
uint32_t chroma_sample_position ;
uint32_t subsampling_x ;
uint32_t subsampling_y ;
uint32_t separate_uv_delta_q ;
};
typedef struct FrameHeader
{
uint32_t show_existing_frame;
uint32_t frame_to_show_map_idx;
uint64_t frame_presentation_time;
uint32_t display_frame_id;
enum FRAME_TYPE frame_type;
uint32_t show_frame;
uint32_t showable_frame;
uint32_t error_resilient_mode;
uint32_t disable_cdf_update;
uint32_t allow_screen_content_tools;
uint32_t force_integer_mv;
uint32_t frame_size_override_flag;
uint32_t order_hint;
uint32_t primary_ref_frame;
uint8_t refresh_frame_flags;
uint32_t FrameWidth;//input
uint32_t FrameHeight;//input
uint32_t use_superres;
uint32_t SuperresDenom;
uint32_t UpscaledWidth;
uint32_t RenderWidth;
uint32_t RenderHeight;
uint32_t allow_intrabc;
int32_t ref_frame_idx[REFS_PER_FRAME];
uint32_t allow_high_precision_mv;
enum INTERP_FILTER interpolation_filter;
//uint32_t is_motion_mode_switchable;
uint32_t use_ref_frame_mvs;
uint32_t disable_frame_end_update_cdf;
uint32_t sbCols;
uint32_t sbRows;
uint32_t sbSize; //64 by default
struct TileInfoAv1 tile_info;
struct QuantizationParams quantization_params;
uint32_t delta_q_present;
uint32_t delta_q_res;
uint32_t delta_lf_present;
uint32_t delta_lf_res;
uint32_t delta_lf_multi;
uint32_t CodedLossless;
uint32_t AllLossless;
struct LoopFilterParams loop_filter_params;
struct CdefParams cdef_params;
struct LRParams lr_params;
enum TX_MODE TxMode;
uint32_t reference_select;
uint32_t skipModeAllowed;
uint32_t skipModeFrame[2];
uint32_t skip_mode_present;
uint32_t allow_warped_motion;
uint32_t reduced_tx_set;
} FH;
typedef struct SequenceHeader
{
uint32_t seq_profile ;
uint32_t still_picture ;
uint32_t reduced_still_picture_header ;
uint32_t timing_info_present_flag ;
uint32_t decoder_model_info_present_flag ;
uint32_t operating_points_cnt_minus_1 ;
uint32_t operating_point_idc[MAX_NUM_OPERATING_POINTS] ;
uint32_t seq_level_idx[MAX_NUM_OPERATING_POINTS] ;
uint32_t seq_tier[MAX_NUM_OPERATING_POINTS] ;
uint32_t decoder_model_present_for_this_op[MAX_NUM_OPERATING_POINTS] ;
uint32_t initial_display_delay_minus_1[MAX_NUM_OPERATING_POINTS] ;
uint32_t frame_width_bits ; //15 as default value
uint32_t frame_height_bits ; //15 as default value
uint32_t frame_id_numbers_present_flag ; // default 0
uint32_t sbSize ; //default 64
uint32_t enable_filter_intra ;
uint32_t enable_intra_edge_filter ;
uint32_t enable_interintra_compound ;
uint32_t enable_masked_compound ;
uint32_t enable_warped_motion ;
uint32_t enable_dual_filter ;
uint32_t enable_order_hint ;//default set to 1
uint32_t enable_jnt_comp ;
uint32_t enable_ref_frame_mvs ;
uint32_t seq_force_screen_content_tools ;
uint32_t seq_force_integer_mv ;
uint32_t order_hint_bits_minus1 ; //default 8 - 1
uint32_t enable_superres ;
uint32_t enable_cdef ;
uint32_t enable_restoration ;
struct ColorConfig color_config; //default
uint32_t film_grain_param_present ;
uint32_t frame_rate_extN;
uint32_t frame_rate_extD;
} SH;
struct ObuExtensionHeader {
uint32_t temporal_id;
uint32_t spatial_id;
};
struct BitOffsets
{
uint32_t QIndexBitOffset;
uint32_t SegmentationBitOffset;
uint32_t SegmentationBitSize;
uint32_t LoopFilterParamsBitOffset;
uint32_t FrameHdrOBUSizeInBits;
uint32_t FrameHdrOBUSizeByteOffset;
uint32_t UncompressedHeaderByteOffset;
uint32_t CDEFParamsBitOffset;
uint32_t CDEFParamsSizeInBits;
};
struct Av1InputParameters
{
char* srcyuv;
char* recyuv;
char* output;
uint32_t profile;
uint32_t order_hint_bits;
uint32_t enable_cdef;
uint32_t width;
uint32_t height;
uint32_t LDB;
uint32_t frame_rate_extN;
uint32_t frame_rate_extD;
uint32_t level;
// for brc
uint32_t bit_rate;
uint8_t MinBaseQIndex;
uint8_t MaxBaseQIndex;
uint32_t intra_period;
uint32_t ip_period;
uint32_t RateControlMethod;
uint32_t BRefType;
int encode_syncmode;
int calc_psnr;
int frame_count;
int frame_width_aligned;
int frame_height_aligned;
uint32_t base_qindex;
int bit_depth;
int target_bitrate;
int max_bitrate;
int buffer_size;
int initial_buffer_fullness;
};
static VADisplay va_dpy;
static VAProfile av1_profile;
static VAEntrypoint entryPoint;
static VAConfigAttrib attrib[VAConfigAttribTypeMax];
static VAConfigAttrib config_attrib[VAConfigAttribTypeMax];
static int config_attrib_num = 0;
static VASurfaceID src_surface[SURFACE_NUM];
static VABufferID coded_buf[SURFACE_NUM];
static VASurfaceID ref_surface[SURFACE_NUM];
static VAConfigID config_id;
static VAContextID context_id;
// buffer
static VAEncSequenceParameterBufferAV1 seq_param;
static VAEncPictureParameterBufferAV1 pic_param;
static VAEncTileGroupBufferAV1 tile_group_param;
// sh fh ips
static struct Av1InputParameters ips;
static FH fh;
static SH sh;
struct BitOffsets offsets;
static unsigned long long current_frame_encoding = 0;
static unsigned long long current_frame_display = 0;
static int current_frame_type;
#define current_slot (current_frame_display % SURFACE_NUM)
/* thread to save coded data/upload source YUV */
struct storage_task_t {
void *next;
unsigned long long display_order;
unsigned long long encode_order;
};
static struct storage_task_t *storage_task_header = NULL, *storage_task_tail = NULL;
#define SRC_SURFACE_IN_ENCODING 0
#define SRC_SURFACE_IN_STORAGE 1
static int srcsurface_status[SURFACE_NUM];
//static int encode_syncmode = 0; moved to input pars
static pthread_mutex_t encode_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t encode_cond = PTHREAD_COND_INITIALIZER;
static pthread_t encode_thread;
static char *coded_fn = NULL;
static FILE *coded_fp = NULL, *srcyuv_fp = NULL, *recyuv_fp = NULL;
static unsigned long long srcyuv_frames = 0;
static int srcyuv_fourcc = VA_FOURCC_IYUV;
static uint64_t frame_size = 0;
/* for performance profiling */
static unsigned int UploadPictureTicks = 0;
static unsigned int BeginPictureTicks = 0;
static unsigned int RenderPictureTicks = 0;
static unsigned int EndPictureTicks = 0;
static unsigned int SyncPictureTicks = 0;
static unsigned int SavePictureTicks = 0;
static unsigned int TotalTicks = 0;
static unsigned int frame_coded = 0;
static int rc_default_modes[] = {
VA_RC_VBR,
VA_RC_CQP,
VA_RC_VBR_CONSTRAINED,
VA_RC_CBR,
VA_RC_VCM,
VA_RC_NONE,
};
static int len_ivf_header;
static int len_seq_header;
static int len_pic_header;
/*
* Helper function for profiling purposes
*/
static unsigned int GetTickCount()
{
struct timeval tv;
if (gettimeofday(&tv, NULL))
return 0;
return tv.tv_usec / 1000 + tv.tv_sec * 1000;
}
static char *fourcc_to_string(int fourcc)
{
switch (fourcc) {
case VA_FOURCC_NV12:
return "NV12";
case VA_FOURCC_IYUV:
return "IYUV";
case VA_FOURCC_YV12:
return "YV12";
case VA_FOURCC_UYVY:
return "UYVY";
default:
return "Unknown";
}
}
static int string_to_fourcc(char *str)
{
CHECK_NULL(str);
int fourcc;
if (!strncmp(str, "NV12", 4))
fourcc = VA_FOURCC_NV12;
else if (!strncmp(str, "IYUV", 4))
fourcc = VA_FOURCC_IYUV;
else if (!strncmp(str, "YV12", 4))
fourcc = VA_FOURCC_YV12;
else if (!strncmp(str, "UYVY", 4))
fourcc = VA_FOURCC_UYVY;
else {
printf("Unknow FOURCC\n");
fourcc = -1;
}
return fourcc;
}
static int string_to_rc(char *str)
{
CHECK_NULL(str);
int rc_mode;
if (!strncmp(str, "NONE", 4))
rc_mode = VA_RC_NONE;
else if (!strncmp(str, "CBR", 3))
rc_mode = VA_RC_CBR;
else if (!strncmp(str, "VBR", 3))
rc_mode = VA_RC_VBR;
else if (!strncmp(str, "VCM", 3))
rc_mode = VA_RC_VCM;
else if (!strncmp(str, "CQP", 3))
rc_mode = VA_RC_CQP;
else if (!strncmp(str, "VBR_CONSTRAINED", 15))
rc_mode = VA_RC_VBR_CONSTRAINED;
else {
printf("Unknown RC mode\n");
rc_mode = -1;
}
return rc_mode;
}
static void print_help()
{
//./av1encode -n 8 -f 30 --intra_period 4 --ip_period 1 --rcmode CQP --srcyuv ./input.yuv --recyuv ./rec.yuv --fourcc IYUV --level 8 --height 1080 --width 1920 --base_q_idx 128 -o ./out.av1 -t 3360000 -u 210 -d 420 --LDB
printf("./av1encode <options>\n");
printf(" -n <frames> -f <frame rate> -o <output>\n");
printf(" --intra_period <number>\n");
printf(" --ip_period <number>\n");
printf(" --rcmode <16 for CQP>\n");
printf(" --srcyuv <filename> load YUV from a file\n");
printf(" --fourcc <NV12|IYUV|YV12> source YUV fourcc\n");
printf(" --recyuv <filename> save reconstructed YUV into a file\n");
printf(" --enablePSNR calculate PSNR of recyuv vs. srcyuv\n");
printf(" --level\n");
printf(" --height <number>\n");
printf(" --width <number>\n");
printf(" --base_q_idx <number> 1-255\n");
printf(" sample usage");
printf("./av1encode -n 8 -f 30 --intra_period 4 --ip_period 1 --rcmode CQP --srcyuv ./input.yuv --recyuv ./rec.yuv --fourcc IYUV --level 8 --height 1080 --width 1920 --base_q_idx 128 -o ./out.av1 -t 3360000 -u 210 -d 420 --LDB");
}
static void process_cmdline(int argc, char *argv[])
{
int c;
const struct option long_opts[] = {
{"help", no_argument, NULL, 0 },
{"intra_period", required_argument, NULL, 1 },
{"ip_period", required_argument, NULL, 2 },
{"rcmode", required_argument, NULL, 3 },
{"srcyuv", required_argument, NULL, 4 },
{"recyuv", required_argument, NULL, 5 },
{"fourcc", required_argument, NULL, 6 },
{"syncmode", no_argument, NULL, 7 },
{"enablePSNR", no_argument, NULL, 8 },
{"level", required_argument, NULL, 9 },
{"height", required_argument, NULL, 10 },
{"width", required_argument, NULL, 11 },
{"base_q_idx", required_argument, NULL, 12},
{"LDB", no_argument, NULL, 13},
{NULL, no_argument, NULL, 0 }
};
int long_index;
while ((c = getopt_long_only(argc, argv, "n:f:o:t:m:u:d:?", long_opts, &long_index)) != EOF)
{
switch (c)
{
case 'n':
ips.frame_count = atoi(optarg);
break;
case 'f':
ips.frame_rate_extN = (int)(atoi(optarg) * 100);
ips.frame_rate_extD = 100;
break;
case 'o':
ips.output = strdup(optarg);
break;
case 1:
ips.intra_period = atoi(optarg);
break;
case 2:
ips.ip_period = atoi(optarg);
break;
case 3:
ips.RateControlMethod = string_to_rc(optarg); //16:cqp 2:CBR 4:VBR
break;
case 4:
ips.srcyuv = strdup(optarg);
break;
case 5:
ips.recyuv = strdup(optarg);
break;
case 6:
srcyuv_fourcc = string_to_fourcc(optarg);
break;
case 7:
ips.encode_syncmode = 1;
break;
case 8:
ips.calc_psnr = 1;
break;
case 9:
ips.level = atoi(optarg);
break;
case 10:
ips.height = atoi(optarg);
ips.frame_height_aligned = (ips.height + 63) & (~63);
break;
case 11:
ips.width = atoi(optarg);
ips.frame_width_aligned = (ips.width + 63) & (~63);
break;
case 12:
ips.base_qindex = atoi(optarg);
break;
case 13:
ips.LDB = 1;
break;
case 't':
ips.target_bitrate = atoi(optarg);
break;
case 'm':
ips.max_bitrate = atoi(optarg);
break;
case 'u':
ips.buffer_size = atoi(optarg) * 8000;
break;
case 'd':
ips.initial_buffer_fullness = atoi(optarg) * 8000;
break;
case 0:
case ':':
case '?':
print_help();
exit(0);
}
}
// init other input parameters as default value
ips.MaxBaseQIndex = 255;
ips.MinBaseQIndex = 1;
ips.bit_depth = 8;
if(ips.RateControlMethod == VA_RC_CBR) ips.max_bitrate = ips.target_bitrate; //set max = target in CBR case
if(ips.RateControlMethod == VA_RC_VBR) //VBR
{
if(ips.max_bitrate == 0)
{
printf("max bitrate is not provided in VBR mode\n");
exit(0);
}
}
// interface with IO
/* open source file */
if (ips.srcyuv) {
srcyuv_fp = fopen(ips.srcyuv, "r");
if (srcyuv_fp == NULL)
printf("Open source YUV file %s failed, use auto-generated YUV data\n", ips.srcyuv);
else {
struct stat tmp;
fstat(fileno(srcyuv_fp), &tmp);
srcyuv_frames = tmp.st_size / (ips.width * ips.height * 1.5);
printf("Source YUV file %s with %llu frames\n", ips.srcyuv, srcyuv_frames);
if (ips.frame_count == 0)
ips.frame_count = srcyuv_frames;
}
}
/* open source file */
if (ips.recyuv) {
recyuv_fp = fopen(ips.recyuv, "w+");
if (recyuv_fp == NULL)
printf("Open reconstructed YUV file %s failed\n", ips.recyuv);
}
if (ips.output == NULL) {
struct stat buf;
if (stat("/tmp", &buf) == 0)
ips.output = strdup("/tmp/test.av1");
else if (stat("/sdcard", &buf) == 0)
ips.output = strdup("/sdcard/test.av1");
else
ips.output = strdup("./test.av1");
}
/* store coded data into a file */
if (ips.output) {
coded_fp = fopen(ips.output, "w+");
} else {
printf("Copy file string failed");
exit(1);
}
if (coded_fp == NULL) {
printf("Open file %s failed, exit\n", ips.output);
exit(1);
}
}
static char *rc_to_string(int rcmode)
{
switch (rcmode) {
case VA_RC_NONE:
return "NONE";
case VA_RC_CBR:
return "CBR";
case VA_RC_VBR:
return "VBR";
case VA_RC_VCM:
return "VCM";
case VA_RC_CQP:
return "CQP";
case VA_RC_VBR_CONSTRAINED:
return "VBR_CONSTRAINED";
default:
return "Unknown";
}
}
static int print_input()
{
printf("frame count: %d \n", ips.frame_count);
printf("frame rate: %d \n", ips.frame_rate_extN / ips.frame_rate_extD);
printf("Intra period: %d \n", ips.intra_period);
printf("Gop ref dist: %d \n", ips.ip_period);
printf("rcmode: %s \n", rc_to_string(ips.RateControlMethod));
printf("source yuv: %s \n", ips.srcyuv);
printf("recon yuv: %s \n", ips.recyuv);
printf("output bitstream: %s \n", ips.output);
printf("level index: %d \n", ips.level);
printf("frame height: %d \n", ips.height);
printf("frame width: %d \n", ips.width);
printf("base_q_index: %d \n", ips.base_qindex);
printf("target_bitrate: %d bps\n", ips.target_bitrate);
printf("max_bitrate: %d bps\n", ips.max_bitrate);
return 0;
}
static int init_va(void)
{
va_dpy = va_open_display();
VAStatus va_status;
int major_ver, minor_ver;
va_status = vaInitialize(va_dpy, &major_ver, &minor_ver);
CHECK_VASTATUS(va_status, "vaInitialize");
av1_profile = VAProfileAV1Profile0;
entryPoint = VAEntrypointEncSliceLP;
unsigned int i;
for (i = 0; i < VAConfigAttribTypeMax; i++)
attrib[i].type = i;
va_status = vaGetConfigAttributes(va_dpy, av1_profile, entryPoint,
&attrib[0], VAConfigAttribTypeMax);
CHECK_VASTATUS(va_status, "vaGetConfigAttributes");
/* check the interested configattrib */
if ((attrib[VAConfigAttribRTFormat].value & VA_RT_FORMAT_YUV420) == 0) {
printf("Not find desired YUV420 RT format\n");
exit(1);
} else {
config_attrib[config_attrib_num].type = VAConfigAttribRTFormat;
config_attrib[config_attrib_num].value = VA_RT_FORMAT_YUV420;
config_attrib_num++;
}
if (attrib[VAConfigAttribRateControl].value != VA_ATTRIB_NOT_SUPPORTED) {
int tmp = attrib[VAConfigAttribRateControl].value;
printf("Support rate control mode (0x%x):", tmp);
if (tmp & VA_RC_NONE)
printf("NONE ");
if (tmp & VA_RC_CBR)
printf("CBR ");
if (tmp & VA_RC_VBR)
printf("VBR ");
if (tmp & VA_RC_VCM)
printf("VCM ");
if (tmp & VA_RC_CQP)
printf("CQP ");
if (tmp & VA_RC_VBR_CONSTRAINED)
printf("VBR_CONSTRAINED ");
printf("\n");
if (ips.RateControlMethod == -1 || !(ips.RateControlMethod & tmp)) {
if (ips.RateControlMethod != -1) {
printf("Warning: Don't support the specified RateControl mode: %s!!!, switch to ", rc_to_string(ips.RateControlMethod));
}
for (i = 0; i < sizeof(rc_default_modes) / sizeof(rc_default_modes[0]); i++) {
if (rc_default_modes[i] & tmp) {
ips.RateControlMethod = rc_default_modes[i];
break;
}
}
printf("RateControl mode: %s\n", rc_to_string(ips.RateControlMethod));
}
config_attrib[config_attrib_num].type = VAConfigAttribRateControl;
config_attrib[config_attrib_num].value = ips.RateControlMethod;
config_attrib_num++;
}
if (attrib[VAConfigAttribEncPackedHeaders].value != VA_ATTRIB_NOT_SUPPORTED) {
int tmp = attrib[VAConfigAttribEncPackedHeaders].value;
printf("Support VAConfigAttribEncPackedHeaders\n");
config_attrib[config_attrib_num].type = VAConfigAttribEncPackedHeaders;
config_attrib[config_attrib_num].value = VA_ENC_PACKED_HEADER_NONE;
if (tmp & VA_ENC_PACKED_HEADER_SEQUENCE) {
printf("Support packed sequence headers\n");
config_attrib[config_attrib_num].value |= VA_ENC_PACKED_HEADER_SEQUENCE;
}
if (tmp & VA_ENC_PACKED_HEADER_PICTURE) {
printf("Support packed picture headers\n");
config_attrib[config_attrib_num].value |= VA_ENC_PACKED_HEADER_PICTURE;
}
if (tmp & VA_ENC_PACKED_HEADER_SLICE) {
printf("Support packed slice headers\n");
config_attrib[config_attrib_num].value |= VA_ENC_PACKED_HEADER_SLICE;
}
if (tmp & VA_ENC_PACKED_HEADER_MISC) {
printf("Support packed misc headers\n");
config_attrib[config_attrib_num].value |= VA_ENC_PACKED_HEADER_MISC;
}
config_attrib_num++;
}
if (attrib[VAConfigAttribEncInterlaced].value != VA_ATTRIB_NOT_SUPPORTED) {
int tmp = attrib[VAConfigAttribEncInterlaced].value;
printf("Support VAConfigAttribEncInterlaced\n");
if (tmp & VA_ENC_INTERLACED_FRAME)
printf("support VA_ENC_INTERLACED_FRAME\n");
if (tmp & VA_ENC_INTERLACED_FIELD)
printf("Support VA_ENC_INTERLACED_FIELD\n");
if (tmp & VA_ENC_INTERLACED_MBAFF)
printf("Support VA_ENC_INTERLACED_MBAFF\n");
if (tmp & VA_ENC_INTERLACED_PAFF)
printf("Support VA_ENC_INTERLACED_PAFF\n");
config_attrib[config_attrib_num].type = VAConfigAttribEncInterlaced;
config_attrib[config_attrib_num].value = VA_ENC_PACKED_HEADER_NONE;
config_attrib_num++;
}
return 0;
}
static int setup_encode()
{
VAStatus va_status;
VASurfaceID *tmp_surfaceid;
int codedbuf_size, i;
va_status = vaCreateConfig(va_dpy, av1_profile, entryPoint,
&config_attrib[0], config_attrib_num, &config_id);
CHECK_VASTATUS(va_status, "vaCreateConfig");
/* create source surfaces */
va_status = vaCreateSurfaces(va_dpy,
VA_RT_FORMAT_YUV420, ips.frame_width_aligned, ips.frame_height_aligned,
&src_surface[0], SURFACE_NUM,
NULL, 0);
CHECK_VASTATUS(va_status, "vaCreateSurfaces");
/* create reference surfaces */
va_status = vaCreateSurfaces(
va_dpy,
VA_RT_FORMAT_YUV420, ips.frame_width_aligned, ips.frame_height_aligned,
&ref_surface[0], SURFACE_NUM,
NULL, 0
);
CHECK_VASTATUS(va_status, "vaCreateSurfaces");
tmp_surfaceid = calloc(2 * SURFACE_NUM, sizeof(VASurfaceID));
if (tmp_surfaceid) {
memcpy(tmp_surfaceid, src_surface, SURFACE_NUM * sizeof(VASurfaceID));
memcpy(tmp_surfaceid + SURFACE_NUM, ref_surface, SURFACE_NUM * sizeof(VASurfaceID));
}
/* Create a context for this encode pipe */
va_status = vaCreateContext(va_dpy, config_id,
ips.frame_width_aligned, ips.frame_height_aligned,
VA_PROGRESSIVE,
tmp_surfaceid, 2 * SURFACE_NUM,
&context_id);
CHECK_VASTATUS(va_status, "vaCreateContext");
free(tmp_surfaceid);
codedbuf_size = ((long long int) ips.frame_width_aligned * ips.frame_height_aligned * 400) / (16 * 16);
for (i = 0; i < SURFACE_NUM; i++) {
/* create coded buffer once for all
* other VA buffers which won't be used again after vaRenderPicture.
* so APP can always vaCreateBuffer for every frame
* but coded buffer need to be mapped and accessed after vaRenderPicture/vaEndPicture
* so VA won't maintain the coded buffer
*/
va_status = vaCreateBuffer(va_dpy, context_id, VAEncCodedBufferType,
codedbuf_size, 1, NULL, &coded_buf[i]);
CHECK_VASTATUS(va_status, "vaCreateBuffer");
}
return 0;
}
static int release_encode()
{
int i;
vaDestroySurfaces(va_dpy, &src_surface[0], SURFACE_NUM);
vaDestroySurfaces(va_dpy, &ref_surface[0], SURFACE_NUM);
for (i = 0; i < SURFACE_NUM; i++)
vaDestroyBuffer(va_dpy, coded_buf[i]);
vaDestroyContext(va_dpy, context_id);
vaDestroyConfig(va_dpy, config_id);
return 0;
}
static int deinit_va()
{
vaTerminate(va_dpy);
va_close_display(va_dpy);
return 0;
}
/*
* Return displaying order with specified periods and encoding order
* displaying_order: displaying order
* frame_type: frame type
*/
void encoding2display_order(
unsigned long long encoding_order, int intra_period,
unsigned long long *displaying_order,
int *frame_type)
{
// simple case for IPPP av1
*displaying_order = encoding_order;
// all KEY FRAME *frame_type = KEY_FRAME;
*frame_type = (encoding_order % intra_period) ? INTER_FRAME : KEY_FRAME;
return;
}
static void
fill_sps_header()
{
memset(&sh, 0, sizeof(sh));
sh.seq_level_idx[0] = ips.level;
sh.frame_width_bits = 15;
sh.frame_height_bits = 15;
sh.sbSize = 64;
sh.order_hint_bits_minus1 = 8 - 1;
sh.enable_cdef = 1;
sh.enable_order_hint = 1;
sh.color_config.separate_uv_delta_q = 1;
}
static void
fill_pps_header(uint64_t displaying_order)
{
fh.show_existing_frame = 0;
fh.frame_to_show_map_idx = 0;
fh.frame_presentation_time = 0;
fh.display_frame_id = 0;
fh.frame_type = current_frame_type;
fh.show_frame = 1;
fh.showable_frame = 1;
fh.error_resilient_mode = (fh.frame_type == KEY_FRAME) ? 1 : 0;
fh.disable_cdf_update = 0;
fh.allow_screen_content_tools = 0;
fh.force_integer_mv = 0;
fh.frame_size_override_flag = 0;
fh.order_hint = displaying_order; //for I/P frame
fh.primary_ref_frame = (fh.frame_type == KEY_FRAME || fh.frame_type == INTRA_ONLY_FRAME) ? PRIMARY_REF_NONE : 0;
// depends on reference frames
// by default, always refresh idx0
fh.refresh_frame_flags = (fh.frame_type == KEY_FRAME || fh.frame_type == INTRA_ONLY_FRAME) ? 0xff : 0x01;
fh.FrameWidth = ips.width;
fh.FrameHeight = ips.height;
fh.use_superres = 0;
fh.SuperresDenom = 0;
fh.UpscaledWidth = fh.FrameWidth;
fh.RenderWidth = fh.FrameWidth;
fh.RenderHeight = fh.FrameHeight;
fh.allow_intrabc = 0;
for(uint8_t i = 0; i < REFS_PER_FRAME; i++)
fh.ref_frame_idx[i] = 0;
fh.allow_high_precision_mv = 0;
fh.interpolation_filter = 0;
fh.use_ref_frame_mvs = 0;
fh.disable_frame_end_update_cdf = 0;
fh.sbCols = ((fh.FrameWidth+63)&(~63))/64;
fh.sbRows = ((fh.FrameHeight+63)&(~63))/64;
fh.sbSize = 64;
fh.tile_info.uniform_tile_spacing_flag = 1;
fh.tile_info.context_update_tile_id = 0;
fh.quantization_params.base_q_idx = ips.base_qindex;
fh.quantization_params.DeltaQYDc = 0;
fh.quantization_params.DeltaQUDc = 0;
fh.quantization_params.DeltaQUAc = 0;
fh.quantization_params.DeltaQVDc = 0;
fh.quantization_params.DeltaQVAc = 0;
fh.quantization_params.using_qmatrix = 0;
fh.quantization_params.qm_y = 15;
fh.quantization_params.qm_u = 15;
fh.quantization_params.qm_v = 15;
fh.delta_q_present = 0;
fh.delta_q_res = 0;
fh.delta_lf_present = 1;
fh.delta_lf_res = 0;
fh.delta_lf_multi = 1;
fh.CodedLossless = 0;
fh.AllLossless = 0;
fh.cdef_params.cdef_damping = 5;
fh.cdef_params.cdef_bits = 3;
fh.cdef_params.cdef_y_pri_strength[0] = 9;
fh.cdef_params.cdef_y_sec_strength[0] = 0;
fh.cdef_params.cdef_uv_pri_strength[0] = 9;
fh.cdef_params.cdef_uv_sec_strength[0] = 0;
fh.cdef_params.cdef_y_pri_strength[1] = 12;
fh.cdef_params.cdef_y_sec_strength[1] = 2;
fh.cdef_params.cdef_uv_pri_strength[1] = 12;
fh.cdef_params.cdef_uv_sec_strength[1] = 2;
fh.cdef_params.cdef_y_pri_strength[2] = 0;
fh.cdef_params.cdef_y_sec_strength[2] = 0;
fh.cdef_params.cdef_uv_pri_strength[2] = 0;
fh.cdef_params.cdef_uv_sec_strength[2] = 0;
fh.cdef_params.cdef_y_pri_strength[3] = 6;
fh.cdef_params.cdef_y_sec_strength[3] = 0;
fh.cdef_params.cdef_uv_pri_strength[3] = 6;
fh.cdef_params.cdef_uv_sec_strength[3] = 0;
fh.cdef_params.cdef_y_pri_strength[4] = 2;
fh.cdef_params.cdef_y_sec_strength[4] = 0;
fh.cdef_params.cdef_uv_pri_strength[4] = 2;
fh.cdef_params.cdef_uv_sec_strength[4] = 0;
fh.cdef_params.cdef_y_pri_strength[5] = 4;
fh.cdef_params.cdef_y_sec_strength[5] = 1;
fh.cdef_params.cdef_uv_pri_strength[5] = 4;
fh.cdef_params.cdef_uv_sec_strength[5] = 1;
fh.cdef_params.cdef_y_pri_strength[6] = 1;
fh.cdef_params.cdef_y_sec_strength[6] = 0;
fh.cdef_params.cdef_uv_pri_strength[6] = 1;
fh.cdef_params.cdef_uv_sec_strength[6] = 0;
fh.cdef_params.cdef_y_pri_strength[7] = 2;
fh.cdef_params.cdef_y_sec_strength[7] = 1;
fh.cdef_params.cdef_uv_pri_strength[7] = 2;
fh.cdef_params.cdef_uv_sec_strength[7] = 1;
fh.loop_filter_params.loop_filter_level[0] = 15;
fh.loop_filter_params.loop_filter_level[1] = 15;
fh.loop_filter_params.loop_filter_level[2] = 8;
fh.loop_filter_params.loop_filter_level[3] = 8;
fh.loop_filter_params.loop_filter_sharpness = 0;
fh.loop_filter_params.loop_filter_delta_enabled = 0;
fh.loop_filter_params.loop_filter_delta_update = 0;
fh.TxMode = TX_MODE_SELECT;
fh.reference_select = ips.LDB ? 1 : 0;
fh.skipModeAllowed = 0;
fh.skipModeFrame[0] = 0;
fh.skipModeFrame[1] = 0;
fh.allow_warped_motion = 0;
fh.reduced_tx_set = 1;
}
// brief interface with va, render bitstream
static void
va_render_packed_data(bitstream* bs)
{
CHECK_BS_NULL(bs);
VAEncPackedHeaderParameterBuffer packedheader_param_buffer;
VABufferID packed_para_bufid = VA_INVALID_ID;
VABufferID packed_data_bufid = VA_INVALID_ID;
VABufferID render_id[2] = {VA_INVALID_ID};
unsigned int length_in_bits = bs->bit_offset;
unsigned char *packedpic_buffer = bs->buffer;
VAStatus va_status;
packedheader_param_buffer.type = VAEncPackedHeaderPicture;
packedheader_param_buffer.bit_length = length_in_bits;
packedheader_param_buffer.has_emulation_bytes = 0;
va_status = vaCreateBuffer(va_dpy,
context_id,
VAEncPackedHeaderParameterBufferType,
sizeof(packedheader_param_buffer), 1, &packedheader_param_buffer,
&packed_para_bufid);
CHECK_VASTATUS(va_status, "vaCreateBuffer");
va_status = vaCreateBuffer(va_dpy,
context_id,
VAEncPackedHeaderDataBufferType,
(length_in_bits + 7) / 8, 1, packedpic_buffer,
&packed_data_bufid);
CHECK_VASTATUS(va_status, "vaCreateBuffer");
render_id[0] = packed_para_bufid;
render_id[1] = packed_data_bufid;
va_status = vaRenderPicture(va_dpy, context_id, render_id, 2);
CHECK_VASTATUS(va_status, "vaRenderPicture");
//free(packedpic_buffer); free outside this function call
if (packed_para_bufid != VA_INVALID_ID) {
vaDestroyBuffer(va_dpy, packed_para_bufid);
packed_para_bufid = VA_INVALID_ID;
}
if (packed_data_bufid != VA_INVALID_ID) {
vaDestroyBuffer(va_dpy, packed_data_bufid);
packed_data_bufid = VA_INVALID_ID;
}
}
static void
render_ivf_frame_header()
{
// write 12 empty byte to driver
// IVF frame header is filled after encoding
// first 4 byte is u32 for bit stream length
// last 8 byte is u64 for display order
bitstream bs;
bitstream_start(&bs);
for (size_t i = 0; i < 12; i++)
{
put_ui(&bs, 0x00, 8);
}
va_render_packed_data(&bs);
bitstream_free(&bs);
}
static void
render_ivf_header()
{
bitstream bs;
bitstream_start(&bs);
uint32_t ivfSeqHeader[11] = {0x46494B44, 0x00200000, 0x31305641,
(uint32_t)(fh.UpscaledWidth + (fh.FrameHeight << 16)),
ips.frame_rate_extN,// FrameRateExtN
ips.frame_rate_extD,// FrameRateExtD
ips.frame_count/*numFramesInFile*/,
0x00000000,
0,0,0 };
//
uint8_t* hdr = (uint8_t*) ivfSeqHeader;
for (size_t i = 0; i < 44; i++)
{
put_ui(&bs, hdr[i], 8);
}
va_render_packed_data(&bs);
bitstream_free(&bs);
}
static void
render_TD()
{
// OBU_TEMPORAL_DELIMITER
bitstream bs;
bitstream_start(&bs);
put_ui(&bs, 0x12, 8);
put_ui(&bs, 0x00, 8);
va_render_packed_data(&bs);
bitstream_free(&bs);
}
static void
build_sps_buffer(VAEncSequenceParameterBufferAV1* sps)
{
CHECK_NULL(sps);
sps->seq_profile = (uint8_t)sh.seq_profile;
sps->seq_level_idx = (uint8_t)(sh.seq_level_idx[0]);
sps->intra_period = ips.intra_period;
sps->ip_period = ips.ip_period;
sps->bits_per_second = ips.target_bitrate;;
sps->order_hint_bits_minus_1 = (uint8_t)(sh.order_hint_bits_minus1);
sps->seq_fields.bits.still_picture = sh.still_picture;
sps->seq_fields.bits.enable_filter_intra = sh.enable_filter_intra;
sps->seq_fields.bits.enable_intra_edge_filter = sh.enable_intra_edge_filter;
sps->seq_fields.bits.enable_interintra_compound = sh.enable_interintra_compound;
sps->seq_fields.bits.enable_masked_compound = sh.enable_masked_compound;
sps->seq_fields.bits.enable_warped_motion = sh.enable_warped_motion;
sps->seq_fields.bits.enable_dual_filter = sh.enable_dual_filter;
sps->seq_fields.bits.enable_order_hint = sh.enable_order_hint;
sps->seq_fields.bits.enable_jnt_comp = sh.enable_jnt_comp;
sps->seq_fields.bits.enable_ref_frame_mvs = sh.enable_ref_frame_mvs;
sps->seq_fields.bits.enable_superres = sh.enable_superres;
sps->seq_fields.bits.enable_cdef = sh.enable_cdef;
sps->seq_fields.bits.enable_restoration = sh.enable_restoration;
sps->seq_fields.bits.bit_depth_minus8 = ips.bit_depth - 8;
sps->seq_fields.bits.subsampling_x = 0;
sps->seq_fields.bits.subsampling_y = 0;
}
static void
render_sequence()
{
VABufferID seq_param_buf_id = VA_INVALID_ID;
VAStatus va_status;
VAEncSequenceParameterBufferAV1 sps_buffer;
memset(&sps_buffer, 0, sizeof(sps_buffer));
build_sps_buffer(&sps_buffer);
va_status = vaCreateBuffer(va_dpy, context_id, VAEncSequenceParameterBufferType,
sizeof(sps_buffer), 1, &sps_buffer, &seq_param_buf_id);
CHECK_VASTATUS(va_status, "vaCreateBuffer");;
va_status = vaRenderPicture(va_dpy, context_id, &seq_param_buf_id, 1);
CHECK_VASTATUS(va_status, "vaRenderPicture");
if (seq_param_buf_id != VA_INVALID_ID) {
vaDestroyBuffer(va_dpy, seq_param_buf_id);
seq_param_buf_id = VA_INVALID_ID;
}
}
static void
render_rc_buffer()
{
VABufferID rc_param_buf = VA_INVALID_ID;
VAStatus va_status;
VABufferID render_id = VA_INVALID_ID;
VAEncMiscParameterBuffer *misc_param;
VAEncMiscParameterRateControl *misc_rate_ctrl;
va_status = vaCreateBuffer(va_dpy, context_id,
VAEncMiscParameterBufferType,
sizeof(VAEncMiscParameterBuffer) + sizeof(VAEncMiscParameterRateControl),
1, NULL, &rc_param_buf);
CHECK_VASTATUS(va_status, "vaCreateBuffer");
vaMapBuffer(va_dpy, rc_param_buf, (void **)&misc_param);
misc_param->type = VAEncMiscParameterTypeRateControl;
misc_rate_ctrl = (VAEncMiscParameterRateControl *)misc_param->data;
memset(misc_rate_ctrl, 0, sizeof(*misc_rate_ctrl));
misc_rate_ctrl->bits_per_second = ips.max_bitrate;
misc_rate_ctrl->target_percentage = (int)(100.0 * (double)ips.target_bitrate / (double)ips.max_bitrate);
vaUnmapBuffer(va_dpy, rc_param_buf);
render_id = rc_param_buf;
va_status = vaRenderPicture(va_dpy, context_id, &render_id, 1);
CHECK_VASTATUS(va_status, "vaRenderPicture");
if (rc_param_buf != VA_INVALID_ID)
{
vaDestroyBuffer(va_dpy, rc_param_buf);
rc_param_buf = VA_INVALID_ID;
}
}
static void
render_hrd_buffer()
{
VABufferID param_buf = VA_INVALID_ID;
VAStatus va_status;
VABufferID render_id = VA_INVALID_ID;
VAEncMiscParameterBuffer *misc_param;
VAEncMiscParameterHRD *misc_hrd;
va_status = vaCreateBuffer(va_dpy, context_id,
VAEncMiscParameterBufferType,
sizeof(VAEncMiscParameterBuffer) + sizeof(VAEncMiscParameterHRD),
1, NULL, &param_buf);
CHECK_VASTATUS(va_status, "vaCreateBuffer");
vaMapBuffer(va_dpy, param_buf, (void **)&misc_param);
misc_param->type = VAEncMiscParameterTypeHRD;
misc_hrd = (VAEncMiscParameterHRD *)misc_param->data;
memset(misc_hrd, 0, sizeof(*misc_hrd));
misc_hrd->initial_buffer_fullness = ips.initial_buffer_fullness;
misc_hrd->buffer_size = ips.buffer_size;
vaUnmapBuffer(va_dpy, param_buf);
render_id = param_buf;
va_status = vaRenderPicture(va_dpy, context_id, &render_id, 1);
CHECK_VASTATUS(va_status, "vaRenderPicture");
if (param_buf != VA_INVALID_ID)
{
vaDestroyBuffer(va_dpy, param_buf);
param_buf = VA_INVALID_ID;
}
}
static void
render_fr_buffer()
{
VABufferID param_buf = VA_INVALID_ID;
VAStatus va_status;
VABufferID render_id = VA_INVALID_ID;
VAEncMiscParameterBuffer *misc_param;
VAEncMiscParameterFrameRate *misc_fr;
va_status = vaCreateBuffer(va_dpy, context_id,
VAEncMiscParameterBufferType,
sizeof(VAEncMiscParameterBuffer) + sizeof(VAEncMiscParameterFrameRate),
1, NULL, &param_buf);
CHECK_VASTATUS(va_status, "vaCreateBuffer");
vaMapBuffer(va_dpy, param_buf, (void **)&misc_param);
misc_param->type = VAEncMiscParameterTypeFrameRate;
misc_fr = (VAEncMiscParameterFrameRate *)misc_param->data;
memset(misc_fr, 0, sizeof(*misc_fr));
misc_fr->framerate = ips.frame_rate_extN | (ips.frame_rate_extD << 16);
vaUnmapBuffer(va_dpy, param_buf);
render_id = param_buf;
va_status = vaRenderPicture(va_dpy, context_id, &render_id, 1);
CHECK_VASTATUS(va_status, "vaRenderPicture");
if (param_buf != VA_INVALID_ID)
{
vaDestroyBuffer(va_dpy, param_buf);
param_buf = VA_INVALID_ID;
}
}
static void
render_misc_buffer()
{
render_rc_buffer();
render_hrd_buffer();
render_fr_buffer();
}
static void
render_tile_group()
{
VABufferID tile_param_buf_id = VA_INVALID_ID;
VAStatus va_status;
VAEncTileGroupBufferAV1 tile_group_buffer = {0}; //default setting
va_status = vaCreateBuffer(va_dpy, context_id, VAEncSliceParameterBufferType,
sizeof(tile_group_buffer), 1, &tile_group_buffer, &tile_param_buf_id);
CHECK_VASTATUS(va_status, "vaCreateBuffer");;
va_status = vaRenderPicture(va_dpy, context_id, &tile_param_buf_id, 1);
CHECK_VASTATUS(va_status, "vaRenderPicture");
if (tile_param_buf_id != VA_INVALID_ID) {
vaDestroyBuffer(va_dpy, tile_param_buf_id);
tile_param_buf_id = VA_INVALID_ID;
}
}
static void
pack_obu_header(bitstream *bs, int obu_type, uint32_t obu_extension_flag)
{
put_ui(bs, 0, 1); //obu_forbidden_bit
put_ui(bs, obu_type, 4); //type
put_ui(bs, obu_extension_flag, 1);
put_ui(bs, 1, 1); //obu_has_size_field
put_ui(bs, 0, 1); //reserved
if (obu_extension_flag) {
// Obu Extension Header
// not written to bitstream by default
}
}
static void
pack_obu_header_size(bitstream *bs,
uint32_t value,
uint8_t fixed_output_len)
{
// pack leb128
uint64_t leb128_buf = 0;
uint8_t leb128_size = 0;
uint8_t* buf = (uint8_t*)(&leb128_buf);
if (!fixed_output_len)
{
// general encoding
do {
buf[leb128_size] = value & 0x7fU;
if (value >>= 7)
{
buf[leb128_size] |= 0x80U;
}
leb128_size++;
} while (value);
}
else
{
// get fixed len of output, in this case, LEB128 will have fixed length
uint8_t value_byte_count = 0;
do {
buf[value_byte_count++] = value & 0x7fU;
value >>= 7;
} while (value);
for (int i = 0; i < fixed_output_len - 1; i++)
{
buf[i] |= 0x80U;
leb128_size++;
}
leb128_size++;
}
// write to bitstream
const uint8_t* ptr = (uint8_t*)(&leb128_buf);
for (uint8_t i = 0; i < leb128_size; i++)
put_ui(bs, ptr[i], 8);
}
static void
pack_operating_points(bitstream* bs)
{
put_ui(bs, sh.operating_points_cnt_minus_1, 5);
for(uint8_t i = 0;i <= sh.operating_points_cnt_minus_1;i++)
{
//put_ui(bs, sh.operating_point_idc[i], 12);
put_ui(bs, sh.operating_point_idc[i] >> 4, 8);
put_ui(bs, sh.operating_point_idc[i] & 0x9f, 4);
put_ui(bs, sh.seq_level_idx[i], 5);
if(sh.seq_level_idx[i]>7)
put_ui(bs, sh.seq_tier[i], 1);
}
}
static void
pack_frame_size_info(bitstream* bs)
{
//pack frame size info
put_ui(bs, 15, 4);//frame_width_bits_minus_1
put_ui(bs, 15, 4);//frame_height_bits_minus_1
put_ui(bs, fh.UpscaledWidth - 1, 16);//max_frame_width_minus_1
put_ui(bs, fh.FrameHeight - 1, 16);//max_frame_height_minus_1
// end of pack frame size info
}
static void
pack_seq_data(bitstream *bs)
{
put_ui(bs, sh.seq_profile, 3);
put_ui(bs, sh.still_picture, 1);
put_ui(bs, 0, 1);//reduced_still_picture_header
put_ui(bs, 0, 1);//timing_info_present_flag
put_ui(bs, 0, 1);//initial_display_delay_present_flag
pack_operating_points(bs);
pack_frame_size_info(bs);
put_ui(bs, 0, 1);//frame_id_numbers_present_flag (affects FH)
put_ui(bs, 0, 1);//use_128x128_superblock
put_ui(bs, sh.enable_filter_intra, 1);//enable_filter_intra
put_ui(bs, sh.enable_intra_edge_filter, 1);//enable_intra_edge_filter
put_ui(bs, sh.enable_interintra_compound, 1);//enable_interintra_compound
put_ui(bs, sh.enable_masked_compound, 1);//enable_masked_compound
put_ui(bs, sh.enable_warped_motion, 1);//enable_warped_motion
put_ui(bs, sh.enable_dual_filter, 1);//enable_dual_filter
put_ui(bs, sh.enable_order_hint, 1);//enable_order_hint
if (sh.enable_order_hint)
{
put_ui(bs, 0, 1); //enable_jnt_comp
put_ui(bs, fh.use_ref_frame_mvs, 1);//enable_ref_frame_mvs
}
put_ui(bs, 1, 1);//seq_choose_screen_content_tools
put_ui(bs, sh.seq_force_integer_mv, 1);//seq_choose_integer_mv
if (!sh.seq_force_integer_mv)
{
put_ui(bs, 0, 1); //seq_force_integer_mv
}
if (sh.enable_order_hint)
{
put_ui(bs, sh.order_hint_bits_minus1, 3);//affects FH
}
put_ui(bs, sh.enable_superres, 1);//enable_superres
put_ui(bs, sh.enable_cdef, 1);//enable_cdef
put_ui(bs, sh.enable_restoration, 1);//enable_restoration
// pack color config
put_ui(bs, sh.color_config.BitDepth == BITDEPTH_10 ? 1 : 0, 1);
if (sh.seq_profile != 1)
put_ui(bs, 0, 1);; //mono_chrome
put_ui(bs, sh.color_config.color_description_present_flag, 1);
if (sh.color_config.color_description_present_flag)
{
put_ui(bs, sh.color_config.color_primaries, 8);
put_ui(bs, sh.color_config.transfer_characteristics, 8);
put_ui(bs, sh.color_config.matrix_coefficients, 8);
}
put_ui(bs, sh.color_config.color_range, 1);//color_range
if (sh.seq_profile == 0)
put_ui(bs, 0, 2); //chroma_sample_position
put_ui(bs, sh.color_config.separate_uv_delta_q, 1); //separate_uv_delta_q
put_ui(bs, 0, 1);//film_grain_params_present
put_trailing_bits(bs);
}
static void
build_packed_seq_header(bitstream* bs)
{
CHECK_BS_NULL(bs);
CHECK_CONDITION(bs->bit_offset == 0);
// handle vairable length
// seq obu data
bitstream obu_data;
bitstream_start(&obu_data);
pack_seq_data(&obu_data);
uint32_t obu_extension_flag = sh.operating_points_cnt_minus_1 ? 1 : 0;
pack_obu_header(bs, OBU_SEQUENCE_HEADER, obu_extension_flag);
//calculate data size
uint32_t obu_size_in_bytes = (obu_data.bit_offset + 7) / 8;
pack_obu_header_size(bs, obu_size_in_bytes, 0);
bitstream_cat(bs, &obu_data);
}
static int
render_packedsequence()
{
int len;
bitstream bs;
bitstream_start(&bs);
build_packed_seq_header(&bs);
len = (bs.bit_offset + 7) / 8;
va_render_packed_data(&bs);
bitstream_free(&bs);
return len;
}
static void
pack_show_existing_frame(bitstream* bs)
{
return; //only for B frame, not enable by default
}
static void
pack_show_frame(bitstream* bs)
{
put_ui(bs, fh.show_frame, 1);
if(!fh.show_frame)
put_ui(bs, fh.showable_frame, 1);
}
static void
pack_error_resilient(bitstream* bs)
{
if (!(fh.frame_type == SWITCH_FRAME || (fh.frame_type == KEY_FRAME && fh.show_frame)))
put_ui(bs, 0, 1); //error_resilient_mode
}
static void
pack_ref_frame_flags(bitstream* bs, uint8_t error_resilient_mode, uint8_t isI)
{
uint8_t primary_ref_frame = PRIMARY_REF_NONE;
if(isI || error_resilient_mode)
primary_ref_frame = PRIMARY_REF_NONE;
else
put_ui(bs, 0, 3); //primary_ref_frame
if (!(fh.frame_type == SWITCH_FRAME || (fh.frame_type == KEY_FRAME && fh.show_frame)))
put_ui(bs, fh.refresh_frame_flags, NUM_REF_FRAMES);
}
static void
pack_interpolation_filter(bitstream* bs)
{
const uint8_t is_filter_switchable = (fh.interpolation_filter == 4 ? 1 : 0);
put_ui(bs, is_filter_switchable, 1);//is_filter_switchable
if (!is_filter_switchable)
{
put_ui(bs, fh.interpolation_filter, 2);//interpolation_filter
}
}
static void
pack_render_size(bitstream* bs)
{
uint32_t render_and_frame_size_different = 0;
put_ui(bs, render_and_frame_size_different, 1);//render_and_frame_size_different
if (render_and_frame_size_different == 1)
{
put_ui(bs, fh.RenderWidth - 1, 16);//render_width_minus_1
put_ui(bs, fh.RenderHeight - 1, 16);//render_height_minus_1
}
}
static void
pack_frame_size(bitstream *bs)
{
if (fh.frame_size_override_flag)
{
put_ui(bs, fh.UpscaledWidth - 1, sh.frame_width_bits + 1); //frame_width_minus_1
put_ui(bs, fh.FrameHeight - 1, sh.frame_height_bits + 1); //frame_height_minus_1
}
}
static void
pack_frame_size_with_refs(bitstream* bs)
{
CHECK_BS_NULL(bs);
uint32_t found_ref = 0;
for (int8_t ref = 0; ref < REFS_PER_FRAME; ref++)
put_ui(bs, found_ref, 1);//found_ref
// if found_ref == 9
pack_frame_size(bs);
pack_render_size(bs);
}
static void
pack_frame_ref_info(bitstream* bs, uint8_t error_resilient_mode)
{
if (sh.enable_order_hint)
put_ui(bs, 0, 1); //frame_refs_short_signaling
for (uint8_t ref = 0; ref < REFS_PER_FRAME; ref++)
put_ui(bs, fh.ref_frame_idx[ref], REF_FRAMES_LOG2);
if (fh.frame_size_override_flag && !error_resilient_mode)
{
pack_frame_size_with_refs(bs);
}
else
{
pack_frame_size(bs);
pack_render_size(bs);
}
put_ui(bs, fh.allow_high_precision_mv, 1); //allow_high_precision_mv
//PackInterpolationFilter(bs, fh);
pack_interpolation_filter(bs);
put_ui(bs, 0, 1);//is_motion_switchable
if (fh.use_ref_frame_mvs)
put_ui(bs, 1, 1); //use_ref_frame_mvs
}
static void
pack_tile_info(bitstream* bs)
{
// use single tile by default
put_ui(bs, 1, 1);//uniform_tile_spacing_flag
put_ui(bs, 0, 1);//increment_tile_cols_log2
put_ui(bs, 0, 1);//increment_tile_rows_log2
}
static uint16_t
write_SU(int32_t value, uint16_t n)
{
int16_t signMask = 1 << (n - 1);
if (value & signMask)
{
value = value - 2 * signMask;
}
return value;
}
static void
pack_delta_q_value(bitstream* bs, int32_t deltaQ)
{
if (deltaQ)
{
put_ui(bs, 1, 1);
put_ui(bs, write_SU(deltaQ, 7), 7);
}
else
put_ui(bs, 0, 1);
}
static void
pack_quantization_params(bitstream* bs)
{
put_ui(bs, fh.quantization_params.base_q_idx, 8); //base_q_idx
pack_delta_q_value(bs, fh.quantization_params.DeltaQYDc);
bool diff_uv_delta = false;
if (fh.quantization_params.DeltaQUDc != fh.quantization_params.DeltaQVDc
|| fh.quantization_params.DeltaQUAc != fh.quantization_params.DeltaQVAc)
diff_uv_delta = true;
if (sh.color_config.separate_uv_delta_q)
put_ui(bs, diff_uv_delta, 1);
pack_delta_q_value(bs, fh.quantization_params.DeltaQUDc);
pack_delta_q_value(bs, fh.quantization_params.DeltaQUAc);
if (diff_uv_delta)
{
pack_delta_q_value(bs, fh.quantization_params.DeltaQVDc);
pack_delta_q_value(bs, fh.quantization_params.DeltaQVAc);
}
put_ui(bs, fh.quantization_params.using_qmatrix, 1);//using_qmatrix
if (fh.quantization_params.using_qmatrix)
{
put_ui(bs, fh.quantization_params.qm_y, 4);
put_ui(bs, fh.quantization_params.qm_u, 4);
if (sh.color_config.separate_uv_delta_q)
put_ui(bs, fh.quantization_params.qm_v, 4);
}
}
static void
pack_loop_filter_params(bitstream* bs)
{
if (fh.CodedLossless || fh.allow_intrabc)
return;
put_ui(bs, fh.loop_filter_params.loop_filter_level[0], 6);//loop_filter_level[0]
put_ui(bs, fh.loop_filter_params.loop_filter_level[1], 6);//loop_filter_level[1]
if (fh.loop_filter_params.loop_filter_level[0] || fh.loop_filter_params.loop_filter_level[1])
{
put_ui(bs, fh.loop_filter_params.loop_filter_level[2], 6);//loop_filter_level[2]
put_ui(bs, fh.loop_filter_params.loop_filter_level[3], 6);//loop_filter_level[3]
}
put_ui(bs, fh.loop_filter_params.loop_filter_sharpness, 3); //loop_filter_sharpness
put_ui(bs, 0, 1); //loop_filter_delta_enabled
}
static void
pack_cdef_params(bitstream* bs)
{
if (!sh.enable_cdef || fh.CodedLossless || fh.allow_intrabc)
return;
uint16_t num_planes = sh.color_config.mono_chrome ? 1 : 3;
put_ui(bs, fh.cdef_params.cdef_damping - 3, 2);//cdef_damping_minus_3
put_ui(bs, fh.cdef_params.cdef_bits, 2);//cdef_bits
for (uint16_t i = 0; i < (1 << fh.cdef_params.cdef_bits); ++i)
{
put_ui(bs, fh.cdef_params.cdef_y_pri_strength[i], 4);//cdef_y_pri_strength[0]
put_ui(bs, fh.cdef_params.cdef_y_sec_strength[i], 2);//cdef_y_sec_strength[0]
if (num_planes > 1)
{
put_ui(bs, fh.cdef_params.cdef_uv_pri_strength[i], 4);//cdef_uv_pri_strength[0]
put_ui(bs, fh.cdef_params.cdef_uv_sec_strength[i], 2);//cdef_uv_sec_strength[0]
}
}
}
static void
pack_lr_params(bitstream* bs)
{
if (fh.AllLossless || fh.allow_intrabc || !sh.enable_restoration)
return;
bool usesLR = false;
bool usesChromaLR = false;
for (int i = 0; i < MAX_MB_PLANE; i++)
{
put_ui(bs, fh.lr_params.lr_type[i], 2);
if (fh.lr_params.lr_type[i] != RESTORE_NONE)
{
usesLR = true;
if (i > 0)
{
usesChromaLR = true;
}
}
}
if (usesLR)
{
put_ui(bs, fh.lr_params.lr_unit_shift, 1);
if (sh.sbSize != 1 && fh.lr_params.lr_unit_shift)
{
put_ui(bs, fh.lr_params.lr_unit_extra_shift, 1);
}
if (sh.color_config.subsampling_x && sh.color_config.subsampling_y && usesChromaLR)
{
put_ui(bs, fh.lr_params.lr_uv_shift, 1);
}
}
}
static void
pack_delta_q_params(bitstream* bs)
{
if (fh.quantization_params.base_q_idx)
put_ui(bs, fh.delta_q_present, 1); //delta_q_present
if (fh.delta_q_present)
{
put_ui(bs, 0, 2); //delta_q_res
put_ui(bs, fh.delta_lf_present, 1); //delta_lf_present
put_ui(bs, 0, 2); //delta_lf_res
put_ui(bs, fh.delta_lf_multi, 1); //delta_lf_multi
}
}
static void
pack_frame_reference_mode(bitstream* bs, bool frameIsIntra)
{
if (frameIsIntra)
return;
put_ui(bs, fh.reference_select, 1); //reference_select
}
static void
pack_skip_mode_params(bitstream* bs)
{
if (fh.skipModeAllowed)
put_ui(bs, fh.skip_mode_present, 1); //skip_mode_present
}
static void
pack_wrapped_motion(bitstream* bs, bool frameIsIntra)
{
if (frameIsIntra)
return;
if (sh.enable_warped_motion)
put_ui(bs, 0, 1); //allow_warped_motion
}
static void
pack_global_motion_params(bitstream* bs, bool frameIsIntra)
{
if (frameIsIntra)
return;
for (uint8_t i = LAST_FRAME; i <= ALTREF_FRAME; i++)
put_ui(bs, 0, 1); //is_global[7]
}
static void
pack_frame_header(bitstream* bs)
{
const uint8_t isI = (fh.frame_type == INTRA_ONLY_FRAME || fh.frame_type == KEY_FRAME);
put_ui(bs, fh.frame_type, 2);
pack_show_frame(bs);
uint8_t error_resilient_mode = 0;
pack_error_resilient(bs);
put_ui(bs, fh.disable_cdf_update, 1);
put_ui(bs, fh.allow_screen_content_tools, 1);
put_ui(bs, fh.frame_size_override_flag, 1);
// pack order hint
if(sh.enable_order_hint)
put_ui(bs, fh.order_hint, sh.order_hint_bits_minus1 + 1);
// PackRefFrameFlags
pack_ref_frame_flags(bs, error_resilient_mode, isI);
if (!isI)
{
pack_frame_ref_info(bs, error_resilient_mode);
}
else
{
pack_frame_size(bs);
pack_render_size(bs);
if (fh.allow_screen_content_tools && fh.UpscaledWidth == fh.FrameWidth)
put_ui(bs, fh.allow_intrabc, 1);
}
if (!fh.disable_cdf_update)
put_ui(bs, fh.disable_frame_end_update_cdf, 1); //disable_frame_end_update_cdf
pack_tile_info(bs);
//quantization_params
offsets.QIndexBitOffset = bs->bit_offset;
pack_quantization_params(bs);
//segmentation_params
offsets.SegmentationBitOffset = bs->bit_offset;
put_ui(bs, 0, 1); //segmentation_enabled
offsets.SegmentationBitSize = bs->bit_offset - offsets.SegmentationBitOffset;
pack_delta_q_params(bs);
offsets.LoopFilterParamsBitOffset = bs->bit_offset;
pack_loop_filter_params(bs);
offsets.CDEFParamsBitOffset = bs->bit_offset;
pack_cdef_params(bs);
offsets.CDEFParamsSizeInBits = bs->bit_offset - offsets.CDEFParamsBitOffset;
pack_lr_params(bs);
const uint8_t tx_mode_select = fh.TxMode ? 1 : 0;
if (!fh.CodedLossless)
put_ui(bs, tx_mode_select, 1); //tx_mode_select
pack_frame_reference_mode(bs, isI);
pack_skip_mode_params(bs);
pack_wrapped_motion(bs, isI);
put_ui(bs, fh.reduced_tx_set, 1); //reduced_tx_set
pack_global_motion_params(bs, isI);
}
static void
build_packed_pic_header(bitstream* bs)
{
// handle vairable length
// pack obu payload and then put header
// pic obu data
bitstream tmp;
bitstream_start(&tmp);
put_ui(&tmp, fh.show_existing_frame, 1); //show_existing_frame
if (fh.show_existing_frame)
pack_show_existing_frame(&tmp); // only for B frame
else
pack_frame_header(&tmp);
offsets.FrameHdrOBUSizeInBits = tmp.bit_offset;
const uint32_t obu_extension_flag = sh.operating_points_cnt_minus_1 ? 1 : 0;
const uint32_t obu_header_offset = bs->bit_offset;
put_aligning_bits(&tmp);
pack_obu_header(bs, OBU_FRAME, obu_extension_flag);
offsets.FrameHdrOBUSizeByteOffset = (bs->bit_offset >> 3) + len_ivf_header + 2 + len_seq_header; // first frame with IVF header
const uint32_t obu_size_in_bytes = (tmp.bit_offset + 7) / 8;
pack_obu_header_size(bs, obu_size_in_bytes, fh.show_existing_frame? 0: 4);
if (!fh.show_existing_frame)
{
// The offset is related to frame or frame header OBU. IVF, sequence, and other headers should not be counted.
const uint32_t obuPayloadOffset = bs->bit_offset - obu_header_offset;
offsets.QIndexBitOffset += obuPayloadOffset;
offsets.SegmentationBitOffset += obuPayloadOffset;
offsets.LoopFilterParamsBitOffset += obuPayloadOffset;
offsets.CDEFParamsBitOffset += obuPayloadOffset;
//offsets.CDEFParamsSizeInBits is not needed to be updated.
offsets.FrameHdrOBUSizeInBits += obuPayloadOffset;
}
bitstream_cat(bs, &tmp);
}
static void
render_packedpicture()
{
bitstream bs;
bitstream_start(&bs);
build_packed_pic_header(&bs);
va_render_packed_data(&bs);
bitstream_free(&bs);
}
static void
fill_ref_params(VAEncPictureParameterBufferAV1* pps)
{
CHECK_NULL(pps);
if(fh.frame_type == KEY_FRAME)
{
return;
}
else if(fh.frame_type == INTER_FRAME)
{
// use last frame as reference
pps->reference_frames[0] = ref_surface[((current_frame_display - 1) % SURFACE_NUM)];
pps->ref_frame_ctrl_l0.fields.search_idx0 = LAST_FRAME;
// for Low delay B
pps->ref_frame_ctrl_l1.fields.search_idx0 = ips.LDB ? BWDREF_FRAME : INTRA_FRAME;
}
}
static void
build_pps_buffer(VAEncPictureParameterBufferAV1* pps)
{
CHECK_NULL(pps);
// InitPPS
memset(&(pps->reference_frames), VA_INVALID_ID, 8);
//frame size
pps->frame_height_minus_1 =(uint16_t)(fh.FrameHeight - 1);
pps->frame_width_minus_1 = (uint16_t)(fh.UpscaledWidth - 1);
//bitstream
pps->coded_buf = coded_buf[current_slot];
for(int k = 0; k < REFS_PER_FRAME; k++)
pps->ref_frame_idx[k] = 0;
pps->picture_flags.bits.use_ref_frame_mvs = fh.use_ref_frame_mvs;
pps->picture_flags.bits.long_term_reference = 0;
pps->picture_flags.bits.allow_intrabc = fh.allow_intrabc;
pps->seg_id_block_size = 0;
//quantizer
pps->y_dc_delta_q = (uint8_t)(fh.quantization_params.DeltaQYDc);
pps->u_dc_delta_q = (uint8_t)(fh.quantization_params.DeltaQUDc);
pps->u_ac_delta_q = (uint8_t)(fh.quantization_params.DeltaQUAc);
pps->v_dc_delta_q = (uint8_t)(fh.quantization_params.DeltaQVDc);
pps->v_ac_delta_q = (uint8_t)(fh.quantization_params.DeltaQVAc);
//other params
pps->picture_flags.bits.error_resilient_mode = fh.error_resilient_mode;
pps->interpolation_filter = (uint8_t)(fh.interpolation_filter);
pps->picture_flags.bits.use_superres = fh.use_superres;
pps->picture_flags.bits.allow_high_precision_mv = fh.allow_high_precision_mv;
pps->picture_flags.bits.reduced_tx_set = fh.reduced_tx_set;
pps->picture_flags.bits.palette_mode_enable = fh.allow_screen_content_tools;
//tx_mod
pps->mode_control_flags.bits.tx_mode = fh.TxMode;
pps->temporal_id = 0;
pps->superres_scale_denominator = (uint8_t)(fh.SuperresDenom);
//q_matrix
pps->qmatrix_flags.bits.using_qmatrix = fh.quantization_params.using_qmatrix;
pps->qmatrix_flags.bits.qm_y = fh.quantization_params.qm_y;
pps->qmatrix_flags.bits.qm_u = fh.quantization_params.qm_u;
pps->qmatrix_flags.bits.qm_v = fh.quantization_params.qm_v;
pps->picture_flags.bits.frame_type = fh.frame_type;
pps->base_qindex = (uint8_t)fh.quantization_params.base_q_idx;
pps->min_base_qindex = ips.MinBaseQIndex;
pps->max_base_qindex = ips.MaxBaseQIndex;
pps->order_hint = (uint8_t)(fh.order_hint);
//reference frame
pps->primary_ref_frame = (uint8_t)(fh.primary_ref_frame);
pps->ref_frame_ctrl_l0.value = 0;
pps->ref_frame_ctrl_l1.value = 0;
fill_ref_params(pps);
pps->refresh_frame_flags = fh.refresh_frame_flags;
// //loop filter
// auto& lf = fh.loop_filter_params;
pps->filter_level[0] = (uint8_t)(fh.loop_filter_params.loop_filter_level[0]);
pps->filter_level[1] = (uint8_t)(fh.loop_filter_params.loop_filter_level[1]);
pps->filter_level_u = (uint8_t)(fh.loop_filter_params.loop_filter_level[2]);
pps->filter_level_v = (uint8_t)(fh.loop_filter_params.loop_filter_level[3]);
pps->loop_filter_flags.bits.sharpness_level = fh.loop_filter_params.loop_filter_sharpness;
pps->loop_filter_flags.bits.mode_ref_delta_enabled = fh.loop_filter_params.loop_filter_delta_enabled;
pps->loop_filter_flags.bits.mode_ref_delta_update = fh.loop_filter_params.loop_filter_delta_update;
for(int k = 0;k < 8;k++)
pps->ref_deltas[k] = 0;
//block-level deltas
pps->mode_control_flags.bits.delta_q_present = fh.delta_q_present;
pps->mode_control_flags.bits.delta_q_res = fh.delta_q_res;
pps->mode_control_flags.bits.delta_lf_res = fh.delta_lf_res;
pps->mode_control_flags.bits.delta_lf_present = fh.delta_lf_present;
pps->mode_control_flags.bits.delta_lf_multi = fh.delta_lf_multi;
pps->mode_control_flags.bits.reference_mode = fh.reference_select ?
REFERENCE_MODE_SELECT : SINGLE_REFERENCE;
pps->mode_control_flags.bits.skip_mode_present = fh.skip_mode_present;
//tile
pps->tile_cols = 1;
pps->width_in_sbs_minus_1[0] = (uint16_t)(((fh.UpscaledWidth+63)&(~63))/64 - 1);
pps->tile_rows = 1;
pps->height_in_sbs_minus_1[0] = (uint16_t)(((fh.FrameHeight+63)&(~63))/64 - 1);
pps->context_update_tile_id = (uint8_t)(fh.tile_info.context_update_tile_id);
//cdef
if(sh.enable_cdef)
{
pps->cdef_damping_minus_3 = (uint8_t)(fh.cdef_params.cdef_damping - 3);
pps->cdef_bits = (uint8_t)(fh.cdef_params.cdef_bits);
for (uint8_t i = 0; i < CDEF_MAX_STRENGTHS; i++)
{
pps->cdef_y_strengths[i] = (uint8_t)(fh.cdef_params.cdef_y_pri_strength[i] * CDEF_STRENGTH_DIVISOR + fh.cdef_params.cdef_y_sec_strength[i]);
pps->cdef_uv_strengths[i] = (uint8_t)(fh.cdef_params.cdef_uv_pri_strength[i] * CDEF_STRENGTH_DIVISOR + fh.cdef_params.cdef_uv_sec_strength[i]);
}
}
//loop restoration
pps->loop_restoration_flags.bits.yframe_restoration_type = (fh.lr_params.lr_type[0] == RESTORE_WIENER) ? 1 : 0;
pps->loop_restoration_flags.bits.cbframe_restoration_type = (fh.lr_params.lr_type[1] == RESTORE_WIENER) ? 1 : 0;
pps->loop_restoration_flags.bits.crframe_restoration_type = (fh.lr_params.lr_type[2] == RESTORE_WIENER) ? 1 : 0;
pps->loop_restoration_flags.bits.lr_unit_shift = fh.lr_params.lr_unit_shift;
pps->loop_restoration_flags.bits.lr_uv_shift = fh.lr_params.lr_uv_shift;
//context
pps->picture_flags.bits.disable_cdf_update = fh.disable_cdf_update;
pps->picture_flags.bits.disable_frame_end_update_cdf = fh.disable_frame_end_update_cdf;
pps->picture_flags.bits.disable_frame_recon = (fh.refresh_frame_flags == 0);
pps->num_tile_groups_minus1 = 0;
pps->tile_group_obu_hdr_info.bits.obu_extension_flag = 0;
pps->tile_group_obu_hdr_info.bits.obu_has_size_field = 1;
pps->tile_group_obu_hdr_info.bits.temporal_id = 0;
pps->tile_group_obu_hdr_info.bits.spatial_id = 0;
//other params
pps->picture_flags.bits.error_resilient_mode = fh.error_resilient_mode;
pps->picture_flags.bits.enable_frame_obu = 1;
pps->reconstructed_frame = ref_surface[current_slot];
//offsets need update
pps->size_in_bits_frame_hdr_obu = offsets.FrameHdrOBUSizeInBits;
pps->byte_offset_frame_hdr_obu_size = offsets.FrameHdrOBUSizeByteOffset;
pps->bit_offset_loopfilter_params = offsets.LoopFilterParamsBitOffset;
pps->bit_offset_qindex = offsets.QIndexBitOffset;
pps->bit_offset_segmentation = offsets.SegmentationBitOffset;
pps->bit_offset_cdef_params = offsets.CDEFParamsBitOffset;
pps->size_in_bits_cdef_params = offsets.CDEFParamsSizeInBits;
//q_matrix
pps->qmatrix_flags.bits.using_qmatrix = fh.quantization_params.using_qmatrix;
pps->qmatrix_flags.bits.qm_y = fh.quantization_params.qm_y;
pps->qmatrix_flags.bits.qm_u = fh.quantization_params.qm_u;
pps->qmatrix_flags.bits.qm_v = fh.quantization_params.qm_v;
pps->skip_frames_reduced_size = 0;
}
static void
render_picture()
{
VABufferID pic_param_buf_id = VA_INVALID_ID;
VAStatus va_status;
VAEncPictureParameterBufferAV1 pps_buffer;
memset(&pps_buffer, 0, sizeof(pps_buffer));
build_pps_buffer(&pps_buffer);
va_status = vaCreateBuffer(va_dpy, context_id, VAEncPictureParameterBufferType,
sizeof(pps_buffer), 1, &pps_buffer, &pic_param_buf_id);
CHECK_VASTATUS(va_status, "vaCreateBuffer");;
va_status = vaRenderPicture(va_dpy, context_id, &pic_param_buf_id, 1);
CHECK_VASTATUS(va_status, "vaRenderPicture");
if (pic_param_buf_id != VA_INVALID_ID) {
vaDestroyBuffer(va_dpy, pic_param_buf_id);
pic_param_buf_id = VA_INVALID_ID;
}
}
static int upload_source_YUV_once_for_all()
{
int box_width = 8;
int row_shift = 0;
int i;
for (i = 0; i < SURFACE_NUM; i++) {
printf("\rLoading data into surface %d.....", i);
upload_surface(va_dpy, src_surface[i], box_width, row_shift, 0);
row_shift++;
if (row_shift == (2 * box_width)) row_shift = 0;
}
printf("Complete surface loading\n");
return 0;
}
static struct storage_task_t * storage_task_dequeue(void)
{
struct storage_task_t *header;
pthread_mutex_lock(&encode_mutex);
header = storage_task_header;
if (storage_task_header != NULL) {
if (storage_task_tail == storage_task_header)
storage_task_tail = NULL;
storage_task_header = header->next;
}
pthread_mutex_unlock(&encode_mutex);
return header;
}
static int load_surface(VASurfaceID surface_id, unsigned long long display_order)
{
unsigned char *srcyuv_ptr = NULL, *src_Y = NULL, *src_U = NULL, *src_V = NULL;
unsigned long long frame_start, mmap_start;
char *mmap_ptr = NULL;
int frame_size, mmap_size;
if (srcyuv_fp == NULL)
return 0;
/* allow encoding more than srcyuv_frames */
display_order = display_order % srcyuv_frames;
frame_size = ips.width * ips.height * 3 / 2; /* for YUV420 */
frame_start = display_order * frame_size;
mmap_start = frame_start & (~0xfff);
mmap_size = (frame_size + (frame_start & 0xfff) + 0xfff) & (~0xfff);
mmap_ptr = mmap(0, mmap_size, PROT_READ, MAP_SHARED,
fileno(srcyuv_fp), mmap_start);
if (mmap_ptr == MAP_FAILED) {
printf("Failed to mmap YUV file (%s)\n", strerror(errno));
return 1;
}
srcyuv_ptr = (unsigned char *)mmap_ptr + (frame_start & 0xfff);
if (srcyuv_fourcc == VA_FOURCC_NV12) {
src_Y = srcyuv_ptr;
src_U = src_Y + ips.width * ips.height;
src_V = NULL;
} else if (srcyuv_fourcc == VA_FOURCC_IYUV ||
srcyuv_fourcc == VA_FOURCC_YV12) {
src_Y = srcyuv_ptr;
if (srcyuv_fourcc == VA_FOURCC_IYUV) {
src_U = src_Y + ips.width * ips.height;
src_V = src_U + (ips.width / 2) * (ips.height / 2);
} else { /* YV12 */
src_V = src_Y + ips.width * ips.height;
src_U = src_V + (ips.width / 2) * (ips.height / 2);
}
} else {
printf("Unsupported source YUV format\n");
exit(1);
}
upload_surface_yuv(va_dpy, surface_id,
srcyuv_fourcc, ips.width, ips.height,
src_Y, src_U, src_V);
if (mmap_ptr)
munmap(mmap_ptr, mmap_size);
return 0;
}
static int save_codeddata(unsigned long long display_order, unsigned long long encode_order)
{
VACodedBufferSegment *buf_list = NULL;
VAStatus va_status;
unsigned int coded_size = 0;
va_status = vaMapBuffer(va_dpy, coded_buf[display_order % SURFACE_NUM], (void **)(&buf_list));
CHECK_VASTATUS(va_status, "vaMapBuffer");
long frame_start = ftell(coded_fp);
while (buf_list != NULL) {
coded_size += fwrite(buf_list->buf, 1, buf_list->size, coded_fp);
buf_list = (VACodedBufferSegment *) buf_list->next;
frame_size += coded_size;
}
long frame_end = ftell(coded_fp);
vaUnmapBuffer(va_dpy, coded_buf[display_order % SURFACE_NUM]);
if(encode_order == 0)
{
//first frame
unsigned int ivf_size = coded_size - 32 - 12;
fseek(coded_fp, frame_start + 32, SEEK_SET);
fwrite(&ivf_size, 4, 1, coded_fp);
fwrite(&display_order, 8, 1, coded_fp);
fseek(coded_fp, frame_end, SEEK_SET);
}
else
{
//other frames
unsigned int ivf_size = coded_size - 12;
fseek(coded_fp, frame_start, SEEK_SET);
fwrite(&ivf_size, 4, 1, coded_fp);
fwrite(&display_order, 8, 1, coded_fp);
fseek(coded_fp, frame_end, SEEK_SET);
}
printf("\n "); /* return back to startpoint */
switch (encode_order % 4) {
case 0:
printf("|");
break;
case 1:
printf("/");
break;
case 2:
printf("-");
break;
case 3:
printf("\\");
break;
}
printf("%08lld", encode_order);
printf("(%06d bytes coded)\n", coded_size);
fflush(coded_fp);
return 0;
}
static int save_recyuv(VASurfaceID surface_id,
unsigned long long display_order,
unsigned long long encode_order)
{
unsigned char *dst_Y = NULL, *dst_U = NULL, *dst_V = NULL;
if (recyuv_fp == NULL)
return 0;
if (srcyuv_fourcc == VA_FOURCC_NV12) {
int uv_size = 2 * (ips.width / 2) * (ips.height / 2);
dst_Y = malloc(2 * uv_size);
if (dst_Y == NULL) {
printf("Failed to allocate memory for dst_Y\n");
exit(1);
}
dst_U = malloc(uv_size);
if (dst_U == NULL) {
printf("Failed to allocate memory for dst_U\n");
free(dst_Y);
exit(1);
}
memset(dst_Y, 0, 2 * uv_size);
memset(dst_U, 0, uv_size);
} else if (srcyuv_fourcc == VA_FOURCC_IYUV ||
srcyuv_fourcc == VA_FOURCC_YV12) {
int uv_size = (ips.width / 2) * (ips.height / 2);
dst_Y = malloc(4 * uv_size);
if (dst_Y == NULL) {
printf("Failed to allocate memory for dst_Y\n");
exit(1);
}
dst_U = malloc(uv_size);
if (dst_U == NULL) {
printf("Failed to allocate memory for dst_U\n");
free(dst_Y);
exit(1);
}
dst_V = malloc(uv_size);
if (dst_V == NULL) {
printf("Failed to allocate memory for dst_V\n");
free(dst_Y);
free(dst_U);
exit(1);
}
memset(dst_Y, 0, 4 * uv_size);
memset(dst_U, 0, uv_size);
memset(dst_V, 0, uv_size);
} else {
printf("Unsupported source YUV format\n");
exit(1);
}
download_surface_yuv(va_dpy, surface_id,
srcyuv_fourcc, ips.width, ips.height,
dst_Y, dst_U, dst_V);
fseek(recyuv_fp, display_order * ips.width * ips.height * 1.5, SEEK_SET);
if (srcyuv_fourcc == VA_FOURCC_NV12) {
int uv_size = 2 * (ips.width / 2) * (ips.height / 2);
fwrite(dst_Y, uv_size * 2, 1, recyuv_fp);
fwrite(dst_U, uv_size, 1, recyuv_fp);
} else if (srcyuv_fourcc == VA_FOURCC_IYUV ||
srcyuv_fourcc == VA_FOURCC_YV12) {
int uv_size = (ips.width / 2) * (ips.height / 2);
fwrite(dst_Y, uv_size * 4, 1, recyuv_fp);
if (srcyuv_fourcc == VA_FOURCC_IYUV) {
fwrite(dst_U, uv_size, 1, recyuv_fp);
fwrite(dst_V, uv_size, 1, recyuv_fp);
} else {
fwrite(dst_V, uv_size, 1, recyuv_fp);
fwrite(dst_U, uv_size, 1, recyuv_fp);
}
}
if (dst_Y)
free(dst_Y);
if (dst_U)
free(dst_U);
if (dst_V)
free(dst_V);
fflush(recyuv_fp);
return 0;
}
static void storage_task(unsigned long long display_order, unsigned long long encode_order)
{
unsigned int tmp;
VAStatus va_status;
tmp = GetTickCount();
va_status = vaSyncSurface(va_dpy, src_surface[display_order % SURFACE_NUM]);
CHECK_VASTATUS(va_status, "vaSyncSurface");
SyncPictureTicks += GetTickCount() - tmp;
tmp = GetTickCount();
save_codeddata(display_order, encode_order);
SavePictureTicks += GetTickCount() - tmp;
save_recyuv(ref_surface[display_order % SURFACE_NUM], display_order, encode_order);
/* reload a new frame data */
tmp = GetTickCount();
if (srcyuv_fp != NULL)
load_surface(src_surface[display_order % SURFACE_NUM], display_order + SURFACE_NUM);
UploadPictureTicks += GetTickCount() - tmp;
pthread_mutex_lock(&encode_mutex);
srcsurface_status[display_order % SURFACE_NUM] = SRC_SURFACE_IN_ENCODING;
pthread_mutex_unlock(&encode_mutex);
}
static void * storage_task_thread(void *t)
{
while (1) {
struct storage_task_t *current;
current = storage_task_dequeue();
if (current == NULL) {
pthread_mutex_lock(&encode_mutex);
pthread_cond_wait(&encode_cond, &encode_mutex);
pthread_mutex_unlock(&encode_mutex);
continue;
}
storage_task(current->display_order, current->encode_order);
free(current);
/* all frames are saved, exit the thread */
if (++frame_coded >= ips.frame_count)
break;
}
return 0;
}
static int storage_task_queue(unsigned long long display_order, unsigned long long encode_order)
{
struct storage_task_t *tmp;
tmp = calloc(1, sizeof(struct storage_task_t));
if (tmp) {
tmp->display_order = display_order;
tmp->encode_order = encode_order;
}
pthread_mutex_lock(&encode_mutex);
if (storage_task_header == NULL) {
storage_task_header = tmp;
storage_task_tail = tmp;
} else {
storage_task_tail->next = tmp;
storage_task_tail = tmp;
}
srcsurface_status[display_order % SURFACE_NUM] = SRC_SURFACE_IN_STORAGE;
pthread_cond_signal(&encode_cond);
pthread_mutex_unlock(&encode_mutex);
return 0;
}
static int encode_frames(void)
{
unsigned int i, tmp;
VAStatus va_status;
//VASurfaceStatus surface_status;
/* upload RAW YUV data into all surfaces */
tmp = GetTickCount();
if (srcyuv_fp != NULL) {
for (i = 0; i < SURFACE_NUM; i++)
load_surface(src_surface[i], i);
} else
upload_source_YUV_once_for_all();
UploadPictureTicks += GetTickCount() - tmp;
/* ready for encoding */
memset(srcsurface_status, SRC_SURFACE_IN_ENCODING, sizeof(srcsurface_status));
memset(&seq_param, 0, sizeof(seq_param));
memset(&pic_param, 0, sizeof(pic_param));
memset(&tile_group_param, 0, sizeof(tile_group_param));
if (ips.encode_syncmode == 0)
pthread_create(&encode_thread, NULL, storage_task_thread, NULL);
for (current_frame_encoding = 0; current_frame_encoding < ips.frame_count; current_frame_encoding++) {
encoding2display_order(current_frame_encoding, ips.intra_period,
&current_frame_display, &current_frame_type);
printf("%s : %lld %s : %lld type : %d\n", "encoding order", current_frame_encoding, "Display order", current_frame_display, current_frame_type);
/* check if the source frame is ready */
while (srcsurface_status[current_slot] != SRC_SURFACE_IN_ENCODING) {
usleep(1);
}
tmp = GetTickCount();
va_status = vaBeginPicture(va_dpy, context_id, src_surface[current_slot]);
CHECK_VASTATUS(va_status, "vaBeginPicture");
BeginPictureTicks += GetTickCount() - tmp;
tmp = GetTickCount(); //start of render process
// prepare parameters used for sequence and frame
fill_sps_header();
fill_pps_header(current_frame_display);
// init length of packed headers
len_ivf_header = 0;
len_seq_header = 0;
len_pic_header = 0;
// render headers
// first frame send IVF sequence header + frame header
if(current_frame_encoding == 0)
{
render_ivf_header(); //44 byte, 32byte sequence ivf header, 12 byte frame ivf header
len_ivf_header = 44;
}
else
{
render_ivf_frame_header(); //12 byte frame ivf header
len_ivf_header = 12;
}
render_TD();//render OBU_TEMPORAL_DELIMITER
if (current_frame_type == KEY_FRAME) {
if(current_frame_encoding == 0) render_sequence(); //render SPS only needed in first frame
len_seq_header = render_packedsequence(); //render packed sequence header
}
else
{
len_seq_header = 0;
}
if((ips.RateControlMethod == 2 || ips.RateControlMethod == 4) && current_frame_encoding == 0)
{
// misc buffer are not need in CQP case
// only needed in first frame
render_misc_buffer();
}
render_packedpicture(); //render packed frame header
render_picture(); //render frame PPS buffer
render_tile_group(); //render tile group buffer
RenderPictureTicks += GetTickCount() - tmp;
tmp = GetTickCount();
va_status = vaEndPicture(va_dpy, context_id);
CHECK_VASTATUS(va_status, "vaEndPicture");
EndPictureTicks += GetTickCount() - tmp;
if (ips.encode_syncmode)
storage_task(current_frame_display, current_frame_encoding);
else /* queue the storage task queue */
storage_task_queue(current_frame_display, current_frame_encoding);
}
if (ips.encode_syncmode == 0) {
int ret;
pthread_join(encode_thread, (void **)&ret);
}
return 0;
}
static int calc_PSNR(double *psnr)
{
char *srcyuv_ptr = NULL, *recyuv_ptr = NULL, tmp;
unsigned long long min_size;
unsigned long long i, sse = 0;
double ssemean;
int fourM = 0x400000; /* 4M */
min_size = MIN(srcyuv_frames, ips.frame_count) * ips.width * ips.height * 1.5;
for (i = 0; i < min_size; i++) {
unsigned long long j = i % fourM;
if ((i % fourM) == 0) {
if (srcyuv_ptr)
munmap(srcyuv_ptr, fourM);
if (recyuv_ptr)
munmap(recyuv_ptr, fourM);
srcyuv_ptr = mmap(0, fourM, PROT_READ, MAP_SHARED, fileno(srcyuv_fp), i);
recyuv_ptr = mmap(0, fourM, PROT_READ, MAP_SHARED, fileno(recyuv_fp), i);
if ((srcyuv_ptr == MAP_FAILED) || (recyuv_ptr == MAP_FAILED)) {
printf("Failed to mmap YUV files\n");
return 1;
}
}
tmp = srcyuv_ptr[j] - recyuv_ptr[j];
sse += tmp * tmp;
}
ssemean = (double)sse / (double)min_size;
*psnr = 20.0 * log10(255) - 10.0 * log10(ssemean);
if (srcyuv_ptr)
munmap(srcyuv_ptr, fourM);
if (recyuv_ptr)
munmap(recyuv_ptr, fourM);
return 0;
}
static int print_performance(unsigned int PictureCount)
{
unsigned int psnr_ret = 1, others = 0;
double psnr = 0, total_size = ips.width * ips.height * 1.5 * ips.frame_count;
if (ips.calc_psnr && srcyuv_fp && recyuv_fp)
psnr_ret = calc_PSNR(&psnr);
others = TotalTicks - UploadPictureTicks - BeginPictureTicks
- RenderPictureTicks - EndPictureTicks - SyncPictureTicks - SavePictureTicks;
printf("\n\n");
printf("PERFORMANCE: Frame Rate : %.2f fps (%d frames, %d ms (%.2f ms per frame))\n",
(double) 1000 * PictureCount / TotalTicks, PictureCount,
TotalTicks, ((double) TotalTicks) / (double) PictureCount);
printf("PERFORMANCE: Compression ratio : %d:1\n", (unsigned int)(total_size / frame_size));
if (psnr_ret == 0)
printf("PERFORMANCE: PSNR : %.2f (%lld frames calculated)\n",
psnr, MIN(ips.frame_count, srcyuv_frames));
printf("PERFORMANCE: UploadPicture : %d ms (%.2f, %.2f%% percent)\n",
(int) UploadPictureTicks, ((double) UploadPictureTicks) / (double) PictureCount,
UploadPictureTicks / (double) TotalTicks / 0.01);
printf("PERFORMANCE: vaBeginPicture : %d ms (%.2f, %.2f%% percent)\n",
(int) BeginPictureTicks, ((double) BeginPictureTicks) / (double) PictureCount,
BeginPictureTicks / (double) TotalTicks / 0.01);
printf("PERFORMANCE: vaRenderHeader : %d ms (%.2f, %.2f%% percent)\n",
(int) RenderPictureTicks, ((double) RenderPictureTicks) / (double) PictureCount,
RenderPictureTicks / (double) TotalTicks / 0.01);
printf("PERFORMANCE: vaEndPicture : %d ms (%.2f, %.2f%% percent)\n",
(int) EndPictureTicks, ((double) EndPictureTicks) / (double) PictureCount,
EndPictureTicks / (double) TotalTicks / 0.01);
printf("PERFORMANCE: vaSyncSurface : %d ms (%.2f, %.2f%% percent)\n",
(int) SyncPictureTicks, ((double) SyncPictureTicks) / (double) PictureCount,
SyncPictureTicks / (double) TotalTicks / 0.01);
printf("PERFORMANCE: SavePicture : %d ms (%.2f, %.2f%% percent)\n",
(int) SavePictureTicks, ((double) SavePictureTicks) / (double) PictureCount,
SavePictureTicks / (double) TotalTicks / 0.01);
printf("PERFORMANCE: Others : %d ms (%.2f, %.2f%% percent)\n",
(int) others, ((double) others) / (double) PictureCount,
others / (double) TotalTicks / 0.01);
if (ips.encode_syncmode == 0)
printf("(Multithread enabled, the timing is only for reference)\n");
return 0;
}
int main(int argc, char **argv)
{
unsigned int start;
process_cmdline(argc, argv);
print_input();
start = GetTickCount();
init_va();
setup_encode();
encode_frames();
release_encode();
deinit_va();
//free memory
if(ips.output) free(ips.output);
if(ips.srcyuv) free(ips.srcyuv);
if(ips.recyuv) free(ips.recyuv);
TotalTicks += GetTickCount() - start;
print_performance(ips.frame_count);
return 0;
}