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 Intel’s 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  */
vbp_utils_uninitialize_context(vbp_context * pcontext)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  */
vbp_utils_initialize_context(vbp_context * pcontext)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 */
vbp_utils_free_parser_memory(vbp_context * pcontext)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  */
vbp_utils_allocate_parser_memory(vbp_context * pcontext)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  */
vbp_utils_parse_es_buffer(vbp_context * pcontext,uint8 init_data_flag)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  */
vbp_utils_create_context(uint32 parser_type,vbp_context ** ppcontext)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  */
vbp_utils_destroy_context(vbp_context * pcontext)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  */
vbp_utils_parse_buffer(vbp_context * pcontext,uint8 * data,uint32 size,uint8 init_data_flag)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  */
vbp_utils_query(vbp_context * pcontext,void ** data)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  */
vbp_utils_flush(vbp_context * pcontext)544 uint32 vbp_utils_flush(vbp_context *pcontext)
545 {
546 	return VBP_IMPL;
547 }
548 
549