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