diff options
author | Austin Yuan <shengquan.yuan@intel.com> | 2015-07-21 17:37:44 +0800 |
---|---|---|
committer | Austin Yuan <shengquan.yuan@intel.com> | 2015-07-21 17:43:47 +0800 |
commit | b672394d89bb609c1dd2ef9fa39002e610f1384c (patch) | |
tree | 1b0c85bd4ba372e114b6f4d0c414f3cc67895658 | |
parent | 4d24331d9bf4813d64e6aa098ff09b3d6cae9fb2 (diff) |
Update va_encode for bugfixing and ROI feature
Signed-off-by: Austin Yuan <shengquan.yuan@intel.com>
Signed-off-by: Mingruo Sun <mingruo.sun@intel.com>
-rw-r--r-- | vaenc/Android.mk | 8 | ||||
-rw-r--r-- | vaenc/README | 423 | ||||
-rw-r--r-- | vaenc/h264encode.c | 158 | ||||
-rw-r--r-- | vaenc/va_encode.c | 196 | ||||
-rw-r--r-- | vaenc/va_encode.h | 13 | ||||
-rw-r--r-- | vaenc/va_surface.c | 4 |
6 files changed, 576 insertions, 226 deletions
diff --git a/vaenc/Android.mk b/vaenc/Android.mk index 65b9f5b..db9dd48 100644 --- a/vaenc/Android.mk +++ b/vaenc/Android.mk @@ -12,11 +12,11 @@ LOCAL_SRC_FILES := \ ../android/gralloc.cpp ../utils/psnr.c ../utils/ssim.c LOCAL_CFLAGS += \ - -DANDROID + -DANDROID -D_LINK_C -#ifeq ($(TARGET_ARCH),x86_64) -LOCAL_CFLAGS += -march=x86-64 -D_LINK_C -#endif +ifeq ($(TARGET_ARCH),x86_64) +LOCAL_CFLAGS += -march=x86-64 +endif LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/../../va \ diff --git a/vaenc/README b/vaenc/README index e8c42c5..a591027 100644 --- a/vaenc/README +++ b/vaenc/README @@ -1,150 +1,277 @@ -1). new_va_encode has an option "-configfile", which could read dynamic RC settings from configure file. - -I. The RC settings include: -frame_start -frame_end -frame_width -frame_height -bits_per_second -target_percentage -window_size -initial_qp -min_qp -max_qp -force_kf -no_ref_last -no_ref_gf -no_ref_arf -frame_rate -intra_period -intra_idr_period -ip_period -quality -refresh_entropy_probs -copy_buffer_to_golden -copy_buffer_to_alternate -refresh_last -refresh_golden_frame -refresh_alternate_frame - -II. How to use "-configfile" -Below is a configure file to support dynamic bitrate change. Take it for example. -[beginrc] -frame_width=1280 -frame_height=720 -frame_start=0 -frame_end=999 -bits_per_second=1000000 -[endrc] -[beginrc] -bits_per_second=2000000 -frame_start=1000 -frame_end=1999 -[endrc] -[beginrc] -frame_start=2000 -frame_end=2999 -bits_per_second=3000000 -[endrc] -[beginrc] -frame_start=3000 -frame_end=3999 -bits_per_second=5000000 -[endrc] - - -2). new_va_encode has options available for VP8 encoding: --w, -h, -framecount, -o, -f, -configfile, -bitrate, -rcMode, -syncmode, -srcyuv, -recyuv, -enablePSNR, -surface(va|malloc), -frame_size_log, -minqp, -maxqp, -raw, -riff, -dynamic_resolution - --rcMode VBR will translated to rc_end_usage=CBR mode in psbvideo driver --rcMode CBR will translated to rc_end_usage=CBR_HRD mode in psbvideo driver --raw output is vp8 element stream --riff will add RIFF file header to VP8 element stream + va_encode: libVA encoding tool + +Content: + 1. Introduction + 2. Quick start + 3. Bitrate control setting + 4. Performance testing + 5. Special feature testing + 6. Dynamic encoding testing + +1. Introduction + +va_encode is a command line encoding tool through VAAPI. It encodes a video +file from a YUV source. The YUV source can be from a storage file, or the +tool itself can auto-generate a white-black checkerboard sequence. + +The tools supports some advanced testing features which is useful for driver +development and tunning. + +2. Quick start + +Simply type "va_encode" on command line, it will encode a clip with bellow +configuration: +(a) codec is H264, resolution 176x144, frame number 60, VBR +(b) input YUV is the auto-generated white-black checkerboard +(c) coded file is saved into /tmp/test.out (Linux) or /sdcard/test.out (Android) + +To encode VP8, the command line is "va_encoder -t VP8" +To encode JPEG, the command line is "va_encoder -t JPEG" +To specify a resolution, use "va_encode -w 1280 -h 720" +To encode more than 60 frames, use "va_encode -n 100" +To encode from a YUV file, use "va_encode -srcyuv yuv_file_name" +To save to another file, use "va_encode -o file_path_and_name" + +For encoding from a YUV file, the tool supports various fourcc, use "-fourcc" +parameter to specify it, e.g. "-fourcc IYUV", "-fourcc YV12". The default format +is NV12 + +3. Rate control settings +(1) RC mode +RC mode can be specified by "-rcMode", e.g. + -rcMode CBR + -rcMode VBR + -rcMode VCM + -rcMode CQP + +(2) Bitrate +Bitrate is set by "-bitrate", e.g. + -bitrate 500000 +It sets the bitrate to 500000bps + +(3) QP +The tool can set the min and max value of QP,e.g. + -minqp 15 + -maxqp 30 + -initalqp 20 +It limites qp range to [15, 30], and set the first IDR frame qp to 20 +This option may not take effect because of the underline HW/driver bit rate +control constrains + +minqp/maxqp is not applicable to CQP mode. Use "-initialqp" to set the qp + +(4) I/P/B setting +Parameters that are used to set I/P/B sequence + -intra_period <number> + -idr_period <number> + -ip_period <number> + +The number for "-idr_period" is special. It means after number of "intra_period", +there will be an IDR frame. + +Bellow is detailed explanation about these parameters (intra_id_period is the result +of "idr_peroid number" * "intra_perid number" from command line): +================================================================ +Assume frame sequence is: Frame#0,#1,#2,...,#M,...,#X,... (encoding order) + 1) period between Frame #X and Frame #N = #X - #N + 2) 0 means infinite for intra_period/intra_idr_period, and 0 is invalid for ip_period + 3) intra_idr_period % intra_period (intra_period > 0) and intra_period % ip_period must be 0 + 4) intra_period and intra_idr_period take precedence over ip_period + 5) if ip_period > 1, intra_period and intra_idr_period are not the strict periods + of I/IDR frames, see bellow examples + ------------------------------------------------------------------- + intra_period intra_idr_period ip_period frame sequence (intra_period/intra_idr_period/ip_period) + 0 ignored 1 IDRPPPPPPP ... (No IDR/I any more) + 0 ignored >=2 IDR(PBB)(PBB)... (No IDR/I any more) + 1 0 ignored IDRIIIIIII... (No IDR any more) + 1 1 ignored IDR IDR IDR IDR... + 1 >=2 ignored IDRII IDRII IDR... (1/3/ignore) + >=2 0 1 IDRPPP IPPP I... (3/0/1) + >=2 0 >=2 IDR(PBB)(PBB)(IBB) (6/0/3) + (PBB)(IBB)(PBB)(IBB)... + >=2 >=2 1 IDRPPPPP IPPPPP IPPPPP (6/18/1) + IDRPPPPP IPPPPP IPPPPP... + >=2 >=2 >=2 {IDR(PBB)(PBB)(IBB)(PBB)(IBB)(PBB)} (6/18/3) + {IDR(PBB)(PBB)(IBB)(PBB)(IBB)(PBB)}... + {IDR(PBB)(PBB)(IBB)(PBB)} (6/12/3) + {IDR(PBB)(PBB)(IBB)(PBB)}... + {IDR(PBB)(PBB)} (6/6/3) + {IDR(PBB)(PBB)}. +================================================================ + +(4) VP8 parameters + -raw output is vp8 element stream + -riff will add RIFF file header to VP8 element stream Note: default output data for VP8 is IVF file -To do correctness test: --correctness_test MUST be used - -some options only for VP8 key frame control: --auto_kf --kf_min_dist --kf_max_dist - -option for error concealment: --error_resilient: default value = 0 -0=off(reset context tables for key frame only), 1=on(reset context tables for both key frames and golden frames) - -VP8 firmware could support resolution change: --dynamic_resolution to test dynamic resolution change feature, create surface with 1080p resolution - - -An example for VP8 dynmaic bitrate testing -[beginrc] -frame_width=176 -frame_height=144 -frame_start=0 -frame_end=4 -force_kf=1 -[endrc] -[beginrc] -frame_start=5 -frame_end=9 -force_kf=0 -[endrc] -[beginrc] -frame_start=10 -frame_end=19 -no_ref_last=1 -no_ref_arf=1 -no_ref_gf=0 -[endrc] -[beginrc] -frame_start=20 -frame_end=29 -no_ref_last=1 -no_ref_arf=0 -no_ref_gf=1 -[endrc] -[beginrc] -frame_start=30 -frame_end=39 -no_ref_last=1 -no_ref_arf=0 -no_ref_gf=0 -[endrc] -[beginrc] -frame_start=40 -frame_end=49 -no_ref_last=0 -no_ref_arf=1 -no_ref_gf=1 -[endrc] -[beginrc] -frame_start=50 -frame_end=59 -no_ref_last=0 -no_ref_arf=1 -no_ref_gf=0 -[endrc] -[beginrc] -frame_start=60 -frame_end=69 -no_ref_last=0 -no_ref_arf=0 -no_ref_gf=1 -[endrc] -[beginrc] -frame_start=70 -frame_end=79 -refresh_last=0 -[endrc] -[beginrc] -frame_start=80 -frame_end=139 -refresh_golden_frame=0 -[endrc] -[beginrc] -frame_start=140 -frame_end=199 -refresh_alternate_frame=0 -[endrc] +Correctness test: + -correctness_test + +Key frame control: + -auto_kf + -kf_min_dist + -kf_max_dist + +Error concealment: + -error_resilient: default value = 0 + 0 = off(reset context tables for key frame only), + 1 = on(reset context tables for both key frames and golden frames) + +4. Performance testing + +(1) Minimize source YUV loading cost +The end-to-end encoding testing includes source YUV loading. It is usually +very slow for large resolutions. Two options here: +(a) don't set "-srcyuv", it will use auto-generated source, and only load once +(b) use "-srcyuv XXX -perf", it always encoding the first 16 frames of the YUV file + +(2) Single thread vs Multiple thread +Parameter "-syncmode" runs encoding with single thread, while without this +parameter, the tool create two threads: one is continously sending encoding frames, +and another continously read from source YUV and save coded file into storage + +Multiple thread or single thread should only have impact to end-to-end fps, the +core encoding fps is a little different: +(1) single thread: core encoding fps counts the time of bellow VAAPIs: + vaBeginPicture/vaRenderPicture/vaEndPicture/vaSyncSurface +(2) multiple thread: core encoding fps counts the time of bellow VAAPIs: + vaBeginPicture/vaRenderPicture/vaEndPicture + vaSyncSurface is not counted because it runs in another thread which may be + in parallel with vaBeginPicture/vaRenderPicture/vaEndPicture + +5. Special feature testing +(1) ROI testing + -roi_enable: enable ROI feature (default 0) + -roi_value: the priority of the ROI region (defautl -2) + -roi_minqp: the min allowed delta QP (defaut -4) + -roi_maxqp: the max allowed delta QP (default 4) + -roi_rect_x/y/w/h: ROI rectangle (default the 1/3 center area of the frame) + + +6. Dynamic encoding testing + +Option "-configfile", which could read dynamic RC settings from configure file. +The RC settings include: + frame_start + frame_end + frame_width + frame_height + bits_per_second + target_percentage + window_size + initial_qp + min_qp + max_qp + force_kf + no_ref_last + no_ref_gf + no_ref_arf + frame_rate + intra_period + intra_idr_period + ip_period + quality + refresh_entropy_probs + copy_buffer_to_golden + copy_buffer_to_alternate + refresh_last + refresh_golden_frame + refresh_alternate_frame + +Write dynamic change settings into a configuration file, e.g. + [beginrc] + frame_width=1280 + frame_height=720 + frame_start=0 + frame_end=999 + bits_per_second=1000000 + [endrc] + [beginrc] + bits_per_second=2000000 + frame_start=1000 + frame_end=1999 + [endrc] + [beginrc] + frame_start=2000 + frame_end=2999 + bits_per_second=3000000 + [endrc] + [beginrc] + frame_start=3000 + frame_end=3999 + bits_per_second=5000000 + [endrc] + +Another example for VP8 dynmaic bitrate testing + [beginrc] + frame_width=176 + frame_height=144 + frame_start=0 + frame_end=4 + force_kf=1 + [endrc] + [beginrc] + frame_start=5 + frame_end=9 + force_kf=0 + [endrc] + [beginrc] + frame_start=10 + frame_end=19 + no_ref_last=1 + no_ref_arf=1 + no_ref_gf=0 + [endrc] + [beginrc] + frame_start=20 + frame_end=29 + no_ref_last=1 + no_ref_arf=0 + no_ref_gf=1 + [endrc] + [beginrc] + frame_start=30 + frame_end=39 + no_ref_last=1 + no_ref_arf=0 + no_ref_gf=0 + [endrc] + [beginrc] + frame_start=40 + frame_end=49 + no_ref_last=0 + no_ref_arf=1 + no_ref_gf=1 + [endrc] + [beginrc] + frame_start=50 + frame_end=59 + no_ref_last=0 + no_ref_arf=1 + no_ref_gf=0 + [endrc] + [beginrc] + frame_start=60 + frame_end=69 + no_ref_last=0 + no_ref_arf=0 + no_ref_gf=1 + [endrc] + [beginrc] + frame_start=70 + frame_end=79 + refresh_last=0 + [endrc] + [beginrc] + frame_start=80 + frame_end=139 + refresh_golden_frame=0 + [endrc] + [beginrc] + frame_start=140 + frame_end=199 + refresh_alternate_frame=0 + [endrc] + +Parameter "-dynamic_resolution" is used to singal application to allocate surface at +1080P resolutioin, then it can test dynamic resolution change feature diff --git a/vaenc/h264encode.c b/vaenc/h264encode.c index d69a2ba..bd4e93a 100644 --- a/vaenc/h264encode.c +++ b/vaenc/h264encode.c @@ -83,6 +83,15 @@ static VAProfile h264_profile = -1; unsigned int h264_entropy_mode = 1; /* cabac */ unsigned int h264_8x8_dct = 0; +unsigned int roi_enable = 0; +unsigned int roi_value = -2; +int roi_minqp = -4; +int roi_maxqp = 4; +unsigned int roi_rec_x = 0; +unsigned int roi_rec_y = 0; +unsigned int roi_rec_w = 0; +unsigned int roi_rec_h = 0; + struct __bitstream { unsigned int *buffer; int bit_offset; @@ -554,7 +563,8 @@ static int update_RefPicList(void) static int render_sequence(void) { - VABufferID seq_param_buf, rc_param_buf, misc_param_tmpbuf, render_id[2]; + VABufferID seq_param_buf = VA_INVALID_ID, rc_param_buf = VA_INVALID_ID; + VABufferID misc_param_tmpbuf = VA_INVALID_ID, render_id[2] = { VA_INVALID_ID, VA_INVALID_ID }; VAStatus va_status; VAEncMiscParameterBuffer *misc_param, *misc_param_tmp; VAEncMiscParameterRateControl *misc_rate_ctrl; @@ -608,13 +618,16 @@ static int render_sequence(void) va_status = vaRenderPicture(va_dpy,context_id, &misc_param_tmpbuf, 1); } + if (buf_destroy) + destroy_vabuffers(va_dpy, 5, seq_param_buf, rc_param_buf, + misc_param_tmpbuf, render_id[0], render_id[1]); return va_status; } static int render_framerate() { - VABufferID frame_rate_param_buf; + VABufferID frame_rate_param_buf = VA_INVALID_ID; VAStatus va_status; VAEncMiscParameterBuffer *misc_param, *misc_param_tmp; VAEncMiscParameterFrameRate *misc_frame_rate; @@ -643,12 +656,15 @@ static int render_framerate() va_status = vaRenderPicture(va_dpy,context_id, &frame_rate_param_buf, 1); CHECK_VASTATUS(va_status,"vaRenderPicture");; + if (buf_destroy) + destroy_vabuffers(va_dpy, 1, frame_rate_param_buf); + return 0; } static int render_rcparam(unsigned int mask, struct rc_param_t *rc_param) { - VABufferID rc_param_buf; + VABufferID rc_param_buf = VA_INVALID_ID; VAStatus va_status; VAEncMiscParameterBuffer *misc_param, *misc_param_tmp; VAEncMiscParameterRateControl *misc_rate_ctrl; @@ -702,6 +718,9 @@ static int render_rcparam(unsigned int mask, struct rc_param_t *rc_param) va_status = vaRenderPicture(va_dpy,context_id, &rc_param_buf, 1); CHECK_VASTATUS(va_status,"vaRenderPicture");; + + if (buf_destroy) + destroy_vabuffers(va_dpy, 1, rc_param_buf); return 0; } @@ -740,7 +759,7 @@ static int calc_poc(int pic_order_cnt_lsb) static int render_picture(void) { - VABufferID pic_param_buf; + VABufferID pic_param_buf = VA_INVALID_ID; VAStatus va_status; int i = 0; @@ -763,7 +782,8 @@ static int render_picture(void) } else { if (h264_autoref == 0) { memcpy(pic_param.ReferenceFrames, ReferenceFrames, numShortTerm*sizeof(VAPictureH264)); - for (i = numShortTerm; i < surface_num; i++) { + /* Reset the rest of non-used references */ + for (i = numShortTerm; i < 16; i++) { pic_param.ReferenceFrames[i].picture_id = VA_INVALID_SURFACE; pic_param.ReferenceFrames[i].flags = VA_PICTURE_H264_INVALID; } @@ -792,13 +812,17 @@ static int render_picture(void) va_status = vaRenderPicture(va_dpy,context_id, &pic_param_buf, 1); CHECK_VASTATUS(va_status,"vaRenderPicture"); + if (buf_destroy) + destroy_vabuffers(va_dpy, 1, pic_param_buf); + return 0; } static int render_packedsequence(void) { VAEncPackedHeaderParameterBuffer packedheader_param_buffer; - VABufferID packedseq_para_bufid, packedseq_data_bufid, render_id[2]; + VABufferID packedseq_para_bufid = VA_INVALID_ID, packedseq_data_bufid = VA_INVALID_ID; + VABufferID render_id[2] = { VA_INVALID_ID, VA_INVALID_ID }; unsigned int length_in_bits; unsigned char *packedseq_buffer = NULL; VAStatus va_status; @@ -829,6 +853,10 @@ static int render_packedsequence(void) CHECK_VASTATUS(va_status,"vaRenderPicture"); free(packedseq_buffer); + + if (buf_destroy) + destroy_vabuffers(va_dpy, 4, packedseq_para_bufid, packedseq_data_bufid, + render_id[0], render_id[1]); return 0; } @@ -836,7 +864,8 @@ static int render_packedsequence(void) static int render_packedpicture(void) { VAEncPackedHeaderParameterBuffer packedheader_param_buffer; - VABufferID packedpic_para_bufid, packedpic_data_bufid, render_id[2]; + VABufferID packedpic_para_bufid = VA_INVALID_ID, packedpic_data_bufid = VA_INVALID_ID; + VABufferID render_id[2] = { VA_INVALID_ID, VA_INVALID_ID }; unsigned int length_in_bits; unsigned char *packedpic_buffer = NULL; VAStatus va_status; @@ -866,14 +895,19 @@ static int render_packedpicture(void) CHECK_VASTATUS(va_status,"vaRenderPicture"); free(packedpic_buffer); + + if (buf_destroy) + destroy_vabuffers(va_dpy, 4, packedpic_para_bufid, packedpic_data_bufid, + render_id[0], render_id[1]); return 0; } static void render_packedsei(void) { + VABufferID packed_sei_header_param_buf_id = VA_INVALID_ID; + VABufferID packed_sei_buf_id = VA_INVALID_ID, render_id[2] = { VA_INVALID_ID, VA_INVALID_ID }; VAEncPackedHeaderParameterBuffer packed_header_param_buffer; - VABufferID packed_sei_header_param_buf_id, packed_sei_buf_id, render_id[2]; unsigned int length_in_bits /*offset_in_bytes*/; unsigned char *packed_sei_buffer = NULL; VAStatus va_status; @@ -925,14 +959,18 @@ static void render_packedsei(void) CHECK_VASTATUS(va_status,"vaRenderPicture"); free(packed_sei_buffer); - + + if (buf_destroy) + destroy_vabuffers(va_dpy, 4, packed_sei_header_param_buf_id, packed_sei_buf_id, + render_id[0], render_id[1]); + return; } static int render_air(void) { VAStatus va_status; - VABufferID misc_parameter_air_buf_id; + VABufferID misc_parameter_air_buf_id = VA_INVALID_ID; VAEncMiscParameterBuffer *misc_param; VAEncMiscParameterAIR *misc_air_param; @@ -959,13 +997,16 @@ static int render_air(void) va_status = vaRenderPicture(va_dpy,context_id, &misc_parameter_air_buf_id, 1); CHECK_VASTATUS(va_status,"vaRenderPicture");; + if (buf_destroy) + destroy_vabuffers(va_dpy, 1, misc_parameter_air_buf_id); + return 0; } static int render_cir(void) { VAStatus va_status; - VABufferID misc_parameter_cir_buf_id; + VABufferID misc_parameter_cir_buf_id = VA_INVALID_ID; VAEncMiscParameterBuffer *misc_param; VAEncMiscParameterCIR *misc_cir_param; @@ -990,12 +1031,15 @@ static int render_cir(void) va_status = vaRenderPicture(va_dpy,context_id, &misc_parameter_cir_buf_id, 1); CHECK_VASTATUS(va_status,"vaRenderPicture"); + if (buf_destroy) + destroy_vabuffers(va_dpy, 1, misc_parameter_cir_buf_id); + return 0; } static int render_hrd(void) { - VABufferID misc_parameter_hrd_buf_id; + VABufferID misc_parameter_hrd_buf_id = VA_INVALID_ID; VAStatus va_status; VAEncMiscParameterBuffer *misc_param; VAEncMiscParameterHRD *misc_hrd_param; @@ -1031,12 +1075,15 @@ static int render_hrd(void) va_status = vaRenderPicture(va_dpy,context_id, &misc_parameter_hrd_buf_id, 1); CHECK_VASTATUS(va_status,"vaRenderPicture");; + if (buf_destroy) + destroy_vabuffers(va_dpy, 1, misc_parameter_hrd_buf_id); + return 0; } static int render_slice(void) { - VABufferID slice_param_buf; + VABufferID slice_param_buf = VA_INVALID_ID; VAStatus va_status; VAEncSliceParameterBufferH264 *slice_param, *current_slice; int i, j, frame_slice_cc = frame_slice_count; @@ -1055,7 +1102,7 @@ static int render_slice(void) for (j = 0; j < frame_slice_cc; j++) { current_slice = slice_param + j; - current_slice->disable_deblocking_filter_idc = 1; + current_slice->disable_deblocking_filter_idc = 0; current_slice->macroblock_address = mb_rendered; if (j == frame_slice_cc - 1) { current_slice->num_macroblocks = (frame_width_mbaligned * frame_height_mbaligned) / (16 * 16) - mb_rendered; @@ -1067,6 +1114,13 @@ static int render_slice(void) if (current_frame_type == FRAME_IDR) { if (current_frame_encoding != 0) ++current_slice->idr_pic_id; + /* Reset reference for IDR also */ + for (i = 0; i < 32; i++) { + current_slice->RefPicList0[i].picture_id = VA_INVALID_SURFACE; + current_slice->RefPicList0[i].flags = VA_PICTURE_H264_INVALID; + current_slice->RefPicList1[i].picture_id = VA_INVALID_SURFACE; + current_slice->RefPicList1[i].flags = VA_PICTURE_H264_INVALID; + } } else if (current_frame_type == FRAME_P) { int refpiclist0_max = h264_maxref & 0xffff; memcpy(current_slice->RefPicList0, RefPicList0_P, refpiclist0_max*sizeof(VAPictureH264)); @@ -1092,8 +1146,8 @@ static int render_slice(void) } } - current_slice->slice_alpha_c0_offset_div2 = 0; - current_slice->slice_beta_offset_div2 = 0; + current_slice->slice_alpha_c0_offset_div2 = 2; + current_slice->slice_beta_offset_div2 = 2; current_slice->direct_spatial_mv_pred_flag = 1; current_slice->pic_order_cnt_lsb = (current_frame_display - current_IDR_display) % MaxPicOrderCntLsb; } @@ -1103,13 +1157,17 @@ static int render_slice(void) va_status = vaRenderPicture(va_dpy, context_id, &slice_param_buf, 1); CHECK_VASTATUS(va_status,"vaRenderPicture"); + + if (buf_destroy) + destroy_vabuffers(va_dpy, 1, slice_param_buf); + return 0; } static int render_max_slice_size(void) { VAStatus va_status; - VABufferID misc_parameter_max_slice_size_buf_id; + VABufferID misc_parameter_max_slice_size_buf_id = VA_INVALID_ID; VAEncMiscParameterBuffer *misc_param; VAEncMiscParameterMaxSliceSize *misc_max_slize_size_param; @@ -1139,6 +1197,62 @@ static int render_max_slice_size(void) va_status = vaRenderPicture(va_dpy, context_id, &misc_parameter_max_slice_size_buf_id, 1); CHECK_VASTATUS(va_status,"vaRenderPicture");; + if (buf_destroy) + destroy_vabuffers(va_dpy, 1, misc_parameter_max_slice_size_buf_id); + + return 0; +} + +static int render_roi(void) +{ + VAStatus va_status; + VABufferID misc_roi_buf_id = VA_INVALID_ID; + VAEncMiscParameterBuffer *misc_param; + VAEncMiscParameterBufferROI *misc_roi_param; + VAEncROI encroi; + + + roi_rec_x = (!roi_rec_x)?frame_width / 3:roi_rec_x; + roi_rec_y = (!roi_rec_x)?frame_height / 3:roi_rec_y; + roi_rec_w = (!roi_rec_w)?frame_width / 3:roi_rec_w; + roi_rec_h = (!roi_rec_h)?frame_height / 3:roi_rec_h; + + va_status = vaCreateBuffer(va_dpy, context_id, + VAEncMiscParameterBufferType, + sizeof(VAEncMiscParameterBuffer) + sizeof(VAEncMiscParameterBufferROI), + 1, + NULL, + &misc_roi_buf_id); + CHECK_VASTATUS(va_status, "vaCreateBuffer"); + + vaMapBuffer(va_dpy, + misc_roi_buf_id, + (void **)&misc_param); + + misc_param->type = VAEncMiscParameterTypeROI; + misc_roi_param = (VAEncMiscParameterBufferROI *)misc_param->data; + + misc_roi_param->num_roi = 1; + misc_roi_param->max_delta_qp = roi_maxqp; + misc_roi_param->min_delta_qp = roi_minqp; + + encroi.roi_rectangle.x = roi_rec_x; + encroi.roi_rectangle.y = roi_rec_y; + encroi.roi_rectangle.width = roi_rec_w; + encroi.roi_rectangle.height = roi_rec_h; + + encroi.roi_value = roi_value; + + misc_roi_param->roi = &encroi; + + vaUnmapBuffer(va_dpy, misc_roi_buf_id); + + va_status = vaRenderPicture(va_dpy, context_id, &misc_roi_buf_id, 1); + CHECK_VASTATUS(va_status,"vaRenderPicture");; + + if (buf_destroy) + destroy_vabuffers(va_dpy, 1, misc_roi_buf_id); + return 0; } @@ -1170,9 +1284,13 @@ static VAStatus h264_render_frame(unsigned int mask, struct rc_param_t *rc_param if (max_slice_size) { render_max_slice_size(); } + if (roi_enable) + render_roi(); } else { //render_sequence(); render_picture(); + if (roi_enable) + render_roi(); //if (rc_mode == VA_RC_CBR) // render_packedsei(); //render_hrd(); @@ -1390,7 +1508,11 @@ static VAStatus h264_get_config(void) printf("Support VAConfigAttribEncAutoReference\n"); h264_autoref = 1; } - + + if (h264_attrib[VAConfigAttribEncROI].value != VA_ATTRIB_NOT_SUPPORTED) { + printf("Support VAConfigAttribEncROI\n"); + } + va_profile = h264_profile; /* diff --git a/vaenc/va_encode.c b/vaenc/va_encode.c index bb34656..ce2a0ad 100644 --- a/vaenc/va_encode.c +++ b/vaenc/va_encode.c @@ -46,6 +46,7 @@ #include <pthread.h> #include <errno.h> #include <math.h> +#include <stdarg.h> #include <va/va.h> #include <va/va_enc_h264.h> #include "va_display.h" @@ -119,8 +120,9 @@ unsigned int misc_priv_type = 0; unsigned int misc_priv_value = 0; int pm_active = 0; -int interactive_mode = 0; - +int interactive_mode = 0; /* stop at every vaEndPicture */ +int buf_destroy = 1; /* explicitly call vaDestroyBuffer */ + static char *current_codec_str = NULL; /* thread to save coded data/upload source YUV */ @@ -319,52 +321,53 @@ static int print_help(void) printf(" -framecount <frame number>\n"); printf(" -n <frame number>\n"); printf(" if set to 0 and srcyuv is set, the frame count is from srcyuv file\n"); + printf(" if set to a negative value, the test will loop endlessly\n"); printf(" -slices <1|2|3...> slice number each frame\n"); printf(" -o <coded_file>\n"); printf(" -dumpframe, save each frame into seperated file coded_file.0, coded_file.1, ... \n"); printf(" -f <frame rate>\n"); printf(" -r <encode fps>, throttle encoding speed instead of running as fast as possible\n"); printf(" -configfile <framename> read dynamic RC settings from configure file\n"); - printf(" --intra_period <number>\n"); - printf(" --idr_period <number>\n"); + printf(" -intra_period <number>\n"); + printf(" -idr_period <number>\n"); printf(" e.g. if set to 2, the real intra_idr_peroid of libva is 2*intra_period\n"); - printf(" --ip_period <number>\n"); - printf(" --bitrate <bitrate>\n"); - printf(" --qpluma <number>\n"); - printf(" --initialqp <number>, initial_qp of VAEncMiscParameterRateControl structure"); - printf(" also set into pic_init_qp of pps\n"); - printf(" --minqp <number>, min_qp of VAEncMiscParameterRateControl structure\n"); - printf(" --maxqp <number>, max_qp of VAEncMiscParameterRateControl structure\n"); - printf(" --sliceqp <number>, qp that set into slice_qp_delta of slice header\n"); - printf(" --rcMode <NONE|CBR|VBR|VCM|CQP|VBR_CONTRAINED>\n"); - printf(" --syncmode: sequentially upload source, encoding, save result, no multi-thread\n"); - printf(" --perf: Only load YUV at the beginning, then continously re-use surface content and skip loading\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(" --sum print encoding statistics calculate PSNR of recyuv vs. srcyuv\n"); - printf(" --entropy <0|1>, 1 means cabac, 0 cavlc\n"); - printf(" --8x8, enable 8x8 transform\n"); - printf(" --profile <BP|MP|HP>\n"); - printf(" --bit_stuffing_dis, disable bit stuffing for CBR mode\n"); - printf(" --carc, enable Content Adaptive Rate Control. A hardware mechanism that calculates\n"); + printf(" -ip_period <number>\n"); + printf(" -bitrate <bitrate>\n"); + printf(" -qpluma <number>\n"); + printf(" -initialqp <number>, initial_qp of VAEncMiscParameterRateControl structure\n"); + printf(" also set into pic_init_qp of pps\n"); + printf(" -minqp <number>, min_qp of VAEncMiscParameterRateControl structure\n"); + printf(" -maxqp <number>, max_qp of VAEncMiscParameterRateControl structure\n"); + printf(" -sliceqp <number>, qp that set into slice_qp_delta of slice header\n"); + printf(" -rcMode <NONE|CBR|VBR|VCM|CQP|VBR_CONTRAINED>\n"); + printf(" -syncmode: sequentially upload source, encoding, save result, no multi-thread\n"); + printf(" -perf: Only load YUV at the beginning, then continously re-use surface content and skip loading\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(" -sum print encoding statistics calculate PSNR of recyuv vs. srcyuv\n"); + printf(" -entropy <0|1>, 1 means cabac, 0 cavlc\n"); + printf(" -8x8, enable 8x8 transform\n"); + printf(" -profile <BP|MP|HP>\n"); + printf(" -bit_stuffing_dis, disable bit stuffing for CBR mode\n"); + printf(" -carc, enable Content Adaptive Rate Control. A hardware mechanism that calculates\n"); printf(" a Qp for each H.264 macroblock based on the complexity of the macroblock.\n"); - printf(" --level <level>\n"); - printf(" --surface <va|malloc|gralloc|linear_gralloc>\n"); - printf(" --stridealign <4|8|16|32|64|...>\n"); - printf(" --heightalign <4|8|16|32|64|...>\n"); + printf(" -level <level>\n"); + printf(" -surface <va|malloc|gralloc|linear_gralloc>\n"); + printf(" -stridealign <4|8|16|32|64|...>\n"); + printf(" -heightalign <4|8|16|32|64|...>\n"); printf(" for VA surface creatation with VASurfaceAttribExternalBufferDescriptor\n"); printf(" It is mainly for video encode share buffer testing\n"); printf(" va: VA_SURFACE_ATTRIB_MEM_TYPE_VA\n"); printf(" malloc: VA_SURFACE_ATTRIB_MEM_TYPE_USER_PTR\n"); printf(" gralloc: VA_SURFACE_ATTRIB_MEM_TYPE_ANDROID_GRALLOC\n"); - printf(" --quality <number>, JPEG encoder's quality setting\n"); - printf(" --autokf <1|0>, VP8 Encoder setting\n"); - printf(" --kf_dist_min <0-kf_dist_max>, VP8 Encoder setting\n"); - printf(" --kf_dist_max <kf_dist_min-1000>, VP8 Encoder setting\n"); - printf(" --error_resilient <kf_dist_min-1000>, VP8 Encoder setting\n"); - printf(" --hrd <buffer size> H264 CBR HRD setting\n"); + printf(" -quality <number>, JPEG encoder's quality setting\n"); + printf(" -autokf <1|0>, VP8 Encoder setting\n"); + printf(" -kf_dist_min <0-kf_dist_max>, VP8 Encoder setting\n"); + printf(" -kf_dist_max <kf_dist_min-1000>, VP8 Encoder setting\n"); + printf(" -error_resilient <kf_dist_min-1000>, VP8 Encoder setting\n"); + printf(" -hrd <buffer size> H264 CBR HRD setting\n"); printf(" -frame_size_log [log_file_path] the log file to save the size of every frame\n"); printf(" -raw to generate vp8 element stream, VP8 Encoder setting\n"); printf(" -riff to generate WebP file, VP8 Encoder setting\n"); @@ -383,15 +386,25 @@ static int print_help(void) printf(" -bitrate_layer0 to set bitrate for layer 0, VP8 Encoder setting\n"); printf(" -bitrate_layer1 to set bitrate for layer 1, VP8 Encoder setting\n"); printf(" -bitrate_layer2 to set bitrate for layer 2, VP8 Encoder setting\n"); - printf(" -surface_num [surface number, 4 - 16], default is 16\n"); - printf(" -entrypoint <LP> to enable VDENC work, default is VAEntrypointEncSlice"); + printf(" -surface_num [surface number, 4 - 16], default is 16 for auto-generated YUV\n"); + printf(" If encoding from source YUV, and surface_num is not set, default is 4\n"); + printf(" -entrypoint <LP> to enable VDENC work, default is VAEntrypointEncSlice\n"); + printf(" -skip_bufdestroy to skip vaDestroyBuffer after vaRenderPicture\n"); + printf(" -roi_enable to make ROI work with CQP mode, AVC Encoder setting\n"); + printf(" -roi_value specifies the priority of the ROI region, AVC Encoder setting\n"); + printf(" -roi_minqp specifies the min allowed delta QPs, AVC Encoder setting\n"); + printf(" -roi_maxqp specifies the max allowed delta QPs, AVC Encoder setting\n"); + printf(" -roi_rec_x defines the ROI boundary in pixels, AVC Encoder setting\n"); + printf(" -roi_rec_y defines the ROI boundary in pixels, AVC Encoder setting\n"); + printf(" -roi_rec_w defines the ROI boundary in pixels, AVC Encoder setting\n"); + printf(" -roi_rec_h defines the ROI boundary in pixels, AVC Encoder setting\n"); return 0; } static int process_cmdline(int argc, char *argv[]) { int atoi_rtn = 0; - char c; + char c, has_surface_num = 0; const struct option long_opts[] = { {"help", no_argument, NULL, 0 }, {"bitrate", required_argument, NULL, 1 }, @@ -451,7 +464,16 @@ static int process_cmdline(int argc, char *argv[]) {"carc", required_argument, NULL, 56}, {"sum", no_argument, NULL, 57}, {"active_pm", no_argument, NULL, 58}, - {"entrypoint", required_argument, NULL, 59}, + {"entrypoint", required_argument, NULL, 59}, + {"skip_bufdestroy", no_argument, NULL, 60}, + {"roi_enable", no_argument, NULL, 61}, + {"roi_value", no_argument, NULL, 62}, + {"roi_minqp", required_argument, NULL, 64}, + {"roi_maxqp", required_argument, NULL, 65}, + {"roi_rec_x", required_argument, NULL, 66}, + {"roi_rec_y", required_argument, NULL, 67}, + {"roi_rec_w", required_argument, NULL, 68}, + {"roi_rec_h", required_argument, NULL, 69}, {NULL, no_argument, NULL, 0 }}; int long_index, i, tmp, intra_idr_period_tmp = -1; @@ -702,6 +724,7 @@ static int process_cmdline(int argc, char *argv[]) break; case 55: ref_surface_num = surface_num = atoi(optarg); + has_surface_num = 1; break; case 56: carc = 1; @@ -715,7 +738,54 @@ static int process_cmdline(int argc, char *argv[]) //case ':': case 59: if (!strncmp(optarg, "LP", 2)) - va_entrypoint = VAEntrypointEncSliceLP; + va_entrypoint = VAEntrypointEncSliceLP; + break; + case 60: + buf_destroy = 0; + break; + case 61: + roi_enable = 1; + break; + case 62: + roi_value = 1; + break; + case 64: + roi_minqp = atoi(optarg); + break; + case 65: + roi_maxqp = atoi(optarg); + break; + case 66: + atoi_rtn = atoi(optarg); + if (atoi_rtn <= 0) { + fprintf(stderr, "rec_x value must be positive!\n"); + exit(1); + } + roi_rec_x = atoi_rtn; + break; + case 67: + atoi_rtn = atoi(optarg); + if (atoi_rtn <= 0) { + fprintf(stderr, "rec_y value must be positive!\n"); + exit(1); + } + roi_rec_y = atoi_rtn; + break; + case 68: + atoi_rtn = atoi(optarg); + if (atoi_rtn <= 0) { + fprintf(stderr, "rec_w value must be positive!\n"); + exit(1); + } + roi_rec_w = atoi_rtn; + break; + case 69: + atoi_rtn = atoi(optarg); + if (atoi_rtn <= 0) { + fprintf(stderr, "rec_h value must be positive!\n"); + exit(1); + } + roi_rec_h = atoi_rtn; break; case '?': print_help(); @@ -748,19 +818,18 @@ static int process_cmdline(int argc, char *argv[]) fstat(fileno(srcyuv_fp), &tmp); srcyuv_frames = tmp.st_size / (frame_width * frame_height * 1.5); - if (0 == frame_count) - frame_count = srcyuv_frames; - - if (0 == srcyuv_frames) { + if (srcyuv_frames == 0) { fclose(srcyuv_fp); srcyuv_fp = NULL; - printf("Source YUV file %s contains 0 valid frame, use auto-generated YUV data\n\n", srcyuv_fn); - } - else + printf("Source YUV file %s contains 0 frame, use auto-generated YUV data\n\n", srcyuv_fn); + } else { + if (frame_count==0) + frame_count = srcyuv_frames; printf("Source YUV file %s with %d frames\n\n", srcyuv_fn, srcyuv_frames); - - if (0 == frame_count) - frame_count = 60; + /* Use 4 surfaces if encoding from a source YUV and user doesn't set surface_num */ + if (!has_surface_num) + ref_surface_num = surface_num = 4; + } } } @@ -1319,6 +1388,23 @@ static void * storage_task_thread(void *t) return 0; } +int destroy_vabuffers(VADisplay dpy, int buf_num, ...) +{ + va_list argp; + VABufferID buf_id; + int i; + + va_start(argp, buf_num); + for (i=0; i<buf_num; i++) { + buf_id = va_arg(argp, VABufferID); + if (buf_id != VA_INVALID_ID) + vaDestroyBuffer(dpy, buf_id); + } + va_end(argp); + + return 0; +} + static int encode_frames(void) { int tmp; @@ -1490,7 +1576,7 @@ static int print_performance(unsigned int PictureCount) printf("\n\n"); - printf("PERFORMANCE: Frame Rate : %.2f fps (%d frames, %d ms (%.2f ms per frame))\n", + printf("PERFORMANCE: End-to-End FPS : %.2f fps (%d frames, %d ms (%.2f ms per frame))\n", (double) 1000*PictureCount / TotalTicks, PictureCount, TotalTicks, ((double) TotalTicks) / (double) PictureCount); printf("PERFORMANCE: Core Encoding FPS : %.2f fps (%d frames, %d ms (%.2f ms per frame))\n", @@ -1501,8 +1587,12 @@ static int print_performance(unsigned int PictureCount) else printf(" (Core Encoding includes vaBegin/vaRender/vaEnd; vaSync in another thread and not counted)\n"); - printf("PERFORMANCE: Compression ratio : %.2f%% (%.0f vs %.0f)\n", frame_size * 100.0/total_size, - frame_size, total_size); + printf("PERFORMANCE: Compression ratio : %.2f", total_size/frame_size); + if ((total_size/(1<<20)) > 999) + printf(" (%.0fM vs %.0fM)\n", total_size/(1<<20), frame_size/(1<<20)); + else + printf(" (%.0fK vs %.0fK)\n", total_size/(1<<10), frame_size/(1<<10)); + if (&jpeg_codec == current_codec) { float tmp = (float)frame_width * frame_height * 1.5 * frame_count/((float)TotalTicks/1000)/1024/1024; float tmp1 = (float)frame_width * frame_height * 1.5 * frame_count/(core_time/1000)/1024/1024; diff --git a/vaenc/va_encode.h b/vaenc/va_encode.h index 11ba3a7..6bca627 100644 --- a/vaenc/va_encode.h +++ b/vaenc/va_encode.h @@ -139,6 +139,7 @@ extern unsigned int surface_type; /* h264 specific variables */ extern unsigned int h264_entropy_mode; /* cabac */ extern unsigned int h264_8x8_dct; +extern unsigned int layer_num; extern unsigned int jpeg_quality; @@ -167,6 +168,16 @@ extern unsigned int bitrate_layer1; extern unsigned int bitrate_layer2; extern unsigned int windows_size; extern int pm_active; +extern int buf_destroy; + +extern unsigned int roi_enable; +extern unsigned int roi_value; +extern int roi_minqp; +extern int roi_maxqp; +extern unsigned int roi_rec_x; +extern unsigned int roi_rec_y; +extern unsigned int roi_rec_w; +extern unsigned int roi_rec_h; int access_statitics(void *p, int encoder_order); int print_statitics(int frame_number, int width, int height); @@ -284,6 +295,7 @@ static inline int string_to_rc(char *str) return rc_mode; } +int destroy_vabuffers(VADisplay dpy, int buf_num, ...); VAStatus create_surfaces(); VAStatus destroy_surfaces(); VAStatus get_surface_attrib(); @@ -300,4 +312,3 @@ extern struct codec_table_t h263_codec; extern struct codec_table_t vp8_codec; extern struct codec_table_t jpeg_codec; static struct codec_table_t *current_codec = &h264_codec; -extern unsigned int layer_num; diff --git a/vaenc/va_surface.c b/vaenc/va_surface.c index bbb4d16..f80a183 100644 --- a/vaenc/va_surface.c +++ b/vaenc/va_surface.c @@ -132,8 +132,8 @@ VAStatus create_surfaces_external(struct codec_table_t *current_codec) } else if (surface_type == SURFACE_TYPE_GRALLOC || surface_type == SURFACE_TYPE_GRALLOC_LINEAR) { unsigned long buffers[SURFACE_NUM]; - //va_status = alloc_gralloc_buffer(surface_num, buffers, frame_width_mbaligned, frame_height_mbaligned, - // (surface_type == SURFACE_TYPE_GRALLOC_LINEAR)); + va_status = alloc_gralloc_buffer(surface_num, buffers, frame_width_mbaligned, frame_height_mbaligned, + (surface_type == SURFACE_TYPE_GRALLOC_LINEAR)); /* stride need to follow gralloc allocator */ setup_externalbuf(&external_srcbuf, surface_type, &attrib_list[0]); |