blob: 57998c562ad39cdda332fa99782d327f0b42c27c [file] [log] [blame]
/**
* Copyright (C) 2020 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 "iv_datatypedef.h"
#include "iv.h"
#include "ivd.h"
#include "impeg2d.h"
typedef struct timeval TIMER;
#define GETTIME(timer) gettimeofday(timer,NULL);
#define ELAPSEDTIME(s_start_timer,s_end_timer, s_elapsed_time) \
s_elapsed_time = (s_end_timer.tv_sec - s_start_timer.tv_sec);
#define MAX_FRAME_WIDTH 2560
#define MAX_FRAME_HEIGHT 1600
#define NEW_FILE_LEN 2095752
FILE *ps_inarg_file = NULL;
FILE *ps_ip_file = NULL;
UWORD8 *pu1_bs_buf = NULL;
UWORD8 *buffer = NULL;
ivd_out_bufdesc_t *ps_out_buf = NULL;
#define WAIT_TIMEOUT (8 * 60)
void free_resources() {
if (ps_inarg_file) {
fclose(ps_inarg_file);
}
if (ps_ip_file) {
fclose(ps_ip_file);
}
if (buffer) {
free(buffer);
}
if (pu1_bs_buf) {
free(pu1_bs_buf);
}
if (ps_out_buf) {
if (ps_out_buf->pu1_bufs[0]) {
free(ps_out_buf->pu1_bufs[0]);
}
free(ps_out_buf);
}
}
void exit_on_error(WORD32 status) {
if (status != IV_SUCCESS) {
free_resources();
exit (EXIT_FAILURE);
}
}
void * app_aligned_malloc(WORD32 alignment, WORD32 i4_size) {
return memalign(alignment, i4_size);
}
void app_aligned_free(void *pv_buf) {
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 = impeg2d_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] =
(MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT);
s_video_decode_ip.s_out_buffer.u4_min_out_buf_size[1] =
((MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT) / 2);
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 = impeg2d_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;
UWORD32 u4_ip_buf_len = 0;
UWORD32 s_elapsed_time = 0;
UWORD32 u4_num_mem_recs = 0;
UWORD32 i = 0;
UWORD32 u4_inarg_file_size = 0;
iv_obj_t *codec_obj = NULL;
void *pv_mem_rec_location = NULL;
TIMER s_start_timer;
TIMER s_end_timer;
GETTIME(&s_start_timer);
if (argc < 2) {
return EXIT_FAILURE;
}
ps_inarg_file = fopen(argv[1], "rb");
if (ps_inarg_file == NULL) {
return EXIT_FAILURE;
}
char *buffer = malloc(NEW_FILE_LEN);
if (buffer == NULL) {
exit_on_error(IV_FAIL);
}
memset(buffer, 0, NEW_FILE_LEN);
ps_ip_file = tmpfile();
if (ps_ip_file < 0) {
exit_on_error(IV_FAIL);
}
fseek(ps_inarg_file, 0, SEEK_END);
u4_inarg_file_size = ftell(ps_inarg_file);
fseek(ps_inarg_file, 0, SEEK_SET);
/* Create final media file */
fread(buffer, u4_inarg_file_size, 1, ps_inarg_file);
fwrite(buffer, 1, NEW_FILE_LEN, ps_ip_file);
/* Create decoder instance */
{
ps_out_buf = (ivd_out_bufdesc_t *) malloc(sizeof(ivd_out_bufdesc_t));
{
iv_num_mem_rec_ip_t s_no_of_mem_rec_query_ip;
iv_num_mem_rec_op_t s_no_of_mem_rec_query_op;
s_no_of_mem_rec_query_ip.u4_size = sizeof(s_no_of_mem_rec_query_ip);
s_no_of_mem_rec_query_op.u4_size = sizeof(s_no_of_mem_rec_query_op);
s_no_of_mem_rec_query_ip.e_cmd = IV_CMD_GET_NUM_MEM_REC;
/* API Call: Get Number of Mem Records */
ret = impeg2d_api_function(NULL, (void *) &s_no_of_mem_rec_query_ip,
(void *) &s_no_of_mem_rec_query_op);
exit_on_error(ret);
u4_num_mem_recs = s_no_of_mem_rec_query_op.u4_num_mem_rec;
}
pv_mem_rec_location = malloc(u4_num_mem_recs * sizeof(iv_mem_rec_t));
if (pv_mem_rec_location == NULL) {
exit_on_error(IV_FAIL);
}
{
impeg2d_fill_mem_rec_ip_t s_fill_mem_rec_ip;
impeg2d_fill_mem_rec_op_t s_fill_mem_rec_op;
iv_mem_rec_t *ps_mem_rec;
UWORD32 total_size = 0;
s_fill_mem_rec_ip.s_ivd_fill_mem_rec_ip_t.e_cmd =
IV_CMD_FILL_NUM_MEM_REC;
s_fill_mem_rec_ip.s_ivd_fill_mem_rec_ip_t.pv_mem_rec_location =
(iv_mem_rec_t *) pv_mem_rec_location;
s_fill_mem_rec_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_wd =
MAX_FRAME_WIDTH;
s_fill_mem_rec_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_ht =
MAX_FRAME_HEIGHT;
s_fill_mem_rec_ip.u4_share_disp_buf = 0;
s_fill_mem_rec_ip.u4_deinterlace = 0;
s_fill_mem_rec_ip.e_output_format = IV_YUV_420SP_UV;
s_fill_mem_rec_ip.s_ivd_fill_mem_rec_ip_t.u4_size =
sizeof(impeg2d_fill_mem_rec_ip_t);
s_fill_mem_rec_op.s_ivd_fill_mem_rec_op_t.u4_size =
sizeof(impeg2d_fill_mem_rec_op_t);
ps_mem_rec = (iv_mem_rec_t *) pv_mem_rec_location;
for (i = 0; i < u4_num_mem_recs; i++)
ps_mem_rec[i].u4_size = sizeof(iv_mem_rec_t);
/* API Call: Fill Mem Records */
ret = impeg2d_api_function(NULL, (void *) &s_fill_mem_rec_ip,
(void *) &s_fill_mem_rec_op);
exit_on_error(ret);
u4_num_mem_recs = s_fill_mem_rec_op.s_ivd_fill_mem_rec_op_t
.u4_num_mem_rec_filled;
ps_mem_rec = (iv_mem_rec_t *) pv_mem_rec_location;
for (i = 0; i < u4_num_mem_recs; i++) {
ps_mem_rec->pv_base = app_aligned_malloc(
ps_mem_rec->u4_mem_alignment, ps_mem_rec->u4_mem_size);
if (ps_mem_rec->pv_base == NULL) {
exit_on_error(IV_FAIL);
}
total_size += ps_mem_rec->u4_mem_size;
ps_mem_rec++;
}
}
{
impeg2d_init_ip_t s_init_ip;
impeg2d_init_op_t s_init_op;
void *fxns = &impeg2d_api_function;
iv_mem_rec_t *mem_tab;
mem_tab = (iv_mem_rec_t *) pv_mem_rec_location;
s_init_ip.s_ivd_init_ip_t.e_cmd =
(IVD_API_COMMAND_TYPE_T) IV_CMD_INIT;
s_init_ip.s_ivd_init_ip_t.pv_mem_rec_location = mem_tab;
s_init_ip.s_ivd_init_ip_t.u4_frm_max_wd = MAX_FRAME_WIDTH;
s_init_ip.s_ivd_init_ip_t.u4_frm_max_ht = MAX_FRAME_HEIGHT;
s_init_ip.u4_share_disp_buf = 0;
s_init_ip.u4_deinterlace = 0;
s_init_ip.s_ivd_init_ip_t.u4_num_mem_rec = u4_num_mem_recs;
s_init_ip.s_ivd_init_ip_t.e_output_format = IV_YUV_420SP_UV;
s_init_ip.s_ivd_init_ip_t.u4_size = sizeof(impeg2d_init_ip_t);
s_init_op.s_ivd_init_op_t.u4_size = sizeof(impeg2d_init_op_t);
codec_obj = (iv_obj_t *) mem_tab[0].pv_base;
codec_obj->pv_fxns = fxns;
codec_obj->u4_size = sizeof(iv_obj_t);
ret = impeg2d_api_function((iv_obj_t *) codec_obj,
(void *) &s_init_ip,
(void *) &s_init_op);
exit_on_error(ret);
}
}
{
ivd_ctl_getbufinfo_ip_t s_ctl_ip;
ivd_ctl_getbufinfo_op_t s_ctl_op;
s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_GETBUFINFO;
s_ctl_ip.u4_size = sizeof(ivd_ctl_getbufinfo_ip_t);
s_ctl_op.u4_size = sizeof(ivd_ctl_getbufinfo_op_t);
ret = impeg2d_api_function((iv_obj_t *) codec_obj, (void *) &s_ctl_ip,
(void *) &s_ctl_op);
exit_on_error(ret);
u4_ip_buf_len = s_ctl_op.u4_min_in_buf_size[0];
}
/* set num of cores */
{
impeg2d_ctl_set_num_cores_ip_t s_ctl_set_cores_ip;
impeg2d_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) IMPEG2D_CMD_CTL_SET_NUM_CORES;
s_ctl_set_cores_ip.u4_num_cores = 2;
s_ctl_set_cores_ip.u4_size = sizeof(impeg2d_ctl_set_num_cores_ip_t);
s_ctl_set_cores_op.u4_size = sizeof(impeg2d_ctl_set_num_cores_op_t);
ret = impeg2d_api_function((iv_obj_t *) codec_obj,
(void *) &s_ctl_set_cores_ip,
(void *) &s_ctl_set_cores_op);
exit_on_error(ret);
}
/* Allocate input and output buffers for IV_YUV_420SP_UV */
{
pu1_bs_buf = (UWORD8 *) malloc(u4_ip_buf_len);
ps_out_buf->pu1_bufs[0] = (UWORD8 *) malloc(
(MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT * 3) / 2);
if ((ps_out_buf->pu1_bufs[0] == NULL) || (pu1_bs_buf == NULL)) {
exit_on_error(IV_FAIL);
}
ps_out_buf->pu1_bufs[1] = ps_out_buf->pu1_bufs[0]
+ (MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT);
}
/* 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 = impeg2d_api_function((iv_obj_t *) codec_obj, (void *) &s_ctl_ip,
(void *) &s_ctl_op);
}
while ((s_elapsed_time < WAIT_TIMEOUT)) {
u4_bytes_remaining = fread(pu1_bs_buf, sizeof(UWORD8), u4_ip_buf_len,
ps_ip_file);
if (u4_bytes_remaining == 0) {
fseek(ps_ip_file, 0, SEEK_SET);
u4_bytes_remaining = fread(pu1_bs_buf, sizeof(UWORD8),
u4_ip_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 = 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] =
(MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT);
s_video_decode_ip.s_out_buffer.u4_min_out_buf_size[1] =
((MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT) / 2);
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 = impeg2d_api_function((iv_obj_t *) codec_obj,
(void *) &s_video_decode_ip,
(void *) &s_video_decode_op);
if (IV_SUCCESS != ret) {
if ((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 = impeg2d_api_function((iv_obj_t *) codec_obj,
(void *) &s_ctl_ip,
(void *) &s_ctl_op);
exit_on_error(ret);
/* set num of cores */
{
impeg2d_ctl_set_num_cores_ip_t s_ctl_set_cores_ip;
impeg2d_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) IMPEG2D_CMD_CTL_SET_NUM_CORES;
s_ctl_set_cores_ip.u4_num_cores = 2;
s_ctl_set_cores_ip.u4_size =
sizeof(impeg2d_ctl_set_num_cores_ip_t);
s_ctl_set_cores_op.u4_size =
sizeof(impeg2d_ctl_set_num_cores_op_t);
ret = impeg2d_api_function(
(iv_obj_t *) codec_obj,
(void *) &s_ctl_set_cores_ip,
(void *) &s_ctl_set_cores_op);
exit_on_error(ret);
}
/* set processsor */
{
impeg2d_ctl_set_processor_ip_t s_ctl_set_num_processor_ip;
impeg2d_ctl_set_processor_op_t s_ctl_set_num_processor_op;
s_ctl_set_num_processor_ip.e_cmd = IVD_CMD_VIDEO_CTL;
s_ctl_set_num_processor_ip.e_sub_cmd =
(IVD_CONTROL_API_COMMAND_TYPE_T) IMPEG2D_CMD_CTL_SET_PROCESSOR;
s_ctl_set_num_processor_ip.u4_size =
sizeof(impeg2d_ctl_set_processor_ip_t);
s_ctl_set_num_processor_op.u4_size =
sizeof(impeg2d_ctl_set_processor_op_t);
ret = impeg2d_api_function(
(iv_obj_t *) codec_obj,
(void *) &s_ctl_set_num_processor_ip,
(void *) &s_ctl_set_num_processor_op);
exit_on_error(ret);
}
} else if (IMPEG2D_UNSUPPORTED_DIMENSIONS
== (IMPEG2D_ERROR_CODES_T) s_video_decode_op
.u4_error_code) {
flush_output(codec_obj, ps_out_buf, pu1_bs_buf,
&u4_op_frm_ts, u4_ip_frm_ts,
u4_bytes_remaining);
break;
} else if (IVD_DISP_FRM_ZERO_OP_BUF_SIZE
== (IMPEG2D_ERROR_CODES_T) s_video_decode_op
.u4_error_code) {
break;
}
}
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;
}
}
}
GETTIME(&s_end_timer);
ELAPSEDTIME(s_start_timer, s_end_timer, s_elapsed_time);
}
/* 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 */
{
iv_retrieve_mem_rec_ip_t s_retrieve_dec_ip;
iv_retrieve_mem_rec_op_t s_retrieve_dec_op;
s_retrieve_dec_ip.pv_mem_rec_location =
(iv_mem_rec_t *) pv_mem_rec_location;
s_retrieve_dec_ip.e_cmd = IV_CMD_RETRIEVE_MEMREC;
s_retrieve_dec_ip.u4_size = sizeof(iv_retrieve_mem_rec_ip_t);
s_retrieve_dec_op.u4_size = sizeof(iv_retrieve_mem_rec_op_t);
ret = impeg2d_api_function((iv_obj_t *) codec_obj,
(void *) &s_retrieve_dec_ip,
(void *) &s_retrieve_dec_op);
exit_on_error(ret);
u4_num_mem_recs = s_retrieve_dec_op.u4_num_mem_rec_filled;
iv_mem_rec_t *ps_mem_rec = s_retrieve_dec_ip.pv_mem_rec_location;
for (UWORD16 u2_i = 0; u2_i < u4_num_mem_recs; u2_i++) {
app_aligned_free(ps_mem_rec->pv_base);
ps_mem_rec++;
}
free(s_retrieve_dec_ip.pv_mem_rec_location);
}
free_resources();
return EXIT_SUCCESS;
}