/* * Copyright (c) 2019 Amlogic, Inc. All rights reserved. * * This source code is subject to the terms and conditions defined in below * which is part of this source code package. * * Description: */ // Copyright (C) 2019 Amlogic, Inc. All rights reserved. // // All information contained herein is Amlogic confidential. // // This software is provided to you pursuant to Software License // Agreement (SLA) with Amlogic Inc ("Amlogic"). This software may be // used only in accordance with the terms of this agreement. // // Redistribution and use in source and binary forms, with or without // modification is strictly prohibited without prior written permission // from Amlogic. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include #include #include #include #include #include #include #include #include #include #include "./test_dma_api.h" #include "../amvenc_lib/include/amvenc.h" #include #include #define WIDTH 3840 #define HEIGHT 3840 // consider rotated frame #define FRAMERATE 60 #define INIT_RETRY 100 #define FORCE_PICTURE_TYPE 0x1 #define CHANGE_TARGET_RATE 0x2 #define CHANGE_MIN_MAX_QP 0x4 #define CHANGE_GOP_PERIOD 0x8 #define LONGTERM_REF_SET 0x10 #define CUST_SIZE_SMOOTH 0x20 #define CUST_APP_H264_PLUS 0x40 #define CHANGE_MULTI_SLICE 0x80 #define FORCE_PICTURE_SKIP 0x100 #define CHANGE_STRICT_RC 0x200 #define ENCODER_STRING_LEN_MAX 256 // GOP mode strings static const char *Gop_string[] = { "Default mode IP only", "All I frame mode", "IP only mode", "IBBBP mode", "IP only 1-frame SVC mode", "IP only 2-frame SVC mode", "IP only 3-frame SVC mode", "IP only 4-frame SVC mode", "IP only customer mode", "reserved", "IP only 5-frame SVC mode", }; typedef struct { int FrameNum; //change frame number int enable_option; //FORCE_PICTURE_TYPE int picType; //amvenc_frame_type_t //CHANGE_TARGET_RATE int bitRate; //CHANGE_MIN_MAX_QP int minQpI; int maxQpI; int maxDeltaQp; int minQpP; int maxQpP; int minQpB; int maxQpB; //CHANGE_GOP_PERIOD int intraQP; int GOPPeriod; //LONGTERM_REF_SET int LTRFlags; //bit 0: UseCurSrcAsLongtermPic; bit 1: Use LTR frame // CUST_SIZE_SMOOTH int smooth_level; //0 normal, 50(middle), 100 (high) // CUST_APP_H264_PLUS int newIDRInterval; // shall be multiply of gop length int QPdelta_IDR; // QP delta apply to IDRs int QPdelta_LTR; // QP delta apply to LTR P frames // Change multi-slice int Slice_Mode; //multi slice mode int Slice_Para; //para // Change strict bitrate control int bitrate_window; //bitrate cal window int pskip_threshold; //threshold for pskip } CfgChangeParam; typedef struct { int seqNum; struct timeval timeFrameStart; struct timeval timeFrameEnd; int encodeEnd; amvenc_handle_t handle_enc; char srcfile[ENCODER_STRING_LEN_MAX]; // yuv data url in your root fs char outfile[ENCODER_STRING_LEN_MAX]; // stream url in your root fs int width; // width int height; // height int gop; // I frame refresh interval int framerate; // framerate int bitrate; // bit rate int num; // encode frame count int fmt; // encode input fmt 1 : nv12, 2 : nv21, 3 : yuv420p(yv12/yu12) int buf_type; // 0:vmalloc, 3:dma buffer int num_planes; // used for dma buffer case. 2 : nv12/nv21, 3 : yuv420p(yv12/yu12) int codec_id; // 4 : h.264, 5 : h.265 int cfg_opt; /* optional, flags to control the encode feature settings bit 0:roi control. 0: disabled (default) 1: enabled bit 1: update control. 0: disabled (default) 1: enabled bit 2 ~ bit 6 encode GOP pattern options: 0 default(IP) 1:I only 2:IP_only 3: IBBBP 4:IP_SVC1 5:IP_SVC2 6: IP_SVC3 7: IP_SVC4 8: CUSTP bit 7:long term references. 0: disabled (default) 1: enabled bit 8:cust source buffer stride . 0: disabled (default) 1: enabled bit 9: convert normal source file stride to cust source stride. 0: disabled (default) 1: enabled bit 10:enable intraRefresh. 0: disabled (default) 1: enabled bit 11 ~ bit 13: profile 0: auto (default) others as following 1: BASELINE(AVC) MAIN (HEVC); 2 MAIN (AVC) main10 (HEVC) 3: HIGH (AVC) STILLPICTURE (HEVC); 4 HIGH10 (AVC) bit 14 ~ bit 15: frame rotation(counter-clockwise, in degree): 0:none, 1:90, 2:180, 3:270 bit 16 ~ bit 17: frame mirroring: 0:none, 1:vertical, 2:horizontal, 3:both V and H bit 18: enable customer bitstream buffer size bit 19 ~ bit 20: enable multi slice mode: 0, one slice(no para), 1 by MB(16x16)/CTU(64x64), 2 by CTU + size(byte) bit 21 cust_qp_delta_en bit 22 strict_rate_ctrl_en (skipP allowed to limit bitrate) default 0 bit 23 forcePicQpEnable default 0 */ char roifile[ENCODER_STRING_LEN_MAX]; // optional, roi info url in root fs, no present if roi is disabled char cfg_file[ENCODER_STRING_LEN_MAX]; // optional, cfg update info url. no present if update is disabled int src_buf_stride; // optional, source buffer stride int intraRefresh ; // optional, lower 4 bits for intra-refresh mode; others for refresh parameter, controlled by intraRefresh bit int bitStreamBuf ; // optional, encoded bitstream buffer size in MB int MultiSlice_parameter; // optional, multi slice parameter in MB/CTU or CTU and size (HIGH_16bits size + LOW_16bit CTU) combined int cust_qp_delta; // optional, cust_qp_delta apply to P frames value >0 lower; <0 increase the quality int strict_rate_control_parmeter; // optional, High 16 bit bitrate window (frames max 120). low 16 bit bitrate threshold (percent) int forcePicQpIPB; } encodecCfgParam; typedef struct { int CurFrameNum; //current frame number int CurGOPSize; // current int CurGOPCounter; int PrevFrameQP; // previous frame QP value int minQpI_base; int maxQpI_base; int maxDeltaQp_base; int minQpP_base; int maxQpP_base; int minQpB_base; int maxQpB_base; int temp_QP_change; // QP enforcing flag int cust_size_smooth_enable; // flag identify size_smooth is on going int smooth_qpdelta; // QP delata apply to I frames. // CUST_APP_H264_PLUS int cust_ltr_enable; //CUST H264 feature enabled int GopLTRInterval; // LTR P frame interval. int GopLTRCounter; // counter to decide LTR P frames. int QPdelta_IDR; // QP delta apply to IDRs int QPdelta_LTR; // QP delta apply to LTR P frames int qp_idr; // real applied qp_idr int qp_ltr; //real applied qp_ltr } PlayStatInfo; static int ParseCfgUpdateFile(FILE *fp, CfgChangeParam *cfg_update); static int ParseEncodeCfgFile(FILE *fp, encodecCfgParam *cfg_encode); static void *encode_thread(void *param); #define CFG_ENCODE_NUM_MAX 6 // Helper function to calculate time diffs. static unsigned int uTimeDiff(struct timeval end, struct timeval start) { return (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec); } //return timeDiff in u64 static unsigned long long uTimeDiffLL(struct timeval end, struct timeval start) { return (unsigned long long )(end.tv_sec - start.tv_sec) * 1000000 + (unsigned long long )(end.tv_usec - start.tv_usec); } int main(int argc, const char *argv[]) { int i = 0; int arg_count = 0; int len = 0; FILE *fp_cfg_encode = NULL; encodecCfgParam cfg_encode[CFG_ENCODE_NUM_MAX]; if ((argc != 2) && (argc < 13)) { printf("Amlogic Encoder Hal API \n"); printf(" usage: venc_hal_test " "[srcfile][outfile][width][height][gop][framerate][bitrate][num][fmt][" "buf type][num_planes][codec_id] [cfg_opt] [roifile] [cfg_file] \n"); printf(" options \t:\n"); printf(" srcfile \t: yuv data url in your root fs\n"); printf(" outfile \t: stream url in your root fs\n"); printf(" width \t: width\n"); printf(" height \t: height\n"); printf(" gop \t: I frame refresh interval\n"); printf(" framerate\t: framerate \n"); printf(" bitrate \t: bit rate \n"); printf(" num \t: encode frame count \n"); printf(" fmt \t: encode input fmt 1 : nv12, 2 : nv21, 3 : yuv420p(yv12/yu12), 5 : RGB888, 6 : RGBA8888\n"); printf(" buf_type \t: 0:vmalloc, 3:dma buffer\n"); printf(" num_planes \t: used for dma buffer case. 2 : nv12/nv21, 3 : yuv420p(yv12/yu12)\n"); printf(" codec_id \t: 4 : h.264, 5 : h.265\n"); printf(" cfg_opt \t: optional, flags to control the encode feature settings\n"); printf(" \t\t bit 0:roi control. 0: disabled (default) 1: enabled\n"); printf(" \t\t bit 1: update control. 0: disabled (default) 1: enabled\n"); printf(" \t\t bit 2 ~ bit 6 encode GOP pattern options:\n"); printf(" \t\t\t 0 default(IP) 1:I only 2:IP_only 3: IBBBP\n"); printf(" \t\t\t 4:IP_SVC1 5:IP_SVC2 6: IP_SVC3 7: IP_SVC4 8: CUSTP 10: IP_SVC5\n"); printf(" \t\t bit 7:long term references. 0: disabled (default) 1: enabled\n"); printf(" \t\t bit 8:cust source buffer stride . 0: disabled (default) 1: enabled\n"); printf(" \t\t bit 9: convert normal source file stride to cust source stride. 0: disabled (default) 1: enabled\n"); printf(" \t\t bit 10:enable intraRefresh. 0: disabled (default) 1: enabled\n"); printf(" \t\t bit 11 ~ bit 13: profile 0: auto (default) others as following\n"); printf(" \t\t 1: BASELINE(AVC) MAIN (HEVC); 2 MAIN (AVC) main10 (HEVC) \n"); printf(" \t\t 3: HIGH (AVC) STILLPICTURE (HEVC); 4 HIGH10 (AVC) \n"); printf(" \t\t bit 14 ~ bit 15: frame rotation(counter-clockwise, in degree): 0:none, 1:90, 2:180, 3:270\n"); printf(" \t\t bit 16 ~ bit 17: frame mirroring: 0:none, 1:vertical, 2:horizontal, 3:both V and H\n"); printf(" \t\t bit 18: enable customer bitstream buffer size\n"); printf(" \t\t bit 19 ~ bit 20: enable multi slice mode: 0, one slice(no para), 1 by MB(16x16)/CTU(64x64), 2 by CTU + size(byte)\n"); printf(" \t\t bit 21 cust_qp_delta_en \n"); printf(" \t\t bit 22 strict_rate_ctrl_en (skipP allowed to limit bitrate) default 0 \n"); printf(" \t\t bit 23 forcePicQpEnable default 0 \n"); printf(" roifile \t: optional, roi info url in root fs, no present if roi is disabled\n"); printf(" cfg_file \t: optional, cfg update info url. no present if update is disabled\n"); printf(" src_buf_stride \t: optional, source buffer stride\n"); printf(" intraRefresh \t: optional, lower 4 bits for intra-refresh mode; others for refresh parameter, controlled by intraRefresh bit\n"); printf(" bitStreamBuf \t: optional, encoded bitstream buffer size in MB\n"); printf(" MultiSlice parameter \t: optional, multi slice parameter in MB/CTU or CTU and size (HIGH_16bits size + LOW_16bit CTU) combined\n"); printf(" cust_qp_delta \t: optional, cust_qp_delta apply to P frames value >0 lower; <0 increase the quality \n"); printf(" strict rate control parmeter \t: optional, High 16 bit bitrate window (frames max 120). low 16 bit bitrate threshold (percent)\n"); printf(" forcePicQpIPB: force qp value\n"); printf("or\n"); printf(" usage: amvenc_enc_test " "[encode_cfg_file]\n"); printf(" options \t:\n"); printf(" encode_cfg_file \t: encode cfg file info url\n"); return -1; } else if (argc == 2) { printf("argv[1]:%s\n", argv[1]); fp_cfg_encode = fopen((argv[1]), "r"); if (fp_cfg_encode == NULL) { printf("open encode cfg file error!\n"); return 0; } memset(cfg_encode, 0, CFG_ENCODE_NUM_MAX * sizeof(encodecCfgParam)); ParseEncodeCfgFile(fp_cfg_encode, cfg_encode); fclose(fp_cfg_encode); if (cfg_encode[0].seqNum == 0) return 0; } else { memset(&cfg_encode[0], 0, sizeof(encodecCfgParam)); len = strlen(argv[1]) > ENCODER_STRING_LEN_MAX ? ENCODER_STRING_LEN_MAX : strlen(argv[1]); strncpy(cfg_encode[0].srcfile, argv[1], len); len = strlen(argv[2]) > ENCODER_STRING_LEN_MAX ? ENCODER_STRING_LEN_MAX : strlen(argv[2]); strncpy(cfg_encode[0].outfile, argv[2], len); cfg_encode[0].width = atoi(argv[3]); cfg_encode[0].height = atoi(argv[4]); cfg_encode[0].gop = atoi(argv[5]); cfg_encode[0].framerate = atoi(argv[6]); cfg_encode[0].bitrate = atoi(argv[7]); cfg_encode[0].num = atoi(argv[8]); cfg_encode[0].fmt = atoi(argv[9]); cfg_encode[0].buf_type = atoi(argv[10]); cfg_encode[0].num_planes = atoi(argv[11]); cfg_encode[0].codec_id = atoi(argv[12]); if (argc > 13) { cfg_encode[0].cfg_opt = atoi(argv[13]); } if (argc > 14) { arg_count = 14; if ((cfg_encode[0].cfg_opt & 0x1) == 0x1 && argc > arg_count) { len = strlen(argv[arg_count]) > ENCODER_STRING_LEN_MAX ? ENCODER_STRING_LEN_MAX : strlen(argv[arg_count]); strncpy(cfg_encode[0].roifile, argv[arg_count], len); printf("roi_url is\t: %s ;\n", cfg_encode[0].roifile); arg_count ++; } if ((cfg_encode[0].cfg_opt & 0x2) == 0x2 && argc > arg_count) { len = strlen(argv[arg_count]) > ENCODER_STRING_LEN_MAX ? ENCODER_STRING_LEN_MAX : strlen(argv[arg_count]); strncpy(cfg_encode[0].cfg_file, argv[arg_count], len); printf("cfg_upd_url is\t: %s ;\n", cfg_encode[0].cfg_file); arg_count ++; } if ((cfg_encode[0].cfg_opt & 0x100) == 0x100 && argc > arg_count) { cfg_encode[0].src_buf_stride = atoi(argv[arg_count]); arg_count ++; } if ((cfg_encode[0].cfg_opt & 0x400) == 0x400 && argc > arg_count) { cfg_encode[0].intraRefresh = atoi(argv[arg_count]); printf("IntraRefresh mode %d, arg %d;\n", (cfg_encode[0].intraRefresh & 0xf), (cfg_encode[0].intraRefresh >> 4)); arg_count ++; } if ((cfg_encode[0].cfg_opt & 0x40000) == 0x40000 && argc > arg_count) { cfg_encode[0].bitStreamBuf = atoi(argv[arg_count]); printf("bitstream_buf_size: %d \n", cfg_encode[0].bitStreamBuf); arg_count ++; } if ((cfg_encode[0].cfg_opt >> 19) & 0x3 && argc > arg_count) { cfg_encode[0].MultiSlice_parameter = atoi(argv[arg_count]); printf("Multi-slices para %d \n", cfg_encode[0].MultiSlice_parameter); arg_count ++; } if ((cfg_encode[0].cfg_opt >> 21) & 0x1 && argc > arg_count) { cfg_encode[0].cust_qp_delta = atoi(argv[arg_count]); printf("cust_qp_delta %d \n", cfg_encode[0].cust_qp_delta); arg_count ++; } if ((cfg_encode[0].cfg_opt >> 22) & 0x1 && argc > arg_count) { cfg_encode[0].strict_rate_control_parmeter = atoi(argv[arg_count]); printf("strict_rate_control_parmeter %d\n", cfg_encode[0].strict_rate_control_parmeter); printf("bit-rate window %d frames, skip_threshold %d\n", cfg_encode[0].strict_rate_control_parmeter>>16, cfg_encode[0].strict_rate_control_parmeter& 0xffff); arg_count ++; } if ((cfg_encode[0].cfg_opt >> 23) & 0x1 && argc > arg_count) { cfg_encode[0].forcePicQpIPB = atoi(argv[arg_count]); printf("forcePicQpIPB %d\n", cfg_encode[0].forcePicQpIPB); arg_count ++; } if (arg_count != argc) { printf("config no match conf %d argc %d\n", cfg_encode[0].cfg_opt, argc); return -1; } } cfg_encode[0].seqNum = 1; } pthread_t tid[CFG_ENCODE_NUM_MAX]; for (i = 0; i < cfg_encode[0].seqNum; i ++) { if (i >= CFG_ENCODE_NUM_MAX) break; pthread_create(&tid[i], NULL, encode_thread, &cfg_encode[i]); } for (i = 0; i < cfg_encode[0].seqNum; i ++) { if (i >= CFG_ENCODE_NUM_MAX) break; pthread_join(tid[i], NULL); } return 0; } static void *encode_thread(void *param) { int width, height, gop, framerate, bitrate, num, my_qp; int ret = 0; int outfd = -1; FILE *fp = NULL; FILE *fp_roi = NULL; FILE *fp_cfg = NULL; int datalen = 0; int retry_cnt = 0; int roi_enabled = 0; int ltf_enabled = 0; int cfg_upd_enabled = 0, has_cfg_update = 0; int cfg_option = 0, frame_num = 0, gop_pattern = 0, profile = 0; int src_buf_stride = 0, conver_stride = 0, intra_refresh_comb = 0; int bitstream_buf_size = 0; int multi_slice = 0, multi_slice_para = 0; int cust_qp_delta = 0, cust_qp_delta_en = 0; int arg_count = 0, arg_roi = 0, arg_upd = 0; int strict_rate_ctrl_en = 0, bitrate_window = 0, skip_threshold = 0; amvenc_img_format_t fmt = AML_IMG_FMT_NONE; CfgChangeParam cfgChange; amvenc_frame_type_t enc_frame_type; PlayStatInfo playStat; unsigned char *vaddr = NULL; amvenc_info_t encode_info; amvenc_buffer_info_t ret_buf; amvenc_codec_id_t codec_id = AML_CODEC_ID_H264; uint32_t frame_rotation; uint32_t frame_mirroring; amvenc_metadata_t encoding_metadata; int forcePicQpEnable = 0; int forcePicQpIPB = 0; unsigned int framesize; unsigned ysize; unsigned usize; unsigned vsize; unsigned uvsize; amvenc_frame_info_t frame_info; int tmp_idr; int fd = -1; amvenc_qp_param_t qp_tbl; int qp_mode = 0; int buf_type = 0; int num_planes = 1; struct usr_ctx_s ctx; unsigned int frameWriteTime = 0; unsigned long long totalTime = 0, ioTime = 0; struct timeval timeStart, timeEnd, readStart, readEnd, writeStart, writeEnd; int len = 0; unsigned char srcfile[ENCODER_STRING_LEN_MAX] = {0}; unsigned char outfile[ENCODER_STRING_LEN_MAX] = {0}; unsigned char roifile[ENCODER_STRING_LEN_MAX] = {0}; unsigned char cfg_file[ENCODER_STRING_LEN_MAX] = {0}; encodecCfgParam *cfg_encode = NULL; pthread_detach(pthread_self()); if (NULL != param) cfg_encode = (encodecCfgParam *)param; else { goto end; } width = cfg_encode->width; if ((width < 1) || (width > WIDTH)) { printf("invalid width \n"); goto end; } height = cfg_encode->height; if ((height < 1) || (height > HEIGHT)) { printf("invalid height \n"); goto end; } gop = cfg_encode->gop; framerate = cfg_encode->framerate; bitrate = cfg_encode->bitrate; num = cfg_encode->num; fmt = cfg_encode->fmt; buf_type = cfg_encode->buf_type; num_planes = cfg_encode->num_planes; switch (cfg_encode->codec_id) { case 0: codec_id = AML_CODEC_ID_NONE; break; case 1: codec_id = AML_CODEC_ID_H261; break; case 2: codec_id = AML_CODEC_ID_H261; break; case 3: codec_id = AML_CODEC_ID_H263; break; case 4: codec_id = AML_CODEC_ID_H264; break; case 5: codec_id = AML_CODEC_ID_H265; break; default: break; } if (codec_id != AML_CODEC_ID_H264 && codec_id != AML_CODEC_ID_H265) { printf("unsupported codec id %d \n", codec_id); goto end; } if ((framerate < 0) || (framerate > FRAMERATE)) { printf("invalid framerate %d \n", framerate); goto end; } if (bitrate <= 0) { printf("invalid bitrate \n"); goto end; } if (num < 0) { printf("invalid num \n"); goto end; } if (buf_type == 3 && (num_planes < 1 || num_planes > 3)) { printf("invalid num_planes \n"); goto end; } printf("src_url is\t: %s ;\n", cfg_encode->srcfile); printf("out_url is\t: %s ;\n", cfg_encode->outfile); printf("width is\t: %d ;\n", width); printf("height is\t: %d ;\n", height); printf("gop is\t: %d ;\n", gop); printf("frmrate is\t: %d ;\n", framerate); printf("bitrate is\t: %d ;\n", bitrate); printf("frm_num is\t: %d ;\n", num); printf("fmt is\t: %d ;\n", fmt); printf("buf_type is\t: %d ;\n", buf_type); printf("num_planes is\t: %d ;\n", num_planes); printf("codec is\t: %d ;\n", codec_id); if (codec_id == AML_CODEC_ID_H265) printf("codec is H265\n"); else printf("codec is H264\n"); if (cfg_encode->cfg_opt > 0) { cfg_option = cfg_encode->cfg_opt; gop_pattern = (cfg_option >> 2) & 0x1f; frame_rotation = (cfg_option >> 14) & 0x03; frame_mirroring = (cfg_option >> 16) & 0x03; printf("frame_rotation=%u, frame_mirroring=%u\n", frame_rotation, frame_mirroring); if (gop_pattern) { if (gop_pattern > 10) { printf("gop_pattern_is: %d invalid;\n", gop_pattern); goto end; } printf("gop_pattern_is \t: %d --> %s;\n", gop_pattern, Gop_string[gop_pattern]); } profile = (cfg_option >>11) & 0x7; if (profile) { if ((profile > 3 && codec_id == AML_CODEC_ID_H265) || profile > 4) { printf("profile: %d invalid;\n", profile); goto end; } printf("profile is \t: %d\n", profile); } if (cfg_option & 0x80) { printf("longterm reference is enabled\n"); ltf_enabled = 1; } multi_slice = (cfg_option >> 19) & 0x3; if (multi_slice) { printf("multi slice is enabled mode: %d\n", multi_slice); } cust_qp_delta_en = (cfg_option >> 21) & 0x1; if (cust_qp_delta_en) { printf("cust qp delta enabled: %d\n", cust_qp_delta_en); } strict_rate_ctrl_en = (cfg_option >> 22) & 0x1; if (strict_rate_ctrl_en) { printf("strict bitrate control enabled: %d\n", strict_rate_ctrl_en); } forcePicQpEnable = (cfg_option >> 23) & 0x1; if (forcePicQpEnable) { printf("forcePicQpEnable: %d\n", forcePicQpEnable); } if ((cfg_option & 0x1) == 0x1 && (strlen(cfg_encode->roifile) > 1)) { printf("roi_url is\t: %s ;\n", cfg_encode->roifile); roi_enabled = 1; len = strlen(cfg_encode->roifile) > ENCODER_STRING_LEN_MAX ? ENCODER_STRING_LEN_MAX : strlen(cfg_encode->roifile); strncpy(roifile, cfg_encode->roifile, len); } if ((cfg_option & 0x2) == 0x2 && (strlen(cfg_encode->cfg_file) > 1)) { printf("cfg_upd_url is\t: %s ;\n", cfg_encode->cfg_file); cfg_upd_enabled = 1; len = strlen(cfg_encode->cfg_file) > ENCODER_STRING_LEN_MAX ? ENCODER_STRING_LEN_MAX : strlen(cfg_encode->cfg_file); strncpy(cfg_file, cfg_encode->cfg_file, len); } if ((cfg_option & 0x100) == 0x100 && cfg_encode->src_buf_stride > 0) { src_buf_stride = cfg_encode->src_buf_stride; conver_stride = (cfg_option & 0x200) >> 9; printf("cust stride is\t: %d convert: %d;\n", src_buf_stride, conver_stride); } if ((cfg_option & 0x400) == 0x400 && cfg_encode->intraRefresh > 0) { intra_refresh_comb = cfg_encode->intraRefresh; printf("IntraRefresh mode %d, arg %d;\n", (intra_refresh_comb & 0xf), (intra_refresh_comb >> 4)); } if ((cfg_option & 0x40000) == 0x40000 && cfg_encode->bitStreamBuf > 0) { bitstream_buf_size = cfg_encode->bitStreamBuf; printf("bitstream_buf_size: %d \n", bitstream_buf_size); } if (multi_slice && cfg_encode->MultiSlice_parameter > 0) { multi_slice_para = cfg_encode->MultiSlice_parameter; printf("Multi-slices para %d \n", multi_slice_para); } if (cust_qp_delta_en && cfg_encode->cust_qp_delta > 0) { cust_qp_delta = cfg_encode->cust_qp_delta; printf("cust_qp_delta %d \n", cust_qp_delta); } if (strict_rate_ctrl_en && cfg_encode->strict_rate_control_parmeter > 0) { bitrate_window = cfg_encode->strict_rate_control_parmeter; skip_threshold = bitrate_window & 0xffff; bitrate_window >>=16; printf("bit-rate window %d frames, skip_threshold %d\n", bitrate_window, skip_threshold); } if (forcePicQpEnable && cfg_encode->forcePicQpIPB > 0) { forcePicQpIPB = cfg_encode->forcePicQpIPB; printf("forcePicQpIPB %d \n", forcePicQpIPB); } } if (src_buf_stride && src_buf_stride < width) { printf("incorrect cust source stride %d width %d", src_buf_stride, width); goto end; } len = strlen(cfg_encode->srcfile) > ENCODER_STRING_LEN_MAX ? ENCODER_STRING_LEN_MAX : strlen(cfg_encode->srcfile); strncpy(srcfile, cfg_encode->srcfile, len); len = strlen(cfg_encode->outfile) > ENCODER_STRING_LEN_MAX ? ENCODER_STRING_LEN_MAX : strlen(cfg_encode->outfile); strncpy(outfile, cfg_encode->outfile, len); unsigned int outbuffer_len = 8*1024 * 1024 * sizeof(char); if (bitstream_buf_size > 8) outbuffer_len = bitstream_buf_size*1024 * 1024 * sizeof(char); unsigned char *outbuffer = (unsigned char *) malloc(outbuffer_len); if (outbuffer == NULL) { printf("Can not malloc outbuffer\n"); goto exit; } unsigned char *inputBuffer = NULL; unsigned char *input[3] = { NULL }; amvenc_buffer_info_t inbuf_info; amvenc_dma_info_t *dma_info = NULL; unsigned char *roi_buffer = NULL; unsigned int roi_size; if (src_buf_stride) { if (fmt == AML_IMG_FMT_RGB888) { framesize = src_buf_stride * height * 3; } else if (fmt == AML_IMG_FMT_RGBA8888) { framesize = src_buf_stride * height * 4; } else { framesize = src_buf_stride * height * 3 / 2; } ysize = src_buf_stride * height; usize = src_buf_stride * height / 4; vsize = src_buf_stride * height / 4; uvsize = src_buf_stride * height / 2; } else { if (fmt == AML_IMG_FMT_RGB888) { framesize = width * height * 3; } else if (fmt == AML_IMG_FMT_RGBA8888) { framesize = width * height * 4; } else { framesize = width * height * 3 / 2; } ysize = width * height; usize = width * height / 4; vsize = width * height / 4; uvsize = width * height / 2; } memset(&inbuf_info, 0, sizeof(amvenc_buffer_info_t)); inbuf_info.buf_type = (amvenc_buffer_type_t) buf_type; inbuf_info.buf_stride = width; if (src_buf_stride != 0) inbuf_info.buf_stride = src_buf_stride; inbuf_info.buf_fmt = fmt; memset(&qp_tbl, 0, sizeof(amvenc_qp_param_t)); memset(&playStat, 0, sizeof(PlayStatInfo)); qp_tbl.qp_min = 0; qp_tbl.qp_max = 51; qp_tbl.qp_I_base = 30; qp_tbl.qp_I_min = 0; qp_tbl.qp_I_max = 51; qp_tbl.qp_P_base = 30; qp_tbl.qp_P_min = 0; qp_tbl.qp_P_max = 51; memset(&encode_info, 0, sizeof(amvenc_info_t)); encode_info.width = width; encode_info.height = height; encode_info.bit_rate = bitrate; encode_info.frame_rate = framerate; encode_info.gop = gop; encode_info.img_format = fmt; encode_info.qp_mode = qp_mode; encode_info.profile = profile; encode_info.forcePicQpEnable = forcePicQpEnable; encode_info.forcePicQpI = forcePicQpIPB; encode_info.forcePicQpB = forcePicQpIPB; encode_info.forcePicQpP = forcePicQpIPB; if (frame_rotation == 0) encode_info.frame_rotation = 0; else if (frame_rotation == 1) encode_info.frame_rotation = 90; else if (frame_rotation == 2) encode_info.frame_rotation = 180; else if (frame_rotation == 3) encode_info.frame_rotation = 270; else { printf("frame rotation angle is wrong\n"); encode_info.frame_rotation = 0; } if (frame_mirroring >= 0 && frame_mirroring <=3) encode_info.frame_mirroring = frame_mirroring; else encode_info.frame_mirroring = 0; if (intra_refresh_comb) { encode_info.intra_refresh_mode = intra_refresh_comb & 0xf; encode_info.intra_refresh_arg = intra_refresh_comb >> 4; } if (gop_pattern) { encode_info.enc_feature_opts |= ((gop_pattern<<2) & 0x7c); } if (bitstream_buf_size) { encode_info.bitstream_buf_sz = bitstream_buf_size; } if (multi_slice) { encode_info.multi_slice_mode = multi_slice; encode_info.multi_slice_arg = multi_slice_para; } if (cust_qp_delta) { encode_info.cust_gop_qp_delta = cust_qp_delta; } if (strict_rate_ctrl_en) { encode_info.strict_rc_window = bitrate_window; encode_info.strict_rc_skip_thresh = skip_threshold; } if (inbuf_info.buf_type == AML_DMA_TYPE) { dma_info = &(inbuf_info.buf_info.dma_info); dma_info->num_planes = num_planes; dma_info->shared_fd[0] = -1; // dma buf fd dma_info->shared_fd[1] = -1; dma_info->shared_fd[2] = -1; ret = create_ctx(&ctx); if (ret < 0) { printf("gdc create fail ret=%d\n", ret); goto exit; } if (dma_info->num_planes == 3) { if (fmt != AML_IMG_FMT_YUV420P) { printf("error fmt %d\n", fmt); goto exit; } ret = alloc_dma_buffer(&ctx, INPUT_BUFF_TYPE, ysize); if (ret < 0) { printf("alloc fail ret=%d, len=%u\n", ret, ysize); goto exit; } vaddr = (unsigned char *) ctx.i_buff[0]; if (!vaddr) { printf("mmap failed,Not enough memory\n"); goto exit; } printf("hoan debug canvas >> alloc_dma_buffer y,ret=%d, vaddr=0x%x\n", ret,vaddr); dma_info->shared_fd[0] = ret; input[0] = vaddr; ret = alloc_dma_buffer(&ctx, INPUT_BUFF_TYPE, usize); if (ret < 0) { printf("alloc fail ret=%d, len=%u\n", ret, usize); goto exit; } vaddr = (unsigned char *) ctx.i_buff[1]; if (!vaddr) { printf("mmap failed,Not enough memory\n"); goto exit; } dma_info->shared_fd[1] = ret; input[1] = vaddr; printf("hoan debug canvas >> alloc_dma_buffer u,ret=%d, vaddr=0x%x\n", ret,vaddr); ret = alloc_dma_buffer(&ctx, INPUT_BUFF_TYPE, vsize); if (ret < 0) { printf("alloc fail ret=%d, len=%u\n", ret, vsize); goto exit; } vaddr = (unsigned char *) ctx.i_buff[2]; if (!vaddr) { printf("mmap failed,Not enough memory\n"); goto exit; } dma_info->shared_fd[2] = ret; input[2] = vaddr; printf("hoan debug canvas >> alloc_dma_buffer v,ret=%d, vaddr=0x%x\n", ret,vaddr); } else if (dma_info->num_planes == 2) { ret = alloc_dma_buffer(&ctx, INPUT_BUFF_TYPE, ysize); if (ret < 0) { printf("alloc fail ret=%d, len=%u\n", ret, ysize); goto exit; } vaddr = (unsigned char *) ctx.i_buff[0]; if (!vaddr) { printf("mmap failed,Not enough memory\n"); goto exit; } dma_info->shared_fd[0] = ret; input[0] = vaddr; if (fmt != AML_IMG_FMT_NV12 && fmt != AML_IMG_FMT_NV21) { printf("error fmt %d\n", fmt); goto exit; } ret = alloc_dma_buffer(&ctx, INPUT_BUFF_TYPE, uvsize); if (ret < 0) { printf("alloc fail ret=%d, len=%u\n", ret, uvsize); goto exit; } vaddr = (unsigned char *) ctx.i_buff[1]; if (!vaddr) { printf("mmap failed,Not enough memory\n"); goto exit; } dma_info->shared_fd[1] = ret; input[1] = vaddr; } else if (dma_info->num_planes == 1) { ret = alloc_dma_buffer(&ctx, INPUT_BUFF_TYPE, framesize); if (ret < 0) { printf("alloc fail ret=%d, len=%u\n", ret, framesize); goto exit; } vaddr = (unsigned char *) ctx.i_buff[0]; if (!vaddr) { printf("mmap failed,Not enough memory\n"); goto exit; } dma_info->shared_fd[0] = ret; input[0] = vaddr; } printf("in[0] %d, in[1] %d, in[2] %d\n", dma_info->shared_fd[0], dma_info->shared_fd[1], dma_info->shared_fd[2]); printf("input[0] %p, input[1] %p,input[2] %p\n", input[0], input[1], input[2]); } else { inputBuffer = (unsigned char *) malloc(framesize); if (inputBuffer == NULL) { printf("Can not allocat inputBuffer\n"); goto exit; } inbuf_info.buf_info.in_ptr[0] = (ulong) (inputBuffer); inbuf_info.buf_info.in_ptr[1] = (ulong) (inputBuffer + ysize); inbuf_info.buf_info.in_ptr[2] = (ulong) (inputBuffer + ysize + usize); } fp = fopen((const char*)srcfile, "rb"); if (fp == NULL) { printf("open src file error!\n"); goto exit; } if (roi_enabled) { fp_roi = fopen((const char*)roifile, "rb"); if (fp_roi == NULL) { printf("open roi file error!\n"); goto exit; } } if (cfg_upd_enabled) { fp_cfg = fopen((const char*)cfg_file, "r"); if (fp_cfg == NULL) { printf("open cfg file error!\n"); goto exit; } has_cfg_update = ParseCfgUpdateFile(fp_cfg, &cfgChange); } outfd = open((const char*)outfile, O_CREAT | O_RDWR | O_TRUNC, 0644); if (outfd < 0) { printf("open dest file error!\n"); goto exit; } // init playState playStat.minQpI_base = 8; playStat.minQpP_base = 8; playStat.minQpB_base = 8; playStat.maxQpI_base = 51; playStat.maxQpP_base = 51; playStat.maxQpB_base = 51; playStat.maxDeltaQp_base = 10; playStat.PrevFrameQP = 30; if (encode_info.qp_mode) { playStat.minQpP_base = qp_tbl.qp_P_min; playStat.maxQpP_base = qp_tbl.qp_P_max; playStat.minQpI_base = qp_tbl.qp_I_min; playStat.maxQpI_base = qp_tbl.qp_I_max; playStat.maxDeltaQp_base = qp_tbl.qp_I_max - qp_tbl.qp_I_min; playStat.PrevFrameQP = qp_tbl.qp_I_base; } playStat.CurGOPSize = encode_info.gop; playStat.qp_ltr = -1; playStat.qp_idr = -1; memset(&frame_info, 0, sizeof(frame_info)); frame_info.frame_size = framesize; frame_info.pitch = width; frame_info.height = height; //frame_info.coding_timestamp = 0; //frame_info.canvas = 0; //frame_info.scale_width = 0; //frame_info.scale_height = 0; //frame_info.crop_left = 0; //frame_info.crop_right = 0; //frame_info.crop_top = 0; //frame_info.crop_bottom = 0; frame_info.bitrate = bitrate; frame_info.frame_rate = framerate; retry: cfg_encode->handle_enc = amvenc_init(codec_id, encode_info, &qp_tbl); if (cfg_encode->handle_enc == 0) { if ( retry_cnt >= INIT_RETRY) { printf("Init encoder retry timeout\n"); goto exit; } else { printf("Init encoder fail retrying \n"); retry_cnt ++; usleep(100*1000); goto retry; } } gettimeofday(&timeStart, NULL); while (num > 0) { gettimeofday(&readStart, NULL); if (conver_stride) { // exmaple of covert normal with stride to cust stride int line; unsigned char *dst; /* y */ if (inbuf_info.buf_type == AML_DMA_TYPE) dst = input[0]; else dst = inputBuffer; memset(dst, 0, ysize); for (line = 0; line < height; line++) { if (fread(dst, 1, width, fp) != width) { printf("read input file error!\n"); goto exit; } dst += src_buf_stride; } if (inbuf_info.buf_type == AML_DMA_TYPE && dma_info->num_planes > 1) dst = input[1]; if (fmt != AML_IMG_FMT_YUV420P) { //nv12 or nv21 memset(dst, 0, uvsize); for (line = 0; line < height / 2; line++) { if (fread(dst, 1, width, fp) != width) { printf("read input file error!\n"); goto exit; } dst += src_buf_stride; } } else { // YUV420p separated memset(dst, 0, usize); for (line = 0; line < height / 2; line++) { if (fread(dst, 1, width / 2, fp) != width / 2) { printf("read input file error!\n"); goto exit; } dst += (src_buf_stride / 2); } if (inbuf_info.buf_type == AML_DMA_TYPE && dma_info->num_planes ==3) dst = input[2]; memset(dst, 0, vsize); for (line = 0; line < height / 2; line++) { if (fread(dst, 1, width / 2, fp) != width / 2) { printf("read input file error!\n"); goto exit; } dst += (src_buf_stride / 2); } } } else if (inbuf_info.buf_type == AML_DMA_TYPE) { // read data to dma buf vaddr if (dma_info->num_planes == 1) { if (fread(input[0], 1, framesize, fp) != framesize) { printf("read input file error!\n"); goto exit; } } else if (dma_info->num_planes == 2) { if (fread(input[0], 1, ysize, fp) != ysize) { printf("read input file error!\n"); goto exit; } if (fread(input[1], 1, uvsize, fp) != uvsize) { printf("read input file error!\n"); goto exit; } } else if (dma_info->num_planes == 3) { if (fread(input[0], 1, ysize, fp) != ysize) { printf("read input file error!\n"); goto exit; } if (fread(input[1], 1, usize, fp) != usize) { printf("read input file error!\n"); goto exit; } if (fread(input[2], 1, vsize, fp) != vsize) { printf("read input file error!\n"); goto exit; } } } else { // read data to vmalloc buf vaddr if (fread(inputBuffer, 1, framesize, fp) != framesize) { printf("read input file error!\n"); goto exit; } } memset(outbuffer, 0, outbuffer_len); if (inbuf_info.buf_type == AML_DMA_TYPE) { sync_cpu(&ctx); } enc_frame_type = AML_FRAME_TYPE_AUTO; gettimeofday(&readEnd, NULL); ioTime += uTimeDiff(readEnd, readStart); gettimeofday(&cfg_encode->timeFrameStart, NULL); if (cfg_upd_enabled && has_cfg_update) { if (cfgChange.FrameNum == frame_num) { // apply updates if (cfgChange.enable_option & FORCE_PICTURE_TYPE) { if (cfgChange.picType == AML_FRAME_TYPE_IDR || cfgChange.picType == AML_FRAME_TYPE_I) { enc_frame_type = AML_FRAME_TYPE_I; printf("force I frame on %d \n", frame_num); } } if (cfgChange.enable_option & CHANGE_TARGET_RATE) { amvenc_change_bitrate( cfg_encode->handle_enc, cfgChange.bitRate); printf("Change bitrate to %d on %d \n", cfgChange.bitRate, frame_num); } } if (cfgChange.FrameNum <= frame_num) { has_cfg_update = ParseCfgUpdateFile(fp_cfg, &cfgChange); } } encoding_metadata = amvenc_encode(cfg_encode->handle_enc, frame_info, enc_frame_type, outbuffer, &inbuf_info, &ret_buf); gettimeofday(&writeStart, NULL); if (encoding_metadata.is_valid) { write(outfd, (unsigned char *) outbuffer, encoding_metadata.encoded_data_length_in_bytes); } else { printf("encode error %d!\n", encoding_metadata.encoded_data_length_in_bytes); } gettimeofday(&writeEnd, NULL); frameWriteTime = uTimeDiff(writeEnd, writeStart); ioTime += frameWriteTime; gettimeofday(&cfg_encode->timeFrameEnd, NULL); //printf("=== Time(us %u HW+SW) ===\n", //uTimeDiff(cfg_encode->timeFrameEnd, cfg_encode->timeFrameStart) - frameWriteTime); num--; frame_num++; playStat.PrevFrameQP = encoding_metadata.extra.average_qp_value; playStat.CurFrameNum++; playStat.CurGOPCounter++; if (playStat.cust_ltr_enable) { playStat.GopLTRCounter++; } } gettimeofday(&timeEnd, NULL); totalTime = uTimeDiffLL(timeEnd, timeStart); printf("[Total time: %llu us], [IO time: %llu us]\n", totalTime, ioTime); if (frame_num > 1) { printf("[Encode Total time: %llu us], [avgTime: %llu us], [avgfps: %d]\n", totalTime - ioTime, (totalTime - ioTime) / frame_num, 1*1000*1000/((totalTime - ioTime) / frame_num)); } exit: if (cfg_encode->handle_enc) amvenc_destroy(cfg_encode->handle_enc); if (outfd >= 0) close(outfd); if (fp) fclose(fp); if (fp_roi) fclose(fp_roi); if (fp_cfg) fclose(fp_cfg); if (outbuffer != NULL) free(outbuffer); if (roi_buffer != NULL) free(roi_buffer); if (inbuf_info.buf_type == AML_DMA_TYPE) { if (dma_info->shared_fd[0] >= 0) close(dma_info->shared_fd[0]); if (dma_info->shared_fd[1] >= 0) close(dma_info->shared_fd[1]); if (dma_info->shared_fd[2] >= 0) close(dma_info->shared_fd[2]); destroy_ctx(&ctx); } else { if (inputBuffer) free(inputBuffer); } printf("Encode End!width:%d\n",width); end: cfg_encode->encodeEnd = 1; pthread_exit(0); return NULL; } static char*mystrncpy(char* dest, const char* src, int len) { assert(dest != NULL && src != NULL); char* temp = dest; int i=0; //while (i++ < len && (*temp++ = *src++) != '\0') {} while (i++ < len && (*temp = *src) != '\n' && (*temp++ = *src++) != '\0') {} if (*(temp) != '\0') *temp = '\0'; return dest; } static int ParseEncodeCfgFile(FILE *fp, encodecCfgParam *cfg_encode) { char* token = NULL; char *delim = " "; static char lineStr[ENCODER_STRING_LEN_MAX*4] = {0}; char valueStr[ENCODER_STRING_LEN_MAX] = {0}; int i = 0; int len = 0; while (1) { if (i >= CFG_ENCODE_NUM_MAX) return 0; if (lineStr[0] == 0x0) { //need a new line; if (fgets(lineStr, ENCODER_STRING_LEN_MAX*4, fp) == NULL) { if (feof(fp)) return 0; continue; } } if (strlen(lineStr) == 1) { // skip null lineStr[0] = 0x0; continue; } if ((lineStr[0] == '#') ||(lineStr[0] == ';')||(lineStr[0] == ':')) { // skip comments lineStr[0] = 0x0; continue; } //printf("[%s][%d]:%s\n",__func__,__LINE__,lineStr); // keep the original memcpy(valueStr, lineStr, strlen(lineStr)); //param is separated by ' ' token = strtok(valueStr, delim); if (token == NULL) { lineStr[0] = 0x0; continue; } token = strtok(NULL, delim); if (token == NULL) { lineStr[0] = 0x0; continue; } len = strlen(token) > ENCODER_STRING_LEN_MAX ? ENCODER_STRING_LEN_MAX : strlen(token); mystrncpy(cfg_encode[i].srcfile, token, len); token = strtok(NULL, delim); if (token == NULL) { lineStr[0] = 0x0; continue; } len = strlen(token) > ENCODER_STRING_LEN_MAX ? ENCODER_STRING_LEN_MAX : strlen(token); mystrncpy(cfg_encode[i].outfile, token, len); token = strtok(NULL, delim); if (token == NULL) { lineStr[0] = 0x0; continue; } cfg_encode[i].width = atoi(token); token = strtok(NULL, delim); if (token == NULL) { lineStr[0] = 0x0; continue; } cfg_encode[i].height = atoi(token); token = strtok(NULL, delim); if (token == NULL) { lineStr[0] = 0x0; continue; } cfg_encode[i].gop = atoi(token); token = strtok(NULL, delim); if (token == NULL) { lineStr[0] = 0x0; continue; } cfg_encode[i].framerate = atoi(token); token = strtok(NULL, delim); if (token == NULL) { lineStr[0] = 0x0; continue; } cfg_encode[i].bitrate = atoi(token); token = strtok(NULL, delim); if (token == NULL) { lineStr[0] = 0x0; continue; } cfg_encode[i].num = atoi(token); token = strtok(NULL, delim); if (token == NULL) { lineStr[0] = 0x0; continue; } cfg_encode[i].fmt = atoi(token); token = strtok(NULL, delim); if (token == NULL) { lineStr[0] = 0x0; continue; } cfg_encode[i].buf_type = atoi(token); token = strtok(NULL, delim); if (token == NULL) { lineStr[0] = 0x0; continue; } cfg_encode[i].num_planes = atoi(token); token = strtok(NULL, delim); if (token == NULL) { lineStr[0] = 0x0; continue; } cfg_encode[i].codec_id = atoi(token); token = strtok(NULL, delim);//cfg_opt optional if (token == NULL) { i++; cfg_encode[0].seqNum++; lineStr[0] = 0x0; continue; } cfg_encode[i].cfg_opt = atoi(token); token = strtok(NULL, delim); if (token == NULL) { i++; cfg_encode[0].seqNum++; lineStr[0] = 0x0; continue; } if ((cfg_encode[i].cfg_opt & 0x1) == 0x1) { len = strlen(token) > ENCODER_STRING_LEN_MAX ? ENCODER_STRING_LEN_MAX : strlen(token); mystrncpy(cfg_encode[i].roifile, token, len); printf("roi_url is\t: %s ;\n", cfg_encode[i].roifile); token = strtok(NULL, delim); if (token == NULL) { i++; cfg_encode[0].seqNum++; lineStr[0] = 0x0; continue; } } if ((cfg_encode[i].cfg_opt & 0x2) == 0x2) { len = strlen(token) > ENCODER_STRING_LEN_MAX ? ENCODER_STRING_LEN_MAX : strlen(token); mystrncpy(cfg_encode[i].cfg_file, token, len); printf("cfg_upd_url[%d] is\t: %s ;\n", i, cfg_encode[i].cfg_file); token = strtok(NULL, delim); if (token == NULL) { i++; cfg_encode[0].seqNum++; lineStr[0] = 0x0; continue; } } if ((cfg_encode[i].cfg_opt & 0x100) == 0x100) { cfg_encode[i].src_buf_stride = atoi(token); token = strtok(NULL, delim); if (token == NULL) { i++; cfg_encode[0].seqNum++; lineStr[0] = 0x0; continue; } } if ((cfg_encode[i].cfg_opt & 0x400) == 0x400) { cfg_encode[i].intraRefresh = atoi(token); printf("IntraRefresh mode %d, arg %d;\n", (cfg_encode[i].intraRefresh & 0xf), (cfg_encode[i].intraRefresh >> 4)); token = strtok(NULL, delim); if (token == NULL) { i++; cfg_encode[0].seqNum++; lineStr[0] = 0x0; continue; } } if ((cfg_encode[i].cfg_opt & 0x40000) == 0x40000) { cfg_encode[i].bitStreamBuf = atoi(token); printf("bitstream_buf_size: %d \n", cfg_encode[i].bitStreamBuf); token = strtok(NULL, delim); if (token == NULL) { i++; cfg_encode[0].seqNum++; lineStr[0] = 0x0; continue; } } if ((cfg_encode[i].cfg_opt >> 19) & 0x3) { cfg_encode[i].MultiSlice_parameter = atoi(token); printf("Multi-slices para %d \n", cfg_encode[i].MultiSlice_parameter); token = strtok(NULL, delim); if (token == NULL) { i++; cfg_encode[0].seqNum++; lineStr[0] = 0x0; continue; } } if ((cfg_encode[i].cfg_opt >> 21) & 0x1) { cfg_encode[i].cust_qp_delta = atoi(token); printf("cust_qp_delta %d \n", cfg_encode[i].cust_qp_delta); token = strtok(NULL, delim); if (token == NULL) { i++; cfg_encode[0].seqNum++; lineStr[0] = 0x0; continue; } } if ((cfg_encode[i].cfg_opt >> 22) & 0x1) { cfg_encode[i].strict_rate_control_parmeter = atoi(token); printf("strict_rate_control_parmeter %d\n", cfg_encode[i].strict_rate_control_parmeter); printf("bit-rate window %d frames, skip_threshold %d\n", cfg_encode[i].strict_rate_control_parmeter>>16, cfg_encode[i].strict_rate_control_parmeter& 0xffff); token = strtok(NULL, delim); if (token == NULL) { i++; cfg_encode[0].seqNum++; lineStr[0] = 0x0; continue; } } if ((cfg_encode[i].cfg_opt >> 23) & 0x1) { cfg_encode[i].forcePicQpIPB = atoi(token); printf("forcePicQpIPB %d\n", cfg_encode[i].forcePicQpIPB); } token = strtok(NULL, delim); if (token == NULL) { i++; cfg_encode[0].seqNum++; lineStr[0] = 0x0; continue; } else { //config no match printf("config no match conf %d command: %s\n", cfg_encode[i].cfg_opt, lineStr); lineStr[0] = 0x0; continue; } } return 0; } static int ParseCfgUpdateFile(FILE *fp, CfgChangeParam *cfg_update) { int parsed_num = 0, frameIdx = 0; char* token = NULL; static char lineStr[256] = {0, }; char valueStr[256] = {0, }; int has_update = 0; while (1) { if (lineStr[0] == 0x0) { //need a new line; if (fgets(lineStr, 256, fp) == NULL ) { if (cfg_update->enable_option && has_update) return 1; else { if (feof(fp)) return 0; continue; } } } if ((lineStr[0] == '#') ||(lineStr[0] == ';')||(lineStr[0] == ':')) { // skip comments lineStr[0] = 0x0; continue; } // keep the original memcpy(valueStr, lineStr, strlen(lineStr)); //frame number is separated by ' ' or ':' token = strtok(valueStr, ": "); if (token == NULL) { lineStr[0] = 0x0; continue; } frameIdx = atoi(token); if (frameIdx <0 || frameIdx < cfg_update->FrameNum) { // invid number lineStr[0] = 0x0; continue; } else if (frameIdx > cfg_update->FrameNum && has_update) {// done the currrent frame; if (cfg_update->enable_option) return 1; has_update = 0; continue; } else if (has_update ==0) {// clear the options cfg_update->FrameNum = frameIdx; cfg_update->enable_option = 0; has_update = 1; } token = strtok(NULL, " :"); // check the operation code while (token && strlen(token) == 1 && strncmp(token, " ", 1) == 0) token = strtok(NULL, " :"); // skip spaces if (token == NULL) { // no operate code lineStr[0] = 0x0; continue; } if (strcasecmp("ForceType",token) == 0) { // force picture type token = strtok(NULL, ":\r\n"); while (token && strlen(token) == 1 && strncmp(token, " ", 1) == 0) token = strtok(NULL, ":\r\n"); //check space if (token) { while ( *token == ' ' ) token++;//skip spaces; cfg_update->picType = atoi(token); cfg_update->enable_option |= FORCE_PICTURE_TYPE; } } else if (strcasecmp("ForceSkip",token) == 0) { // force picture type if (token) { cfg_update->enable_option |= FORCE_PICTURE_SKIP; } } else if (strcasecmp("ChangeBitRate",token) == 0) { token = strtok(NULL, ":\r\n"); while ( token && strlen(token) == 1 && strncmp(token, " ", 1) == 0) token = strtok(NULL, ":\r\n"); //check space if (token) { while ( *token == ' ' ) token++;//skip spaces; cfg_update->bitRate = atoi(token); cfg_update->enable_option |= CHANGE_TARGET_RATE; } } else if (strcasecmp("ChangeMinMaxQP",token) == 0) { token = strtok(NULL, ":\r\n"); while (token && strlen(token) == 1 && strncmp(token, " ", 1) == 0) token = strtok(NULL, ":\r\n"); //check space if (token) { while ( *token == ' ' ) token++;//skip spaces; parsed_num = sscanf(token, "%d %d %d %d %d %d %d", &cfg_update->minQpI, &cfg_update->maxQpI, &cfg_update->maxDeltaQp, &cfg_update->minQpP, &cfg_update->maxQpP, &cfg_update->minQpB, &cfg_update->maxQpB); if (parsed_num == 7) cfg_update->enable_option |= CHANGE_MIN_MAX_QP; } } else if (strcasecmp("ChangePeriodGOP",token) == 0) { token = strtok(NULL, ":\r\n"); while ( token && strlen(token) == 1 && strncmp(token, " ", 1) == 0) token = strtok(NULL, ":\r\n"); //check space if (token) { while ( *token == ' ' ) token++;//skip spaces; parsed_num = sscanf(token, "%d %d", &cfg_update->intraQP, &cfg_update->GOPPeriod); if (parsed_num == 2) cfg_update->enable_option |= CHANGE_GOP_PERIOD; } } else if (strcasecmp("SetLongTermRef",token) == 0) { token = strtok(NULL, ":\r\n"); while ( token && strlen(token) == 1 && strncmp(token, " ", 1) == 0) token = strtok(NULL, ":\r\n"); //check space if (token) { while ( *token == ' ' ) token++;//skip spaces; cfg_update->LTRFlags = atoi(token); cfg_update->enable_option |= LONGTERM_REF_SET; } } else if (strcasecmp("SetCustSmooth",token) == 0) { token = strtok(NULL, ":\r\n"); while ( token && strlen(token) == 1 && strncmp(token, " ", 1) == 0) token = strtok(NULL, ":\r\n"); //check space if (token) { while ( *token == ' ' ) token++;//skip spaces; cfg_update->smooth_level = atoi(token); cfg_update->enable_option |= CUST_SIZE_SMOOTH; } } else if (strcasecmp("SetCustH264P",token) == 0) { token = strtok(NULL, ":\r\n"); while ( token && strlen(token) == 1 && strncmp(token, " ", 1) == 0) token = strtok(NULL, ":\r\n"); //check space if (token) { while ( *token == ' ' ) token++;//skip spaces; parsed_num = sscanf(token, "%d %d %d", &cfg_update->newIDRInterval, &cfg_update->QPdelta_IDR, &cfg_update->QPdelta_LTR); if (parsed_num == 3) cfg_update->enable_option |= CUST_APP_H264_PLUS; } } else if (strcasecmp("ChangeMultiSlice",token) == 0) { token = strtok(NULL, ":\r\n"); while ( token && strlen(token) == 1 && strncmp(token, " ", 1) == 0) token = strtok(NULL, ":\r\n"); //check space if (token) { while ( *token == ' ' ) token++;//skip spaces; parsed_num = sscanf(token, "%d %d", &cfg_update->Slice_Mode, &cfg_update->Slice_Para); if (parsed_num == 2) cfg_update->enable_option |= CHANGE_MULTI_SLICE; } } else if (strcasecmp("ChangeStrictRC",token) == 0) { token = strtok(NULL, ":\r\n"); while ( token && strlen(token) == 1 && strncmp(token, " ", 1) == 0) token = strtok(NULL, ":\r\n"); //check space if (token) { while ( *token == ' ' ) token++;//skip spaces; parsed_num = sscanf(token, "%d %d", &cfg_update->bitrate_window, &cfg_update->pskip_threshold); if (parsed_num == 2) cfg_update->enable_option |= CHANGE_STRICT_RC; } } lineStr[0] = 0x0; continue; } }