Home | History | Annotate | Download | only in parser
      1 /*
      2  INTEL CONFIDENTIAL
      3  Copyright 2009 Intel Corporation All Rights Reserved.
      4  The source code contained or described herein and all documents related to the source code ("Material") are owned by Intel Corporation or its suppliers or licensors. Title to the Material remains with Intel Corporation or its suppliers and licensors. The Material contains trade secrets and proprietary and confidential information of Intel or its suppliers and licensors. The Material is protected by worldwide copyright and trade secret laws and treaty provisions. No part of the Material may be used, copied, reproduced, modified, published, uploaded, posted, transmitted, distributed, or disclosed in any way without Intels prior express written permission.
      5 
      6  No license under any patent, copyright, trade secret or other intellectual property right is granted to or conferred upon you by disclosure or delivery of the Materials, either expressly, by implication, inducement, estoppel or otherwise. Any license under such intellectual property rights must be express and approved by Intel in writing.
      7  */
      8 
      9 
     10 #include <glib.h>
     11 #include <dlfcn.h>
     12 
     13 #include "vc1.h"
     14 #include "h264.h"
     15 #include "vbp_loader.h"
     16 #include "vbp_utils.h"
     17 #include "vbp_vc1_parser.h"
     18 #include "vbp_h264_parser.h"
     19 #include "vbp_mp42_parser.h"
     20 
     21 
     22 
     23 /* buffer counter */
     24 uint32 buffer_counter = 0;
     25 
     26 
     27 /**
     28  *
     29  * uninitialize parser context
     30  *
     31  */
     32 static uint32 vbp_utils_uninitialize_context(vbp_context *pcontext)
     33 {
     34 	uint32 error = VBP_OK;
     35 
     36 	if (NULL == pcontext)
     37 	{
     38 		return error;
     39 	}
     40 
     41 	/* not need to reset parser entry points. */
     42 
     43 	g_free(pcontext->parser_ops);
     44 	pcontext->parser_ops = NULL;
     45 
     46 
     47 	if (pcontext->fd_parser)
     48 	{
     49 		dlclose(pcontext->fd_parser);
     50 		pcontext->fd_parser = NULL;
     51 	}
     52 
     53 	return error;
     54 }
     55 
     56 /**
     57  *
     58  * initialize parser context
     59  *
     60  */
     61 static uint32 vbp_utils_initialize_context(vbp_context *pcontext)
     62 {
     63 	uint32 error = VBP_OK;
     64 	char *parser_name;
     65 
     66 	switch (pcontext->parser_type)
     67 	{
     68 		case VBP_VC1:
     69 		parser_name = "libmixvbp_vc1.so.0";
     70 		break;
     71 
     72 		/* MPEG-2 parser is not supported. */
     73 
     74 		/*  case VBP_MPEG2:
     75 		parser_name = "libmixvbp_mpeg2.so.0";
     76 		break;*/
     77 
     78 		case VBP_MPEG4:
     79 		parser_name = "libmixvbp_mpeg4.so.0";
     80 		break;
     81 
     82 		case VBP_H264:
     83 		parser_name = "libmixvbp_h264.so.0";
     84 		break;
     85 
     86 		default:
     87 		g_warning ("Warning!  Unsupported parser type!");
     88 		return VBP_TYPE;
     89 	}
     90 
     91 	pcontext->fd_parser = dlopen(parser_name, RTLD_LAZY);
     92 	if (NULL == pcontext->fd_parser)
     93 	{
     94 		ETRACE("Failed to load parser %s.", parser_name);
     95 		error =  VBP_LOAD;
     96 		goto cleanup;
     97 	}
     98 
     99 	pcontext->parser_ops = g_try_new(viddec_parser_ops_t, 1);
    100 	if (NULL == pcontext->parser_ops)
    101 	{
    102 		ETRACE("Failed to allocate memory");
    103 		error =  VBP_MEM;
    104 		goto cleanup;
    105 	}
    106 
    107 #define SET_FUNC_POINTER(X, Y)\
    108 	case X:\
    109 	pcontext->func_init_parser_entries = vbp_init_parser_entries_##Y;\
    110 	pcontext->func_allocate_query_data = vbp_allocate_query_data_##Y;\
    111 	pcontext->func_free_query_data = vbp_free_query_data_##Y;\
    112 	pcontext->func_parse_init_data = vbp_parse_init_data_##Y;\
    113 	pcontext->func_parse_start_code = vbp_parse_start_code_##Y;\
    114 	pcontext->func_process_parsing_result = vbp_process_parsing_result_##Y;\
    115 	pcontext->func_populate_query_data = vbp_populate_query_data_##Y;\
    116 	break;
    117 
    118 	switch (pcontext->parser_type)
    119 	{
    120 		SET_FUNC_POINTER(VBP_VC1, vc1);
    121 		SET_FUNC_POINTER(VBP_MPEG4, mp42);
    122 		SET_FUNC_POINTER(VBP_H264, h264);
    123 	}
    124 
    125 	/* set entry points for parser operations:
    126 		init
    127 		parse_sc
    128 		parse_syntax
    129 		get_cxt_size
    130 		is_wkld_done
    131 		is_frame_start
    132 	*/
    133 	error = pcontext->func_init_parser_entries(pcontext);
    134 
    135 cleanup:
    136 
    137 	if (VBP_OK != error)
    138 	{
    139 		/* no need to log error.  the loader would have done so already. */
    140 		vbp_utils_uninitialize_context(pcontext);
    141 	}
    142 
    143 	return error;
    144 }
    145 
    146 /**
    147 *
    148 * free allocated memory.
    149 *
    150 */
    151 static uint32 vbp_utils_free_parser_memory(vbp_context *pcontext)
    152 {
    153 	if (NULL == pcontext)
    154 	{
    155 		return VBP_OK;
    156 	}
    157 
    158 	if (pcontext->func_free_query_data)
    159 	{
    160 		pcontext->func_free_query_data(pcontext);
    161 	}
    162 
    163 	g_free(pcontext->workload2);
    164 	pcontext->workload2 = NULL;
    165 
    166 	g_free(pcontext->workload1);
    167 	pcontext->workload1 = NULL;
    168 
    169 	g_free(pcontext->persist_mem);
    170 	pcontext->persist_mem = NULL;
    171 
    172 	g_free(pcontext->parser_cxt);
    173 	pcontext->parser_cxt = NULL;
    174 
    175 	return VBP_OK;
    176 }
    177 
    178 
    179 /**
    180  *
    181  * allocate memory
    182  *
    183  */
    184 static uint32 vbp_utils_allocate_parser_memory(vbp_context *pcontext)
    185 {
    186 	/* pcontext is guaranteed to be valid input. */
    187 	uint32 error = VBP_OK;
    188 	viddec_parser_memory_sizes_t sizes;
    189 
    190 	pcontext->parser_cxt = g_try_new(viddec_pm_cxt_t, 1);
    191 	if (NULL == pcontext->parser_cxt)
    192 	{
    193 		ETRACE("Failed to allocate memory");
    194 		error = VBP_MEM;
    195 		goto cleanup;
    196 	}
    197 
    198 	/* invoke parser entry to get context size */
    199 	/* no return value, should always succeed. */
    200 	pcontext->parser_ops->get_cxt_size(&sizes);
    201 
    202 	/* allocate persistent memory for parser */
    203 	if (sizes.persist_size)
    204 	{
    205 		pcontext->persist_mem = g_try_malloc(sizes.persist_size);
    206 		if (NULL == pcontext->persist_mem)
    207 		{
    208 			ETRACE("Failed to allocate memory");
    209 			error = VBP_MEM;
    210 			goto cleanup;
    211 		}
    212 	}
    213 	else
    214 	{
    215 		/* OK for VC-1, MPEG2 and MPEG4. */
    216 		if ((VBP_VC1 == pcontext->parser_type) ||
    217 			(VBP_MPEG2 == pcontext->parser_type) ||
    218 			(VBP_MPEG4 == pcontext->parser_type))
    219 		{
    220 			pcontext->persist_mem = NULL;
    221 		}
    222 		else
    223 		{
    224 			/* mandatory for H.264 */
    225 			ETRACE("Failed to allocate memory");
    226 			error =  VBP_CXT;
    227 			goto cleanup;
    228 		}
    229 	}
    230 
    231 	/* allocate a new workload with 1000 items. */
    232 	pcontext->workload1 = g_try_malloc(sizeof(viddec_workload_t) +
    233 		(MAX_WORKLOAD_ITEMS * sizeof(viddec_workload_item_t)));
    234 	if (NULL == pcontext->workload1)
    235 	{
    236 		ETRACE("Failed to allocate memory");
    237 		error = VBP_MEM;
    238 		goto cleanup;
    239 	}
    240 
    241 	/* allocate a second workload with 1000 items. */
    242 	pcontext->workload2 = g_try_malloc(sizeof(viddec_workload_t) +
    243 		(MAX_WORKLOAD_ITEMS * sizeof(viddec_workload_item_t)));
    244 	if (NULL == pcontext->workload2)
    245 	{
    246 		ETRACE("Failed to allocate memory");
    247 		error = VBP_MEM;
    248 		goto cleanup;
    249 	}
    250 
    251 	/* allocate format-specific query data */
    252 	error = pcontext->func_allocate_query_data(pcontext);
    253 
    254 cleanup:
    255 	if (error != VBP_OK)
    256 	{
    257 		vbp_utils_free_parser_memory(pcontext);
    258 	}
    259 	return error;
    260 }
    261 
    262 
    263 
    264 /**
    265  *
    266  * parse the elementary sample buffer or codec configuration data
    267  *
    268  */
    269 static uint32 vbp_utils_parse_es_buffer(vbp_context *pcontext, uint8 init_data_flag)
    270 {
    271 	viddec_pm_cxt_t *cxt = pcontext->parser_cxt;
    272 	viddec_parser_ops_t *ops = pcontext->parser_ops;
    273 	uint32 error = VBP_OK;
    274 	int i;
    275 
    276 	/* reset list number. func_parse_init_data or func_parse_start_code will
    277 	* set it equal to number of sequence headers, picture headers or slices headers
    278 	* found in the sample buffer
    279 	*/
    280 	cxt->list.num_items = 0;
    281 
    282 	/**
    283 	* READ THIS NOTE: cxt->getbits.is_emul_reqd must be set to 1
    284 	* for H.264 and MPEG-4, VC1 advanced profile and set to 0
    285 	* for VC1 simple or main profile when parsing the frame
    286 	* buffer. When parsing the sequence header, it must be set to 1
    287 	* always.
    288 	*
    289 	* PARSER IMPLEMENTOR: set this flag in the parser.
    290 	*/
    291 
    292 	/*
    293 	if ((codec_type == VBP_H264)  || (codec_type == VBP_MPEG4))
    294 	{
    295 		cxt->getbits.is_emul_reqd = 1;
    296 	}
    297 	*/
    298 
    299 
    300 	/* populate the list.*/
    301 	if (init_data_flag)
    302 	{
    303 		error = pcontext->func_parse_init_data(pcontext);
    304 	}
    305 	else
    306 	{
    307 		error = pcontext->func_parse_start_code(pcontext);
    308 	}
    309 
    310 	if (VBP_OK != error)
    311 	{
    312 		ETRACE("Failed to parse the start code!");
    313 		return error;
    314 	}
    315 
    316 	/* set up bitstream buffer */
    317 	cxt->getbits.list = &(cxt->list);
    318 
    319 	/* setup buffer pointer */
    320 	cxt->getbits.bstrm_buf.buf = cxt->parse_cubby.buf;
    321 
    322 	/*
    323 	* TO DO:
    324 	* check if cxt->getbits.is_emul_reqd is set properly
    325 	*/
    326 
    327 	for (i = 0; i < cxt->list.num_items; i++)
    328 	{
    329 		/* setup bitstream parser */
    330 		cxt->getbits.bstrm_buf.buf_index = cxt->list.data[i].stpos;
    331 		cxt->getbits.bstrm_buf.buf_st = cxt->list.data[i].stpos;
    332 		cxt->getbits.bstrm_buf.buf_end = cxt->list.data[i].edpos;
    333 
    334 		/* It is possible to end up with buf_offset not equal zero. */
    335 		cxt->getbits.bstrm_buf.buf_bitoff = 0;
    336 
    337 		cxt->getbits.au_pos = 0;
    338     	cxt->getbits.list_off = 0;
    339     	cxt->getbits.phase = 0;
    340     	cxt->getbits.emulation_byte_counter = 0;
    341 
    342 		cxt->list.start_offset = cxt->list.data[i].stpos;
    343 		cxt->list.end_offset = cxt->list.data[i].edpos;
    344 		cxt->list.total_bytes = cxt->list.data[i].edpos - cxt->list.data[i].stpos;
    345 
    346 		/* invoke parse entry point to parse the buffer */
    347 		error = ops->parse_syntax((void *)cxt, (void *)&(cxt->codec_data[0]));
    348 
    349 		/* can't return error for now. Neet further investigation */
    350 
    351 		/*if (0 != error)
    352 		{
    353 			ETRACE("failed to parse the syntax: %d!", error);
    354 			return error;
    355 		}*/
    356 
    357 		/*
    358 		 * process parsing result
    359 		 */
    360 		error = pcontext->func_process_parsing_result(pcontext, i);
    361 
    362 		if (0 != error)
    363 		{
    364 			ETRACE("Failed to process parsing result.");
    365 			return error;
    366 		}
    367 	}
    368 
    369 	/* currently always assume a complete frame is supplied for parsing, so
    370 	 * there is no need to check if workload is done
    371 	 */
    372 
    373 	/*
    374 	uint32_t codec_errors = 0;
    375 	uint32_t state;
    376 
    377 	error = ops->is_wkld_done(
    378 		(void *)cxt,
    379 		(void *)&(cxt->codec_data[0]),
    380 		(uint32_t)cxt->sc_prefix_info.next_sc,
    381 		&codec_errors);
    382 	state = (ret == VIDDEC_PARSE_FRMDONE) ? VBP_DONE : VBP_OK;
    383 	return state;
    384 	*/
    385 
    386 	return VBP_OK;
    387 }
    388 
    389 
    390 /**
    391  *
    392  * create the parser context
    393  *
    394  */
    395 uint32 vbp_utils_create_context(uint32 parser_type, vbp_context **ppcontext)
    396 {
    397 	uint32 error = VBP_OK;
    398 	vbp_context *pcontext = NULL;
    399 
    400 	/* prevention from the failure */
    401 	*ppcontext =  NULL;
    402 
    403 	pcontext = g_try_new0(vbp_context, 1);
    404 	if (NULL == pcontext)
    405 	{
    406 		error = VBP_MEM;
    407 		goto cleanup;
    408 	}
    409 
    410 	pcontext->parser_type = parser_type;
    411 
    412 	/* load parser, initialize parser operators and entry points */
    413 	error = vbp_utils_initialize_context(pcontext);
    414     if (VBP_OK != error)
    415     {
    416 		goto cleanup;
    417 	}
    418 
    419 	/* allocate parser context, persistent memory, query data and workload */
    420 	error = vbp_utils_allocate_parser_memory(pcontext);
    421 	if (VBP_OK != error)
    422 	{
    423 		goto cleanup;
    424 	}
    425 
    426 	viddec_pm_utils_list_init(&(pcontext->parser_cxt->list));
    427 	viddec_pm_utils_bstream_init(&(pcontext->parser_cxt->getbits), NULL, 0);
    428 	pcontext->parser_cxt->cur_buf.list_index = -1;
    429 	pcontext->parser_cxt->parse_cubby.phase = 0;
    430 
    431 	/* invoke the entry point to initialize the parser. */
    432 	pcontext->parser_ops->init(
    433 		(void *)pcontext->parser_cxt->codec_data,
    434 		(void *)pcontext->persist_mem,
    435 		 FALSE);
    436 
    437 	viddec_emit_init(&(pcontext->parser_cxt->emitter));
    438 
    439 	/* overwrite init with our number of items. */
    440 	pcontext->parser_cxt->emitter.cur.max_items = MAX_WORKLOAD_ITEMS;
    441 	pcontext->parser_cxt->emitter.next.max_items = MAX_WORKLOAD_ITEMS;
    442 
    443 	/* set up to find the first start code. */
    444 	pcontext->parser_cxt->sc_prefix_info.first_sc_detect = 1;
    445 
    446 	/* indicates initialized OK. */
    447 	pcontext->identifier = MAGIC_NUMBER;
    448 	*ppcontext = pcontext;
    449 	error = VBP_OK;
    450 
    451 cleanup:
    452 
    453 	if (VBP_OK != error)
    454 	{
    455 		vbp_utils_free_parser_memory(pcontext);
    456 		vbp_utils_uninitialize_context(pcontext);
    457 		g_free(pcontext);
    458 		pcontext = NULL;
    459 	}
    460 
    461 	return error;
    462 }
    463 
    464 /**
    465  *
    466  * destroy the context.
    467  *
    468  */
    469 uint32 vbp_utils_destroy_context(vbp_context *pcontext)
    470 {
    471 	/* entry point, not need to validate input parameters. */
    472 	vbp_utils_free_parser_memory(pcontext);
    473 	vbp_utils_uninitialize_context(pcontext);
    474 	g_free(pcontext);
    475 	pcontext = NULL;
    476 
    477 	return VBP_OK;
    478 }
    479 
    480 
    481 /**
    482  *
    483  * parse the sample buffer or parser configuration data.
    484  *
    485  */
    486 uint32 vbp_utils_parse_buffer(vbp_context *pcontext, uint8 *data, uint32 size,  uint8 init_data_flag)
    487 {
    488 	/* entry point, not need to validate input parameters. */
    489 
    490 	uint32 error = VBP_OK;
    491 
    492 	/* ITRACE("buffer counter: %d",buffer_counter);  */
    493 
    494 	/* set up emitter. */
    495 	pcontext->parser_cxt->emitter.cur.data = pcontext->workload1;
    496 	pcontext->parser_cxt->emitter.next.data = pcontext->workload2;
    497 
    498 	/* reset bit offset */
    499 	pcontext->parser_cxt->getbits.bstrm_buf.buf_bitoff = 0;
    500 
    501 
    502 	/* set up cubby. */
    503 	pcontext->parser_cxt->parse_cubby.buf = data;
    504 	pcontext->parser_cxt->parse_cubby.size = size;
    505 	pcontext->parser_cxt->parse_cubby.phase = 0;
    506 
    507 	error = vbp_utils_parse_es_buffer(pcontext, init_data_flag);
    508 
    509 	/* rolling count of buffers. */
    510 	if (0 == init_data_flag)
    511 	{
    512 		buffer_counter++;
    513 	}
    514 	return error;
    515 }
    516 
    517 /**
    518  *
    519  * provide query data back to the consumer
    520  *
    521  */
    522 uint32 vbp_utils_query(vbp_context *pcontext, void **data)
    523 {
    524 	/* entry point, not need to validate input parameters. */
    525 	uint32 error = VBP_OK;
    526 
    527 	error = pcontext->func_populate_query_data(pcontext);
    528 	if (VBP_OK == error)
    529 	{
    530 		*data = pcontext->query_data;
    531 	}
    532 	else
    533 	{
    534 		*data = NULL;
    535 	}
    536 	return error;
    537 }
    538 
    539 /**
    540  *
    541  * flush parsing buffer. Currently it is no op.
    542  *
    543  */
    544 uint32 vbp_utils_flush(vbp_context *pcontext)
    545 {
    546 	return VBP_IMPL;
    547 }
    548 
    549