| /** |
| * Copyright (C) 2019 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| #define _GNU_SOURCE |
| #include <sys/types.h> |
| #include <sys/wait.h> |
| #include <sys/time.h> |
| #include <stdlib.h> |
| #include "ihevc_typedefs.h" |
| #include "ihevcd_cxa.h" |
| |
| #define TOTAL_BUF_LEN (1280 * 720 * 3 / 2) |
| #define BUF_LEN_0 (1280 * 720) |
| #define BUF_LEN_1 (1280 * 720 / 2) |
| |
| FILE *ps_ip_file = NULL; |
| UWORD8 *pu1_bs_buf = NULL; |
| ivd_out_bufdesc_t *ps_out_buf = NULL; |
| |
| #define EXIT_ON_ERROR(status) \ |
| {\ |
| if (IV_SUCCESS != status) {\ |
| if(ps_ip_file)\ |
| fclose(ps_ip_file);\ |
| \ |
| if(ps_out_buf) { \ |
| if(ps_out_buf->pu1_bufs[0]) {\ |
| free(ps_out_buf->pu1_bufs[0]);\ |
| }\ |
| free(ps_out_buf);\ |
| }\ |
| \ |
| if(pu1_bs_buf)\ |
| free (pu1_bs_buf);\ |
| \ |
| exit(EXIT_SUCCESS);\ |
| }\ |
| } |
| |
| void * ihevca_aligned_malloc(void *pv_ctxt, WORD32 alignment, WORD32 i4_size) { |
| (void) pv_ctxt; |
| return memalign(alignment, i4_size); |
| } |
| |
| void ihevca_aligned_free(void *pv_ctxt, void *pv_buf) { |
| (void) pv_ctxt; |
| free(pv_buf); |
| return; |
| } |
| |
| void flush_output(iv_obj_t *codec_obj, ivd_out_bufdesc_t *ps_out_buf, |
| UWORD8 *pu1_bs_buf, UWORD32 *pu4_op_frm_ts, |
| UWORD32 u4_ip_frm_ts, UWORD32 u4_bytes_remaining) { |
| WORD32 ret; |
| |
| do { |
| ivd_ctl_flush_ip_t s_ctl_ip; |
| ivd_ctl_flush_op_t s_ctl_op; |
| |
| if (*pu4_op_frm_ts >= (10000)) |
| break; |
| |
| s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL; |
| s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_FLUSH; |
| s_ctl_ip.u4_size = sizeof(ivd_ctl_flush_ip_t); |
| s_ctl_op.u4_size = sizeof(ivd_ctl_flush_op_t); |
| ret = ihevcd_cxa_api_function((iv_obj_t *) codec_obj, |
| (void *) &s_ctl_ip, (void *) &s_ctl_op); |
| |
| if (IV_SUCCESS == ret) { |
| ivd_video_decode_ip_t s_video_decode_ip; |
| ivd_video_decode_op_t s_video_decode_op; |
| |
| s_video_decode_ip.e_cmd = IVD_CMD_VIDEO_DECODE; |
| s_video_decode_ip.u4_ts = u4_ip_frm_ts; |
| s_video_decode_ip.pv_stream_buffer = pu1_bs_buf; |
| s_video_decode_ip.u4_num_Bytes = u4_bytes_remaining; |
| s_video_decode_ip.u4_size = sizeof(ivd_video_decode_ip_t); |
| s_video_decode_ip.s_out_buffer.u4_min_out_buf_size[0] = BUF_LEN_0; |
| s_video_decode_ip.s_out_buffer.u4_min_out_buf_size[1] = BUF_LEN_1; |
| s_video_decode_ip.s_out_buffer.u4_min_out_buf_size[2] = 0; |
| s_video_decode_ip.s_out_buffer.pu1_bufs[0] = |
| ps_out_buf->pu1_bufs[0]; |
| s_video_decode_ip.s_out_buffer.pu1_bufs[1] = |
| ps_out_buf->pu1_bufs[1]; |
| s_video_decode_ip.s_out_buffer.pu1_bufs[2] = NULL; |
| s_video_decode_ip.s_out_buffer.u4_num_bufs = 2; |
| s_video_decode_op.u4_size = sizeof(ivd_video_decode_op_t); |
| |
| ret = ihevcd_cxa_api_function((iv_obj_t *) codec_obj, |
| (void *) &s_video_decode_ip, |
| (void *) &s_video_decode_op); |
| |
| if (1 == s_video_decode_op.u4_output_present) { |
| (*pu4_op_frm_ts)++; |
| } |
| } |
| } while (IV_SUCCESS == ret); |
| } |
| |
| int main(WORD32 argc, CHAR *argv[]) { |
| WORD32 ret = 0; |
| UWORD32 file_pos = 0; |
| UWORD32 u4_ip_frm_ts = 0, u4_op_frm_ts = 0; |
| WORD32 u4_bytes_remaining = 0; |
| iv_obj_t *codec_obj = NULL; |
| |
| if (argc < 2) { |
| return EXIT_SUCCESS; |
| } |
| ps_ip_file = fopen(argv[1], "rb"); |
| if (NULL == ps_ip_file) { |
| return EXIT_SUCCESS; |
| } |
| |
| /* Allocate input and output buffers for IV_YUV_420SP_UV */ |
| { |
| pu1_bs_buf = (UWORD8 *) malloc(TOTAL_BUF_LEN); |
| ps_out_buf = (ivd_out_bufdesc_t *) malloc(sizeof(ivd_out_bufdesc_t)); |
| if ((pu1_bs_buf == NULL) || (ps_out_buf == NULL)) { |
| EXIT_ON_ERROR(IV_FAIL) |
| } |
| ps_out_buf->pu1_bufs[0] = (UWORD8 *) malloc(TOTAL_BUF_LEN); |
| if (ps_out_buf->pu1_bufs[0] == NULL) { |
| EXIT_ON_ERROR(IV_FAIL) |
| } |
| memset(pu1_bs_buf, 0, TOTAL_BUF_LEN); |
| |
| ps_out_buf->pu1_bufs[1] = ps_out_buf->pu1_bufs[0] + BUF_LEN_0; |
| } |
| |
| /* Create decoder instance */ |
| { |
| ihevcd_cxa_create_ip_t s_create_ip; |
| ihevcd_cxa_create_op_t s_create_op; |
| memset(&s_create_ip, 0, sizeof(ihevcd_cxa_create_ip_t)); |
| memset(&s_create_op, 0, sizeof(ihevcd_cxa_create_op_t)); |
| |
| void *fxns = &ihevcd_cxa_api_function; |
| s_create_ip.s_ivd_create_ip_t.e_cmd = IVD_CMD_CREATE; |
| s_create_ip.s_ivd_create_ip_t.e_output_format = IV_YUV_420SP_UV; |
| s_create_ip.s_ivd_create_ip_t.pf_aligned_alloc = ihevca_aligned_malloc; |
| s_create_ip.s_ivd_create_ip_t.pf_aligned_free = ihevca_aligned_free; |
| s_create_ip.s_ivd_create_ip_t.u4_size = sizeof(ihevcd_cxa_create_ip_t); |
| s_create_op.s_ivd_create_op_t.u4_size = sizeof(ihevcd_cxa_create_op_t); |
| |
| ret = ihevcd_cxa_api_function(NULL, (void *) &s_create_ip, |
| (void *) &s_create_op); |
| EXIT_ON_ERROR(ret); |
| |
| codec_obj = (iv_obj_t*) s_create_op.s_ivd_create_op_t.pv_handle; |
| codec_obj->pv_fxns = fxns; |
| codec_obj->u4_size = sizeof(iv_obj_t); |
| } |
| |
| /* set num of cores */ |
| { |
| ihevcd_cxa_ctl_set_num_cores_ip_t s_ctl_set_cores_ip; |
| ihevcd_cxa_ctl_set_num_cores_op_t s_ctl_set_cores_op; |
| |
| s_ctl_set_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL; |
| s_ctl_set_cores_ip.e_sub_cmd = |
| (IVD_CONTROL_API_COMMAND_TYPE_T) IHEVCD_CXA_CMD_CTL_SET_NUM_CORES; |
| s_ctl_set_cores_ip.u4_num_cores = 1; |
| s_ctl_set_cores_ip.u4_size = sizeof(ihevcd_cxa_ctl_set_num_cores_ip_t); |
| s_ctl_set_cores_op.u4_size = sizeof(ihevcd_cxa_ctl_set_num_cores_op_t); |
| |
| ret = ihevcd_cxa_api_function((iv_obj_t *) codec_obj, |
| (void *) &s_ctl_set_cores_ip, |
| (void *) &s_ctl_set_cores_op); |
| EXIT_ON_ERROR(ret); |
| } |
| |
| /* Set the decoder in frame decode mode */ |
| { |
| ivd_ctl_set_config_ip_t s_ctl_ip; |
| ivd_ctl_set_config_op_t s_ctl_op; |
| |
| s_ctl_ip.u4_disp_wd = 0; |
| s_ctl_ip.e_frm_skip_mode = IVD_SKIP_NONE; |
| s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT; |
| s_ctl_ip.e_vid_dec_mode = IVD_DECODE_FRAME; |
| s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL; |
| s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS; |
| s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t); |
| s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t); |
| |
| ret = ihevcd_cxa_api_function((iv_obj_t *) codec_obj, |
| (void *) &s_ctl_ip, (void *) &s_ctl_op); |
| EXIT_ON_ERROR(ret); |
| } |
| |
| while ((u4_bytes_remaining = fread(pu1_bs_buf, sizeof(UWORD8), |
| TOTAL_BUF_LEN, ps_ip_file))) { |
| { |
| ivd_video_decode_ip_t s_video_decode_ip; |
| ivd_video_decode_op_t s_video_decode_op; |
| |
| s_video_decode_ip.e_cmd = IVD_CMD_VIDEO_DECODE; |
| s_video_decode_ip.u4_ts = u4_ip_frm_ts; |
| s_video_decode_ip.pv_stream_buffer = pu1_bs_buf; |
| s_video_decode_ip.u4_num_Bytes = TOTAL_BUF_LEN; |
| s_video_decode_ip.u4_size = sizeof(ivd_video_decode_ip_t); |
| s_video_decode_ip.s_out_buffer.u4_min_out_buf_size[0] = BUF_LEN_0; |
| s_video_decode_ip.s_out_buffer.u4_min_out_buf_size[1] = BUF_LEN_1; |
| s_video_decode_ip.s_out_buffer.u4_min_out_buf_size[2] = 0; |
| s_video_decode_ip.s_out_buffer.pu1_bufs[0] = |
| ps_out_buf->pu1_bufs[0]; |
| s_video_decode_ip.s_out_buffer.pu1_bufs[1] = |
| ps_out_buf->pu1_bufs[1]; |
| s_video_decode_ip.s_out_buffer.pu1_bufs[2] = NULL; |
| s_video_decode_ip.s_out_buffer.u4_num_bufs = 2; |
| s_video_decode_op.u4_size = sizeof(ivd_video_decode_op_t); |
| |
| /* API Call: Video Decode */ |
| ret = ihevcd_cxa_api_function((iv_obj_t *) codec_obj, |
| (void *) &s_video_decode_ip, |
| (void *) &s_video_decode_op); |
| |
| if ((IV_SUCCESS != ret) |
| && ((s_video_decode_op.u4_error_code & 0xFF) |
| == IVD_RES_CHANGED)) { |
| ivd_ctl_reset_ip_t s_ctl_ip; |
| ivd_ctl_reset_op_t s_ctl_op; |
| |
| flush_output(codec_obj, ps_out_buf, pu1_bs_buf, &u4_op_frm_ts, |
| u4_ip_frm_ts, u4_bytes_remaining); |
| |
| s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL; |
| s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_RESET; |
| s_ctl_ip.u4_size = sizeof(ivd_ctl_reset_ip_t); |
| s_ctl_op.u4_size = sizeof(ivd_ctl_reset_op_t); |
| |
| ret = ihevcd_cxa_api_function((iv_obj_t *) codec_obj, |
| (void *) &s_ctl_ip, |
| (void *) &s_ctl_op); |
| EXIT_ON_ERROR(ret); |
| |
| /* set num of cores */ |
| { |
| ihevcd_cxa_ctl_set_num_cores_ip_t s_ctl_set_cores_ip; |
| ihevcd_cxa_ctl_set_num_cores_op_t s_ctl_set_cores_op; |
| |
| s_ctl_set_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL; |
| s_ctl_set_cores_ip.e_sub_cmd = |
| (IVD_CONTROL_API_COMMAND_TYPE_T) IHEVCD_CXA_CMD_CTL_SET_NUM_CORES; |
| s_ctl_set_cores_ip.u4_num_cores = 1; |
| s_ctl_set_cores_ip.u4_size = |
| sizeof(ihevcd_cxa_ctl_set_num_cores_ip_t); |
| s_ctl_set_cores_op.u4_size = |
| sizeof(ihevcd_cxa_ctl_set_num_cores_op_t); |
| |
| ret = ihevcd_cxa_api_function((iv_obj_t *) codec_obj, |
| (void *) &s_ctl_set_cores_ip, |
| (void *) &s_ctl_set_cores_op); |
| EXIT_ON_ERROR(ret); |
| } |
| } |
| file_pos += s_video_decode_op.u4_num_bytes_consumed; |
| fseek(ps_ip_file, file_pos, SEEK_SET); |
| u4_ip_frm_ts++; |
| |
| if (1 == s_video_decode_op.u4_output_present) { |
| u4_op_frm_ts++; |
| } else { |
| if ((s_video_decode_op.u4_error_code >> IVD_FATALERROR) & 1) { |
| break; |
| } |
| } |
| } |
| } |
| |
| /* To get the last decoded frames, call process with NULL input */ |
| flush_output(codec_obj, ps_out_buf, pu1_bs_buf, &u4_op_frm_ts, u4_ip_frm_ts, |
| u4_bytes_remaining); |
| |
| /* Delete decoder and close all the files and free all the memory */ |
| { |
| ivd_delete_ip_t s_delete_dec_ip; |
| ivd_delete_op_t s_delete_dec_op; |
| |
| s_delete_dec_ip.e_cmd = IVD_CMD_DELETE; |
| s_delete_dec_ip.u4_size = sizeof(ivd_delete_ip_t); |
| s_delete_dec_op.u4_size = sizeof(ivd_delete_op_t); |
| |
| ret = ihevcd_cxa_api_function((iv_obj_t *) codec_obj, |
| (void *) &s_delete_dec_ip, |
| (void *) &s_delete_dec_op); |
| |
| EXIT_ON_ERROR(ret); |
| } |
| return EXIT_SUCCESS; |
| } |