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