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 #include <glib.h> 9 #include <va/va_x11.h> 10 11 #include "mixvideolog.h" 12 #include "mixvideoformat_h264.h" 13 14 #ifdef MIX_LOG_ENABLE 15 static int mix_video_h264_counter = 0; 16 #endif /* MIX_LOG_ENABLE */ 17 18 /* The parent class. The pointer will be saved 19 * in this class's initialization. The pointer 20 * can be used for chaining method call if needed. 21 */ 22 static MixVideoFormatClass *parent_class = NULL; 23 24 static void mix_videoformat_h264_finalize(GObject * obj); 25 26 /* 27 * Please note that the type we pass to G_DEFINE_TYPE is MIX_TYPE_VIDEOFORMAT 28 */ 29 G_DEFINE_TYPE (MixVideoFormat_H264, mix_videoformat_h264, MIX_TYPE_VIDEOFORMAT); 30 31 static void mix_videoformat_h264_init(MixVideoFormat_H264 * self) { 32 MixVideoFormat *parent = MIX_VIDEOFORMAT(self); 33 34 /* public member initialization */ 35 /* These are all public because MixVideoFormat objects are completely internal to MixVideo, 36 no need for private members */ 37 self->dpb_surface_table = NULL; 38 39 /* NOTE: we don't need to do this here. 40 * This just demostrates how to access 41 * member varibles beloned to parent 42 */ 43 parent->initialized = FALSE; 44 } 45 46 static void mix_videoformat_h264_class_init( 47 MixVideoFormat_H264Class * klass) { 48 49 /* root class */ 50 GObjectClass *gobject_class = (GObjectClass *) klass; 51 52 /* direct parent class */ 53 MixVideoFormatClass *video_format_class = 54 MIX_VIDEOFORMAT_CLASS(klass); 55 56 /* parent class for later use */ 57 parent_class = g_type_class_peek_parent(klass); 58 59 /* setup finializer */ 60 gobject_class->finalize = mix_videoformat_h264_finalize; 61 62 /* setup vmethods with base implementation */ 63 /* This is where we can override base class methods if needed */ 64 video_format_class->getcaps = mix_videofmt_h264_getcaps; 65 video_format_class->initialize = mix_videofmt_h264_initialize; 66 video_format_class->decode = mix_videofmt_h264_decode; 67 video_format_class->flush = mix_videofmt_h264_flush; 68 video_format_class->eos = mix_videofmt_h264_eos; 69 video_format_class->deinitialize = mix_videofmt_h264_deinitialize; 70 } 71 72 MixVideoFormat_H264 * 73 mix_videoformat_h264_new(void) { 74 MixVideoFormat_H264 *ret = 75 g_object_new(MIX_TYPE_VIDEOFORMAT_H264, NULL); 76 77 return ret; 78 } 79 80 void mix_videoformat_h264_finalize(GObject * obj) { 81 gint32 pret = VBP_OK; 82 83 /* clean up here. */ 84 85 MixVideoFormat *parent = NULL; 86 MixVideoFormat_H264 *self = MIX_VIDEOFORMAT_H264(obj); 87 GObjectClass *root_class = (GObjectClass *) parent_class; 88 89 parent = MIX_VIDEOFORMAT(self); 90 91 //surfacepool is deallocated by parent 92 //inputbufqueue is deallocated by parent 93 //parent calls vaDestroyConfig, vaDestroyContext and vaDestroySurfaces 94 95 //Free the DPB surface table 96 //First remove all the entries (frames will be unrefed) 97 g_hash_table_remove_all(self->dpb_surface_table); 98 //Then unref the table 99 g_hash_table_unref(self->dpb_surface_table); 100 self->dpb_surface_table = NULL; 101 102 g_mutex_lock(parent->objectlock); 103 parent->initialized = TRUE; 104 parent->parse_in_progress = FALSE; 105 parent->current_timestamp = 0; 106 107 //Close the parser 108 pret = vbp_close(parent->parser_handle); 109 parent->parser_handle = NULL; 110 if (pret != VBP_OK) 111 { 112 LOG_E( "Error closing parser\n"); 113 } 114 115 g_mutex_unlock(parent->objectlock); 116 117 /* Chain up parent */ 118 if (root_class->finalize) { 119 root_class->finalize(obj); 120 } 121 } 122 123 MixVideoFormat_H264 * 124 mix_videoformat_h264_ref(MixVideoFormat_H264 * mix) { 125 return (MixVideoFormat_H264 *) g_object_ref(G_OBJECT(mix)); 126 } 127 128 /* H.264 vmethods implementation */ 129 MIX_RESULT mix_videofmt_h264_getcaps(MixVideoFormat *mix, GString *msg) { 130 131 MIX_RESULT ret = MIX_RESULT_SUCCESS; 132 133 if (mix == NULL || msg == NULL) 134 { 135 LOG_E( "NUll pointer passed in\n"); 136 return MIX_RESULT_NULL_PTR; 137 } 138 139 LOG_V( "Begin\n"); 140 141 /* Chainup parent method. 142 */ 143 144 if (parent_class->getcaps) { 145 ret = parent_class->getcaps(mix, msg); 146 } 147 148 LOG_V( "End\n"); 149 150 return ret; 151 } 152 153 MIX_RESULT mix_videofmt_h264_initialize(MixVideoFormat *mix, 154 MixVideoConfigParamsDec * config_params, 155 MixFrameManager * frame_mgr, 156 MixBufferPool * input_buf_pool, 157 MixSurfacePool ** surface_pool, 158 VADisplay va_display ) { 159 160 uint32 pret = 0; 161 MIX_RESULT ret = MIX_RESULT_SUCCESS; 162 enum _vbp_parser_type ptype = VBP_H264; 163 vbp_data_h264 *data = NULL; 164 MixVideoFormat *parent = NULL; 165 MixIOVec *header = NULL; 166 gint numprofs = 0, numactualprofs = 0; 167 gint numentrypts = 0, numactualentrypts = 0; 168 VADisplay vadisplay = NULL; 169 VAProfile *profiles = NULL; 170 VAEntrypoint *entrypts = NULL; 171 VAConfigAttrib attrib; 172 VAStatus vret = VA_STATUS_SUCCESS; 173 guint extra_surfaces = 0; 174 VASurfaceID *surfaces = NULL; 175 guint numSurfaces = 0; 176 177 //TODO Partition this method into smaller methods 178 179 if (mix == NULL || config_params == NULL || frame_mgr == NULL || input_buf_pool == NULL || va_display == NULL) 180 { 181 LOG_E( "NUll pointer passed in\n"); 182 return MIX_RESULT_NULL_PTR; 183 } 184 185 LOG_V( "Begin\n"); 186 187 /* Chainup parent method. */ 188 189 if (parent_class->initialize) { 190 ret = parent_class->initialize(mix, config_params, 191 frame_mgr, input_buf_pool, surface_pool, 192 va_display); 193 } 194 195 if (ret != MIX_RESULT_SUCCESS) 196 { 197 LOG_E( "Error initializing\n"); 198 return ret; 199 } 200 201 if (!MIX_IS_VIDEOFORMAT_H264(mix)) 202 return MIX_RESULT_INVALID_PARAM; 203 204 parent = MIX_VIDEOFORMAT(mix); 205 MixVideoFormat_H264 *self = MIX_VIDEOFORMAT_H264(mix); 206 207 LOG_V( "Locking\n"); 208 //From now on, we exit this function through cleanup: 209 g_mutex_lock(parent->objectlock); 210 211 LOG_V( "Before vbp_open\n"); 212 //Load the bitstream parser 213 pret = vbp_open(ptype, &(parent->parser_handle)); 214 215 LOG_V( "After vbp_open\n"); 216 if (!(pret == VBP_OK)) 217 { 218 ret = MIX_RESULT_FAIL; 219 LOG_E( "Error opening parser\n"); 220 goto cleanup; 221 } 222 LOG_V( "Opened parser\n"); 223 224 ret = mix_videoconfigparamsdec_get_header(config_params, 225 &header); 226 227 if ((ret != MIX_RESULT_SUCCESS) || (header == NULL)) 228 { 229 ret = MIX_RESULT_FAIL; 230 LOG_E( "Cannot get header data\n"); 231 goto cleanup; 232 } 233 234 ret = mix_videoconfigparamsdec_get_extra_surface_allocation(config_params, 235 &extra_surfaces); 236 237 if (ret != MIX_RESULT_SUCCESS) 238 { 239 ret = MIX_RESULT_FAIL; 240 LOG_E( "Cannot get extra surface allocation setting\n"); 241 goto cleanup; 242 } 243 244 LOG_V( "Calling parse on header data, handle %d\n", (int)parent->parser_handle); 245 246 pret = vbp_parse(parent->parser_handle, header->data, 247 header->data_size, TRUE); 248 249 if (!((pret == VBP_OK) || (pret == VBP_DONE))) 250 { 251 ret = MIX_RESULT_FAIL; 252 LOG_E( "Error parsing header data\n"); 253 goto cleanup; 254 } 255 256 LOG_V( "Parsed header\n"); 257 258 //Get the header data and save 259 pret = vbp_query(parent->parser_handle, (void *)&data); 260 261 if ((pret != VBP_OK) || (data == NULL)) 262 { 263 ret = MIX_RESULT_FAIL; 264 LOG_E( "Error reading parsed header data\n"); 265 goto cleanup; 266 } 267 268 LOG_V( "Queried parser for header data\n"); 269 270 //Time for libva initialization 271 272 vadisplay = parent->va_display; 273 274 numprofs = vaMaxNumProfiles(vadisplay); 275 profiles = g_malloc(numprofs*sizeof(VAProfile)); 276 277 if (!profiles) 278 { 279 ret = MIX_RESULT_NO_MEMORY; 280 LOG_E( "Error allocating memory\n"); 281 goto cleanup; 282 } 283 284 vret = vaQueryConfigProfiles(vadisplay, profiles, 285 &numactualprofs); 286 if (!(vret == VA_STATUS_SUCCESS)) 287 { 288 ret = MIX_RESULT_FAIL; 289 LOG_E( "Error initializing video driver\n"); 290 goto cleanup; 291 } 292 293 //check the desired profile support 294 gint vaprof = 0; 295 296 //TODO Need to cover more cases 297 switch (data->codec_data->profile_idc) 298 { 299 #if 1 300 //TODO Reinstate this once constraint_set1 flag has been added to codec_data 301 case 66: //Baseline profile 302 303 LOG_V( "mix_videofmt_h264_initialize: Baseline profile\n"); 304 if (data->codec_data->constraint_set1_flag == 0) 305 { 306 for (; vaprof < numactualprofs; vaprof++) 307 { 308 if (profiles[vaprof] == VAProfileH264Baseline) 309 break; 310 } 311 } else 312 { 313 for (; vaprof < numactualprofs; vaprof++) 314 { 315 if (profiles[vaprof] == VAProfileH264High) 316 break; 317 } 318 } 319 if ((vaprof >= numprofs) || ((profiles[vaprof] != VAProfileH264Baseline) && (profiles[vaprof] != VAProfileH264High))) 320 //Did not get the profile we wanted 321 { 322 ret = MIX_RESULT_FAIL; 323 LOG_E( "Profile not supported by driver\n"); 324 goto cleanup; 325 } 326 break; 327 #endif 328 329 #if 0 330 //Code left in place in case bug is fixed in libva 331 case 77: //Main profile (need to set to High for libva bug) 332 LOG_V( "mix_videofmt_h264_initialize: Main profile\n"); 333 334 for (; vaprof < numactualprofs; vaprof++) 335 { 336 if (profiles[vaprof] == VAProfileH264Main) 337 break; 338 } 339 if (vaprof >= numprofs || profiles[vaprof] != VAProfileH264Main) 340 //Did not get the profile we wanted 341 { 342 ret = MIX_RESULT_FAIL; 343 LOG_E( "Profile not supported by driver\n"); 344 goto cleanup; 345 } 346 break; 347 #endif 348 349 case 100: //High profile 350 default: //Set to High as default 351 352 LOG_V( "High profile\n"); 353 354 for (; vaprof < numactualprofs; vaprof++) 355 { 356 if (profiles[vaprof] == VAProfileH264High) 357 break; 358 } 359 if (vaprof >= numprofs || profiles[vaprof] != VAProfileH264High) 360 //Did not get the profile we wanted 361 { 362 ret = MIX_RESULT_FAIL; 363 LOG_E( "Profile not supported by driver\n"); 364 goto cleanup; 365 } 366 break; 367 368 369 } 370 371 numentrypts = vaMaxNumEntrypoints(vadisplay); 372 entrypts = g_malloc(numentrypts*sizeof(VAEntrypoint)); 373 374 if (!entrypts) 375 { 376 ret = MIX_RESULT_NO_MEMORY; 377 LOG_E( "Error allocating memory\n"); 378 goto cleanup; 379 } 380 381 vret = vaQueryConfigEntrypoints(vadisplay, profiles[vaprof], 382 entrypts, &numactualentrypts); 383 if (!(vret == VA_STATUS_SUCCESS)) 384 { 385 ret = MIX_RESULT_FAIL; 386 LOG_E( "Error initializing driver\n"); 387 goto cleanup; 388 } 389 390 gint vaentrypt = 0; 391 for (; vaentrypt < numactualentrypts; vaentrypt++) 392 { 393 if (entrypts[vaentrypt] == VAEntrypointVLD) 394 break; 395 } 396 if (vaentrypt >= numentrypts || entrypts[vaentrypt] != VAEntrypointVLD) 397 //Did not get the entrypt we wanted 398 { 399 ret = MIX_RESULT_FAIL; 400 LOG_E( "Entry point not supported by driver\n"); 401 goto cleanup; 402 } 403 404 //We are requesting RT attributes 405 attrib.type = VAConfigAttribRTFormat; 406 407 vret = vaGetConfigAttributes(vadisplay, profiles[vaprof], 408 entrypts[vaentrypt], &attrib, 1); 409 410 //TODO Handle other values returned for RT format 411 // and check with requested format provided in config params 412 //Right now only YUV 4:2:0 is supported by libva 413 // and this is our default 414 if (((attrib.value & VA_RT_FORMAT_YUV420) == 0) || 415 vret != VA_STATUS_SUCCESS) 416 { 417 ret = MIX_RESULT_FAIL; 418 LOG_E( "Error initializing driver\n"); 419 goto cleanup; 420 } 421 422 //Initialize and save the VA config ID 423 vret = vaCreateConfig(vadisplay, profiles[vaprof], 424 entrypts[vaentrypt], &attrib, 1, &(parent->va_config)); 425 426 if (!(vret == VA_STATUS_SUCCESS)) 427 { 428 ret = MIX_RESULT_FAIL; 429 LOG_E( "Error initializing driver\n"); 430 goto cleanup; 431 } 432 433 LOG_V( "Created libva config with profile %d\n", vaprof); 434 435 436 //Initialize the surface pool 437 438 LOG_V( "Codec data says num_ref_frames is %d\n", data->codec_data->num_ref_frames); 439 440 441 // handle both frame and field coding for interlaced content 442 int num_ref_pictures = data->codec_data->num_ref_frames; 443 if (!data->codec_data->frame_mbs_only_flag && 444 !data->codec_data->mb_adaptive_frame_field_flag) 445 { 446 447 // field coding, two fields share the same surface. 448 //num_ref_pictures *= 2; 449 } 450 451 //Adding 1 to work around VBLANK issue 452 parent->va_num_surfaces = 1 + extra_surfaces + (((num_ref_pictures + 3) < 453 MIX_VIDEO_H264_SURFACE_NUM) ? 454 (num_ref_pictures + 3) 455 : MIX_VIDEO_H264_SURFACE_NUM); 456 457 numSurfaces = parent->va_num_surfaces; 458 459 parent->va_surfaces = g_malloc(sizeof(VASurfaceID)*numSurfaces); 460 461 surfaces = parent->va_surfaces; 462 463 if (surfaces == NULL) 464 { 465 ret = MIX_RESULT_FAIL; 466 LOG_E( "Cannot allocate temporary data\n"); 467 goto cleanup; 468 } 469 470 LOG_V( "Codec data says picture size is %d x %d\n", (data->pic_data[0].pic_parms->picture_width_in_mbs_minus1 + 1) * 16, (data->pic_data[0].pic_parms->picture_height_in_mbs_minus1 + 1) * 16); 471 LOG_V( "getcaps says picture size is %d x %d\n", parent->picture_width, parent->picture_height); 472 473 vret = vaCreateSurfaces(vadisplay, (data->pic_data[0].pic_parms->picture_width_in_mbs_minus1 + 1) * 16, 474 (data->pic_data[0].pic_parms->picture_height_in_mbs_minus1 + 1) * 16, entrypts[vaentrypt], 475 numSurfaces, surfaces); 476 477 if (!(vret == VA_STATUS_SUCCESS)) 478 { 479 ret = MIX_RESULT_FAIL; 480 LOG_E( "Error allocating surfaces\n"); 481 goto cleanup; 482 } 483 484 parent->surfacepool = mix_surfacepool_new(); 485 *surface_pool = parent->surfacepool; 486 487 if (parent->surfacepool == NULL) 488 { 489 ret = MIX_RESULT_FAIL; 490 LOG_E( "Error initializing surface pool\n"); 491 goto cleanup; 492 } 493 494 495 ret = mix_surfacepool_initialize(parent->surfacepool, 496 surfaces, numSurfaces); 497 498 switch (ret) 499 { 500 case MIX_RESULT_SUCCESS: 501 break; 502 case MIX_RESULT_ALREADY_INIT: //This case is for future use when we can be initialized multiple times. It is to detect when we have not been reset before re-initializing. 503 default: 504 ret = MIX_RESULT_ALREADY_INIT; 505 LOG_E( "Error init failure\n"); 506 goto cleanup; 507 break; 508 } 509 510 LOG_V( "Created %d libva surfaces\n", numSurfaces); 511 512 //Initialize and save the VA context ID 513 //Note: VA_PROGRESSIVE libva flag is only relevant to MPEG2 514 vret = vaCreateContext(vadisplay, parent->va_config, 515 parent->picture_width, parent->picture_height, 516 0, surfaces, numSurfaces, 517 &(parent->va_context)); 518 if (!(vret == VA_STATUS_SUCCESS)) 519 { 520 ret = MIX_RESULT_FAIL; 521 LOG_E( "Error initializing video driver\n"); 522 goto cleanup; 523 } 524 525 LOG_V( "Created libva context width %d, height %d\n", parent->picture_width, parent->picture_height); 526 527 //Create our table of Decoded Picture Buffer "in use" surfaces 528 self->dpb_surface_table = g_hash_table_new_full(NULL, NULL, mix_videofmt_h264_destroy_DPB_key, mix_videofmt_h264_destroy_DPB_value); 529 530 if (self->dpb_surface_table == NULL) 531 { 532 ret = MIX_RESULT_NO_MEMORY; 533 LOG_E( "Error allocating dbp surface table\n"); 534 goto cleanup; //leave this goto here in case other code is added between here and cleanup label 535 } 536 537 cleanup: 538 if (ret != MIX_RESULT_SUCCESS) { 539 pret = vbp_close(parent->parser_handle); 540 parent->parser_handle = NULL; 541 parent->initialized = FALSE; 542 543 } else { 544 parent->initialized = TRUE; 545 } 546 547 if (header != NULL) 548 { 549 if (header->data != NULL) 550 g_free(header->data); 551 g_free(header); 552 header = NULL; 553 } 554 555 g_free(profiles); 556 g_free(entrypts); 557 558 LOG_V( "Unlocking\n"); 559 g_mutex_unlock(parent->objectlock); 560 561 562 return ret; 563 } 564 565 MIX_RESULT mix_videofmt_h264_decode(MixVideoFormat *mix, MixBuffer * bufin[], 566 gint bufincnt, MixVideoDecodeParams * decode_params) { 567 568 uint32 pret = 0; 569 int i = 0; 570 MixVideoFormat *parent = NULL; 571 MIX_RESULT ret = MIX_RESULT_SUCCESS; 572 guint64 ts = 0; 573 vbp_data_h264 *data = NULL; 574 gboolean discontinuity = FALSE; 575 MixInputBufferEntry *bufentry = NULL; 576 577 LOG_V( "Begin\n"); 578 579 if (mix == NULL || bufin == NULL || decode_params == NULL ) 580 { 581 LOG_E( "NUll pointer passed in\n"); 582 return MIX_RESULT_NULL_PTR; 583 } 584 585 /* Chainup parent method. 586 We are not chaining up to parent method for now. 587 */ 588 589 #if 0 590 if (parent_class->decode) { 591 return parent_class->decode(mix, bufin, bufincnt, 592 decode_params); 593 } 594 #endif 595 596 if (!MIX_IS_VIDEOFORMAT_H264(mix)) 597 return MIX_RESULT_INVALID_PARAM; 598 599 parent = MIX_VIDEOFORMAT(mix); 600 601 602 ret = mix_videodecodeparams_get_timestamp(decode_params, 603 &ts); 604 if (ret != MIX_RESULT_SUCCESS) 605 { 606 return MIX_RESULT_FAIL; 607 } 608 609 ret = mix_videodecodeparams_get_discontinuity(decode_params, 610 &discontinuity); 611 if (ret != MIX_RESULT_SUCCESS) 612 { 613 return MIX_RESULT_FAIL; 614 } 615 616 //From now on, we exit this function through cleanup: 617 618 LOG_V( "Locking\n"); 619 g_mutex_lock(parent->objectlock); 620 621 LOG_V( "parse in progress is %d\n", parent->parse_in_progress); 622 //If this is a new frame and we haven't retrieved parser 623 // workload data from previous frame yet, do so 624 if ((ts != parent->current_timestamp) && 625 (parent->parse_in_progress)) 626 { 627 628 //query for data 629 pret = vbp_query(parent->parser_handle, 630 (void *) &data); 631 632 if ((pret != VBP_OK) || (data == NULL)) 633 { 634 ret = MIX_RESULT_FAIL; 635 LOG_E( "Error initializing parser\n"); 636 goto cleanup; 637 } 638 639 LOG_V( "Queried for last frame data\n"); 640 641 //process and decode data 642 ret = mix_videofmt_h264_process_decode(mix, 643 data, parent->current_timestamp, 644 parent->discontinuity_frame_in_progress); 645 646 if (ret != MIX_RESULT_SUCCESS) 647 { 648 //We log this but need to process the new frame data, so do not return 649 LOG_E( "Process_decode failed.\n"); 650 } 651 652 LOG_V( "Called process and decode for last frame\n"); 653 654 parent->parse_in_progress = FALSE; 655 656 } 657 658 parent->current_timestamp = ts; 659 parent->discontinuity_frame_in_progress = discontinuity; 660 661 LOG_V( "Starting current frame %d, timestamp %"G_GINT64_FORMAT"\n", mix_video_h264_counter++, ts); 662 663 for (i = 0; i < bufincnt; i++) 664 { 665 666 LOG_V( "Calling parse for current frame, parse handle %d, buf %x, size %d\n", (int)parent->parser_handle, (guint)bufin[i]->data, bufin[i]->size); 667 668 pret = vbp_parse(parent->parser_handle, 669 bufin[i]->data, 670 bufin[i]->size, 671 FALSE); 672 673 LOG_V( "Called parse for current frame\n"); 674 675 if ((pret == VBP_DONE) || (pret == VBP_OK)) 676 { 677 //query for data 678 pret = vbp_query(parent->parser_handle, 679 (void *) &data); 680 681 if ((pret != VBP_OK) || (data == NULL)) 682 { 683 ret = MIX_RESULT_FAIL; 684 LOG_E( "Error getting parser data\n"); 685 goto cleanup; 686 } 687 688 LOG_V( "Called query for current frame\n"); 689 690 //Increase the ref count of this input buffer 691 mix_buffer_ref(bufin[i]); 692 693 //Create a new MixInputBufferEntry 694 //TODO make this from a pool to optimize 695 bufentry = g_malloc(sizeof( 696 MixInputBufferEntry)); 697 if (bufentry == NULL) 698 { 699 ret = MIX_RESULT_NO_MEMORY; 700 LOG_E( "Error allocating bufentry\n"); 701 goto cleanup; 702 } 703 704 bufentry->buf = bufin[i]; 705 LOG_V( "Setting bufentry %x for mixbuffer %x ts to %"G_GINT64_FORMAT"\n", (guint)bufentry, (guint)bufentry->buf, ts); 706 bufentry->timestamp = ts; 707 708 LOG_V( "Enqueue this input buffer for current frame\n"); 709 LOG_V( "bufentry->timestamp %"G_GINT64_FORMAT"\n", bufentry->timestamp); 710 711 //Enqueue this input buffer 712 g_queue_push_tail(parent->inputbufqueue, 713 (gpointer)bufentry); 714 715 //process and decode data 716 ret = mix_videofmt_h264_process_decode(mix, 717 data, ts, discontinuity); 718 719 if (ret != MIX_RESULT_SUCCESS) 720 { 721 //We log this but continue since we need to complete our processing of input buffers 722 LOG_E( "Process_decode failed.\n"); 723 } 724 725 LOG_V( "Called process and decode for current frame\n"); 726 727 parent->parse_in_progress = FALSE; 728 } 729 else if (pret != VBP_OK) 730 { 731 //We log this but continue since we need to complete our processing of input buffers 732 LOG_E( "Parsing failed.\n"); 733 ret = MIX_RESULT_FAIL; 734 } 735 else 736 { 737 738 LOG_V( "Enqueuing buffer and going on to next (if any) for this frame\n"); 739 740 //Increase the ref count of this input buffer 741 mix_buffer_ref(bufin[i]); 742 743 //Create a new MixInputBufferEntry 744 //TODO make this from a pool to optimize 745 bufentry = g_malloc(sizeof 746 (MixInputBufferEntry)); 747 if (bufentry == NULL) 748 { 749 ret = MIX_RESULT_NO_MEMORY; 750 LOG_E( "Error allocating bufentry\n"); 751 goto cleanup; 752 } 753 bufentry->buf = bufin[i]; 754 LOG_V( "Setting bufentry %x for mixbuffer %x ts to %"G_GINT64_FORMAT"\n", (guint)bufentry, (guint)bufentry->buf, ts); 755 bufentry->timestamp = ts; 756 757 LOG_V( "Enqueue this input buffer for current frame\n"); 758 LOG_V( "bufentry->timestamp %"G_GINT64_FORMAT"\n", bufentry->timestamp); 759 760 //Enqueue this input buffer 761 g_queue_push_tail(parent->inputbufqueue, 762 (gpointer)bufentry); 763 LOG_V( "Setting parse_in_progress to TRUE\n"); 764 parent->parse_in_progress = TRUE; 765 } 766 767 } 768 769 770 cleanup: 771 772 LOG_V( "Unlocking\n"); 773 g_mutex_unlock(parent->objectlock); 774 775 LOG_V( "End\n"); 776 777 return ret; 778 } 779 780 MIX_RESULT mix_videofmt_h264_flush(MixVideoFormat *mix) { 781 782 MIX_RESULT ret = MIX_RESULT_SUCCESS; 783 784 LOG_V( "Begin\n"); 785 786 if (mix == NULL) 787 { 788 LOG_E( "Null pointer passed in\n"); 789 return MIX_RESULT_NULL_PTR; 790 } 791 792 uint32 pret = 0; 793 MixInputBufferEntry *bufentry = NULL; 794 795 796 /* Chainup parent method. 797 We are not chaining up to parent method for now. 798 */ 799 800 #if 0 801 if (parent_class->flush) { 802 return parent_class->flush(mix, msg); 803 } 804 #endif 805 806 MixVideoFormat_H264 *self = MIX_VIDEOFORMAT_H264(mix); 807 808 g_mutex_lock(mix->objectlock); 809 810 //Clear the contents of inputbufqueue 811 while (!g_queue_is_empty(mix->inputbufqueue)) 812 { 813 bufentry = (MixInputBufferEntry *) g_queue_pop_head( 814 mix->inputbufqueue); 815 if (bufentry == NULL) continue; 816 817 mix_buffer_unref(bufentry->buf); 818 g_free(bufentry); 819 } 820 821 //Clear parse_in_progress flag and current timestamp 822 mix->parse_in_progress = FALSE; 823 mix->discontinuity_frame_in_progress = FALSE; 824 mix->current_timestamp = 0; 825 826 //Clear the DPB surface table 827 g_hash_table_remove_all(self->dpb_surface_table); 828 829 //Call parser flush 830 pret = vbp_flush(mix->parser_handle); 831 if (pret != VBP_OK) 832 ret = MIX_RESULT_FAIL; 833 834 g_mutex_unlock(mix->objectlock); 835 836 LOG_V( "End\n"); 837 838 return ret; 839 } 840 841 MIX_RESULT mix_videofmt_h264_eos(MixVideoFormat *mix) { 842 843 MIX_RESULT ret = MIX_RESULT_SUCCESS; 844 vbp_data_h264 *data = NULL; 845 uint32 pret = 0; 846 847 LOG_V( "Begin\n"); 848 849 if (mix == NULL) 850 { 851 LOG_E( "Null pointer passed in\n"); 852 return MIX_RESULT_NULL_PTR; 853 } 854 855 /* Chainup parent method. 856 We are not chaining up to parent method for now. 857 */ 858 859 #if 0 860 if (parent_class->eos) { 861 return parent_class->eos(mix, msg); 862 } 863 #endif 864 865 g_mutex_lock(mix->objectlock); 866 867 //if a frame is in progress, process the frame 868 if (mix->parse_in_progress) 869 { 870 //query for data 871 pret = vbp_query(mix->parser_handle, 872 (void *) &data); 873 874 if ((pret != VBP_OK) || (data == NULL)) 875 { 876 ret = MIX_RESULT_FAIL; 877 LOG_E( "Error getting last parse data\n"); 878 goto cleanup; 879 } 880 881 //process and decode data 882 ret = mix_videofmt_h264_process_decode(mix, 883 data, mix->current_timestamp, 884 mix->discontinuity_frame_in_progress); 885 mix->parse_in_progress = FALSE; 886 if (ret != MIX_RESULT_SUCCESS) 887 { 888 LOG_E( "Error processing last frame\n"); 889 goto cleanup; 890 } 891 892 } 893 894 cleanup: 895 896 g_mutex_unlock(mix->objectlock); 897 898 //Call Frame Manager with _eos() 899 ret = mix_framemanager_eos(mix->framemgr); 900 901 LOG_V( "End\n"); 902 903 return ret; 904 905 906 } 907 908 MIX_RESULT mix_videofmt_h264_deinitialize(MixVideoFormat *mix) { 909 910 //Note this method is not called; may remove in future 911 912 LOG_V( "Begin\n"); 913 914 if (mix == NULL) 915 { 916 LOG_E( "Null pointer passed in\n"); 917 return MIX_RESULT_NULL_PTR; 918 } 919 920 /* Chainup parent method. 921 */ 922 923 if (parent_class->deinitialize) { 924 return parent_class->deinitialize(mix); 925 } 926 927 //Most stuff is cleaned up in parent_class->finalize() and in _finalize 928 929 LOG_V( "End\n"); 930 931 return MIX_RESULT_SUCCESS; 932 } 933 #define HACK_DPB 934 #ifdef HACK_DPB 935 static inline void mix_videofmt_h264_hack_dpb(MixVideoFormat *mix, 936 vbp_picture_data_h264* pic_data 937 ) 938 { 939 940 gboolean found = FALSE; 941 guint tflags = 0; 942 VAPictureParameterBufferH264 *pic_params = pic_data->pic_parms; 943 VAPictureH264 *pRefList = NULL; 944 int i = 0, j = 0, k = 0, list = 0; 945 946 MixVideoFormat_H264 *self = MIX_VIDEOFORMAT_H264(mix); 947 948 //Set the surface ID for everything in the parser DPB to INVALID 949 for (i = 0; i < 16; i++) 950 { 951 pic_params->ReferenceFrames[i].picture_id = VA_INVALID_SURFACE; 952 pic_params->ReferenceFrames[i].frame_idx = -1; 953 pic_params->ReferenceFrames[i].TopFieldOrderCnt = -1; 954 pic_params->ReferenceFrames[i].BottomFieldOrderCnt = -1; 955 pic_params->ReferenceFrames[i].flags = VA_PICTURE_H264_INVALID; //assuming we don't need to OR with existing flags 956 } 957 958 pic_params->num_ref_frames = 0; 959 960 for (i = 0; i < pic_data->num_slices; i++) 961 { 962 963 //Copy from the List0 and List1 surface IDs 964 pRefList = pic_data->slc_data[i].slc_parms.RefPicList0; 965 for (list = 0; list < 2; list++) 966 { 967 for (j = 0; j < 32; j++) 968 { 969 if (pRefList[j].flags & VA_PICTURE_H264_INVALID) 970 { 971 break; //no more valid reference frames in this list 972 } 973 found = FALSE; 974 for (k = 0; k < pic_params->num_ref_frames; k++) 975 { 976 if (pic_params->ReferenceFrames[k].TopFieldOrderCnt == pRefList[j].TopFieldOrderCnt) 977 { 978 ///check for complementary field 979 tflags = pic_params->ReferenceFrames[k].flags | pRefList[j].flags; 980 //If both TOP and BOTTOM are set, we'll clear those flags 981 if ((tflags & VA_PICTURE_H264_TOP_FIELD) && 982 (tflags & VA_PICTURE_H264_TOP_FIELD)) 983 pic_params->ReferenceFrames[k].flags = VA_PICTURE_H264_SHORT_TERM_REFERENCE; 984 found = TRUE; //already in the DPB; will not add this one 985 break; 986 } 987 } 988 if (!found) 989 { 990 guint poc = mix_videofmt_h264_get_poc(&(pRefList[j])); 991 gpointer video_frame = g_hash_table_lookup(self->dpb_surface_table, (gpointer)poc); 992 pic_params->ReferenceFrames[pic_params->num_ref_frames].picture_id = 993 ((MixVideoFrame *)video_frame)->frame_id; 994 995 LOG_V( "Inserting frame id %d into DPB\n", pic_params->ReferenceFrames[pic_params->num_ref_frames].picture_id); 996 997 pic_params->ReferenceFrames[pic_params->num_ref_frames].flags = 998 pRefList[j].flags; 999 pic_params->ReferenceFrames[pic_params->num_ref_frames].frame_idx = 1000 pRefList[j].frame_idx; 1001 pic_params->ReferenceFrames[pic_params->num_ref_frames].TopFieldOrderCnt = 1002 pRefList[j].TopFieldOrderCnt; 1003 pic_params->ReferenceFrames[pic_params->num_ref_frames++].BottomFieldOrderCnt = 1004 pRefList[j].BottomFieldOrderCnt; 1005 } 1006 1007 } 1008 pRefList = pic_data->slc_data[i].slc_parms.RefPicList1; 1009 } 1010 1011 } 1012 } 1013 #endif 1014 1015 1016 MIX_RESULT mix_videofmt_h264_process_decode_picture(MixVideoFormat *mix, 1017 vbp_data_h264 *data, 1018 guint64 timestamp, 1019 gboolean discontinuity, 1020 int pic_index, 1021 MixVideoFrame *frame) 1022 { 1023 1024 MIX_RESULT ret = MIX_RESULT_SUCCESS; 1025 VAStatus vret = VA_STATUS_SUCCESS; 1026 VADisplay vadisplay = NULL; 1027 VAContextID vacontext; 1028 guint buffer_id_cnt = 0; 1029 VABufferID *buffer_ids = NULL; 1030 1031 //TODO Partition this method into smaller methods 1032 1033 LOG_V( "Begin\n"); 1034 1035 if ((mix == NULL) || (data == NULL) || (data->pic_data == NULL) || (frame == NULL)) 1036 { 1037 LOG_E( "Null pointer passed in\n"); 1038 return MIX_RESULT_NULL_PTR; 1039 } 1040 1041 vbp_picture_data_h264* pic_data = &(data->pic_data[pic_index]); 1042 1043 1044 //After this point, all exits from this function are through cleanup: 1045 1046 if (!MIX_IS_VIDEOFORMAT_H264(mix)) 1047 return MIX_RESULT_INVALID_PARAM; 1048 1049 MixVideoFormat_H264 *self = MIX_VIDEOFORMAT_H264(mix); 1050 1051 VAPictureParameterBufferH264 *pic_params = pic_data->pic_parms; 1052 1053 if (pic_params == NULL) 1054 { 1055 ret = MIX_RESULT_NULL_PTR; 1056 LOG_E( "Error reading parser data\n"); 1057 goto cleanup; 1058 } 1059 1060 //TODO 1061 //Check for frame gaps and repeat frames if necessary 1062 1063 LOG_V( "num_slices is %d, allocating %d buffer_ids\n", pic_data->num_slices, (pic_data->num_slices * 2) + 2); 1064 1065 buffer_ids = g_malloc(sizeof(VABufferID) * 1066 ((pic_data->num_slices * 2) + 2)); 1067 1068 if (buffer_ids == NULL) 1069 { 1070 LOG_E( "Cannot allocate buffer IDs\n"); 1071 ret = MIX_RESULT_NO_MEMORY; 1072 goto cleanup; 1073 } 1074 1075 //Set up reference frames for the picture parameter buffer 1076 1077 //Set the picture type (I, B or P frame) 1078 //For H.264 we use the first encountered slice type for this (check - may need to change later to search all slices for B type) 1079 MixFrameType frame_type = TYPE_INVALID; 1080 1081 switch (pic_data->slc_data->slc_parms.slice_type) 1082 { 1083 case 0: 1084 case 3: 1085 case 5: 1086 case 8: 1087 frame_type = TYPE_P; 1088 break; 1089 case 1: 1090 case 6: 1091 frame_type = TYPE_B; 1092 break; 1093 case 2: 1094 case 4: 1095 case 7: 1096 case 9: 1097 frame_type = TYPE_I; 1098 break; 1099 default: 1100 break; 1101 } 1102 1103 //Do not have to check for B frames after a seek 1104 //Note: Demux should seek to IDR (instantaneous decoding refresh) frame, otherwise 1105 // DPB will not be correct and frames may come in with invalid references 1106 // This will be detected when DPB is checked for valid mapped surfaces and 1107 // error returned from there. 1108 1109 LOG_V( "Getting a new surface for frame_num %d\n", pic_params->frame_num); 1110 LOG_V( "frame type is %d\n", frame_type); 1111 1112 1113 1114 //Set the frame type for the frame object (used in reordering by frame manager) 1115 ret = mix_videoframe_set_frame_type(frame, frame_type); 1116 1117 if (ret != MIX_RESULT_SUCCESS) 1118 { 1119 LOG_E( "Error setting frame type on frame\n"); 1120 goto cleanup; 1121 } 1122 1123 LOG_V( "Updating DPB for libva\n"); 1124 1125 //Now handle the reference frames and surface IDs for DPB and current frame 1126 mix_videofmt_h264_handle_ref_frames(mix, pic_params, frame); 1127 1128 #ifdef HACK_DPB 1129 //We have to provide a hacked DPB rather than complete DPB for libva as workaround 1130 mix_videofmt_h264_hack_dpb(mix, pic_data); 1131 #endif 1132 1133 //Libva buffer set up 1134 1135 vadisplay = mix->va_display; 1136 vacontext = mix->va_context; 1137 1138 LOG_V( "Creating libva picture parameter buffer\n"); 1139 LOG_V( "picture parameter buffer shows num_ref_frames is %d\n", pic_params->num_ref_frames); 1140 1141 //First the picture parameter buffer 1142 vret = vaCreateBuffer(vadisplay, vacontext, 1143 VAPictureParameterBufferType, 1144 sizeof(VAPictureParameterBufferH264), 1145 1, 1146 pic_params, 1147 &buffer_ids[buffer_id_cnt]); 1148 buffer_id_cnt++; 1149 1150 if (vret != VA_STATUS_SUCCESS) 1151 { 1152 ret = MIX_RESULT_FAIL; 1153 LOG_E( "Video driver returned error from vaCreateBuffer\n"); 1154 goto cleanup; 1155 } 1156 1157 LOG_V( "Creating libva IQMatrix buffer\n"); 1158 1159 1160 //Then the IQ matrix buffer 1161 vret = vaCreateBuffer(vadisplay, vacontext, 1162 VAIQMatrixBufferType, 1163 sizeof(VAIQMatrixBufferH264), 1164 1, 1165 data->IQ_matrix_buf, 1166 &buffer_ids[buffer_id_cnt]); 1167 buffer_id_cnt++; 1168 1169 if (vret != VA_STATUS_SUCCESS) 1170 { 1171 ret = MIX_RESULT_FAIL; 1172 LOG_E( "Video driver returned error from vaCreateBuffer\n"); 1173 goto cleanup; 1174 } 1175 1176 1177 //Now for slices 1178 int i = 0; 1179 gpointer video_frame; 1180 for (;i < pic_data->num_slices; i++) 1181 { 1182 1183 LOG_V( "Creating libva slice parameter buffer, for slice %d\n", i); 1184 1185 //Do slice parameters 1186 1187 //First patch up the List0 and List1 surface IDs 1188 int j = 0; 1189 guint poc = 0; 1190 for (; j <= pic_data->slc_data[i].slc_parms.num_ref_idx_l0_active_minus1; j++) 1191 { 1192 if (!(pic_data->slc_data[i].slc_parms.RefPicList0[j].flags & VA_PICTURE_H264_INVALID)) 1193 { 1194 poc = mix_videofmt_h264_get_poc(&(pic_data->slc_data[i].slc_parms.RefPicList0[j])); 1195 video_frame = g_hash_table_lookup(self->dpb_surface_table, (gpointer)poc); 1196 if (video_frame == NULL) 1197 { 1198 LOG_E( "unable to find surface of picture %d (current picture %d).", poc, mix_videofmt_h264_get_poc(&pic_params->CurrPic)); 1199 ret = MIX_RESULT_FAIL; 1200 goto cleanup; 1201 } 1202 else 1203 { 1204 pic_data->slc_data[i].slc_parms.RefPicList0[j].picture_id = 1205 ((MixVideoFrame *)video_frame)->frame_id; 1206 } 1207 } 1208 1209 } 1210 1211 if ((pic_data->slc_data->slc_parms.slice_type == 1) || (pic_data->slc_data->slc_parms.slice_type == 6)) 1212 { 1213 for (j = 0; j <= pic_data->slc_data[i].slc_parms.num_ref_idx_l1_active_minus1; j++) 1214 { 1215 if (!(pic_data->slc_data[i].slc_parms.RefPicList1[j].flags & VA_PICTURE_H264_INVALID)) 1216 { 1217 poc = mix_videofmt_h264_get_poc(&(pic_data->slc_data[i].slc_parms.RefPicList1[j])); 1218 video_frame = g_hash_table_lookup(self->dpb_surface_table, (gpointer)poc); 1219 if (video_frame == NULL) 1220 { 1221 LOG_E( "unable to find surface of picture %d (current picture %d).", poc, mix_videofmt_h264_get_poc(&pic_params->CurrPic)); 1222 ret = MIX_RESULT_FAIL; 1223 goto cleanup; 1224 } 1225 else 1226 { 1227 pic_data->slc_data[i].slc_parms.RefPicList1[j].picture_id = 1228 ((MixVideoFrame *)video_frame)->frame_id; 1229 } 1230 } 1231 } 1232 } 1233 1234 1235 //Then do the libva setup 1236 1237 vret = vaCreateBuffer(vadisplay, vacontext, 1238 VASliceParameterBufferType, 1239 sizeof(VASliceParameterBufferH264), 1240 1, 1241 &(pic_data->slc_data[i].slc_parms), 1242 &buffer_ids[buffer_id_cnt]); 1243 1244 if (vret != VA_STATUS_SUCCESS) 1245 { 1246 ret = MIX_RESULT_FAIL; 1247 LOG_E( "Video driver returned error from vaCreateBuffer\n"); 1248 goto cleanup; 1249 } 1250 1251 buffer_id_cnt++; 1252 1253 1254 LOG_V( "Creating libva slice data buffer for slice %d, using slice address %x, with offset %d and size %u\n", i, (guint)pic_data->slc_data[i].buffer_addr, pic_data->slc_data[i].slc_parms.slice_data_offset, pic_data->slc_data[i].slice_size); 1255 1256 1257 //Do slice data 1258 1259 vret = vaCreateBuffer(vadisplay, vacontext, 1260 VASliceDataBufferType, 1261 //size 1262 pic_data->slc_data[i].slice_size, 1263 //num_elements 1264 1, 1265 //slice data buffer pointer 1266 //Note that this is the original data buffer ptr; 1267 // offset to the actual slice data is provided in 1268 // slice_data_offset in VASliceParameterBufferH264 1269 pic_data->slc_data[i].buffer_addr + pic_data->slc_data[i].slice_offset, 1270 &buffer_ids[buffer_id_cnt]); 1271 1272 buffer_id_cnt++; 1273 1274 if (vret != VA_STATUS_SUCCESS) 1275 { 1276 ret = MIX_RESULT_FAIL; 1277 LOG_E( "Video driver returned error from vaCreateBuffer\n"); 1278 goto cleanup; 1279 } 1280 1281 } 1282 1283 gulong surface = 0; 1284 1285 //Get our surface ID from the frame object 1286 ret = mix_videoframe_get_frame_id(frame, &surface); 1287 1288 if (ret != MIX_RESULT_SUCCESS) 1289 { 1290 LOG_E( "Error getting surface ID from frame object\n"); 1291 goto cleanup; 1292 } 1293 1294 LOG_V( "Calling vaBeginPicture\n"); 1295 1296 //Now we can begin the picture 1297 vret = vaBeginPicture(vadisplay, vacontext, surface); 1298 1299 if (vret != VA_STATUS_SUCCESS) 1300 { 1301 ret = MIX_RESULT_FAIL; 1302 LOG_E( "Video driver returned error from vaBeginPicture\n"); 1303 goto cleanup; 1304 } 1305 1306 LOG_V( "Calling vaRenderPicture\n"); 1307 1308 //Render the picture 1309 vret = vaRenderPicture(vadisplay, vacontext, 1310 buffer_ids, 1311 buffer_id_cnt); 1312 1313 1314 if (vret != VA_STATUS_SUCCESS) 1315 { 1316 ret = MIX_RESULT_FAIL; 1317 LOG_E( "Video driver returned error from vaRenderPicture\n"); 1318 goto cleanup; 1319 } 1320 1321 LOG_V( "Calling vaEndPicture\n"); 1322 1323 //End picture 1324 vret = vaEndPicture(vadisplay, vacontext); 1325 1326 if (vret != VA_STATUS_SUCCESS) 1327 { 1328 ret = MIX_RESULT_FAIL; 1329 LOG_E( "Video driver returned error from vaEndPicture\n"); 1330 goto cleanup; 1331 } 1332 1333 LOG_V( "Calling vaSyncSurface\n"); 1334 1335 //Decode the picture 1336 vret = vaSyncSurface(vadisplay, surface); 1337 1338 if (vret != VA_STATUS_SUCCESS) 1339 { 1340 ret = MIX_RESULT_FAIL; 1341 LOG_E( "Video driver returned error from vaSyncSurface\n"); 1342 goto cleanup; 1343 } 1344 1345 1346 if (pic_index == 0) 1347 { 1348 //Set the discontinuity flag 1349 mix_videoframe_set_discontinuity(frame, discontinuity); 1350 1351 //Set the timestamp 1352 mix_videoframe_set_timestamp(frame, timestamp); 1353 1354 guint32 frame_structure = VA_FRAME_PICTURE; 1355 if (pic_params->CurrPic.flags & VA_PICTURE_H264_TOP_FIELD) 1356 { 1357 frame_structure = VA_TOP_FIELD; 1358 } 1359 else if (pic_params->CurrPic.flags & VA_PICTURE_H264_BOTTOM_FIELD) 1360 { 1361 frame_structure = VA_BOTTOM_FIELD; 1362 } 1363 mix_videoframe_set_frame_structure(frame, frame_structure); 1364 } 1365 else 1366 { 1367 // frame must be field-coded, no need to set 1368 // discontinuity falg and time stamp again 1369 mix_videoframe_set_frame_structure(frame, VA_BOTTOM_FIELD | VA_TOP_FIELD); 1370 } 1371 1372 //TODO need to save off frame when handling is added for repeat frames? 1373 1374 //TODO Complete YUVDUMP code and move into base class 1375 #ifdef YUVDUMP 1376 if (mix_video_h264_counter < 10) 1377 ret = GetImageFromSurface (mix, frame); 1378 // g_usleep(5000000); 1379 #endif /* YUVDUMP */ 1380 1381 LOG_V( "Enqueueing the frame with frame manager, timestamp %"G_GINT64_FORMAT"\n", timestamp); 1382 1383 1384 cleanup: 1385 1386 if (NULL != buffer_ids) 1387 g_free(buffer_ids); 1388 1389 1390 LOG_V( "End\n"); 1391 1392 return ret; 1393 1394 } 1395 1396 1397 MIX_RESULT mix_videofmt_h264_process_decode(MixVideoFormat *mix, 1398 vbp_data_h264 *data, 1399 guint64 timestamp, 1400 gboolean discontinuity) 1401 { 1402 MIX_RESULT ret = MIX_RESULT_SUCCESS; 1403 int i = 0; 1404 1405 if ((mix == NULL) || (data == NULL)) 1406 { 1407 LOG_E( "Null pointer passed in\n"); 1408 return MIX_RESULT_NULL_PTR; 1409 } 1410 1411 //Get a frame from the surface pool 1412 MixVideoFrame *frame = NULL; 1413 1414 ret = mix_surfacepool_get(mix->surfacepool, &frame); 1415 1416 if (ret != MIX_RESULT_SUCCESS) 1417 { 1418 LOG_E( "Error getting frame from surfacepool\n"); 1419 return MIX_RESULT_FAIL; 1420 } 1421 1422 1423 for (i = 0; i < data->num_pictures; i++) 1424 { 1425 ret = mix_videofmt_h264_process_decode_picture(mix, data, timestamp, discontinuity, i, frame); 1426 if (ret != MIX_RESULT_SUCCESS) 1427 { 1428 LOG_E( "Failed to process decode picture %d, error = %#X.", data->buf_number, ret); 1429 break; 1430 } 1431 } 1432 1433 if (ret == MIX_RESULT_SUCCESS) 1434 { 1435 //Enqueue the decoded frame using frame manager 1436 ret = mix_framemanager_enqueue(mix->framemgr, frame); 1437 if (ret != MIX_RESULT_SUCCESS) 1438 { 1439 LOG_E( "Error enqueuing frame object\n"); 1440 mix_videoframe_unref(frame); 1441 } 1442 1443 } 1444 else 1445 { 1446 mix_videoframe_unref(frame); 1447 } 1448 mix_videofmt_h264_release_input_buffers(mix, timestamp); 1449 1450 return ret; 1451 } 1452 1453 MIX_RESULT mix_videofmt_h264_handle_ref_frames(MixVideoFormat *mix, 1454 VAPictureParameterBufferH264* pic_params, 1455 MixVideoFrame * current_frame 1456 ) { 1457 1458 guint poc = 0; 1459 1460 LOG_V( "Begin\n"); 1461 1462 if (mix == NULL || current_frame == NULL || pic_params == NULL) 1463 { 1464 LOG_E( "Null pointer passed in\n"); 1465 return MIX_RESULT_NULL_PTR; 1466 } 1467 1468 1469 LOG_V( "Pic_params has flags %d, topfieldcnt %d, bottomfieldcnt %d. Surface ID is %d\n", pic_params->CurrPic.flags, pic_params->CurrPic.TopFieldOrderCnt, pic_params->CurrPic.BottomFieldOrderCnt, (gint) current_frame->frame_id); 1470 1471 #ifdef MIX_LOG_ENABLE 1472 if (pic_params->CurrPic.flags & VA_PICTURE_H264_INVALID) 1473 LOG_V( "Flags show VA_PICTURE_H264_INVALID\n"); 1474 1475 if (pic_params->CurrPic.flags & VA_PICTURE_H264_TOP_FIELD) 1476 LOG_V( "Flags show VA_PICTURE_H264_TOP_FIELD\n"); 1477 1478 if (pic_params->CurrPic.flags & VA_PICTURE_H264_BOTTOM_FIELD) 1479 LOG_V( "Flags show VA_PICTURE_H264_BOTTOM_FIELD\n"); 1480 1481 if (pic_params->CurrPic.flags & VA_PICTURE_H264_SHORT_TERM_REFERENCE) 1482 LOG_V( "Flags show VA_PICTURE_H264_SHORT_TERM_REFERENCE\n"); 1483 1484 if (pic_params->CurrPic.flags & VA_PICTURE_H264_LONG_TERM_REFERENCE) 1485 LOG_V( "Flags show VA_PICTURE_H264_LONG_TERM_REFERENCE\n"); 1486 #endif 1487 1488 MixVideoFormat_H264 *self = MIX_VIDEOFORMAT_H264(mix); 1489 1490 1491 //First we need to check the parser DBP against our DPB table 1492 //So for each item in our DBP table, we look to see if it is in the parser DPB 1493 //If it is not, it gets unrefed and removed 1494 #ifdef MIX_LOG_ENABLE 1495 guint num_removed = 1496 #endif 1497 g_hash_table_foreach_remove(self->dpb_surface_table, mix_videofmt_h264_check_in_DPB, pic_params); 1498 1499 LOG_V( "%d entries removed from DPB surface table at this frame\n", num_removed); 1500 1501 1502 MixVideoFrame *mvf = NULL; 1503 gboolean found = FALSE; 1504 //Set the surface ID for everything in the parser DPB 1505 int i = 0; 1506 for (; i < 16; i++) 1507 { 1508 if (!(pic_params->ReferenceFrames[i].flags & VA_PICTURE_H264_INVALID)) 1509 { 1510 1511 poc = mix_videofmt_h264_get_poc(&(pic_params->ReferenceFrames[i])); 1512 LOG_V( "Looking up poc %d in dpb table\n", poc); 1513 found = g_hash_table_lookup_extended(self->dpb_surface_table, (gpointer)poc, NULL, (gpointer)&mvf); 1514 1515 if (found) 1516 { 1517 pic_params->ReferenceFrames[i].picture_id = mvf->frame_id; 1518 LOG_V( "Looked up poc %d in dpb table found frame ID %d\n", poc, (gint)mvf->frame_id); 1519 } else { 1520 LOG_V( "Looking up poc %d in dpb table did not find value\n", poc); 1521 } 1522 LOG_V( "For poc %d, set surface id for DPB index %d to %d\n", poc, i, (gint)pic_params->ReferenceFrames[i].picture_id); 1523 } 1524 1525 } 1526 1527 1528 //Set picture_id for current picture 1529 pic_params->CurrPic.picture_id = current_frame->frame_id; 1530 1531 //Check to see if current frame is a reference frame 1532 if ((pic_params->CurrPic.flags & VA_PICTURE_H264_SHORT_TERM_REFERENCE) || (pic_params->CurrPic.flags & VA_PICTURE_H264_LONG_TERM_REFERENCE)) 1533 { 1534 //Get current frame's POC 1535 poc = mix_videofmt_h264_get_poc(&(pic_params->CurrPic)); 1536 1537 //Increment the reference count for this frame 1538 mix_videoframe_ref(current_frame); 1539 1540 LOG_V( "Inserting poc %d, surfaceID %d\n", poc, (gint)current_frame->frame_id); 1541 //Add this frame to the DPB surface table 1542 g_hash_table_insert(self->dpb_surface_table, (gpointer)poc, current_frame); 1543 } 1544 1545 1546 1547 LOG_V( "End\n"); 1548 1549 return MIX_RESULT_SUCCESS; 1550 } 1551 1552 guint mix_videofmt_h264_get_poc(VAPictureH264 *pic) 1553 { 1554 1555 if (pic == NULL) 1556 return 0; 1557 1558 if (pic->flags & VA_PICTURE_H264_BOTTOM_FIELD) 1559 return pic->BottomFieldOrderCnt; 1560 1561 1562 if (pic->flags & VA_PICTURE_H264_TOP_FIELD) 1563 return pic->TopFieldOrderCnt; 1564 1565 return pic->TopFieldOrderCnt; 1566 1567 } 1568 1569 1570 gboolean mix_videofmt_h264_check_in_DPB(gpointer key, gpointer value, gpointer user_data) 1571 { 1572 gboolean ret = TRUE; 1573 1574 if ((value == NULL) || (user_data == NULL)) //Note that 0 is valid value for key 1575 return FALSE; 1576 1577 VAPictureH264* vaPic = NULL; 1578 int i = 0; 1579 for (; i < 16; i++) 1580 { 1581 vaPic = &(((VAPictureParameterBufferH264*)user_data)->ReferenceFrames[i]); 1582 if (vaPic->flags & VA_PICTURE_H264_INVALID) 1583 continue; 1584 1585 if ((guint)key == vaPic->TopFieldOrderCnt || 1586 (guint)key == vaPic->BottomFieldOrderCnt) 1587 { 1588 ret = FALSE; 1589 break; 1590 } 1591 } 1592 1593 return ret; 1594 } 1595 1596 void mix_videofmt_h264_destroy_DPB_key(gpointer data) 1597 { 1598 //TODO remove this method and don't register it with the hash table foreach call; it is no longer needed 1599 LOG_V( "Begin, poc of %d\n", (guint)data); 1600 LOG_V( "End\n"); 1601 1602 return; 1603 } 1604 1605 void mix_videofmt_h264_destroy_DPB_value(gpointer data) 1606 { 1607 LOG_V( "Begin\n"); 1608 if (data == NULL) 1609 return ; 1610 mix_videoframe_unref((MixVideoFrame *)data); 1611 1612 return; 1613 } 1614 1615 1616 MIX_RESULT mix_videofmt_h264_release_input_buffers(MixVideoFormat *mix, 1617 guint64 timestamp 1618 ) { 1619 1620 MixInputBufferEntry *bufentry = NULL; 1621 gboolean done = FALSE; 1622 1623 LOG_V( "Begin\n"); 1624 1625 if (mix == NULL) 1626 return MIX_RESULT_NULL_PTR; 1627 1628 //Dequeue and release all input buffers for this frame 1629 1630 LOG_V( "Releasing all the MixBuffers for this frame\n"); 1631 1632 //While the head of the queue has timestamp == current ts 1633 //dequeue the entry, unref the MixBuffer, and free the struct 1634 done = FALSE; 1635 while (!done) 1636 { 1637 bufentry = (MixInputBufferEntry *) g_queue_peek_head( 1638 mix->inputbufqueue); 1639 if (bufentry == NULL) break; 1640 LOG_V( "head of queue buf %x, timestamp %"G_GINT64_FORMAT", buffer timestamp %"G_GINT64_FORMAT"\n", (guint)bufentry->buf, timestamp, bufentry->timestamp); 1641 1642 if (bufentry->timestamp != timestamp) 1643 { 1644 LOG_V( "buf %x, timestamp %"G_GINT64_FORMAT", buffer timestamp %"G_GINT64_FORMAT"\n", (guint)bufentry->buf, timestamp, bufentry->timestamp); 1645 done = TRUE; 1646 break; 1647 } 1648 1649 bufentry = (MixInputBufferEntry *) g_queue_pop_head( 1650 mix->inputbufqueue); 1651 LOG_V( "Unref this MixBuffers %x\n", (guint)bufentry->buf); 1652 mix_buffer_unref(bufentry->buf); 1653 g_free(bufentry); 1654 } 1655 1656 1657 LOG_V( "End\n"); 1658 1659 return MIX_RESULT_SUCCESS; 1660 } 1661 1662 1663 1664