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