blob: d0942cd4164b4f4039640dd3b060f9c5f4fc6eb5 [file] [log] [blame]
/*
* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* 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 <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <pthread.h>
#include <fcntl.h>
#include <errno.h>
#include <media/msm_vidc.h>
#include <linux/videodev2.h>
#include <linux/ion.h>
#include <linux/msm_ion.h>
#include <linux/types.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <utils/Log.h>
#include <string.h>
#include <time.h>
#include <semaphore.h>
#include <poll.h>
#include <queue.h>
#include <ring_queue.h>
#define DEVICE_BASE_MINOR 32
#define MAX_LINE 2048
#define MAX_FILE_PATH_SIZE 128
#define MAX_NAME_LENGTH 128
#define TIMEOUT 20000 /*In milliseconds*/
#define MAX_NUM_BUFS 32
#define MEM_DEVICE "/dev/ion"
#define MEM_HEAP_ID ION_CP_MM_HEAP_ID
#define EXTRADATA_IDX(__num_planes) (__num_planes - 1)
#define D(fmt, args...) \
do { \
if(input_args->verbosity >= 2) \
printf("D/vidc_test: " fmt, ##args); \
}while(0)
#define V(fmt, args...) \
do { \
if(input_args->verbosity >= 1) \
printf("V/vidc_test: " fmt, ##args); \
}while(0)
#define I(fmt, args...) \
do { \
printf("I/vidc_test: " fmt, ##args); \
}while(0)
#define E(fmt, args...) \
do { \
printf("E/vidc_test: " fmt, ##args); \
}while(0)
enum session_type {
ENCODER_SESSION = 0,
DECODER_SESSION,
};
enum port_type {
OUTPUT_PORT = 0,
CAPTURE_PORT,
MAX_PORTS
};
enum read_type {
NOT_ARBITRARY_NUMBER = 0,
FIX_NUMBER,
RANDOM_NUMBER,
};
typedef enum status {
SUCCESS = 0,
ERROR,
FAILURE
} status;
enum test_types {
NOMINAL,
ADVERSARIAL,
REPEAT,
STRESS,
HELP,
};
typedef enum paramtype {
STRING,
INT16,
INT32,
FLOAT,
DOUBLE,
INT32_ARRAY,
INT16_ARRAY,
FLOAT_ARRAY,
DOUBLE_ARRAY,
FLAG,
} paramtype;
struct ion_info {
int ion_device_fd;
struct ion_fd_data fd_ion_data;
struct ion_allocation_data ion_alloc_data;
};
struct bufinfo {
__u32 offset;
__u8* vaddr;
__u32 size;
struct ion_info ion;
enum v4l2_buf_type buf_type;
int index;
};
struct extradata_buffer_info {
__u32 buffer_size;
__u8* uaddr;
__u32 count;
__u32 size;
struct ion_info ion;
};
struct v4l2testappval {
int fd;
struct v4l2_requestbuffers bufreq[MAX_PORTS];
struct v4l2_format fmt[MAX_PORTS];
struct v4l2_fmtdesc fdesc[MAX_PORTS];
struct bufinfo binfo[MAX_PORTS][MAX_NUM_BUFS];
struct extradata_buffer_info extradata_info;
Queue buf_queue[MAX_PORTS];
ring_buf_header ring_info;
pthread_mutex_t q_lock[MAX_PORTS];
pthread_cond_t cond[MAX_PORTS];
FILE *inputfile,*outputfile,*buf_file;
pthread_t thread_id[MAX_PORTS];
pthread_t poll_tid;
unsigned int ebd_count;
unsigned int fbd_count;
int stop_feeding;
status cur_test_status;
int events_subscribed;
int poll_created;
__u8 *ring_buf;
int secure_mode;
int verbosity;
};
struct arguments {
char input[MAX_FILE_PATH_SIZE];
char output[MAX_FILE_PATH_SIZE];
char config[MAX_FILE_PATH_SIZE];
char bufsize_filename[MAX_FILE_PATH_SIZE];
char device_mode[20];
int session;
unsigned long input_height,
input_width,
bit_rate,
frame_rate,
frame_count,
stream_format,
output_order,
enable_pic_type,
keep_aspect_ratio,
post_loop_deblocker,
divx_format,
profile,
level,
entropy_mode,
cabac_model,
idr_period,
intra_period_p_frames,
intra_period_b_frames,
request_i_frame,
rate_control,
mb_error_map_reporting,
loop_filter_mode,
loop_filter_alpha,
loop_filter_beta,
rotation,
i_frame_qp,
p_frame_qp,
b_frame_qp,
slice_mode,
slice_mode_mb,
slice_mode_bytes,
continue_data_transfer,
alloc_type,
enable_frame_assembly,
n_read_mode,
read_bytes,
ring_num_hdrs,
output_buf_size,
random_seed;
char codec_type[20], read_mode[20];
char sequence[300][MAX_FILE_PATH_SIZE];
int verbosity;
int repeat;
};
typedef struct inputparam {
const char * param_name;
paramtype param_type;
void * param_ptr;
int array_size;
} param;
static int parse_args(int argc, char **argv);
int parse_cfg(const char *filename);
int parse_param_file(const char * filename, const param * tptab, const int tptab_size);
int parse_sequences(struct arguments *input_args);
static status search_for_preset_param(const param * tptab, const char * param_name, int * pTableIndex, const int table_size);
static size_t find_first_non_whitespace_reverse(const char * str, size_t start_pos);
static int querycap(int fd);
static int enum_formats(int fd, enum v4l2_buf_type buf_type);
static int set_format(int fd, enum v4l2_buf_type buf_type);
static int get_format(int fd, enum v4l2_buf_type buf_type);
static int get_bufreqs(int fd, enum v4l2_buf_type buf_type);
static int qbuf(int fd, enum v4l2_buf_type buf_type);
static int run(int fd);
static int deqbufs(int fd, enum v4l2_buf_type buf_type);
static int streamon(int fd, enum v4l2_buf_type buf_type);
static int streamoff(int fd, enum v4l2_buf_type buf_type);
static int set_control(int fd, struct v4l2_control *control);
static int get_control(int fd, struct v4l2_control *control);
static int subscribe_event(int fd, struct v4l2_event_subscription *sub);
static int unsubscribe_event(int fd, struct v4l2_event_subscription *sub);
static int decoder_cmd(int fd, struct v4l2_decoder_cmd *dec);
static void* poll_func(void *data);
int read_annexb_nalu(FILE * bits, unsigned char * pBuf);
int read_one_frame(FILE * bits, unsigned char * pBuf);
int read_n_bytes(FILE * file, unsigned char * pBuf, int n);
int get_bytes_to_read(void);
static int find_start_code(const unsigned char * pBuf, unsigned int zeros_in_startcode);
static void nominal_test();
static void adversarial_test();
static void repeatability_test();
static void stress_test();
static int alloc_map_ion_memory(__u32 buffer_size, __u32 alignment,
struct ion_allocation_data *alloc_data, struct ion_fd_data *fd_data, int flag);
void free_ion_memory(struct ion_info *buf_ion_info);
int get_extradata_value(const char * param_name);
static struct arguments *input_args;
static int sequence_count;
static struct v4l2testappval video_inst;
static int num_of_test_fail;
static int num_of_test_pass;
static const int event_type[] = {
V4L2_EVENT_MSM_VIDC_FLUSH_DONE,
V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_SUFFICIENT,
V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_INSUFFICIENT,
V4L2_EVENT_MSM_VIDC_CLOSE_DONE,
V4L2_EVENT_MSM_VIDC_SYS_ERROR
};
static void (*test_func[]) () = {
[NOMINAL] = nominal_test,
[ADVERSARIAL] = adversarial_test,
[REPEAT] = repeatability_test,
[STRESS] = stress_test,
};
inline int clip2(int x) {
x = x -1;
x = x | x >> 1;
x = x | x >> 2;
x = x | x >> 4;
x = x | x >> 16;
x = x + 1;
return x;
}
void help()
{
printf("\n\n");
printf("=============================\n");
printf("msm-vidc-test -c <config file> \n");
printf("=============================\n\n");
printf(" eg: msm-vidc-test -c input.cfg \n\n");
printf(" -c, --config <file> Configuration file (required)\n");
printf(" -v, --verbose <#> 0 minimal verbosity,\n");
printf(" 1 to include details,\n");
printf(" 2 to debug messages.\n");
printf(" -n, Nominal test (default)\n");
printf(" -r <#times>, Repeat test #times\n");
printf(" -h, --help Print this menu\n");
printf("=============================\n\n\n");
}
static int parse_args(int argc, char **argv)
{
int rc = 0;
int command;
struct option longopts[] = {
{ "nominal", no_argument, NULL, 'n'},
{ "adversarial", no_argument, NULL, 'a'},
{ "stress", no_argument, NULL, 's'},
{ "repeat", required_argument, NULL, 'r'},
{ "verbose", required_argument, NULL, 'v'},
{ "config", required_argument, NULL, 'c'},
{ "help", no_argument, NULL, 'h'},
{ NULL, 0, NULL, 0},
};
while ((command = getopt_long(argc, argv, "nasr:v:c:h", longopts,
NULL)) != -1) {
switch (command) {
case 'n':
rc |= 1 << NOMINAL;
break;
case 'a':
rc |= 1 << ADVERSARIAL;
break;
case 'r':
rc |= 1 << REPEAT;
input_args->repeat = atoi(optarg);
break;
case 's':
rc |= 1 << STRESS;
break;
case 'v':
input_args->verbosity = atoi(optarg);
break;
case 'c':
strlcpy(input_args->config, optarg, MAX_FILE_PATH_SIZE);
break;
case 'h':
help();
rc |= 1 << HELP;
break;
default:
E("Invalid argument: %c\n", command);
return -1;
}
}
if (!rc)
rc = 1 << NOMINAL;
return rc;
}
int parse_cfg(const char *filename)
{
int rc = 0;
param param_table[] = {
{"device_mode", STRING, input_args->device_mode,MAX_FILE_PATH_SIZE},
{"input_height", INT32, &input_args->input_height,MAX_FILE_PATH_SIZE},
{"input_width", INT32, &input_args->input_width,MAX_FILE_PATH_SIZE},
{"frame_count", INT32, &input_args->frame_count,MAX_FILE_PATH_SIZE},
{"codec_type", STRING, input_args->codec_type,MAX_FILE_PATH_SIZE},
{"input_file", STRING, input_args->input,MAX_FILE_PATH_SIZE},
{"output_file", STRING, input_args->output,MAX_FILE_PATH_SIZE},
{"read_mode", STRING, input_args->read_mode,MAX_FILE_PATH_SIZE},
{"read_bytes", INT32, &input_args->read_bytes,MAX_FILE_PATH_SIZE},
{"random_seed", INT32, &input_args->random_seed,MAX_FILE_PATH_SIZE},
{"fix_buf_size_file", STRING, input_args->bufsize_filename,MAX_FILE_PATH_SIZE},
{"ring_num_headers", INT32, &input_args->ring_num_hdrs,MAX_FILE_PATH_SIZE},
{"ring_buf_size", INT32, &input_args->output_buf_size,MAX_FILE_PATH_SIZE},
{"output_buf_size", INT32, &input_args->output_buf_size,MAX_FILE_PATH_SIZE},
{"eot", FLAG, NULL,0}
};
rc = parse_param_file(filename, param_table, sizeof(param_table)/sizeof(param_table[0]));
if (rc) {
E("Failed to parse param file: %s\n", filename);
goto err;
}
rc = parse_sequences(input_args);
if (rc) {
E("Failed to parse sequences\n");
}
err:
return rc;
}
int get_extradata_value(const char * param_name)
{
int val = -1;
const char *v4l2_name;
if ((v4l2_name = "NONE") && !strncmp(param_name, v4l2_name, strlen(v4l2_name))) {
val = V4L2_MPEG_VIDC_EXTRADATA_NONE;
} else if ((v4l2_name = "MB_QUANTIZATION") && !strncmp(param_name, v4l2_name, strlen(v4l2_name))) {
val = V4L2_MPEG_VIDC_EXTRADATA_MB_QUANTIZATION;
} else if ((v4l2_name = "INTERLACE_VIDEO") && !strncmp(param_name, v4l2_name, strlen(v4l2_name))) {
val = V4L2_MPEG_VIDC_EXTRADATA_INTERLACE_VIDEO;
} else if ((v4l2_name = "VC1_FRAMEDISP") && !strncmp(param_name, v4l2_name, strlen(v4l2_name))) {
val = V4L2_MPEG_VIDC_EXTRADATA_VC1_FRAMEDISP;
} else if ((v4l2_name = "VC1_SEQDISP") && !strncmp(param_name, v4l2_name, strlen(v4l2_name))) {
val = V4L2_MPEG_VIDC_EXTRADATA_VC1_SEQDISP;
} else if ((v4l2_name = "TIMESTAMP") && !strncmp(param_name, v4l2_name, strlen(v4l2_name))) {
val = V4L2_MPEG_VIDC_EXTRADATA_TIMESTAMP;
} else if ((v4l2_name = "S3D_FRAME_PACKING") && !strncmp(param_name, v4l2_name, strlen(v4l2_name))) {
val = V4L2_MPEG_VIDC_EXTRADATA_S3D_FRAME_PACKING;
} else if ((v4l2_name = "FRAME_RATE") && !strncmp(param_name, v4l2_name, strlen(v4l2_name))) {
val = V4L2_MPEG_VIDC_EXTRADATA_FRAME_RATE;
} else if ((v4l2_name = "PANSCAN_WINDOW") && !strncmp(param_name, v4l2_name, strlen(v4l2_name))) {
val = V4L2_MPEG_VIDC_EXTRADATA_PANSCAN_WINDOW;
} else if ((v4l2_name = "RECOVERY_POINT_SEI") && !strncmp(param_name, v4l2_name, strlen(v4l2_name))) {
val = V4L2_MPEG_VIDC_EXTRADATA_RECOVERY_POINT_SEI;
} else if ((v4l2_name = "CLOSED_CAPTION_UD") && !strncmp(param_name, v4l2_name, strlen(v4l2_name))) {
val = V4L2_MPEG_VIDC_EXTRADATA_CLOSED_CAPTION_UD;
} else if ((v4l2_name = "AFD_UD") && !strncmp(param_name, v4l2_name, strlen(v4l2_name))) {
val = V4L2_MPEG_VIDC_EXTRADATA_AFD_UD;
} else if ((v4l2_name = "MULTISLICE_INFO") && !strncmp(param_name, v4l2_name, strlen(v4l2_name))) {
val = V4L2_MPEG_VIDC_EXTRADATA_MULTISLICE_INFO;
} else if ((v4l2_name = "NUM_CONCEALED_MB") && !strncmp(param_name, v4l2_name, strlen(v4l2_name))) {
val = V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB;
} else if ((v4l2_name = "METADATA_FILLER") && !strncmp(param_name, v4l2_name, strlen(v4l2_name))) {
val = V4L2_MPEG_VIDC_EXTRADATA_METADATA_FILLER;
} else if ((v4l2_name = "INPUT_CROP") && !strncmp(param_name, v4l2_name, strlen(v4l2_name))) {
val = V4L2_MPEG_VIDC_INDEX_EXTRADATA_INPUT_CROP;
} else if ((v4l2_name = "DIGITAL_ZOOM") && !strncmp(param_name, v4l2_name, strlen(v4l2_name))) {
val = V4L2_MPEG_VIDC_INDEX_EXTRADATA_DIGITAL_ZOOM;
} else if ((v4l2_name = "ASPECT_RATIO") && !strncmp(param_name, v4l2_name, strlen(v4l2_name))) {
val = V4L2_MPEG_VIDC_INDEX_EXTRADATA_ASPECT_RATIO;
} else if ((v4l2_name = "MPEG2_SEQDISP") && !strncmp(param_name, v4l2_name, strlen(v4l2_name))) {
val = V4L2_MPEG_VIDC_EXTRADATA_MPEG2_SEQDISP;
} else {
E("Not found %s \n", param_name);
val = -1;
}
return val;
}
int handle_extradata_v4l2(struct v4l2_buffer v4l2_buf)
{
struct bufinfo *binfo = NULL;
struct msm_vidc_extradata_header *data = NULL;
struct v4l2_plane *plane = NULL;
const char * p_extradata = NULL;
unsigned int consumed_len = 0;
unsigned int pos = 0;
int rc = 0;
int buf_index;
int extra_idx;
int port;
int bytesused;
if (v4l2_buf.type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
D("Test app only handle extra data for CAPTURE PORT\n");
return 0;
} else {
port = CAPTURE_PORT;
}
extra_idx = EXTRADATA_IDX(video_inst.fmt[port].fmt.pix_mp.num_planes);
if (!extra_idx) {
D("Port doesn't have planes for extra data\n");
return 0;
}
buf_index = v4l2_buf.index;
binfo = &video_inst.binfo[port][buf_index];
plane = v4l2_buf.m.planes;
bytesused = plane[extra_idx].bytesused;
// TODO: Fix driver trash values for plane[extra_idx].m.userptr & plane[extra_idx].data_offset
// While that fix is done using alternative method to get the extradata address
p_extradata = (const char *)video_inst.extradata_info.uaddr + buf_index * video_inst.extradata_info.buffer_size;
D("extra_idx = %d, buf_index = %d, bytesused = %d, p_extradata = %p or other = %p, data_offset = %u, reserved[0] = %u, reserved[1] = %u\n",
extra_idx, buf_index, bytesused, p_extradata,
((const char *)plane[extra_idx].m.userptr + plane[extra_idx].data_offset),
plane[extra_idx].data_offset,
plane[1].reserved[0], plane[1].reserved[1]);
if (!video_inst.extradata_info.uaddr) {
D("No memory allocated for extra data buffer\n");
return 0;
}
consumed_len = 0;
data = (struct msm_vidc_extradata_header *)p_extradata;
if (data) {
while ((consumed_len < video_inst.extradata_info.buffer_size)
&& (data->type != MSM_VIDC_EXTRADATA_NONE)) {
if ((consumed_len + data->size) > video_inst.extradata_info.buffer_size) {
D("Invalid extra data size\n");
break;
}
rc++;
switch (data->type) {
case MSM_VIDC_EXTRADATA_INTERLACE_VIDEO:
{
struct msm_vidc_interlace_payload *payload;
payload = (struct msm_vidc_interlace_payload *)data->data;
if (payload) {
switch (payload->format) {
case MSM_VIDC_INTERLACE_FRAME_PROGRESSIVE:
I("MSM_VIDC_EXTRADATA_INTERLACE_VIDEO -> MSM_VIDC_INTERLACE_FRAME_PROGRESSIVE\n");
break;
case MSM_VIDC_INTERLACE_INTERLEAVE_FRAME_TOPFIELDFIRST:
I("MSM_VIDC_EXTRADATA_INTERLACE_VIDEO -> MSM_VIDC_INTERLACE_INTERLEAVE_FRAME_TOPFIELDFIRST\n");
break;
case MSM_VIDC_INTERLACE_INTERLEAVE_FRAME_BOTTOMFIELDFIRST:
I("MSM_VIDC_EXTRADATA_INTERLACE_VIDEO -> MSM_VIDC_INTERLACE_INTERLEAVE_FRAME_BOTTOMFIELDFIRST\n");
break;
case MSM_VIDC_INTERLACE_FRAME_TOPFIELDFIRST:
I("MSM_VIDC_EXTRADATA_INTERLACE_VIDEO -> MSM_VIDC_INTERLACE_FRAME_TOPFIELDFIRST\n");
break;
case MSM_VIDC_INTERLACE_FRAME_BOTTOMFIELDFIRST:
I("MSM_VIDC_EXTRADATA_INTERLACE_VIDEO -> MSM_VIDC_INTERLACE_FRAME_BOTTOMFIELDFIRST\n");
break;
default:
E("Not recognized MSM_VIDC_EXTRADATA_INTERLACE_VIDEO: 0x%x\n", payload->format);
break;
}
}
break;
}
case MSM_VIDC_EXTRADATA_FRAME_RATE:
{
struct msm_vidc_framerate_payload *frame_rate_payload;
frame_rate_payload = (struct msm_vidc_framerate_payload *)data->data;
I("MSM_VIDC_EXTRADATA_FRAME_RATE = %u\n", frame_rate_payload->frame_rate);
break;
}
case MSM_VIDC_EXTRADATA_TIMESTAMP:
{
struct msm_vidc_ts_payload *time_stamp_payload;
time_stamp_payload = (struct msm_vidc_ts_payload *)data->data;
I("MSM_VIDC_EXTRADATA_TIMESTAMP = timestamp_hi:timestamp_low = %u:%u\n",
time_stamp_payload->timestamp_hi, time_stamp_payload->timestamp_lo);
break;
}
case MSM_VIDC_EXTRADATA_NUM_CONCEALED_MB:
{
struct msm_vidc_concealmb_payload *conceal_mb_payload;
unsigned int num_MB_in_frame;
unsigned int num_conceal_MB;
conceal_mb_payload = (struct msm_vidc_concealmb_payload *)data->data;
num_MB_in_frame = ((video_inst.fmt[port].fmt.pix_mp.width + 15) *
(video_inst.fmt[port].fmt.pix_mp.height+ 15)) >> 8;
num_conceal_MB = ((num_MB_in_frame > 0)?(conceal_mb_payload->num_mbs * 100 / num_MB_in_frame) : 0);
I("MSM_VIDC_EXTRADATA_NUM_CONCEALED_MB -> num_mbs = %u, num_conceal_MB = %u\n",
conceal_mb_payload->num_mbs, num_conceal_MB);
break;
}
case MSM_VIDC_EXTRADATA_INDEX:
{
int * p_type;
p_type = (int *)(data->data);
if (p_type) {
if (*p_type == MSM_VIDC_EXTRADATA_ASPECT_RATIO) {
struct msm_vidc_aspect_ratio_payload *aspect_ratio_payload;
aspect_ratio_payload = (struct msm_vidc_aspect_ratio_payload *)(++p_type);
if (aspect_ratio_payload) {
I("MSM_VIDC_EXTRADATA_INDEX->MSM_VIDC_EXTRADATA_ASPECT_RATIO = %u x %u\n",
aspect_ratio_payload->aspect_width, aspect_ratio_payload->aspect_height);
}
} else {
E("MSM_VIDC_EXTRADATA_INDEX not recognized by application: %u\n", *p_type);
}
} else {
E("MSM_VIDC_EXTRADATA_INDEX is NULL\n");
}
break;
}
case MSM_VIDC_EXTRADATA_RECOVERY_POINT_SEI:
{
struct msm_vidc_recoverysei_payload *recovery_sei_payload;
unsigned int recovery_sei_flags;
recovery_sei_payload = (struct msm_vidc_recoverysei_payload *)data->data;
recovery_sei_flags = recovery_sei_payload->flags;
I("MSM_VIDC_EXTRADATA_RECOVERY_POINT_SEI = %x\n", recovery_sei_payload->flags);
if (recovery_sei_flags != MSM_VIDC_FRAME_RECONSTRUCTION_CORRECT) {
I("***************************************************\n");
E("MSM_VIDC_EXTRADATA_RECOVERY_POINT_SEI: DATACORRUPT Received\n");
I("***************************************************\n");
}
break;
}
case MSM_VIDC_EXTRADATA_PANSCAN_WINDOW:
{
struct msm_vidc_panscan_window_payload *panscan_payload = NULL;
panscan_payload = (struct msm_vidc_panscan_window_payload *)data->data;
I("MSM_VIDC_EXTRADATA_PANSCAN_WINDOW received\n");
break;
}
case MSM_VIDC_EXTRADATA_MPEG2_SEQDISP: //SEQUENCE : SET_CTRL VIDEO_EXTRADATA MPEG2_SEQDISP
{
struct msm_vidc_mpeg2_seqdisp_payload *seqdisp_payload;
seqdisp_payload = (struct msm_vidc_mpeg2_seqdisp_payload *)data->data;
if (seqdisp_payload) {
I("MSM_VIDC_EXTRADATA_MPEG2_SEQDISP: display size = %u x %u\n",
seqdisp_payload->disp_width,
seqdisp_payload->disp_height);
} else {
I("MSM_VIDC_EXTRADATA_MPEG2_SEQDISP: NULL\n");
}
break;
}
default:
rc--;
E("MSM_VIDC_EXTRADATA not recognized by application = 0x%x\n", data->type);
goto unrecognized_extradata;
}
consumed_len += data->size;
data = (struct msm_vidc_extradata_header *)((char *)data + data->size);
}
}
unrecognized_extradata:
return rc;
}
static int deqbufs(int fd, enum v4l2_buf_type buf_type)
{
int rc = 0;
return rc;
}
int alloc_map_ion_memory(__u32 buffer_size,
__u32 alignment, struct ion_allocation_data *alloc_data,
struct ion_fd_data *fd_data, int flag)
{
int fd = -EINVAL;
int rc = -EINVAL;
int ion_dev_flag;
const int secure_mode = video_inst.secure_mode;
struct ion_info ion_buf_info;
if (!alloc_data || buffer_size <= 0 || !fd_data) {
E("Invalid arguments to alloc_map_ion_memory\n");
return -EINVAL;
}
ion_dev_flag = O_RDONLY;
fd = open (MEM_DEVICE, ion_dev_flag);
if (fd < 0) {
E("opening ion device failed with fd = %d\n", fd);
return fd;
}
alloc_data->flags = 0;
if (!secure_mode && (flag & ION_FLAG_CACHED)) {
alloc_data->flags |= ION_FLAG_CACHED;
}
alloc_data->len = buffer_size;
alloc_data->align = clip2(alignment);
if (alloc_data->align < 4096) {
alloc_data->align = 4096;
}
if ((secure_mode) && (flag & ION_SECURE))
alloc_data->flags |= ION_SECURE;
alloc_data->heap_mask = ION_HEAP(ION_IOMMU_HEAP_ID);
if (secure_mode)
alloc_data->heap_mask = ION_HEAP(MEM_HEAP_ID);
rc = ioctl(fd,ION_IOC_ALLOC,alloc_data);
if (rc || !alloc_data->handle) {
E("ION ALLOC memory failed \n");
alloc_data->handle = NULL;
close(fd);
fd = -ENOMEM;
return fd;
}
fd_data->handle = alloc_data->handle;
rc = ioctl(fd,ION_IOC_MAP,fd_data);
if (rc) {
E("ION MAP failed \n");
ion_buf_info.ion_alloc_data = *alloc_data;
ion_buf_info.ion_device_fd = fd;
ion_buf_info.fd_ion_data = *fd_data;
free_ion_memory(&ion_buf_info);
fd_data->fd =-1;
close(fd);
fd = -ENOMEM;
}
return fd;
}
void free_ion_memory(struct ion_info *buf_ion_info)
{
if (!buf_ion_info) {
E("ION: free called with invalid fd/allocdata\n");
return;
}
if (ioctl(buf_ion_info->ion_device_fd,ION_IOC_FREE,
&buf_ion_info->ion_alloc_data.handle)) {
E("ION: free failed\n");
}
D("Closing ION device fd: %d\n", buf_ion_info->ion_device_fd);
close(buf_ion_info->ion_device_fd);
buf_ion_info->ion_device_fd = -1;
buf_ion_info->ion_alloc_data.handle = NULL;
buf_ion_info->fd_ion_data.fd = -1;
}
int alloc_extra_data(void)
{
int rc = 0;
struct extradata_buffer_info *edata_info = &video_inst.extradata_info;
if (edata_info->size == 0) {
rc = 0;
D("No extra data buffer required, edata size = %d\n", edata_info->size);
return rc;
}
if (edata_info->ion.ion_alloc_data.handle) {
rc = munmap((void *)edata_info->uaddr, edata_info->size);
if (rc)
E("Fail to munmap(%p, %u)\n", (void *)edata_info->uaddr, edata_info->size);
close(edata_info->ion.fd_ion_data.fd);
free_ion_memory(&edata_info->ion);
}
edata_info->size = (edata_info->size + 4095) & (~4095);
edata_info->ion.ion_device_fd = alloc_map_ion_memory(
edata_info->size,
4096,
&edata_info->ion.ion_alloc_data,
&edata_info->ion.fd_ion_data,
0);
if (edata_info->ion.ion_device_fd >= 0) {
edata_info->uaddr = (__u8 *)mmap(NULL, edata_info->size,
PROT_READ | PROT_WRITE, MAP_SHARED,
edata_info->ion.fd_ion_data.fd, 0);
if (edata_info->uaddr == MAP_FAILED) {
E("Failed to get buffer virtual address\n");
close(edata_info->ion.fd_ion_data.fd);
free_ion_memory(&edata_info->ion);
rc = -ENOMEM;
} else {
D("Success alloc extra data buf size = %d, ion_device_fd = %d, uaddr = %p, fd_ion_data = %d\n",
edata_info->size, edata_info->ion.ion_device_fd,
edata_info->uaddr, edata_info->ion.fd_ion_data.fd);
}
} else {
E("Failed to allocate memory\n");
rc = -ENOMEM;
}
return rc;
}
static void free_buffers()
{
int i, port, rc;
struct bufinfo *binfo = NULL;
int check_ring_fd = -1;
for (port = 0; port < MAX_PORTS; port++) {
if (port == CAPTURE_PORT && video_inst.extradata_info.size) {
struct extradata_buffer_info *edata_info = &video_inst.extradata_info;
if (edata_info->ion.ion_alloc_data.handle != NULL) {
rc = munmap((void *)edata_info->uaddr, edata_info->size);
if (rc)
E("Fail to munmap(%p, %u)\n", (void *)edata_info->uaddr, edata_info->size);
close(edata_info->ion.fd_ion_data.fd);
free_ion_memory(&edata_info->ion);
}
}
for(i = 0; i < MAX_NUM_BUFS; i++) {
binfo = &video_inst.binfo[port][i];
if (binfo->ion.ion_alloc_data.handle != NULL && check_ring_fd != binfo->ion.fd_ion_data.fd) {
check_ring_fd = binfo->ion.fd_ion_data.fd; //ring buffer shall be free only once
rc = munmap((void *)binfo->vaddr, binfo->size);
if (rc)
E("Fail to munmap(%p, %u)\n", (void *)binfo->vaddr, binfo->size);
close(binfo->ion.fd_ion_data.fd);
free_ion_memory(&binfo->ion);
}
}
}
}
static int prepare_bufs(int fd, enum v4l2_buf_type buf_type)
{
int i = 0;
struct bufinfo *binfo = NULL;
struct v4l2_buffer buf;
struct v4l2_plane plane[VIDEO_MAX_PLANES];
int size = 0;
int numbufs = 0;
int port = CAPTURE_PORT;
int align = 4096;
if (buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
size = video_inst.fmt[CAPTURE_PORT].fmt.pix_mp.plane_fmt[0].sizeimage;
numbufs = video_inst.bufreq[CAPTURE_PORT].count;
port = CAPTURE_PORT;
} else {
if (input_args->output_buf_size > 0) {
size = input_args->output_buf_size;
} else {
size = video_inst.fmt[OUTPUT_PORT].fmt.pix_mp.plane_fmt[0].sizeimage;
}
numbufs = video_inst.bufreq[OUTPUT_PORT].count;
port = OUTPUT_PORT;
}
size = (size + (align-1)) & (~(align-1));
V("Port: %d: buffer size required per buffer: %d, num of buf: %d\n",
port, size, numbufs);
int rc = 0;
if (fd < 0) {
E("Invalid fd: %d\n", fd);
return -EINVAL;
}
if (port == CAPTURE_PORT) {
rc = alloc_extra_data();
if (rc) {
E("Fail extra data allocation\n");
return rc;
}
}
for (i=0; i< numbufs; i++) {
int extra_idx = 0;
binfo = &video_inst.binfo[port][i];
binfo->ion.ion_device_fd = alloc_map_ion_memory(size,
align,
&binfo->ion.ion_alloc_data,
&binfo->ion.fd_ion_data,
0);
if (binfo->ion.ion_device_fd < 0) {
E("Failed to allocate memory\n");
rc = -ENOMEM;
break;
}
binfo->vaddr = (__u8 *)mmap(NULL, size,
PROT_READ | PROT_WRITE, MAP_SHARED,
binfo->ion.fd_ion_data.fd, 0);
if (binfo->vaddr == MAP_FAILED) {
E("Failed to get buffer virtual address\n");
close(binfo->ion.fd_ion_data.fd);
free_ion_memory(&binfo->ion);
rc = -ENOMEM;
break;
}
binfo->buf_type = buf_type;
binfo->index = i;
binfo->size = size;
buf.index = i;
buf.type = buf_type;
buf.memory = V4L2_MEMORY_USERPTR;
plane[0].length = size;
plane[0].m.userptr = (unsigned long)binfo->vaddr;
plane[0].reserved[0] = binfo->ion.fd_ion_data.fd;
plane[0].reserved[1] = 0;
plane[0].data_offset = binfo->offset;
extra_idx = EXTRADATA_IDX(video_inst.fmt[CAPTURE_PORT].fmt.pix_mp.num_planes);
if (port == CAPTURE_PORT &&
((extra_idx >= 1) && (extra_idx < VIDEO_MAX_PLANES))) {
buf.length = video_inst.fmt[CAPTURE_PORT].fmt.pix_mp.num_planes;
plane[extra_idx].length = video_inst.extradata_info.buffer_size;
plane[extra_idx].m.userptr = (long unsigned int) (video_inst.extradata_info.uaddr + i * video_inst.extradata_info.buffer_size);
plane[extra_idx].reserved[0] = video_inst.extradata_info.ion.fd_ion_data.fd;
plane[extra_idx].reserved[1] = i * video_inst.extradata_info.buffer_size;
plane[extra_idx].data_offset = 0;
} else {
buf.length = 1;
}
buf.m.planes = plane;
D("Preparing Buffer port:%d : binfo: %p, vaddr: %p, fd: %d\n",
port, binfo, binfo->vaddr, binfo->ion.fd_ion_data.fd);
pthread_mutex_lock(&video_inst.q_lock[port]);
if(push(&video_inst.buf_queue[port], (void *) binfo) < 0) {
E("Error in pushing buffers to queue \n");
}
pthread_mutex_unlock(&video_inst.q_lock[port]);
rc = ioctl(fd, VIDIOC_PREPARE_BUF, &buf);
if (rc) {
E("Failed to prepare bufs\n");
break;
}
}
return rc;
}
static int allocate_ring_buffer(int fd, enum v4l2_buf_type buf_type)
{
int i;
struct bufinfo *binfo, *binfo_tmp;
struct v4l2_buffer buf;
struct v4l2_plane plane[VIDEO_MAX_PLANES];
int size = 0;
int ring_size = 0;
int numbufs = 0;
int port = OUTPUT_PORT;
int align = 4096;
int rc = 0;
if (fd < 0) {
E("Invalid fd: %d\n", fd);
return -EINVAL;
}
if (buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
size = video_inst.fmt[OUTPUT_PORT].fmt.pix_mp.plane_fmt[0].sizeimage;
numbufs = video_inst.bufreq[OUTPUT_PORT].count;
port = OUTPUT_PORT;
} else {
E("Ring buffer on CAPTURE port not supported\n");
return -EINVAL;
}
D("User requested ring_buf_size = %lu, component requested size = %d\n",
input_args->output_buf_size, size);
if (input_args->output_buf_size) {
if ((int)input_args->output_buf_size < size)
D("Warning: Ring buffer size is less than requested size = %d\n",
size);
ring_size = input_args->output_buf_size;
} else {
ring_size = size;
}
ring_size = (ring_size + (align-1)) & (~(align-1));
V("Port: %d: Buffer size required per buffer: %d, num of buf: %d, aligned size = %d\n",
port, size, numbufs, ring_size);
{
i = 0;
binfo = &video_inst.binfo[port][i];
binfo->ion.ion_device_fd = alloc_map_ion_memory(ring_size,
align,
&binfo->ion.ion_alloc_data,
&binfo->ion.fd_ion_data,
0);
if (binfo->ion.ion_device_fd < 0) {
E("Failed to allocate memory\n");
rc = -ENOMEM;
goto ring_error;
}
binfo->vaddr = (__u8 *)mmap(NULL, ring_size,
PROT_READ | PROT_WRITE, MAP_SHARED,
binfo->ion.fd_ion_data.fd, 0);
if (binfo->vaddr == MAP_FAILED) {
E("Failed to get buffer virtual address\n");
close(binfo->ion.fd_ion_data.fd);
free_ion_memory(&binfo->ion);
rc = -ENOMEM;
goto ring_error;
}
binfo->buf_type = buf_type;
binfo->index = i;
binfo->size = ring_size;
buf.index = i;
buf.type = buf_type;
buf.memory = V4L2_MEMORY_USERPTR;
plane[0].length = ring_size;
plane[0].m.userptr = (unsigned long)binfo->vaddr;
plane[0].reserved[0] = binfo->ion.fd_ion_data.fd;
plane[0].reserved[1] = 0;
plane[0].data_offset = binfo->offset;
buf.length = 1;
buf.m.planes = plane;
V("Preparing Ring Buffer %p\n", binfo->vaddr);
rc = ioctl(fd, VIDIOC_PREPARE_BUF, &buf);
if (rc) {
E("Failed to prepare ring bufer\n");
goto ring_error;
}
}
for (i = 1; i < numbufs; i++) {
binfo_tmp = binfo;
binfo = &video_inst.binfo[port][i];
memcpy(binfo, binfo_tmp, sizeof(struct bufinfo));
binfo->index = i;
}
pthread_mutex_lock(&video_inst.q_lock[port]);
for (i = 0; i < numbufs; i++) {
binfo = &video_inst.binfo[port][i];
D("push to queue:%d : binfo: %p, vaddr: %p\n",
port, binfo, binfo->vaddr);
if (push(&video_inst.buf_queue[port], (void *) binfo) < 0)
E("Error in pushing buffers to queue \n");
}
pthread_mutex_unlock(&video_inst.q_lock[port]);
// Initialize ring buffer header
video_inst.ring_info.ring_base_addr = (__u32)binfo->vaddr;
video_inst.ring_info.ring_size = binfo->size;
video_inst.ring_info.ring_is_empty = 1;
video_inst.ring_info.ring_is_full = 0;
video_inst.ring_info.ring_read_idx = 0;
video_inst.ring_info.ring_write_idx = 0;
video_inst.ring_buf = (__u8 *)calloc(size, sizeof(__u8));
if (!video_inst.ring_buf) {
E("ring_buf allocation failed\n");
rc = -ENOMEM;
goto ring_error;
}
ring_error:
return rc;
}
int configure_session (void)
{
int is_encode, is_decode;
I("Input dimensions Height = %ld, Width = %ld, Frame Count = %ld \n",
input_args->input_height,input_args->input_width,input_args->frame_count);
I("CODEC type = %s \n",input_args->codec_type);
is_encode = !strcmp(input_args->device_mode,"ENCODE");
is_decode = !strcmp(input_args->device_mode,"DECODE");
if (!is_encode && !is_decode) {
E("Error \n");
return -EINVAL;
}
if (is_decode) {
input_args->session = DECODER_SESSION;
V("decode mode*** \n");
} else {
input_args->session = ENCODER_SESSION;
V("Encode mode*** \n");
}
I("Current session is %d\n", input_args->session);
if (!strcmp(input_args->read_mode, "FIX")) {
I("Read mode: %s\n", input_args->read_mode);
input_args->n_read_mode = FIX_NUMBER;
} else if (!strcmp(input_args->read_mode, "ARBITRARY")) {
I("Read mode: %s\n", input_args->read_mode);
input_args->n_read_mode = RANDOM_NUMBER;
} else {
I("Read mode: DEFAULT\n");
input_args->n_read_mode = NOT_ARBITRARY_NUMBER;
}
I("Input file: %s\n", input_args->input);
I("Output file: %s\n", input_args->output);
if (strncmp(input_args->bufsize_filename, "beefbeef", 8))
I("fix_buf_size_file: %s\n", input_args->bufsize_filename);
if (input_args->ring_num_hdrs)
I("Number of headers to use for OUTPUT port: %ld\n", input_args->ring_num_hdrs);
if (input_args->output_buf_size)
I("Output port/Ring buffer size: %ld\n", input_args->output_buf_size);
return 0;
}
int commands_controls(void)
{
int i,pos1,pos2,pos3,pos4,str_len,rc=0;
char line[MAX_LINE], param_name[MAX_NAME_LENGTH], param_name1[MAX_NAME_LENGTH];
int fd = -1;
V("\n \n ****** Commands and Controls ****** \n \n");
for(i=0; i<sequence_count && !rc; i++) {
str_len = strlen(input_args->sequence[i]);
rc = 0;
pos1 = strcspn(input_args->sequence[i]," ");
strlcpy(param_name,input_args->sequence[i],pos1+1);
if(!(strncmp(param_name,"OPEN\r",pos1))) {
V("OPEN Command\n");
if (input_args->session == DECODER_SESSION) {
V("Opening decoder\n");
fd = open("/dev/video32", O_RDWR);
} else {
V("Opening encoder\n");
fd = open("/dev/video33", O_RDWR);
}
if (fd < 0) {
E("Failed to open video device\n");
rc = -ENODEV;
break;
}
video_inst.fd = fd;
} else if(!(strncmp(param_name,"GET_BUFREQ",pos1))) {
V("GET_BUFREQ Command\n");
pos2 = strcspn(input_args->sequence[i]+pos1+1," ");
if (pos2 == 0) {
if (pos1+1 == str_len) {
E("No Port Specified \n");
rc = -EINVAL;
goto close_fd;
}
do {
pos2 = strcspn(input_args->sequence[i]+pos1+1," ");
pos1++;
} while(pos1+1 < str_len && pos2 == 0);
pos1--;
}
strlcpy(param_name,input_args->sequence[i]+pos1+1,pos2+1);
if(!(strncmp(param_name,"CAPTURE\r",pos2))) {
V("GET_BUFREQ on CAPTURE port \n");
rc = get_bufreqs(fd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
if (rc) {
E("Failed to get buffer requirements on capture port\n");
goto close_fd;
}
} else if (!(strncmp(param_name,"OUTPUT\r",pos2))) {
V("GET_BUFREQ on OUTPUT port \n");
rc = get_bufreqs(fd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
if (rc) {
E("Failed to get buffer requirements on output port\n");
goto close_fd;
}
} else {
E("Wrong port sepcified\n");
rc = -EINVAL;
goto close_fd;
}
} else if(!(strncmp(param_name,"QUEUE",pos1))) {
V("QUEUE Command\n");
pos2 = strcspn(input_args->sequence[i]+pos1+1," ");
if (pos2 == 0) {
if (pos1+1 == str_len) {
E("No Port Specified \n");
rc = -EINVAL;
goto close_fd;
}
do {
pos2 = strcspn(input_args->sequence[i]+pos1+1," ");
pos1++;
} while(pos1+1 < str_len && pos2 == 0);
pos1--;
}
strlcpy(param_name,input_args->sequence[i]+pos1+1,pos2+1);
if(!(strncmp(param_name,"CAPTURE\r",pos2))) {
V("QUEUE Buffers on CAPTURE port \n");
rc = qbuf(fd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
if (rc) {
E("Failed to queue buffers\n");
goto close_fd;
}
} else if (!(strncmp(param_name,"OUTPUT\r",pos2))) {
V("QUEUE Buffers on OUTPUT port \n");
rc = qbuf(fd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
if (rc) {
E("Failed to queue buffers\n");
goto close_fd;
}
} else {
E("Wrong port sepcified\n");
rc = -EINVAL;
goto close_fd;
}
} else if(!(strncmp(param_name,"RUN\r",pos1))) {
V("RUN command\n");
rc = run(fd);
} else if(!(strncmp(param_name,"DEQUEUE\r",pos1))) {
rc = deqbufs(fd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
} else if(!(strncmp(param_name,"PAUSE\r",pos1))) {
V("PAUSE Command\n");
} else if(!(strncmp(param_name,"RESUME\r",pos1))) {
V("RESUME Command\n");
} else if(!(strncmp(param_name,"FLUSH\r",pos1))) {
V("FLUSH Command\n");
} else if(!(strncmp(param_name,"POLL\r",pos1))) {
V("POLL Command\n");
} else if(!(strncmp(param_name,"ENUM_FORMATS",pos1))) {
V("ENUM_FORMATS Command\n");
pos2 = strcspn(input_args->sequence[i]+pos1+1," ");
if (pos2 == 0) {
if (pos1+1 == str_len) {
E("No Port Specified \n");
rc = -EINVAL;
goto close_fd;
}
do {
pos2 = strcspn(input_args->sequence[i]+pos1+1," ");
pos1++;
} while(pos1+1 < str_len && pos2 == 0);
pos1--;
}
strlcpy(param_name,input_args->sequence[i]+pos1+1,pos2+1);
if(!(strncmp(param_name,"CAPTURE\r",pos2))) {
V("ENUM_FORMATS on CAPTURE port \n");
enum_formats(fd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
} else if (!(strncmp(param_name,"OUTPUT\r",pos2))) {
V("ENUM_FORMATS on OUTPUT port \n");
enum_formats(fd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
} else {
E("Wrong port sepcified\n");
rc = -EINVAL;
goto close_fd;
}
} else if(!(strncmp(param_name,"QUERY_CAP\r",pos1))) {
V("QUERY_CAP Command**\n");
rc = querycap(fd);
if (rc) {
E("Failed to query capabilities\n");
goto close_fd;
}
} else if(!(strncmp(param_name,"SUBSCRIBE_EVENT\r",pos1))) {
V("SUBSCRIBE_EVENT Command**\n");
struct v4l2_event_subscription sub;
rc=subscribe_event(fd, &sub);
if (rc) {
E("Failed to subscribe event \n");
goto close_fd;
}
rc = pthread_create(&video_inst.poll_tid, NULL, poll_func, (void *)fd);
if (rc) {
E("Failed to create poll thread: %d\n", rc);
return rc;
}
video_inst.poll_created= 1;
} else if(!(strncmp(param_name,"UNSUBSCRIBE_EVENT\r",pos1))) {
V("UNSUBSCRIBE_EVENT Command**\n");
struct v4l2_event_subscription sub;
rc=unsubscribe_event(fd, &sub);
if (rc) {
E("Failed to unsubscribe event \n");
goto close_fd;
}
} else if(!(strncmp(param_name,"SET_CTRL",pos1))) {
V("SET_CTRL Command\n");
struct v4l2_control control;
pos2 = strcspn(input_args->sequence[i]+pos1+1," ");
strlcpy(param_name,input_args->sequence[i]+pos1+1,pos2+1);
if(!(strncmp(param_name,"FRAME_RATE",pos2))) {
V("FRAME_RATE Control\n");
pos3 = strcspn(input_args->sequence[i]+pos1+1+pos2+1," ");
strlcpy(param_name,input_args->sequence[i]+pos1+1+pos2+1,pos3+1);
input_args->frame_rate=atoi(param_name);
V("FRAME_RATE = %ld\n",input_args->frame_rate);
control.id = V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE;
control.value = input_args->frame_rate;
rc = set_control(fd, &control);
V("STREAM_FORMAT Set Control Done\n");
} else if(!(strncmp(param_name,"IDR_PERIOD",pos2))) {
V("IDR_PERIOD Control\n");
pos3 = strcspn(input_args->sequence[i]+pos1+1+pos2+1," ");
strlcpy(param_name,input_args->sequence[i]+pos1+1+pos2+1,pos3+1);
input_args->idr_period =atoi(param_name);
V("STREAM_FORMAT = %ld\n",input_args->idr_period);
control.id = V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD;
control.value = input_args->idr_period;
rc = set_control(fd, &control);
V("IDR_PERIOD Set Control Done\n");
} else if(!(strncmp(param_name,"INTRA_PERIOD_P_FRAMES",pos2))) {
V("INTRA_PERIOD_P_FRAMES Control\n");
pos3 = strcspn(input_args->sequence[i]+pos1+1+pos2+1," ");
strlcpy(param_name,input_args->sequence[i]+pos1+1+pos2+1,pos3+1);
input_args->intra_period_p_frames =atoi(param_name);
V("INTRA_PERIOD_P_FRAMES = %ld\n",input_args->intra_period_p_frames);
control.id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES;
control.value = input_args->intra_period_p_frames;
rc = set_control(fd, &control);
V("INTRA_PERIOD_P_FRAMES Set Control Done\n");
} else if(!(strncmp(param_name,"INTRA_PERIOD_B_FRAMES",pos2))) {
V("INTRA_PERIOD_B_FRAMES Control\n");
pos3 = strcspn(input_args->sequence[i]+pos1+1+pos2+1," ");
strlcpy(param_name,input_args->sequence[i]+pos1+1+pos2+1,pos3+1);
input_args->intra_period_b_frames =atoi(param_name);
V("INTRA_PERIOD_B_FRAMES = %ld\n",input_args->intra_period_b_frames);
control.id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES;
control.value = input_args->intra_period_b_frames;
rc = set_control(fd, &control);
V("INTRA_PERIOD_B_FRAMES Set Control Done\n");
} else if(!(strncmp(param_name,"REQUEST_I_FRAME",pos2))) {
V("REQUEST_I_FRAME Control\n");
pos3 = strcspn(input_args->sequence[i]+pos1+1+pos2+1," ");
strlcpy(param_name,input_args->sequence[i]+pos1+1+pos2+1,pos3+1);
input_args->request_i_frame = atoi(param_name);
V("STREAM_FORMAT = %ld\n",input_args->request_i_frame);
//control.id = V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_IFRAME;
//control.value = input_args->intra_period;
//rc = set_control(fd, &control);
V("REQUEST_I_FRAME Set Control Done\n");
//input_args->request_i_frame = 0;
} else if(!(strncmp(param_name,"RATE_CONTROL",pos2))) {
V("RATE_CONTROL Control\n");
pos3 = strcspn(input_args->sequence[i]+pos1+1+pos2+1," ");
strlcpy(param_name,input_args->sequence[i]+pos1+1+pos2+1,pos3+1);
input_args->rate_control =atoi(param_name);
V("STREAM_FORMAT = %ld\n",input_args->rate_control);
control.id = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL;
control.value = input_args->rate_control;
rc = set_control(fd, &control);
V("RATE_CONTROL Set Control Done\n");
} else if(!(strncmp(param_name,"BIT_RATE",pos2))) {
V("\n BIT_RATE Control\n");
pos3 = strcspn(input_args->sequence[i]+pos1+1+pos2+1," ");
strlcpy(param_name,input_args->sequence[i]+pos1+1+pos2+1,pos3+1);
input_args->bit_rate=atoi(param_name);
V("\n BIT_RATE = %ld\n",input_args->bit_rate);
control.id = V4L2_CID_MPEG_VIDEO_BITRATE;
control.value = input_args->bit_rate;
rc = set_control(fd, &control);
V("BIT_RATE Set Control Done\n");
} else if(!(strncmp(param_name,"ENTROPY_MODE",pos2))) {
V("ENTROPY_MODE Control\n");
pos3 = strcspn(input_args->sequence[i]+pos1+1+pos2+1," ");
strlcpy(param_name,input_args->sequence[i]+pos1+1+pos2+1,pos3+1);
input_args->entropy_mode =atoi(param_name);
V("STREAM_FORMAT = %ld\n",input_args->entropy_mode);
control.id = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE;
control.value = input_args->entropy_mode;
rc = set_control(fd, &control);
V("ENTROPY_MODE Set Control Done\n");
} else if(!(strncmp(param_name,"CABAC_MODEL",pos2))) {
V("CABAC_MODEL Control\n");
pos3 = strcspn(input_args->sequence[i]+pos1+1+pos2+1," ");
strlcpy(param_name,input_args->sequence[i]+pos1+1+pos2+1,pos3+1);
input_args->cabac_model =atoi(param_name);
V("CABAC_MODEL = %ld\n",input_args->cabac_model);
control.id = V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL;
control.value = input_args->cabac_model;
rc = set_control(fd, &control);
V("CABAC_MODEL Set Control Done\n");
} else if(!(strncmp(param_name,"PROFILE",pos2))) {
V("PROFILE Control\n");
pos3 = strcspn(input_args->sequence[i]+pos1+1+pos2+1," ");
strlcpy(param_name,input_args->sequence[i]+pos1+1+pos2+1,pos3+1);
input_args->profile =atoi(param_name);
V("STREAM_FORMAT = %ld\n",input_args->stream_format);
control.id = V4L2_CID_MPEG_VIDEO_H264_PROFILE;
control.value = input_args->profile;
rc = set_control(fd, &control);
V("PROFILE Set Control Done\n");
} else if(!(strncmp(param_name,"LEVEL",pos2))) {
V("LEVEL Control\n");
pos3 = strcspn(input_args->sequence[i]+pos1+1+pos2+1," ");
strlcpy(param_name,input_args->sequence[i]+pos1+1+pos2+1,pos3+1);
input_args->level =atoi(param_name);
V("STREAM_FORMAT = %ld\n",input_args->level);
control.id = V4L2_CID_MPEG_VIDEO_H264_LEVEL;
control.value = input_args->level;
rc = set_control(fd, &control);
V("LEVEL Set Control Done\n");
} else if(!(strncmp(param_name,"ROTATION",pos2))) {
V("ROTATION Control\n");
pos3 = strcspn(input_args->sequence[i]+pos1+1+pos2+1," ");
strlcpy(param_name,input_args->sequence[i]+pos1+1+pos2+1,pos3+1);
input_args->rotation =atoi(param_name);
V("ROTATION = %ld\n",input_args->rotation);
control.id = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION;
control.value = input_args->rotation;
rc = set_control(fd, &control);
V("ROTATION Set Control Done\n");
} else if(!(strncmp(param_name,"I_FRAME_QP",pos2))) {
V("I_FRAME_QP Control\n");
pos3 = strcspn(input_args->sequence[i]+pos1+1+pos2+1," ");
strlcpy(param_name,input_args->sequence[i]+pos1+1+pos2+1,pos3+1);
input_args->i_frame_qp =atoi(param_name);
V("I_FRAME_QP = %ld\n",input_args->i_frame_qp);
control.id = V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP;
control.value = input_args->i_frame_qp;
rc = set_control(fd, &control);
V("I_FRAME_QP Set Control Done\n");
} else if(!(strncmp(param_name,"P_FRAME_QP",pos2))) {
V("P_FRAME_QP Control\n");
pos3 = strcspn(input_args->sequence[i]+pos1+1+pos2+1," ");
strlcpy(param_name,input_args->sequence[i]+pos1+1+pos2+1,pos3+1);
input_args->p_frame_qp =atoi(param_name);
V("P_FRAME_QP = %ld\n",input_args->p_frame_qp);
control.id = V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP;
control.value = input_args->p_frame_qp;
rc = set_control(fd, &control);
V("P_FRAME_QP Set Control Done\n");
} else if(!(strncmp(param_name,"B_FRAME_QP",pos2))) {
V("B_FRAME_QP Control\n");
pos3 = strcspn(input_args->sequence[i]+pos1+1+pos2+1," ");
strlcpy(param_name,input_args->sequence[i]+pos1+1+pos2+1,pos3+1);
input_args->b_frame_qp =atoi(param_name);
V("B_FRAME_QP = %ld\n",input_args->b_frame_qp);
control.id = V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP;
control.value = input_args->b_frame_qp;
rc = set_control(fd, &control);
V("B_FRAME_QP Set Control Done\n");
} else if(!(strncmp(param_name,"SLICE_MODE",pos2))) {
V("SLICE_MODE Control\n");
pos3 = strcspn(input_args->sequence[i]+pos1+1+pos2+1," ");
strlcpy(param_name,input_args->sequence[i]+pos1+1+pos2+1,pos3+1);
input_args->slice_mode =atoi(param_name);
V("SLICE_MODE = %ld\n",input_args->slice_mode);
control.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE;
control.value = input_args->slice_mode;
rc = set_control(fd, &control);
V("SLICE_MODE Set Control Done\n");
} else if(!(strncmp(param_name,"SLICE_MODE_BYTES",pos2))) {
V("SLICE_MODE_BYTES Control\n");
pos3 = strcspn(input_args->sequence[i]+pos1+1+pos2+1," ");
strlcpy(param_name,input_args->sequence[i]+pos1+1+pos2+1,pos3+1);
input_args->slice_mode_bytes =atoi(param_name);
V("SLICE_MODE_BYTES = %ld\n",input_args->slice_mode_bytes);
control.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES;
control.value = input_args->slice_mode_bytes;
rc = set_control(fd, &control);
V("SLICE_MODE_BYTES Set Control Done\n");
} else if(!(strncmp(param_name,"SLICE_MODE_MB",pos2))) {
V("SLICE_MODE_MB Control\n");
pos3 = strcspn(input_args->sequence[i]+pos1+1+pos2+1," ");
strlcpy(param_name,input_args->sequence[i]+pos1+1+pos2+1,pos3+1);
input_args->slice_mode_mb =atoi(param_name);
V("SLICE_MODE_MB = %ld\n",input_args->slice_mode_mb);
control.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB;
control.value = input_args->slice_mode_mb;
rc = set_control(fd, &control);
V("SLICE_MODE_MB Set Control Done\n");
} else if(!(strncmp(param_name,"LOOP_FILTER_MODE",pos2))) {
V("LOOP_FILTER_MODE Control\n");
pos3 = strcspn(input_args->sequence[i]+pos1+1+pos2+1," ");
strlcpy(param_name,input_args->sequence[i]+pos1+1+pos2+1,pos3+1);
input_args->loop_filter_mode =atoi(param_name);
V("STREAM_FORMAT = %ld\n",input_args->loop_filter_mode);
control.id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE;
control.value = input_args->loop_filter_mode;
rc = set_control(fd, &control);
V("LOOP_FILTER_MODE Set Control Done\n");
} else if(!(strncmp(param_name,"LOOP_FILTER_ALPHA",pos2))) {
V("LOOP_FILTER_ALPHA Control\n");
pos3 = strcspn(input_args->sequence[i]+pos1+1+pos2+1," ");
strlcpy(param_name,input_args->sequence[i]+pos1+1+pos2+1,pos3+1);
input_args->loop_filter_alpha =atoi(param_name);
V("STREAM_FORMAT = %ld\n",input_args->loop_filter_alpha);
control.id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA;
control.value = input_args->loop_filter_alpha;
rc = set_control(fd, &control);
V("LOOP_FILTER_ALPHA Set Control Done\n");
} else if(!(strncmp(param_name,"LOOP_FILTER_BETA",pos2))) {
V("LOOP_FILTER_BETA Control\n");
pos3 = strcspn(input_args->sequence[i]+pos1+1+pos2+1," ");
strlcpy(param_name,input_args->sequence[i]+pos1+1+pos2+1,pos3+1);
input_args->loop_filter_beta =atoi(param_name);
V("STREAM_FORMAT = %ld\n",input_args->loop_filter_beta);
control.id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA;
control.value = input_args->loop_filter_beta;
rc = set_control(fd, &control);
V("LOOP_FILTER_BETA Set Control Done\n");
} else if(!(strncmp(param_name,"STREAM_FORMAT",pos2))) {
V("STREAM_FORMAT Control\n");
pos3 = strcspn(input_args->sequence[i]+pos1+1+pos2+1," ");
strlcpy(param_name,input_args->sequence[i]+pos1+1+pos2+1,pos3+1);
input_args->stream_format =atoi(param_name);
V("STREAM_FORMAT = %ld\n",input_args->stream_format);
control.id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT;
control.value = input_args->stream_format;
rc = set_control(fd, &control);
V("STREAM_FORMAT Set Control Done\n");
} else if(!(strncmp(param_name,"OUTPUT_ORDER",pos2))) {
V("OUTPUT_ORDER Control\n");
pos3 = strcspn(input_args->sequence[i]+pos1+1+pos2+1," ");
strlcpy(param_name,input_args->sequence[i]+pos1+1+pos2+1,pos3+1);
input_args->output_order =atoi(param_name);
V("OUTPUT_ORDER = %ld\n",input_args->output_order);
control.id = V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER;
control.value = input_args->output_order;
rc = set_control(fd, &control);
V("OUTPUT_ORDER Set Control Done\n");
} else if(!(strncmp(param_name,"ENABLE_PIC_TYPE",pos2))) {
V("ENABLE_PIC_TYPE Control\n");
pos3 = strcspn(input_args->sequence[i]+pos1+1+pos2+1," ");
strlcpy(param_name,input_args->sequence[i]+pos1+1+pos2+1,pos3+1);
input_args->enable_pic_type =atoi(param_name);
V("ENABLE_PIC_TYPE = %ld\n",input_args->enable_pic_type);
control.id = V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_PICTURE_TYPE;
control.value = input_args->enable_pic_type;
rc = set_control(fd, &control);
V("ENABLE_PIC_TYPE Set Control Done\n");
} else if(!(strncmp(param_name,"KEEP_ASPECT_RATIO",pos2))) {
V("KEEP_ASPECT_RATIO Control\n");
pos3 = strcspn(input_args->sequence[i]+pos1+1+pos2+1," ");
strlcpy(param_name,input_args->sequence[i]+pos1+1+pos2+1,pos3+1);
input_args->keep_aspect_ratio =atoi(param_name);
V("KEEP_ASPECT_RATIO = %ld\n",input_args->keep_aspect_ratio);
control.id = V4L2_CID_MPEG_VIDC_VIDEO_KEEP_ASPECT_RATIO;
control.value = input_args->keep_aspect_ratio;
rc = set_control(fd, &control);
V("KEEP_ASPECT_RATIO Set Control Done\n");
} else if(!(strncmp(param_name,"POST_LOOP_DEBLOCKER",pos2))) {
V("POST_LOOP_DEBLOCKER Control\n");
pos3 = strcspn(input_args->sequence[i]+pos1+1+pos2+1," ");
strlcpy(param_name,input_args->sequence[i]+pos1+1+pos2+1,pos3+1);
input_args->post_loop_deblocker =atoi(param_name);
V("POST_LOOP_DEBLOCKER = %ld\n",input_args->post_loop_deblocker);
control.id = V4L2_CID_MPEG_VIDC_VIDEO_POST_LOOP_DEBLOCKER_MODE;
control.value = input_args->post_loop_deblocker;
rc = set_control(fd, &control);
V("POST_LOOP_DEBLOCKER Set Control Done\n");
} else if(!(strncmp(param_name,"DIVX_FORMAT",pos2))) {
V("DIVX_FORMAT Control\n");
pos3 = strcspn(input_args->sequence[i]+pos1+1+pos2+1," ");
strlcpy(param_name,input_args->sequence[i]+pos1+1+pos2+1,pos3+1);
input_args->divx_format =atoi(param_name);
V("DIVX_FORMAT = %ld\n",input_args->divx_format);
control.id = V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT;
control.value = input_args->divx_format;
rc = set_control(fd, &control);
V("DIVX_FORMAT Set Control Done\n");
} else if(!(strncmp(param_name,"MB_ERROR_MAP_REPORTING",pos2))) {
V("MB_ERROR_MAP_REPORTING Control\n");
pos3 = strcspn(input_args->sequence[i]+pos1+1+pos2+1," ");
strlcpy(param_name,input_args->sequence[i]+pos1+1+pos2+1,pos3+1);
input_args->mb_error_map_reporting =atoi(param_name);
V("MB_ERROR_MAP_REPORTING = %ld\n",input_args->mb_error_map_reporting);
control.id = V4L2_CID_MPEG_VIDC_VIDEO_MB_ERROR_MAP_REPORTING;
control.value = input_args->mb_error_map_reporting;
rc = set_control(fd, &control);
V("MB_ERROR_MAP_REPORTING Set Control Done\n");
} else if(!(strncmp(param_name,"CONTINUE_DATA_TRANSFER",pos2))) {
V("CONTINUE_DATA_TRANSFER Control\n");
pos3 = strcspn(input_args->sequence[i]+pos1+1+pos2+1," ");
strlcpy(param_name,input_args->sequence[i]+pos1+1+pos2+1,pos3+1);
input_args->continue_data_transfer =atoi(param_name);
V("CONTINUE_DATA_TRANSFER = %ld\n",input_args->continue_data_transfer);
control.id = V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER;
control.value = input_args->continue_data_transfer;
rc = set_control(fd, &control);
V("CONTINUE_DATA_TRANSFER (smooth streaming) Set Control Done\n");
} else if(!(strncmp(param_name,"ALLOC_TYPE",pos2))) {
V("ALLOC_TYPE Control\n");
pos3 = strcspn(input_args->sequence[i]+pos1+1+pos2+1," ");
strlcpy(param_name,input_args->sequence[i]+pos1+1+pos2+1,pos3+1);
input_args->alloc_type =atoi(param_name);
if(input_args->alloc_type == V4L2_MPEG_VIDC_VIDEO_RING)
V("Ring buffer allocation \n");
else if(input_args->alloc_type == V4L2_MPEG_VIDC_VIDEO_STATIC)
V("Static buffer allocation \n");
else
E("Incorrect ALLOC_TYPE\n");
control.id = V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_INPUT;
control.value = input_args->alloc_type;
rc = set_control(fd, &control);
V("ALLOC_TYPE Set Control Done\n");
} else if(!(strncmp(param_name,"FRAME_ASSEMBLY",pos2))) {
V("FRAME_ASSEMBLY Control\n");
pos3 = strcspn(input_args->sequence[i]+pos1+1+pos2+1," ");
strlcpy(param_name,input_args->sequence[i]+pos1+1+pos2+1,pos3+1);
input_args->enable_frame_assembly =atoi(param_name);
V("FRAME_ASSEMBLY = %ld\n",input_args->enable_frame_assembly);
control.id = V4L2_CID_MPEG_VIDC_VIDEO_FRAME_ASSEMBLY;
control.value = input_args->enable_frame_assembly;
rc = set_control(fd, &control);
V("FRAME_ASSEMBLY Set Control Done\n");
} else if(!(strncmp(param_name,"VIDEO_EXTRADATA",pos2))) {
V("VIDEO_EXTRADATA Control\n");
rc = 0;
pos3 = strcspn(input_args->sequence[i]+pos1+1+pos2+1," ");
strlcpy(param_name,input_args->sequence[i]+pos1+1+pos2+1,pos3+1);
control.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA;
control.value = get_extradata_value(param_name);
if (control.value < 0) {
E("Parser didn't handle SET_CTRL VIDEO_EXTRADATA %s \n",
param_name);
rc = -1;
} else {
rc = set_control(fd, &control);
V("VIDEO_EXTRADATA Set Control Done\n");
}
} else {
E("ERROR .... Wrong Control \n");
rc = -EINVAL;
goto close_fd;
}
} else if(!(strncmp(param_name,"GET_CTRL\r",pos1))) {
V("GET_CTRL Command\n");
struct v4l2_control control;
pos2 = strcspn(input_args->sequence[i]+pos1+1," ");
strlcpy(param_name,input_args->sequence[i]+pos1+1,pos2+1);
if(!(strncmp(param_name,"STREAM_FORMAT\r",pos2))) {
V("STREAM_FORMAT Control\n");
control.id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT;
rc = get_control(fd, &control);
V("STREAM_FORMAT Get Control Done\n");
} else {
E("ERROR .... Wrong Control \n");
rc = -EINVAL;
goto close_fd;
}
} else if(!(strncmp(param_name,"CLOSE\r",pos1))) {
V("CLOSE Command\n");
// TODO: handle this command
} else if(!(strncmp(param_name,"STREAM_ON",pos1))) {
V("STREAM_ON Command\n");
pos2 = strcspn(input_args->sequence[i]+pos1+1," ");
if (pos2 == 0) {
if (pos1+1 == str_len) {
E("No Port Specified \n");
rc = -EINVAL;
goto close_fd;
}
do {
pos2 = strcspn(input_args->sequence[i]+pos1+1," ");
pos1++;
} while(pos1+1 < str_len && pos2 == 0);
pos1--;
}
strlcpy(param_name,input_args->sequence[i]+pos1+1,pos2+1);
if(!(strncmp(param_name,"CAPTURE\r",pos2))) {
V("CAPTURE PORT Stream ON \n");
rc = streamon(fd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
if (rc) {
E("Failed to call streamon on V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE\n");
goto close_fd;
}
} else if (!(strncmp(param_name,"OUTPUT\r",pos2))) {
V("OUTPUT PORT Stream ON \n");
rc = streamon(fd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
if (rc) {
E("Failed to call streamon on V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE\n");
goto close_fd;
}
} else {
E("Wrong port sepcified\n");
rc = -EINVAL;
goto close_fd;
}
} else if(!(strncmp(param_name,"STREAM_OFF",pos1))) {
V("STREAM_OFF Command\n");
pos2 = strcspn(input_args->sequence[i]+pos1+1," ");
if (pos2 == 0) {
if (pos1+1 == str_len) {
E("No Port Specified \n");
rc = -EINVAL;
goto close_fd;
}
do {
pos2 = strcspn(input_args->sequence[i]+pos1+1," ");
pos1++;
} while(pos1+1 < str_len && pos2 == 0);
pos1--;
}
strlcpy(param_name,input_args->sequence[i]+pos1+1,pos2+1);
if(!(strncmp(param_name,"CAPTURE\r",pos2))) {
V("CAPTURE PORT Stream OFF \n");
rc = streamoff(fd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
if (rc) {
E("Failed to call streamoff on capture port\n");
goto close_fd;
}
} else if (!(strncmp(param_name,"OUTPUT\r",pos2))) {
V("OUTPUT PORT Stream OFF \n");
rc = streamoff(fd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
if (rc) {
E("Failed to call streamoff on capture port\n");
goto close_fd;
}
} else {
E("Wrong port sepcified\n");
rc = -EINVAL;
goto close_fd;
}
} else if(!(strncmp(param_name,"SET_FMT",pos1))) {
V("SET_FMT Command\n");
pos2 = strcspn(input_args->sequence[i]+pos1+1," ");
if (pos2 == 0) {
if (pos1+1 == str_len) {
E("No Port Specified \n");
rc = -EINVAL;
goto close_fd;
}
do {
pos2 = strcspn(input_args->sequence[i]+pos1+1," ");
pos1++;
} while(pos1+1 < str_len && pos2 == 0);
pos1--;
}
strlcpy(param_name,input_args->sequence[i]+pos1+1,pos2+1);
if(!(strncmp(param_name,"CAPTURE\r",pos2))) {
V("SET_FMT on CAPTURE port \n");
rc = set_format(fd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
if (rc) {
E("Failed to set format on capture port\n");
goto close_fd;
}
} else if (!(strncmp(param_name,"OUTPUT\r",pos2))) {
V("SET_FMT on OUTPUT port \n");
rc = set_format(fd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
if (rc) {
E("Failed to set format on output port\n");
goto close_fd;
}
} else {
E("Wrong port sepcified\n");
rc = -EINVAL;
goto close_fd;
}
} else if(!(strncmp(param_name,"GET_FMT",pos1))) {
V("GET_FMT Command\n");
pos2 = strcspn(input_args->sequence[i]+pos1+1," ");
if (pos2 == 0) {
if (pos1+1 == str_len) {
E("No Port Specified \n");
rc = -EINVAL;
goto close_fd;
}
do {
pos2 = strcspn(input_args->sequence[i]+pos1+1," ");
pos1++;
} while(pos1+1 < str_len && pos2 == 0);
pos1--;
}
strlcpy(param_name,input_args->sequence[i]+pos1+1,pos2+1);
if(!(strncmp(param_name,"CAPTURE\r",pos2))) {
V("GET_FMT on CAPTURE port \n");
rc = get_format(fd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
if (rc) {
E("Failed to get format on capture port\n");
goto close_fd;
}
} else if (!(strncmp(param_name,"OUTPUT\r",pos2))) {
V("GET_FMT on OUTPUT port \n");
rc = get_format(fd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
if (rc) {
E("Failed to get format on capture port\n");
goto close_fd;
}
} else {
E("Wrong port sepcified\n");
rc = -EINVAL;
goto close_fd;
}
} else if(!(strncmp(param_name,"PREPARE_BUFS",pos1))) {
V("PREPARE_BUFS Command\n");
pos2 = strcspn(input_args->sequence[i]+pos1+1," ");
if (pos2 == 0) {
if (pos1+1 == str_len) {
E("No Port Specified \n");
rc = -EINVAL;
goto close_fd;
}
do {
pos2 = strcspn(input_args->sequence[i]+pos1+1," ");
pos1++;
} while(pos1+1 < str_len && pos2 == 0);
pos1--;
}
strlcpy(param_name,input_args->sequence[i]+pos1+1,pos2+1);
if(!(strncmp(param_name,"CAPTURE\r",pos2))) {
V("PREPARE_BUFS on CAPTURE port \n");
rc = prepare_bufs(fd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
if (rc) {
E("Failed to prepare buffers on capture port\n");
goto close_fd;
}
} else if (!(strncmp(param_name,"OUTPUT\r",pos2))) {
V("PREPARE_BUFS on OUTPUT port \n");
rc = prepare_bufs(fd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
if (rc) {
E("Failed to prepare buffers on output port\n");
goto close_fd;
}
} else {
E("Wrong port sepcified\n");
rc = -EINVAL;
goto close_fd;
}
} else if(!(strncmp(param_name,"ALLOC_RING_BUF", pos1))) {
V("ALLOC_RING_BUF Command\n");
rc = allocate_ring_buffer(fd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
if (rc) {
E("Failed to allcate ring buffer on output port\n");
goto close_fd;
}
} else if(!(strncmp(param_name,"SLEEP",pos1))) {
int sleep_time = 0;
V("SLEEP Command\n");
pos2 = strcspn(input_args->sequence[i]+pos1+1," ");
strlcpy(param_name,input_args->sequence[i]+pos1+1,pos2+1);
sleep_time = atoi(param_name);
V("Sleeping for %d\n", sleep_time);
sleep(sleep_time);
V("Waking up!\n");
} else {
E("WRONG Command\n");
rc = -EINVAL;
goto close_fd;
}
}
close_fd:
return rc;
}
int parse_sequences(struct arguments *input_args)
{
FILE * fp;
char line[MAX_LINE], param_name[128], arr_seps[]=" ,\t\n", * token, * str_wbuf;
size_t pos1, pos2, pos3, len;
int iTableIndex, arr_read,is_sequence;
float flt;
size_t str_wlen;
int temp32;
short * p16;
iTableIndex = 0;
sequence_count = 0;
if(!(fp = fopen(input_args->config,"rt"))) {
return -EIO;
}
while(fgets(line,MAX_LINE-1,fp)) {
len = strlen(line);
pos1 = strcspn(line, "#");
pos2 = strcspn(line,":");
if(pos2 == len)
continue;
line[pos2] = '\t';
sscanf(line,"%s",param_name);
is_sequence=strcmp(param_name,"SEQUENCE");
if(is_sequence != 0)
continue;
for( ; pos2<len; pos2++) {
if(line[pos2]!=' '&& line[pos2]!='\t' && line[pos2]!='\r')
break;
}
pos3 = pos2 + find_first_non_whitespace_reverse(line+pos2,pos1 - pos2);
str_wbuf = input_args->sequence[iTableIndex++];
str_wlen = pos3 - pos2 + 1;
strlcpy(str_wbuf,line+pos2,str_wlen+1);
sequence_count++;
}
fclose(fp);
return 0;
}
int parse_param_file(const char * filename, const param * tptab, const int tptab_size)
{
FILE * fp;
char line[MAX_LINE], param_name[128],arr_seps[]=" ,\t\n", * token, * str_wbuf;
size_t pos1, pos2, pos3, len;
int iTableIndex, arr_read;
float flt;
size_t str_wlen;
int temp32;
short * p16;
if(!(fp = fopen(filename,"rt"))) {
E("fail to open configuration file: %s\n", filename);
return -EIO;
}
while(fgets(line,MAX_LINE-1,fp)) {
len = strlen(line);
pos1 = strcspn(line, "#");
pos2 = strcspn(line,":");
if(pos2 == len)
continue;
line[pos2] = '\t';
sscanf(line,"%s",param_name);
if(search_for_preset_param(
tptab,param_name,&iTableIndex,tptab_size) != SUCCESS) {
if(iTableIndex >= tptab_size || iTableIndex < 0) {
E("Malformed param_table[]\n");
return -EOVERFLOW;
}
continue;
}
switch((tptab+iTableIndex)->param_type) {
case INT32:
sscanf(line+pos2+1,"%d",(int*)(tptab+iTableIndex)->param_ptr);
break;
case INT16:
sscanf(line+pos2+1,"%d",&temp32);
p16 = ((short*)(tptab+iTableIndex)->param_ptr);
*p16 = (short)temp32;
break;
case FLOAT:
sscanf(line+pos2+1,"%f",&flt);
*(float*)(tptab+iTableIndex)->param_ptr = flt;
break;
case DOUBLE:
sscanf(line+pos2+1,"%f",&flt);
*(double*)(tptab+iTableIndex)->param_ptr = flt;
break;
case INT32_ARRAY:
case INT16_ARRAY:
case FLOAT_ARRAY:
case DOUBLE_ARRAY:
arr_read = 0;
token = strtok(line+pos2,arr_seps);
while(token != NULL && arr_read < (tptab+iTableIndex)->array_size) {
if((tptab+iTableIndex)->param_type == INT32_ARRAY)
((int*)(tptab+iTableIndex)->param_ptr)[arr_read++] = atoi(token);
else if((tptab+iTableIndex)->param_type == INT16_ARRAY)
((short*)(tptab+iTableIndex)->param_ptr)[arr_read++] = atoi(token);
else if((tptab+iTableIndex)->param_type == FLOAT_ARRAY)
((float*)(tptab+iTableIndex)->param_ptr)[arr_read++] = (float)atof(token);
else
((double*)(tptab+iTableIndex)->param_ptr)[arr_read++] = atof(token);
token = strtok( NULL, arr_seps );
}
break;
case STRING:
for( ; pos2<len; pos2++) {
if(line[pos2]!=' '&& line[pos2]!='\t' && line[pos2]!='\r')
break;
}
pos3 = pos2 + find_first_non_whitespace_reverse(line+pos2,pos1 - pos2);
str_wbuf = (char*)(tptab+iTableIndex)->param_ptr;
str_wlen = pos3 - pos2 + 1;
if((int)str_wlen > (tptab+iTableIndex)->array_size - 1) {
str_wlen = (tptab+iTableIndex)->array_size - 1;
}
strlcpy(str_wbuf,line+pos2,str_wlen+1);
break;
case FLAG:
break;
}
}
fclose(fp);
return 0;
}
static status search_for_preset_param(const param * tptab, const char * param_name, int * pTableIndex, const int table_size)
{
const param * p = tptab;
* pTableIndex = -1;
while(strcmp(p->param_name,"eot")) {
(*pTableIndex) ++;
if(!strcmp(p->param_name,param_name)) {
return SUCCESS;
}
p++;
if(*pTableIndex >= table_size)
return ERROR;
}
return ERROR;
}
static size_t find_first_non_whitespace_reverse(const char * str, size_t start_pos)
{
size_t len = strlen(str);
int pos;
pos = (start_pos > len - 1) ? len - 1 : start_pos;
if(pos == 0)
return pos;
for(; pos-- >=0 ;) {
if(str[pos] != ' ' && str[pos] != '\t' && str[pos]!='\r')
break;
}
return pos;
}
static int set_control(int fd, struct v4l2_control *control)
{
int rc;
D("Calling IOCTL set control for id=%d, val=%d\n", control->id, control->value);
rc = ioctl(fd, VIDIOC_S_CTRL, control);
if (rc) {
E("Failed to set control id=%d, val=%d\n", control->id, control->value);;
return -1;
}
D("Success IOCTL set control for id=%d, value=%d\n", control->id, control->value);
return 0;
}
static int get_control(int fd, struct v4l2_control *control)
{
int rc;
D("Calling IOCTL get control for id=%d\n", control->id);
rc = ioctl(fd, VIDIOC_G_CTRL, control);
if (rc) {
E("Failed to get control\n");
return -1;
}
D("Success IOCTL get control for id=%d, value=%d\n", control->id, control->value);
return 0;
}
static int subscribe_event(int fd, struct v4l2_event_subscription *sub)
{
int i, rc;
int size_event = sizeof(event_type)/sizeof(int);
for (i = 0; i < size_event; i++) {
memset(sub, 0, sizeof(*sub));
sub->type = event_type[i];
D("Calling IOCTL to Subscribe Event id = %d \n", sub->type);
rc = ioctl(fd, VIDIOC_SUBSCRIBE_EVENT, sub);
if (rc) {
E("Failed to get control\n");
return -1;
}
V("Success IOCTL to Subscribe Event id = %d \n", sub->type);
video_inst.events_subscribed += 1;
}
return 0;
}
static int unsubscribe_event(int fd, struct v4l2_event_subscription *sub)
{
int i, rc;
int size_event = sizeof(event_type)/sizeof(int);
for (i = 0; i < size_event; i++) {
sub->type = event_type[i];
D("Calling IOCTL to UnSubscribe Event id = %d \n", sub->type);
rc = ioctl(fd, VIDIOC_UNSUBSCRIBE_EVENT, sub);
if (rc) {
E("Failed to UnSubscribe event\n");
return -1;
}
V("Success IOCTL to UnSubscribe Event id = %d \n", sub->type);
video_inst.events_subscribed -= 1;
}
return 0;
}
static int decoder_cmd(int fd, struct v4l2_decoder_cmd *dec)
{
int rc;
V("Calling IOCTL to Decoder cmd id = %d \n", dec->cmd);
rc = ioctl(fd, VIDIOC_DECODER_CMD, dec);
if (rc) {
E("Failed to get control\n");
return -1;
}
return 0;
}
static int enum_formats(int fd, enum v4l2_buf_type buf_type)
{
struct v4l2_fmtdesc fdesc;
fdesc.type = buf_type;
int i, rc;
for(i = 0;; i++) {
fdesc.index = i;
rc = ioctl(fd, VIDIOC_ENUM_FMT, &fdesc);
if (rc)
break;
V("Enum fmt: description: %s, fmt: %x, flags = %x\n", fdesc.description,
fdesc.pixelformat, fdesc.flags);
}
return 0;
}
static int get_format(int fd, enum v4l2_buf_type buf_type)
{
struct v4l2_format fmt;
int port;
int rc;
int extra_idx = 0;
int extra_data_size = 0;
memset(&fmt, 0, sizeof(fmt));
fmt.type = buf_type;
rc = ioctl(fd, VIDIOC_G_FMT, &fmt);
if (rc) {
E("Failed to get format\n");
return -1;
}
port = buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ? CAPTURE_PORT : OUTPUT_PORT;
V("VIDIOC_G_FMT port = %d: height = %d, width = %d, format = %x, size = %d\n",
port,
fmt.fmt.pix_mp.height,
fmt.fmt.pix_mp.width,
fmt.fmt.pix_mp.pixelformat,
fmt.fmt.pix_mp.plane_fmt[0].sizeimage);
V("stride = %d, scanlines = %d, num_planes = %d\n",
fmt.fmt.pix_mp.plane_fmt[0].bytesperline,
fmt.fmt.pix_mp.plane_fmt[0].reserved[0],
fmt.fmt.pix_mp.num_planes);
switch(port) {
case CAPTURE_PORT :
video_inst.fmt[CAPTURE_PORT].fmt.pix_mp.height=fmt.fmt.pix_mp.height;
video_inst.fmt[CAPTURE_PORT].fmt.pix_mp.width=fmt.fmt.pix_mp.width;
video_inst.fmt[CAPTURE_PORT].fmt.pix_mp.pixelformat=fmt.fmt.pix_mp.pixelformat;
video_inst.fmt[CAPTURE_PORT].fmt.pix_mp.plane_fmt[0].sizeimage=fmt.fmt.pix_mp.plane_fmt[0].sizeimage;
video_inst.fmt[CAPTURE_PORT].fmt.pix_mp.num_planes=fmt.fmt.pix_mp.num_planes;
video_inst.fmt[CAPTURE_PORT].fmt.pix_mp.plane_fmt[0].bytesperline=
fmt.fmt.pix_mp.plane_fmt[0].bytesperline;
video_inst.fmt[CAPTURE_PORT].fmt.pix_mp.plane_fmt[0].reserved[0]=
fmt.fmt.pix_mp.plane_fmt[0].reserved[0];
extra_idx = EXTRADATA_IDX(fmt.fmt.pix_mp.num_planes);
if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
extra_data_size = fmt.fmt.pix_mp.plane_fmt[extra_idx].sizeimage;
D("Required extra data size per buffer = %d, idx = %d\n", extra_data_size, extra_idx);
} else if (extra_idx >= VIDEO_MAX_PLANES) {
E("Extradata index is more than allowed: %d\n", extra_idx);
return -1;
}
/* If count has has not been initialize it will update the extradata_ingo again in get_bufreqs() */
video_inst.extradata_info.size = video_inst.bufreq[CAPTURE_PORT].count * extra_data_size;
video_inst.extradata_info.count = video_inst.bufreq[CAPTURE_PORT].count;
video_inst.extradata_info.buffer_size = extra_data_size;
D("Update: VIDIOC_G_FMT: extra data all buffers size = %d\n",
video_inst.extradata_info.size);
break;
case OUTPUT_PORT :
video_inst.fmt[OUTPUT_PORT].fmt.pix_mp.height=fmt.fmt.pix_mp.height;
video_inst.fmt[OUTPUT_PORT].fmt.pix_mp.width=fmt.fmt.pix_mp.width;
video_inst.fmt[OUTPUT_PORT].fmt.pix_mp.pixelformat=fmt.fmt.pix_mp.pixelformat;
video_inst.fmt[OUTPUT_PORT].fmt.pix_mp.plane_fmt[0].sizeimage=fmt.fmt.pix_mp.plane_fmt[0].sizeimage;
video_inst.fmt[OUTPUT_PORT].fmt.pix_mp.num_planes=fmt.fmt.pix_mp.num_planes;
break;
default :
break;
}
return 0;
}
static int get_v4l2_format(char *fmt_str)
{
int fmt = V4L2_PIX_FMT_H264;
if (!fmt_str) {
E("Invalid input\n");
return -EINVAL;
}
if (!strcmp(fmt_str, "H.264")) {
fmt = V4L2_PIX_FMT_H264;
} else if (!strcmp(fmt_str, "MPEG4")) {
fmt = V4L2_PIX_FMT_MPEG4;
V("\n MPEG4 Selected \n ");
} else if (!strcmp(fmt_str, "VP8")) {
fmt = V4L2_PIX_FMT_VP8;
} else if (!strcmp(fmt_str, "MPEG2")) {
fmt = V4L2_PIX_FMT_MPEG2;
} else {
E("Unrecognized format string.\n");
fmt = -1;
}
return fmt;
}
static int set_format(int fd, enum v4l2_buf_type buf_type)
{
struct v4l2_format fmt;
int port;
int format = 0;
int rc = 0;
if (input_args->session == DECODER_SESSION) {
if (buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
format = get_v4l2_format(input_args->codec_type);
if (format == -1)
return -EINVAL;
} else if (buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
format = V4L2_PIX_FMT_NV12;
} else {
E("Invalid port\n");
return -EINVAL;
}
} else if (input_args->session == ENCODER_SESSION) {
V("Inside ENCODER SESSION set_format\n");
if (buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
format = V4L2_PIX_FMT_NV12;
} else if (buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
format = get_v4l2_format(input_args->codec_type);
if (format == -1)
return -EINVAL;
} else {
E("Invalid port\n");
return -EINVAL;
}
} else {
E("Invalid session");
return -EINVAL;
}
port = buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ? CAPTURE_PORT : OUTPUT_PORT;
memset(&fmt, 0, sizeof(fmt));
fmt.type = buf_type;
fmt.fmt.pix_mp.height = input_args->input_height;
fmt.fmt.pix_mp.width = input_args->input_width;
fmt.fmt.pix_mp.pixelformat = format;
V("VIDIOC_S_FMT port = %d: h: %d, w: %d, size: %d\n",
port, fmt.fmt.pix_mp.height, fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.plane_fmt[0].sizeimage);
rc = ioctl(fd, VIDIOC_S_FMT, &fmt);
if (rc) {
E("Failed to set format\n");
return -1;
}
D("height = %d, width = %d, format = 0x%x, size = %d\n", fmt.fmt.pix_mp.height,
fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.pixelformat,
fmt.fmt.pix_mp.plane_fmt[0].sizeimage);
switch(port) {
case CAPTURE_PORT :
video_inst.fmt[CAPTURE_PORT].fmt.pix_mp.height=fmt.fmt.pix_mp.height;
video_inst.fmt[CAPTURE_PORT].fmt.pix_mp.width=fmt.fmt.pix_mp.width;
video_inst.fmt[CAPTURE_PORT].fmt.pix_mp.pixelformat=fmt.fmt.pix_mp.pixelformat;
video_inst.fmt[CAPTURE_PORT].fmt.pix_mp.plane_fmt[0].sizeimage=fmt.fmt.pix_mp.plane_fmt[0].sizeimage;
break;
case OUTPUT_PORT :
video_inst.fmt[OUTPUT_PORT].fmt.pix_mp.height=fmt.fmt.pix_mp.height;
video_inst.fmt[OUTPUT_PORT].fmt.pix_mp.width=fmt.fmt.pix_mp.width;
video_inst.fmt[OUTPUT_PORT].fmt.pix_mp.pixelformat=fmt.fmt.pix_mp.pixelformat;
video_inst.fmt[OUTPUT_PORT].fmt.pix_mp.plane_fmt[0].sizeimage=fmt.fmt.pix_mp.plane_fmt[0].sizeimage;
break;
default :
break;
}
return rc;
}
static int querycap(int fd)
{
struct v4l2_capability cap;
int rc;
rc = ioctl(fd, VIDIOC_QUERYCAP, &cap);
if (rc) {
E("Failed to query capabilities\n");
} else {
V("Capabilities: driver_name = %s, card = %s, bus_info = %s,"
" version = %d, capabilities = %x\n", cap.driver, cap.card,
cap.bus_info, cap.version, cap.capabilities);
}
return rc;
}
static int get_bufreqs(int fd, enum v4l2_buf_type buf_type)
{
struct v4l2_requestbuffers bufreq;
int port;
int rc;
port = buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ? CAPTURE_PORT : OUTPUT_PORT;
if (port == OUTPUT_PORT && input_args->ring_num_hdrs)
bufreq.count = input_args->ring_num_hdrs;
else
bufreq.count = 2;
bufreq.type = buf_type;
bufreq.memory = V4L2_MEMORY_USERPTR;
rc = ioctl(fd, VIDIOC_REQBUFS, &bufreq);
if (rc) {
E("Failed to query bufreqs\n");
return -1;
}
V("VIDIOC_REQBUFS port = %d: count = %d\n", port, bufreq.count);
switch(port) {
case CAPTURE_PORT :
video_inst.bufreq[CAPTURE_PORT].count = bufreq.count;
video_inst.bufreq[CAPTURE_PORT].type = bufreq.type;
video_inst.extradata_info.size = bufreq.count * video_inst.extradata_info.buffer_size;
video_inst.extradata_info.count = bufreq.count;
D("Update: VIDIOC_REQBUFS extra data all buffers size = %d\n",
video_inst.extradata_info.size);
break;
case OUTPUT_PORT :
video_inst.bufreq[OUTPUT_PORT].count = bufreq.count;
video_inst.bufreq[OUTPUT_PORT].type = bufreq.type;
break;
default :
break;
}
return 0;
}
static int streamon(int fd, enum v4l2_buf_type buf_type)
{
int rc;
int port;
port = buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ? CAPTURE_PORT : OUTPUT_PORT;
D("VIDIOC_STREAMON port = %d\n", port);
rc = ioctl(fd, VIDIOC_STREAMON, &buf_type);
if (rc) {
E("Failed to call streamon\n");
}
return rc;
}
static int streamoff(int fd, enum v4l2_buf_type buf_type)
{
int rc;
struct timespec timeout;
enum v4l2_buf_type btype;
int port;
if (buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
port = CAPTURE_PORT;
} else if (buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
port = OUTPUT_PORT;
} else {
E("Capability not supported\n");
return -EINVAL;
}
if (port == OUTPUT_PORT) {
btype = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
pthread_join(video_inst.thread_id[OUTPUT_PORT], NULL);
} else {
btype = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
if (!video_inst.stop_feeding) {
while (1) {
pthread_mutex_lock(&video_inst.q_lock[port]);
rc = pthread_cond_wait(&video_inst.cond[port],
&video_inst.q_lock[port]);
if (video_inst.stop_feeding) {
pthread_mutex_unlock(&video_inst.q_lock[port]);
break;
}
pthread_mutex_unlock(&video_inst.q_lock[port]);
}
}
}
D("VIDIOC_STREAMOFF port = %d\n", port);
rc = ioctl(fd, VIDIOC_STREAMOFF, &btype);
if (rc) {
E("Failed to call streamoff on port %d\n", port);
}
return rc;
}
int read_yuv_nv12(FILE *filp, unsigned char *pbuf)
{
int rc = 0;
int size = 0;
int stride = 0;
if (!filp || !pbuf) {
E("Invalid input\n");
return -EINVAL;
}
stride = (input_args->input_width + 31) & (~31);
size = input_args->input_height * stride * 3/2;
rc = fread (pbuf, 1, size, filp);
return rc;
}
static int q_single_buf(struct bufinfo *binfo)
{
int rc = 0;
struct v4l2_buffer buf;
struct v4l2_plane plane[VIDEO_MAX_PLANES];
int eos = 0;
int port = MAX_PORTS;
int extra_idx = 0;
int read_size = 0;
int bytes_to_read = 0;
if(!binfo) {
E("Invalid binfo: %p\n", binfo);
return -EINVAL;
}
port = binfo->buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ?
OUTPUT_PORT : CAPTURE_PORT;
D("%s: fill port: %d data\n", __FUNCTION__, port);
memset(&buf, 0, sizeof(buf));
if (port == OUTPUT_PORT) {
if (input_args->session == DECODER_SESSION) {
if (input_args->alloc_type == V4L2_MPEG_VIDC_VIDEO_RING) {
if (input_args->n_read_mode) {
bytes_to_read = get_bytes_to_read();
V("Reading arbitrary bytes = %d\n", bytes_to_read);
rc = read_n_bytes(video_inst.inputfile,
video_inst.ring_buf,
bytes_to_read);
} else {
rc = read_one_frame(video_inst.inputfile, video_inst.ring_buf);
V("Copy read frame to ring buffer, size = %d\n", rc);
}
} else {
if (input_args->n_read_mode) {
bytes_to_read = input_args->read_bytes;
V("Reading bytes = %d\n", bytes_to_read);
rc = read_n_bytes(video_inst.inputfile,
binfo->vaddr,
bytes_to_read);
} else {
rc = read_one_frame(video_inst.inputfile, binfo->vaddr);
V("Copy read frame to buffer, size = %d\n", rc);
}
}
} else if (input_args->session == ENCODER_SESSION) {
rc = read_yuv_nv12(video_inst.inputfile, binfo->vaddr);
} else {
E("Invalid session\n");
return -EINVAL;
}
if (rc < 0) {
E("Error reading file\n");
return -EINVAL;
} else if (rc == 0) {
V("EOS:END OF STREAM\n");
eos = 1;
buf.flags = V4L2_QCOM_BUF_FLAG_EOS;
}
read_size = rc;
if (input_args->alloc_type == V4L2_MPEG_VIDC_VIDEO_RING) {
binfo->offset = ring_buf_write(&video_inst.ring_info,
video_inst.ring_buf,
(__u32*)&read_size);
D("ETB: offset = %d\n", binfo->offset);
if (read_size < rc) {
E("Error writing to ring buffer: %d \n", read_size);
return -EINVAL;
}
}
D("ETB: bytesused: %d\n", read_size);
}
buf.index = binfo->index;
buf.type = binfo->buf_type;
buf.memory = V4L2_MEMORY_USERPTR;
plane[0].bytesused = read_size;
plane[0].length = binfo->size;
plane[0].m.userptr = (unsigned long)binfo->vaddr;
plane[0].reserved[0] = binfo->ion.fd_ion_data.fd;
plane[0].reserved[1] = 0;
plane[0].data_offset = binfo->offset;
extra_idx = EXTRADATA_IDX(video_inst.fmt[CAPTURE_PORT].fmt.pix_mp.num_planes);
if (port == CAPTURE_PORT) {
if ((extra_idx >= 1) && (extra_idx < VIDEO_MAX_PLANES)) {
plane[extra_idx].bytesused = 0;
plane[extra_idx].length = video_inst.extradata_info.buffer_size;
plane[extra_idx].m.userptr = (unsigned long)(video_inst.extradata_info.uaddr + buf.index * video_inst.extradata_info.buffer_size);
plane[extra_idx].reserved[0] = video_inst.extradata_info.ion.fd_ion_data.fd;
plane[extra_idx].reserved[1] = buf.index * video_inst.extradata_info.buffer_size;
plane[extra_idx].data_offset = 0;
buf.length = video_inst.fmt[CAPTURE_PORT].fmt.pix_mp.num_planes;
D("Queueing extra data: port:(%d), index: %d, fd = %d,reserved[1] = %u, userptr = %p,"
" offset = %d, flags=0x%x, bytesused= %d, length= %d, num_planes = %d\n",
port, buf.index,
plane[extra_idx].reserved[0], plane[extra_idx].reserved[1],
(void *)plane[extra_idx].m.userptr,
plane[extra_idx].data_offset, buf.flags,
plane[extra_idx].bytesused, plane[extra_idx].length, buf.length);
} else
buf.length = 1;
} else {
buf.length = 1;
}
buf.m.planes = plane;
D("Queueing:%d, port:(%d) fd = %d, userptr = %p,"
" offset = %d, flags=0x%x, bytesused= %d, length= %d\n",
video_inst.fd, port,
plane[0].reserved[0], (void *)plane[0].m.userptr,
plane[0].data_offset, buf.flags,
plane[0].bytesused, plane[0].length);
rc = ioctl(video_inst.fd, VIDIOC_QBUF, &buf);
if (rc) {
rc = -errno;
E("Failed to qbuf to driver rc = %d\n", rc);
}
if(video_inst.ebd_count == input_args->request_i_frame) {
struct v4l2_control control;
control.id = V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_IFRAME;
control.value = 1;
rc = set_control(video_inst.fd, &control);
input_args->request_i_frame = -1;
}
if (eos) {
rc = -1; //Don't modify unless you know what are you doing
}
D("EXIT: %s: rc = %d\n", __FUNCTION__, rc);
return rc;
}
static int qbuf(int fd, enum v4l2_buf_type buf_type)
{
int rc = 0;
int port;
if (buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
port = CAPTURE_PORT;
} else if (buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
port = OUTPUT_PORT;
} else {
E("Capability not supported\n");
return -EINVAL;
}
struct bufinfo *binfo = pop(&video_inst.buf_queue[port]);
if (binfo) {
rc = q_single_buf(binfo);
if (rc == -1) {
D("EOS received exit thread, port: %d\n", port);
}
else if (rc) {
E("Failed to q buf exit thread, port: %d\n", port);
}
} else
V("Buffer queue empty, port: %d\n", port);
return rc;
}
static void* queue_func(void *data)
{
struct bufinfo *binfo;
int port = (int)data;
int rc = 0,ret = 0;
struct timespec timeout;
struct timeval now;
D("queue_func thread port: %d\n", port);
while(1) {
pthread_mutex_lock(&video_inst.q_lock[port]);
if (video_inst.stop_feeding) {
D("Aborting the session, port: %d\n", port);
pthread_mutex_unlock(&video_inst.q_lock[port]);
break;
}
binfo = pop(&video_inst.buf_queue[port]);
D("pop'ed binfo (%d)\n", port);
pthread_mutex_unlock(&video_inst.q_lock[port]);
if(binfo == NULL) {
D("No free Buffer to queue. Waiting(%d)... \n", port);
pthread_mutex_lock(&video_inst.q_lock[port]);
gettimeofday(&now,NULL);
timeout.tv_sec = now.tv_sec+TIMEOUT/1000;
timeout.tv_nsec = now.tv_usec;
rc = pthread_cond_timedwait(&video_inst.cond[port],
&video_inst.q_lock[port], &timeout);
if (rc == ETIMEDOUT) {
E("pthread condition wait timedout, port: %d\n", port);
pthread_mutex_unlock(&video_inst.q_lock[port]);
break;
}
binfo = pop(&video_inst.buf_queue[port]);
D("pop'ed binfo after wait (%d)\n", port);
pthread_mutex_unlock(&video_inst.q_lock[port]);
}
if (!rc && binfo) {
rc = q_single_buf(binfo);
if (rc == -1) {
D("EOS received exit thread, port: %d\n", port);
break;
}
else if (rc) {
E("Failed to q buf exit thread, port: %d\n", port);
D("Requesting stop_feeding in all port threads\n");
video_inst.stop_feeding = 1;
break;
}
D("q_single_buf(%d) succeed\n", port);
} else {
E("Error in getting free buffer: %d, %p\n", rc, binfo);
break;
}
}
D("Exiting queue_func: %d\n", port);
return 0;
}
static void* poll_func(void *data)
{
struct bufinfo *binfo;
int num_bytes_written=0;
struct pollfd pfd;
int fd = (int) data;
int rc = 0;
struct v4l2_event dqevent;
struct v4l2_buffer v4l2_buf;
int stride;
struct v4l2_plane plane[VIDEO_MAX_PLANES];
int filled_len = 0;
stride = (input_args->input_width + 31) & (~31);
pfd.fd = fd;
pfd.events = POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLRDBAND | POLLPRI;
while(1) {
rc = poll(&pfd, 1, TIMEOUT);
if (!rc) {
E("Poll timedout\n");
break;
} else if (rc < 0) {
E("Error while polling: %d\n", rc);
break;
}
D("events = 0x%x\n", pfd.revents);
if ((pfd.revents & POLLIN) || (pfd.revents & POLLRDNORM)) {
v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
v4l2_buf.memory = V4L2_MEMORY_USERPTR;
v4l2_buf.length = video_inst.fmt[CAPTURE_PORT].fmt.pix_mp.num_planes;
v4l2_buf.m.planes = plane;
while(!ioctl(pfd.fd, VIDIOC_DQBUF, &v4l2_buf)) {
binfo = &video_inst.binfo[CAPTURE_PORT][v4l2_buf.index];
pthread_mutex_lock(&video_inst.q_lock[CAPTURE_PORT]);
++video_inst.fbd_count;
if (v4l2_buf.flags & V4L2_QCOM_BUF_FLAG_EOS ||
video_inst.fbd_count >= input_args->frame_count) {
if (v4l2_buf.flags & V4L2_QCOM_BUF_FLAG_EOS)
V("Received eos on capture port, flags = 0x%x\n", v4l2_buf.flags);
else
V("frame_count reached = %d\n", video_inst.fbd_count);
video_inst.stop_feeding = 1;
video_inst.cur_test_status = SUCCESS;
}
filled_len = plane[0].bytesused;
D("FBD COUNT: %d, filled length = %d, userptr = %p, offset = %d, flags = 0x%x\n",
video_inst.fbd_count, filled_len, (void *)plane[0].m.userptr, plane[0].data_offset, v4l2_buf.flags);
if (input_args->session == DECODER_SESSION && filled_len) {
int stride = video_inst.fmt[CAPTURE_PORT].fmt.pix_mp.plane_fmt[0].bytesperline;
int scanlines = video_inst.fmt[CAPTURE_PORT].fmt.pix_mp.plane_fmt[0].reserved[0];
const char *temp = (const char *)plane[0].m.userptr;
unsigned i;
int bytes_written = 0;
for (i = 0; i < input_args->input_height; i++) {
bytes_written += fwrite(temp, input_args->input_width, 1, video_inst.outputfile);
temp += stride;
}
temp = (const char *)binfo->vaddr + stride * scanlines;
for(i = 0; i < input_args->input_height/2; i++) {
bytes_written += fwrite(temp, input_args->input_width, 1, video_inst.outputfile);
temp += stride;
}
D("Written %d segments successfully, stride = %d, scan_lines = %d, frame = %d x %d\n",
bytes_written, stride, scanlines, (int)input_args->input_width, (int)input_args->input_height);
} else if (input_args->session == ENCODER_SESSION) {
rc = fwrite((const char *)binfo->vaddr,
filled_len,1,video_inst.outputfile);
if (rc > 0) {
D("Written %d bytes successfully\n", rc);
} else {
if (!filled_len)
E("Failed to write output\n");
}
}
rc = handle_extradata_v4l2(v4l2_buf);
if (rc >= 0) {
V("Got %d extra data fields\n", rc);
} else {
E("Error getting extra data\n");
}
rc = push(&video_inst.buf_queue[CAPTURE_PORT], (void *) binfo);
if (rc) {
E("Failed(rc = %d) to push buffer into: %d queue\n", rc, CAPTURE_PORT);
pthread_mutex_unlock(&video_inst.q_lock[CAPTURE_PORT]);
break;
}
pthread_cond_broadcast(&video_inst.cond[CAPTURE_PORT]);
pthread_mutex_unlock(&video_inst.q_lock[CAPTURE_PORT]);
}
} else if ((pfd.revents & POLLOUT) || (pfd.revents & POLLWRNORM)) {
memset(&v4l2_buf, 0, sizeof(v4l2_buf));
memset(&plane, 0, sizeof(plane));
v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
v4l2_buf.memory = V4L2_MEMORY_USERPTR;
v4l2_buf.m.planes = plane;
v4l2_buf.length = video_inst.fmt[OUTPUT_PORT].fmt.pix_mp.num_planes;
D("dqbuf:port(0)\n");
while (!ioctl(pfd.fd, VIDIOC_DQBUF, &v4l2_buf)) {
__u32 nOffset = 0;
binfo = &video_inst.binfo[OUTPUT_PORT][v4l2_buf.index];
pthread_mutex_lock(&video_inst.q_lock[OUTPUT_PORT]);
++video_inst.ebd_count;
D("EBD COUNT: %d\n", video_inst.ebd_count);
if (input_args->alloc_type == V4L2_MPEG_VIDC_VIDEO_RING) {
D("Getting offset... port (0)\n");
nOffset = v4l2_buf.m.planes[0].data_offset;
D("port(0): new ring buf offset: %d\n", nOffset);
D("port(0): v4l2 index: %d, binfo index: %d\n",
v4l2_buf.index, binfo->index);
rc = ring_buf_read(&video_inst.ring_info, NULL, nOffset);
if (rc)
E("Error reading ring buffer\n");
else
D("Success updating ring offset\n");
}
D("push buf in port (0)\n");
rc = push(&video_inst.buf_queue[OUTPUT_PORT], (void *) binfo);
if (rc) {
E("Failed(rc = %d) to push buffer into: %d queue\n", rc, OUTPUT_PORT);
pthread_mutex_unlock(&video_inst.q_lock[OUTPUT_PORT]);
break;
}
pthread_cond_broadcast(&video_inst.cond[OUTPUT_PORT]);
pthread_mutex_unlock(&video_inst.q_lock[OUTPUT_PORT]);
}
} else if (pfd.revents & POLLRDBAND) {
D("TODO: Some event has happened\n");
} else if (pfd.revents & POLLPRI) {
rc = ioctl(pfd.fd, VIDIOC_DQEVENT, &dqevent);
if(dqevent.type == V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_INSUFFICIENT ) {
V("\n Port Reconfig recieved insufficient\n");
} else if (dqevent.type == V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_SUFFICIENT) {
V("\n Setting changed sufficient\n");
} else if (dqevent.type == V4L2_EVENT_MSM_VIDC_FLUSH_DONE) {
V("\n Flush Done Recieved \n");
} else if (dqevent.type == V4L2_EVENT_MSM_VIDC_CLOSE_DONE) {
V("\n Close Done Recieved \n");
break;
} else if(dqevent.type == V4L2_EVENT_MSM_VIDC_SYS_ERROR) {
E("\n SYS Error Recieved \n");
break;
} else {
E("\n Some event has occurred!! Type: 0x%x\n", dqevent.type);
continue;
}
} else if (pfd.revents & POLLERR) {
if (!video_inst.events_subscribed) {
break;
}
} else {
E("TODO: An error occured\n ");
break;
}
}
D("EXIT poll()\n");
return NULL;
}
static int run(int fd)
{
int rc = 0;
//In success poll_func() will change the status
video_inst.cur_test_status = FAILURE;
rc = pthread_create(&video_inst.thread_id[OUTPUT_PORT], NULL, queue_func, (void *)OUTPUT_PORT);
if (rc) {
E("Failed to create output queue thread: %d\n", rc);
return rc;
}
rc = pthread_create(&video_inst.thread_id[CAPTURE_PORT], NULL, queue_func, (void *)CAPTURE_PORT);
if (rc) {
E("Failed to create capture queue thread: %d\n", rc);
return rc;
}
if (!video_inst.poll_created) {
rc = pthread_create(&video_inst.poll_tid, NULL, poll_func, (void *)fd);
if (rc) {
E("Failed to create poll thread: %d\n", rc);
return rc;
}
}
return rc;
}
static void nominal_test()
{
int rc = 0;
int i;
struct v4l2_decoder_cmd dec;
video_inst.cur_test_status = SUCCESS;
rc = parse_cfg(input_args->config);
if (rc) {
E("Failed to parse configuration file\n");
help();
return;
}
video_inst.inputfile = fopen(input_args->input,"rb");
if (!video_inst.inputfile) {
E("Failed to open input file %s\n", input_args->input);
goto err;
}
video_inst.outputfile = fopen(input_args->output,"wb");
if (!video_inst.outputfile) {
E("Failed to open output file %s\n", input_args->output);
goto fail_op_file;
}
if ((strncmp(input_args->bufsize_filename, "beefbeef", 8))) {
video_inst.buf_file = fopen(input_args->bufsize_filename, "rb");
if (!video_inst.buf_file) {
E("Failed to buffer sizes file %s\n", input_args->bufsize_filename);
goto fail_buf_file;
}
}
V("Setting seed: srand(%lu) \n", input_args->random_seed);
srand(input_args->random_seed);
for (i = 0; i < MAX_PORTS; i++) {
pthread_mutex_init(&video_inst.q_lock[i], 0);
pthread_cond_init(&video_inst.cond[i], 0);
}
rc = configure_session();
if (rc) {
E("Failed to configure session\n");
goto fail_config_session;
}
rc = commands_controls();
if (rc) {
E("Failed to set controls\n");
goto fail_config_session;
}
V("Waiting for threads to join\n");
for (i = 0; i < MAX_PORTS; i++) {
pthread_join(video_inst.thread_id[i], NULL);
}
if (input_args->session == DECODER_SESSION) {
V("Flush OUTPUT port \n");
dec.cmd = V4L2_DEC_QCOM_CMD_FLUSH;
dec.flags = V4L2_DEC_QCOM_CMD_FLUSH_OUTPUT;
rc = decoder_cmd(video_inst.fd, &dec);
if (rc)
E("Failed to flush OUTPUT port\n");
V("Flush CAPTURE port \n");
dec.cmd = V4L2_DEC_QCOM_CMD_FLUSH;
dec.flags = V4L2_DEC_QCOM_CMD_FLUSH_CAPTURE;
rc = decoder_cmd(video_inst.fd, &dec);
if (rc)
E("Failed to flush CAPTURE port\n");
V("Stopping...\n");
dec.cmd = V4L2_DEC_CMD_STOP;
rc = decoder_cmd(video_inst.fd, &dec);
}
V("CAPTURE PORT Stream OFF \n");
rc = streamoff(video_inst.fd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
if (rc)
E("Failed to call streamoff on capture port\n");
V("OUTPUT PORT Stream OFF \n");
rc = streamoff(video_inst.fd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
if (rc)
E("Failed to call streamoff on capture port\n");
V("Waiting for poll to join\n");
pthread_join(video_inst.poll_tid, NULL);
fail_config_session:
for (i = 0; i < MAX_PORTS; i++) {
pthread_mutex_destroy(&video_inst.q_lock[i]);
}
if (video_inst.buf_file)
fclose(video_inst.buf_file);
fail_buf_file:
fclose(video_inst.outputfile);
fail_op_file:
fclose(video_inst.inputfile);
err:
if (video_inst.cur_test_status == SUCCESS && !rc) {
num_of_test_pass++;
I("Test passed\n");
} else {
num_of_test_fail++;
I("Test fail\n");
}
for (i = 0; i < MAX_PORTS; i++)
free_queue(&video_inst.buf_queue[i]);
close(video_inst.fd);
free_buffers();
//De-initialize global variables for repetability test
D("Clear Global variables\n");
video_inst.ebd_count = 0;
video_inst.fbd_count = 0;
video_inst.stop_feeding = 0;
video_inst.events_subscribed = 0;
video_inst.poll_created = 0;
video_inst.cur_test_status = FAILURE;
video_inst.extradata_info.size = 0;
}
static void adversarial_test()
{
I("adversial_test not implemented yet\n");
}
static void repeatability_test()
{
int test_number;
for (test_number = 1; test_number <= input_args->repeat; test_number++) {
I("Test #%d \n", test_number);
nominal_test();
}
}
static void stress_test()
{
I("stress_test not implemented yet\n");
}
int main(int argc, char *argv[])
{
int rc = 0;
int i;
int test_mask;
input_args = (struct arguments *)malloc(sizeof(struct arguments));
if (input_args == NULL)
return -1;
/* Setting defaults */
memset(input_args, 0, sizeof(*input_args));
memset(&video_inst, 0, sizeof(video_inst));
input_args->request_i_frame = -1;
input_args->verbosity = 1;
strlcpy(input_args->bufsize_filename, "beefbeef", MAX_FILE_PATH_SIZE);
test_mask = parse_args(argc, argv);
if (test_mask < 0) {
E("Failed to parse args\n");
help();
goto err;
}
if (test_mask & (1U << HELP))
goto err;
for (i = 0; i < (int)(sizeof(test_func)/sizeof(*(test_func))); i++) {
/* Look for the test that was selected */
if (!(test_mask & (1U << i)))
continue;
/* This test was selected, so run it */
I("Test type selected: \n");
switch (i) {
case NOMINAL:
I("Nominal (default) test\n");
break;
case ADVERSARIAL:
I("Adversarial\n");
break;
case REPEAT:
I("Repeatability\n");
break;
case STRESS:
I("Stress\n");
break;
case HELP:
I("HELP\n");
break;
default:
E("Not listed test\n");
break;
}
test_func[i] ();
}
I("\n\n\t\tTest results:\n");
if (!num_of_test_fail && !num_of_test_pass)
I("\tNo test executed\n");
else {
I("\tTest pass: %d\n", num_of_test_pass);
I("\tTest fail: %d\n\n\n", num_of_test_fail);
}
if(num_of_test_fail)
rc = -1;
err:
free(input_args);
return rc;
}
int read_mpeg2_chunk(FILE * bits, unsigned char * pBuf)
{
const unsigned int mp2StartCode = 0x00000100;
const unsigned int mp2GrpStartCode = 0x000001B8;
const unsigned int mp2SeqHdrCode = 0x000001B3;
const unsigned int mp2SeqEndCode = 0x000001B7;
const unsigned int read_max = 10000;
static unsigned int word = 0x0;
unsigned char temp_buf[read_max];
unsigned int length = 0;
unsigned int seqFound = 0;
unsigned int picFound = 0;
unsigned int seqEndFound = 0;
unsigned int read_size = 0;
unsigned int curr_ptr = 0;
int is_full_frame_found = 0;
if (word == mp2SeqHdrCode) {
D("mpeg2: Previous word is mp2SeqHdrCode 0x%x\n", word);
seqFound = 1;
} else if (word == mp2StartCode) {
D("mpeg2: Previous word is mp2StartCode 0x%x\n", word);
picFound = 1;
} else if (word == mp2SeqEndCode) {
D("mpeg2: Previous word is mp2SeqEndCode 0x%x\n", word);
seqEndFound = 1;
} else {
D("mpeg2: Previous word is 0x%x \n", word);
}
if (word && !seqEndFound) {
*pBuf++ = (word >>24) & 0xff;
*pBuf++ = (word >> 16) & 0xff;
*pBuf++ = (word >> 8) & 0xff;
*pBuf++ = word & 0xff;
length = 4;
}
while (!feof(bits)) {
read_size = fread(temp_buf, 1, read_max, bits);
if (read_size == 0) {
D("\n EOF reached \n");
break;
}
curr_ptr = 0;
D("mpeg2: read_size = %d\n", read_size);
do {
word = (word << 8) | temp_buf[curr_ptr++];
if (word == mp2StartCode) {
if (picFound) {
is_full_frame_found = 1;
length++;
break;
} else {
picFound = 1;
length++;
}
} else if (word == mp2SeqHdrCode) {
if (picFound) {
is_full_frame_found = 1;
length++;
break;
} else {
seqFound = 1;
length++;
}
} else if (word == mp2SeqEndCode) {
length++;
is_full_frame_found = 1;
D("mpeg2: mp2SeqEndCode found!!!\n");
break;
} else {
length++;
}
} while(curr_ptr < read_size);
memcpy(pBuf, temp_buf, curr_ptr);
pBuf+=curr_ptr;
fseek (bits, (int)(curr_ptr - read_size), SEEK_CUR);
if (is_full_frame_found) {
D("mpeg2: Found something: pic = %u, seq = %u\n", picFound, seqFound);
if (word != mp2SeqEndCode)
length-=4; // Not consider last word to avoid repetition
break;
}
}
D("mpeg2: last word: 0x%x\n", word);
if (!is_full_frame_found) {
D("mpeg2: no full frame found\n");
}
return length;
}
int read_mpeg4_chunk(FILE * bits, unsigned char * pBuf)
{
unsigned char temp_buf[2048];
const int mp4StartCode = 0x000001B6;
static int first_time=0;
int findStartCode = 0;
int startCodeFound = 0;
int read_size = 0;
int curr_ptr = 0;
int word = 0,i;
int length = 0;
if(first_time == 1) {
pBuf[0]=0;
pBuf[1]=0;
pBuf[2]=1;
pBuf[3]=0xb6;
pBuf+=4;
}
while (startCodeFound == 0 && (!feof(bits))) {
read_size = fread(temp_buf, 1, 256, bits);
if (read_size == 0) {
V("\n EOF reached \n");
break;
}
curr_ptr = 0;
do {
word = (word << 8) | temp_buf[curr_ptr++];
findStartCode = (word == mp4StartCode);
if(findStartCode) {
if (startCodeFound) {
length -= 3;
} else {
startCodeFound = 1;
length++;
}
break;
} else
length++;
} while(curr_ptr < read_size);
memcpy(pBuf, temp_buf, curr_ptr);
pBuf+=curr_ptr;
}
fseek (bits, (int)(curr_ptr - read_size), SEEK_CUR);
if(first_time == 0) {
length -= 4;
first_time = 1;
}
return length;
}
int read_vp8_chunk(FILE * bits, unsigned char * pBuf)
{
int read_length;
unsigned long long time_stamp;
static int ivf_header_read = 0;
if(ivf_header_read == 0) {
read_length = fread (pBuf, 1, 32, bits);
V("\n Read IVF HEADER \n ");
ivf_header_read = 1;
if(pBuf[0] == 'D' && pBuf[1] == 'K' && pBuf[2] == 'I' && pBuf[3] == 'F') {
V(" \n IVF header found \n ");
} else {
V(" \n No IVF header found \n ");
lseek((int)bits, -32, SEEK_CUR);
}
}
if( 1 != fread (&read_length, 4, 1, bits)) {
V("\n input EOS Reached \n");
return 0;
}
D("\n Read Length =%d \n",read_length);
fread (&time_stamp, 8, 1, bits);
D("\n Time Stamp =%lld \n",time_stamp);
fread (pBuf, 1, read_length, bits);
return read_length;
}
int read_annexb_nalu(FILE * bits, unsigned char * pBuf)
{
int info2, info3, pos = 0;
int StartCodeFound, rewind;
static int first_time = 0;
info2 = 0;
info3 = 0;
if (3 != fread (pBuf, 1, 3, bits)) {
return 0;
}
info2 = find_start_code(pBuf, 2);
if (info2 != 1) {
if(1 != fread(pBuf+3, 1, 1, bits)) {
return 0;
}
info3 = find_start_code(pBuf, 3);
}
if (info2 != 1 && info3 != 1) {
E ("get_annexb_nalu: no Start Code at the begin of the NALU, return -1\n");
return -1;
}
if( info2 == 1) {
pos = 3;
} else if(info3 ==1 ) {
pos = 4;
} else {
E( " Panic: Error \n");
return -1;
}
StartCodeFound = 0;
info2 = 0;
info3 = 0;
while (!StartCodeFound) {
if (feof (bits)) {
return pos-1;
}
pBuf[pos++] = fgetc (bits);
info3 = find_start_code(pBuf+pos-4, 3);
if(info3 != 1)
info2 = find_start_code(pBuf+pos-3, 2);
StartCodeFound = (info2 == 1 || info3 == 1);
if (StartCodeFound && first_time < 2) {
++first_time;
StartCodeFound = 0;
}
}
// Here, we have found another start code (and read length of startcode bytes more than we should
// have. Hence, go back in the file
rewind = 0;
if(info3 == 1)
rewind = -4;
else if (info2 == 1)
rewind = -3;
else
E(" Panic: Error in next start code search \n");
if (0 != fseek (bits, rewind, SEEK_CUR)) {
fprintf(stderr,"GetAnnexbNALU: Cannot fseek %d in the bit stream file", rewind);
}
return (pos+rewind);
}
static int find_start_code(const unsigned char * pBuf, unsigned int zeros_in_startcode)
{
unsigned int info = 1, i;
for (i = 0; i < zeros_in_startcode; i++) {
if(pBuf[i] != 0)
info = 0;
}
if(pBuf[i] != 1)
info = 0;
return info;
}
int read_one_frame(FILE * bits, unsigned char * pBuf)
{
int read_length;
if (!strcmp(input_args->codec_type, "H.264")) {
read_length = read_annexb_nalu(bits,pBuf);
} else if (!strcmp(input_args->codec_type, "MPEG4")) {
read_length = read_mpeg4_chunk(bits,pBuf);
} else if (!strcmp(input_args->codec_type, "VP8")) {
read_length = read_vp8_chunk(bits,pBuf);
} else if (!strcmp(input_args->codec_type, "MPEG2")) {
read_length = read_mpeg2_chunk(bits,pBuf);
D("mpeg2: chunk starts w/ 0x%x\n", pBuf[0]);
D("mpeg2: chunk starts w/ 0x%x\n", pBuf[1]);
D("mpeg2: chunk starts w/ 0x%x\n", pBuf[2]);
D("mpeg2: chunk starts w/ 0x%x\n", pBuf[3]);
} else {
E("\n Unrecognised CODECS \n");
read_length = -1;
}
return read_length;
}
int read_n_bytes(FILE * file, unsigned char * pBuf, int n)
{
int read_bytes = 0;
read_bytes = fread (pBuf, 1, n, file);
if (read_bytes != n) {
if (feof(file))
V("info: EOF: as been reach\n");
else
E("Error: Reading file\n");
}
return read_bytes;
}
int get_bytes_to_read(void)
{
int bytes = 0;
char line[MAX_LINE];
int max_read_size = (input_args->input_width * input_args->input_height * 3/2)/2;
int max_numbufs = video_inst.bufreq[OUTPUT_PORT].count;
static unsigned int index = 0;
static int is_read_done = 0;
if (input_args->n_read_mode == RANDOM_NUMBER) {
/* Trying to queue at least one frame in the available buffers minus 1*/
V("bytes_to_read shall be > %d\n", max_read_size/(max_numbufs-1));
do {
bytes = rand() % max_read_size;
V("try rand(): bytes = %d\n", bytes);
} while (bytes < (max_read_size/(max_numbufs-1)));
} else { /* FIX_NUMBER */
/* Read initial values from file then continue using: input_args->read_bytes */
if (strncmp(input_args->bufsize_filename, "beefbeef", 8) && !is_read_done) {
if(fgets(line, MAX_LINE-1, video_inst.buf_file)) {
bytes = atoi(line);
index++;
} else {
is_read_done = 1;
V("No more data in file: %s, values read: %d\n",
input_args->bufsize_filename, index);
}
}
if (!strncmp(input_args->bufsize_filename, "beefbeef", 8) ||
(strncmp(input_args->bufsize_filename, "beefbeef", 8) && is_read_done)) {
bytes = input_args->read_bytes;
if(!bytes || bytes > max_read_size) {
V("Warning: Limit bytes to read!! bytes = %d\n", max_read_size);
bytes = max_read_size;
}
}
}
return bytes;
}