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 <string.h> 10 #include "mixvideolog.h" 11 #include "mixvideoformat_mp42.h" 12 13 enum { 14 MP4_VOP_TYPE_I = 0, 15 MP4_VOP_TYPE_P = 1, 16 MP4_VOP_TYPE_B = 2, 17 MP4_VOP_TYPE_S = 3, 18 }; 19 20 /* 21 * This is for divx packed stream 22 */ 23 typedef struct _PackedStream PackedStream; 24 struct _PackedStream { 25 vbp_picture_data_mp42 *picture_data; 26 MixBuffer *mix_buffer; 27 }; 28 29 /* 30 * Clone and destroy vbp_picture_data_mp42 31 */ 32 static vbp_picture_data_mp42 *mix_videoformat_mp42_clone_picture_data( 33 vbp_picture_data_mp42 *picture_data); 34 static void mix_videoformat_mp42_free_picture_data( 35 vbp_picture_data_mp42 *picture_data); 36 static void mix_videoformat_mp42_flush_packed_stream_queue( 37 GQueue *packed_stream_queue); 38 39 /* The parent class. The pointer will be saved 40 * in this class's initialization. The pointer 41 * can be used for chaining method call if needed. 42 */ 43 static MixVideoFormatClass *parent_class = NULL; 44 45 static void mix_videoformat_mp42_finalize(GObject * obj); 46 47 /* 48 * Please note that the type we pass to G_DEFINE_TYPE is MIX_TYPE_VIDEOFORMAT 49 */ 50 G_DEFINE_TYPE( MixVideoFormat_MP42, mix_videoformat_mp42, MIX_TYPE_VIDEOFORMAT); 51 52 static void mix_videoformat_mp42_init(MixVideoFormat_MP42 * self) { 53 MixVideoFormat *parent = MIX_VIDEOFORMAT(self); 54 55 self->reference_frames[0] = NULL; 56 self->reference_frames[1] = NULL; 57 58 self->last_frame = NULL; 59 self->last_vop_coding_type = -1; 60 61 self->packed_stream_queue = NULL; 62 63 /* NOTE: we don't need to do this here. 64 * This just demostrates how to access 65 * member varibles beloned to parent 66 */ 67 parent->initialized = FALSE; 68 } 69 70 static void mix_videoformat_mp42_class_init(MixVideoFormat_MP42Class * klass) { 71 72 /* root class */ 73 GObjectClass *gobject_class = (GObjectClass *) klass; 74 75 /* direct parent class */ 76 MixVideoFormatClass *video_format_class = MIX_VIDEOFORMAT_CLASS(klass); 77 78 /* parent class for later use */ 79 parent_class = g_type_class_peek_parent(klass); 80 81 /* setup finializer */ 82 gobject_class->finalize = mix_videoformat_mp42_finalize; 83 84 /* setup vmethods with base implementation */ 85 video_format_class->getcaps = mix_videofmt_mp42_getcaps; 86 video_format_class->initialize = mix_videofmt_mp42_initialize; 87 video_format_class->decode = mix_videofmt_mp42_decode; 88 video_format_class->flush = mix_videofmt_mp42_flush; 89 video_format_class->eos = mix_videofmt_mp42_eos; 90 video_format_class->deinitialize = mix_videofmt_mp42_deinitialize; 91 } 92 93 MixVideoFormat_MP42 *mix_videoformat_mp42_new(void) { 94 MixVideoFormat_MP42 *ret = g_object_new(MIX_TYPE_VIDEOFORMAT_MP42, NULL); 95 96 return ret; 97 } 98 99 void mix_videoformat_mp42_finalize(GObject * obj) { 100 /* clean up here. */ 101 102 /* MixVideoFormat_MP42 *mix = MIX_VIDEOFORMAT_MP42(obj); */ 103 GObjectClass *root_class = (GObjectClass *) parent_class; 104 MixVideoFormat *parent = NULL; 105 gint32 vbp_ret = VBP_OK; 106 MixVideoFormat_MP42 *self = NULL; 107 108 LOG_V("Begin\n"); 109 110 if (obj == NULL) { 111 LOG_E("obj is NULL\n"); 112 return; 113 } 114 115 if (!MIX_IS_VIDEOFORMAT_MP42(obj)) { 116 LOG_E("obj is not mixvideoformat_mp42\n"); 117 return; 118 } 119 120 self = MIX_VIDEOFORMAT_MP42(obj); 121 parent = MIX_VIDEOFORMAT(self); 122 123 //surfacepool is deallocated by parent 124 //inputbufqueue is deallocated by parent 125 //parent calls vaDestroyConfig, vaDestroyContext and vaDestroySurfaces 126 127 g_mutex_lock(parent->objectlock); 128 129 /* unref reference frames */ 130 { 131 gint idx = 0; 132 for (idx = 0; idx < 2; idx++) { 133 if (self->reference_frames[idx] != NULL) { 134 mix_videoframe_unref(self->reference_frames[idx]); 135 self->reference_frames[idx] = NULL; 136 } 137 } 138 } 139 140 141 /* Reset state */ 142 parent->initialized = TRUE; 143 parent->parse_in_progress = FALSE; 144 parent->discontinuity_frame_in_progress = FALSE; 145 parent->current_timestamp = 0; 146 147 /* Close the parser */ 148 vbp_ret = vbp_close(parent->parser_handle); 149 parent->parser_handle = NULL; 150 151 if (self->packed_stream_queue) { 152 mix_videoformat_mp42_flush_packed_stream_queue(self->packed_stream_queue); 153 g_queue_free(self->packed_stream_queue); 154 } 155 self->packed_stream_queue = NULL; 156 157 g_mutex_unlock(parent->objectlock); 158 159 /* Chain up parent */ 160 if (root_class->finalize) { 161 root_class->finalize(obj); 162 } 163 164 LOG_V("End\n"); 165 } 166 167 MixVideoFormat_MP42 * 168 mix_videoformat_mp42_ref(MixVideoFormat_MP42 * mix) { 169 return (MixVideoFormat_MP42 *) g_object_ref(G_OBJECT(mix)); 170 } 171 172 /* MP42 vmethods implementation */ 173 MIX_RESULT mix_videofmt_mp42_getcaps(MixVideoFormat *mix, GString *msg) { 174 175 //This method is reserved for future use 176 177 LOG_V("Begin\n"); 178 if (parent_class->getcaps) { 179 return parent_class->getcaps(mix, msg); 180 } 181 182 LOG_V("End\n"); 183 return MIX_RESULT_NOTIMPL; 184 } 185 186 MIX_RESULT mix_videofmt_mp42_initialize(MixVideoFormat *mix, 187 MixVideoConfigParamsDec * config_params, MixFrameManager * frame_mgr, 188 MixBufferPool * input_buf_pool, MixSurfacePool ** surface_pool, 189 VADisplay va_display) { 190 uint32 vbp_ret = 0; 191 MIX_RESULT ret = MIX_RESULT_FAIL; 192 193 vbp_data_mp42 *data = NULL; 194 MixVideoFormat *parent = NULL; 195 MixIOVec *header = NULL; 196 197 VAProfile va_profile = VAProfileMPEG4AdvancedSimple; 198 VAConfigAttrib attrib; 199 200 VAStatus va_ret = VA_STATUS_SUCCESS; 201 guint number_extra_surfaces = 0; 202 VASurfaceID *surfaces = NULL; 203 guint numSurfaces = 0; 204 205 MixVideoFormat_MP42 *self = MIX_VIDEOFORMAT_MP42(mix); 206 207 if (mix == NULL || config_params == NULL || frame_mgr == NULL) { 208 return MIX_RESULT_NULL_PTR; 209 } 210 211 if (!MIX_IS_VIDEOFORMAT_MP42(mix)) { 212 return MIX_RESULT_INVALID_PARAM; 213 } 214 215 LOG_V("begin\n"); 216 217 if (parent_class->initialize) { 218 ret = parent_class->initialize(mix, config_params, frame_mgr, 219 input_buf_pool, surface_pool, va_display); 220 if (ret != MIX_RESULT_SUCCESS) { 221 LOG_E("Failed to initialize parent!\n"); 222 return ret; 223 } 224 } 225 226 parent = MIX_VIDEOFORMAT(mix); 227 228 g_mutex_lock(parent->objectlock); 229 230 parent->initialized = FALSE; 231 232 vbp_ret = vbp_open(VBP_MPEG4, &(parent->parser_handle)); 233 234 if (vbp_ret != VBP_OK) { 235 LOG_E("Failed to call vbp_open()\n"); 236 ret = MIX_RESULT_FAIL; 237 goto cleanup; 238 } 239 240 /* 241 * avidemux doesn't pass codec_data, we need handle this. 242 */ 243 244 LOG_V("Try to get header data from config_param\n"); 245 246 ret = mix_videoconfigparamsdec_get_header(config_params, &header); 247 if (ret == MIX_RESULT_SUCCESS && header != NULL) { 248 249 LOG_V("Found header data from config_param\n"); 250 vbp_ret = vbp_parse(parent->parser_handle, header->data, header->data_size, 251 TRUE); 252 253 LOG_V("vbp_parse() returns 0x%x\n", vbp_ret); 254 255 g_free(header->data); 256 g_free(header); 257 258 if (!((vbp_ret == VBP_OK) || (vbp_ret == VBP_DONE))) { 259 LOG_E("Failed to call vbp_parse() to parse header data!\n"); 260 goto cleanup; 261 } 262 263 /* Get the header data and save */ 264 265 LOG_V("Call vbp_query()\n"); 266 vbp_ret = vbp_query(parent->parser_handle, (void *) &data); 267 LOG_V("vbp_query() returns 0x%x\n", vbp_ret); 268 269 if ((vbp_ret != VBP_OK) || (data == NULL)) { 270 LOG_E("Failed to call vbp_query() to query header data parsing result\n"); 271 goto cleanup; 272 } 273 274 if ((data->codec_data.profile_and_level_indication & 0xF8) == 0xF0) { 275 va_profile = VAProfileMPEG4AdvancedSimple; 276 LOG_V("The profile is VAProfileMPEG4AdvancedSimple from header data\n"); 277 } else { 278 va_profile = VAProfileMPEG4Simple; 279 LOG_V("The profile is VAProfileMPEG4Simple from header data\n"); 280 } 281 } 282 283 va_display = parent->va_display; 284 285 /* We are requesting RT attributes */ 286 attrib.type = VAConfigAttribRTFormat; 287 288 va_ret = vaGetConfigAttributes(va_display, va_profile, VAEntrypointVLD, 289 &attrib, 1); 290 if (va_ret != VA_STATUS_SUCCESS) { 291 LOG_E("Failed to call vaGetConfigAttributes()\n"); 292 goto cleanup; 293 } 294 295 if ((attrib.value & VA_RT_FORMAT_YUV420) == 0) { 296 LOG_E("The attrib.value is wrong!\n"); 297 goto cleanup; 298 } 299 300 va_ret = vaCreateConfig(va_display, va_profile, VAEntrypointVLD, &attrib, 301 1, &(parent->va_config)); 302 303 if (va_ret != VA_STATUS_SUCCESS) { 304 LOG_E("Failed to call vaCreateConfig()!\n"); 305 goto cleanup; 306 } 307 308 ret = mix_videoconfigparamsdec_get_extra_surface_allocation(config_params, 309 &number_extra_surfaces); 310 311 if (ret != MIX_RESULT_SUCCESS) { 312 LOG_E("Failed to call mix_videoconfigparams_get_extra_surface_allocation()!\n"); 313 goto cleanup; 314 } 315 316 parent->va_num_surfaces = number_extra_surfaces + 4; 317 if (parent->va_num_surfaces > MIX_VIDEO_MP42_SURFACE_NUM) { 318 parent->va_num_surfaces = MIX_VIDEO_MP42_SURFACE_NUM; 319 } 320 321 numSurfaces = parent->va_num_surfaces; 322 323 parent->va_surfaces = g_malloc(sizeof(VASurfaceID) * numSurfaces); 324 if (!parent->va_surfaces) { 325 LOG_E("Not enough memory to allocate surfaces!\n"); 326 ret = MIX_RESULT_NO_MEMORY; 327 goto cleanup; 328 } 329 330 surfaces = parent->va_surfaces; 331 332 va_ret = vaCreateSurfaces(va_display, parent->picture_width, 333 parent->picture_height, VA_RT_FORMAT_YUV420, numSurfaces, 334 surfaces); 335 if (va_ret != VA_STATUS_SUCCESS) { 336 LOG_E("Failed to call vaCreateSurfaces()!\n"); 337 goto cleanup; 338 } 339 340 parent->surfacepool = mix_surfacepool_new(); 341 if (parent->surfacepool == NULL) { 342 LOG_E("Not enough memory to create surface pool!\n"); 343 ret = MIX_RESULT_NO_MEMORY; 344 goto cleanup; 345 } 346 347 *surface_pool = parent->surfacepool; 348 349 ret = mix_surfacepool_initialize(parent->surfacepool, surfaces, 350 numSurfaces); 351 352 /* Initialize and save the VA context ID 353 * Note: VA_PROGRESSIVE libva flag is only relevant to MPEG2 354 */ 355 va_ret = vaCreateContext(va_display, parent->va_config, 356 parent->picture_width, parent->picture_height, 0, surfaces, 357 numSurfaces, &(parent->va_context)); 358 359 if (va_ret != VA_STATUS_SUCCESS) { 360 LOG_E("Failed to call vaCreateContext()!\n"); 361 ret = MIX_RESULT_FAIL; 362 goto cleanup; 363 } 364 365 /* 366 * Packed stream queue 367 */ 368 369 self->packed_stream_queue = g_queue_new(); 370 if (!self->packed_stream_queue) { 371 LOG_E("Failed to crate packed stream queue!\n"); 372 ret = MIX_RESULT_NO_MEMORY; 373 goto cleanup; 374 } 375 376 self->last_frame = NULL; 377 self->last_vop_coding_type = -1; 378 parent->initialized = FALSE; 379 ret = MIX_RESULT_SUCCESS; 380 381 cleanup: 382 383 g_mutex_unlock(parent->objectlock); 384 385 LOG_V("End\n"); 386 387 return ret; 388 } 389 390 MIX_RESULT mix_videofmt_mp42_decode(MixVideoFormat *mix, MixBuffer * bufin[], 391 gint bufincnt, MixVideoDecodeParams * decode_params) { 392 uint32 vbp_ret = 0; 393 MixVideoFormat *parent = NULL; 394 MIX_RESULT ret = MIX_RESULT_FAIL; 395 guint64 ts = 0; 396 vbp_data_mp42 *data = NULL; 397 gboolean discontinuity = FALSE; 398 MixInputBufferEntry *bufentry = NULL; 399 gint i = 0; 400 401 LOG_V("Begin\n"); 402 403 if (mix == NULL || bufin == NULL || decode_params == NULL) { 404 return MIX_RESULT_NULL_PTR; 405 } 406 407 if (!MIX_IS_VIDEOFORMAT_MP42(mix)) { 408 return MIX_RESULT_INVALID_PARAM; 409 } 410 411 parent = MIX_VIDEOFORMAT(mix); 412 413 g_mutex_lock(parent->objectlock); 414 415 ret = mix_videodecodeparams_get_timestamp(decode_params, &ts); 416 if (ret != MIX_RESULT_SUCCESS) { 417 LOG_E("Failed to get timestamp\n"); 418 goto cleanup; 419 } 420 421 LOG_I("ts after mix_videodecodeparams_get_timestamp() = %"G_GINT64_FORMAT"\n", ts); 422 423 ret 424 = mix_videodecodeparams_get_discontinuity(decode_params, 425 &discontinuity); 426 if (ret != MIX_RESULT_SUCCESS) { 427 LOG_E("Failed to get discontinuity\n"); 428 goto cleanup; 429 } 430 431 /* If this is a new frame and we haven't retrieved parser 432 * workload data from previous frame yet, do so 433 */ 434 435 if ((ts != parent->current_timestamp) && (parent->parse_in_progress)) { 436 437 LOG_V("timestamp changed and parsing is still in progress\n"); 438 439 /* this is new data and the old data parsing is not complete, continue 440 * to parse the old data 441 */ 442 vbp_ret = vbp_query(parent->parser_handle, (void *) &data); 443 LOG_V("vbp_query() returns 0x%x\n", vbp_ret); 444 445 if ((vbp_ret != VBP_OK) || (data == NULL)) { 446 ret = MIX_RESULT_FAIL; 447 LOG_E("vbp_ret != VBP_OK || data == NULL\n"); 448 goto cleanup; 449 } 450 451 ret = mix_videofmt_mp42_process_decode(mix, data, 452 parent->current_timestamp, 453 parent->discontinuity_frame_in_progress); 454 455 if (ret != MIX_RESULT_SUCCESS) { 456 /* We log this but need to process 457 * the new frame data, so do not return 458 */ 459 LOG_W("process_decode failed.\n"); 460 } 461 462 /* we are done parsing for old data */ 463 parent->parse_in_progress = FALSE; 464 } 465 466 parent->current_timestamp = ts; 467 parent->discontinuity_frame_in_progress = discontinuity; 468 469 /* we parse data buffer one by one */ 470 for (i = 0; i < bufincnt; i++) { 471 472 LOG_V( 473 "Calling parse for current frame, parse handle %d, buf %x, size %d\n", 474 (int) parent->parser_handle, (guint) bufin[i]->data, 475 bufin[i]->size); 476 477 vbp_ret = vbp_parse(parent->parser_handle, bufin[i]->data, 478 bufin[i]->size, FALSE); 479 480 LOG_V("vbp_parse() returns 0x%x\n", vbp_ret); 481 482 /* The parser failed to parse */ 483 if (vbp_ret != VBP_DONE && vbp_ret != VBP_OK) { 484 LOG_E("vbp_parse() ret = %d\n", vbp_ret); 485 ret = MIX_RESULT_FAIL; 486 goto cleanup; 487 } 488 489 LOG_V("vbp_parse() ret = %d\n", vbp_ret); 490 491 if (vbp_ret == VBP_OK || vbp_ret == VBP_DONE) { 492 493 LOG_V("Now, parsing is done (VBP_DONE)!\n"); 494 495 vbp_ret = vbp_query(parent->parser_handle, (void *) &data); 496 LOG_V("vbp_query() returns 0x%x\n", vbp_ret); 497 498 if ((vbp_ret != VBP_OK) || (data == NULL)) { 499 ret = MIX_RESULT_FAIL; 500 goto cleanup; 501 } 502 503 /* Increase the ref count of this input buffer */ 504 mix_buffer_ref(bufin[i]); 505 506 /* Create a new MixInputBufferEntry 507 * TODO: make this from a pool later 508 */ 509 bufentry = g_malloc(sizeof(MixInputBufferEntry)); 510 if (bufentry == NULL) { 511 ret = MIX_RESULT_NO_MEMORY; 512 goto cleanup; 513 } 514 515 bufentry->buf = bufin[i]; 516 bufentry->timestamp = ts; 517 518 LOG_I("bufentry->buf = %x bufentry->timestamp FOR VBP_DONE = %"G_GINT64_FORMAT"\n", bufentry->buf, bufentry->timestamp); 519 520 /* Enqueue this input buffer */ 521 g_queue_push_tail(parent->inputbufqueue, (gpointer) bufentry); 522 523 /* process and decode data */ 524 ret 525 = mix_videofmt_mp42_process_decode(mix, data, ts, 526 discontinuity); 527 528 if (ret != MIX_RESULT_SUCCESS) { 529 /* We log this but continue since we need 530 * to complete our processing 531 */ 532 LOG_W("process_decode failed.\n"); 533 } 534 535 LOG_V("Called process and decode for current frame\n"); 536 537 parent->parse_in_progress = FALSE; 538 539 } 540 #if 0 541 /* 542 * The DHG parser checks for next_sc, if next_sc is a start code, it thinks the current parsing is done: VBP_DONE. 543 * For our situtation, this not the case. The start code is always begin with the gstbuffer. At the end of frame, 544 * the start code is never found. 545 */ 546 547 else if (vbp_ret == VBP_OK) { 548 549 LOG_V("Now, parsing is not done (VBP_OK)!\n"); 550 551 LOG_V( 552 "Enqueuing buffer and going on to next (if any) for this frame\n"); 553 554 /* Increase the ref count of this input buffer */ 555 mix_buffer_ref(bufin[i]); 556 557 /* Create a new MixInputBufferEntry 558 * TODO make this from a pool later 559 */ 560 bufentry = g_malloc(sizeof(MixInputBufferEntry)); 561 if (bufentry == NULL) { 562 ret = MIX_RESULT_FAIL; 563 goto cleanup; 564 } 565 566 bufentry->buf = bufin[i]; 567 bufentry->timestamp = ts; 568 LOG_I("bufentry->buf = %x bufentry->timestamp FOR VBP_OK = %"G_GINT64_FORMAT"\n", bufentry->buf, bufentry->timestamp); 569 570 /* Enqueue this input buffer */ 571 g_queue_push_tail(parent->inputbufqueue, (gpointer) bufentry); 572 parent->parse_in_progress = TRUE; 573 } 574 #endif 575 } 576 577 cleanup: 578 579 g_mutex_unlock(parent->objectlock); 580 581 LOG_V("End\n"); 582 583 return ret; 584 } 585 586 MIX_RESULT mix_videofmt_mp42_process_decode(MixVideoFormat *mix, 587 vbp_data_mp42 *data, guint64 timestamp, gboolean discontinuity) { 588 589 MIX_RESULT ret = MIX_RESULT_SUCCESS; 590 VAStatus va_ret = VA_STATUS_SUCCESS; 591 VADisplay va_display = NULL; 592 VAContextID va_context; 593 594 MixVideoFormat_MP42 *self = NULL; 595 vbp_picture_data_mp42 *picture_data = NULL; 596 VAPictureParameterBufferMPEG4 *picture_param = NULL; 597 VAIQMatrixBufferMPEG4 *iq_matrix_buffer = NULL; 598 vbp_slice_data_mp42 *slice_data = NULL; 599 VASliceParameterBufferMPEG4 *slice_param = NULL; 600 601 gint frame_type = -1; 602 guint buffer_id_number = 0; 603 guint buffer_id_cnt = 0; 604 VABufferID *buffer_ids = NULL; 605 MixVideoFrame *frame = NULL; 606 607 gint idx = 0, jdx = 0; 608 gulong surface = 0; 609 610 MixBuffer *mix_buffer = NULL; 611 gboolean is_from_queued_data = FALSE; 612 613 LOG_V("Begin\n"); 614 615 if ((mix == NULL) || (data == NULL)) { 616 return MIX_RESULT_NULL_PTR; 617 } 618 619 if (!MIX_IS_VIDEOFORMAT_MP42(mix)) { 620 return MIX_RESULT_INVALID_PARAM; 621 } 622 623 self = MIX_VIDEOFORMAT_MP42(mix); 624 625 LOG_V("data->number_pictures = %d\n", data->number_pictures); 626 627 if (data->number_pictures == 0) { 628 LOG_W("data->number_pictures == 0\n"); 629 mix_videofmt_mp42_release_input_buffers(mix, timestamp); 630 return ret; 631 } 632 633 is_from_queued_data = FALSE; 634 635 /* Do we have packed frames? */ 636 if (data->number_pictures > 1) { 637 638 /* 639 640 Assumption: 641 642 1. In one packed frame, there's only one P or I frame and the 643 reference frame will be the first one in the packed frame 644 2. In packed frame, there's no skipped frame(vop_coded = 0) 645 3. In one packed frame, if there're n B frames, there will be 646 n N-VOP frames to follow the packed frame. 647 The timestamp of each N-VOP frame will be used for each B frames 648 in the packed frame 649 4. N-VOP frame is the frame with vop_coded = 0. 650 651 {P, B, B, B }, N, N, N, P, P, P, I, ... 652 653 */ 654 655 MixInputBufferEntry *bufentry = NULL; 656 PackedStream *packed_stream = NULL; 657 vbp_picture_data_mp42 *cloned_picture_data = NULL; 658 659 LOG_V("This is packed frame\n"); 660 661 /* 662 * Is the packed_frame_queue empty? If not, how come 663 * a packed frame can follow another packed frame without 664 * necessary number of N-VOP between them? 665 */ 666 667 if (!g_queue_is_empty(self->packed_stream_queue)) { 668 ret = MIX_RESULT_FAIL; 669 LOG_E("The previous packed frame is not fully processed yet!\n"); 670 goto cleanup; 671 } 672 673 /* Packed frame shall be something like this {P, B, B, B, ... B } */ 674 for (idx = 0; idx < data->number_pictures; idx++) { 675 picture_data = &(data->picture_data[idx]); 676 picture_param = &(picture_data->picture_param); 677 frame_type = picture_param->vop_fields.bits.vop_coding_type; 678 679 /* Is the first frame in the packed frames a reference frame? */ 680 if (idx == 0 && frame_type != MP4_VOP_TYPE_I && frame_type 681 != MP4_VOP_TYPE_P) { 682 ret = MIX_RESULT_FAIL; 683 LOG_E("The first frame in packed frame is not I or B\n"); 684 goto cleanup; 685 } 686 687 if (idx != 0 && frame_type != MP4_VOP_TYPE_B) { 688 ret = MIX_RESULT_FAIL; 689 LOG_E("The frame other than the first one in packed frame is not B\n"); 690 goto cleanup; 691 } 692 693 if (picture_data->vop_coded == 0) { 694 ret = MIX_RESULT_FAIL; 695 LOG_E("In packed frame, there's unexpected skipped frame\n"); 696 goto cleanup; 697 } 698 } 699 700 LOG_V("The packed frame looks valid\n"); 701 702 /* Okay, the packed-frame looks ok. Now, we enqueue all the B frames */ 703 bufentry 704 = (MixInputBufferEntry *) g_queue_peek_head(mix->inputbufqueue); 705 if (bufentry == NULL) { 706 ret = MIX_RESULT_FAIL; 707 LOG_E("There's data in in inputbufqueue\n"); 708 goto cleanup; 709 } 710 711 LOG_V("Enqueue all B frames in the packed frame\n"); 712 713 mix_buffer = bufentry->buf; 714 for (idx = 1; idx < data->number_pictures; idx++) { 715 picture_data = &(data->picture_data[idx]); 716 cloned_picture_data = mix_videoformat_mp42_clone_picture_data( 717 picture_data); 718 if (!cloned_picture_data) { 719 ret = MIX_RESULT_NO_MEMORY; 720 LOG_E("Failed to allocate memory for cloned picture_data\n"); 721 goto cleanup; 722 } 723 724 packed_stream = g_malloc(sizeof(PackedStream)); 725 if (packed_stream == NULL) { 726 ret = MIX_RESULT_NO_MEMORY; 727 LOG_E("Failed to allocate memory for packed_stream\n"); 728 goto cleanup; 729 } 730 731 packed_stream->mix_buffer = mix_buffer_ref(mix_buffer); 732 packed_stream->picture_data = cloned_picture_data; 733 734 g_queue_push_tail(self->packed_stream_queue, 735 (gpointer) packed_stream); 736 } 737 738 LOG_V("Prepare to decode the first frame in the packed frame\n"); 739 740 /* we are going to process the firs frame */ 741 picture_data = &(data->picture_data[0]); 742 743 } else { 744 745 LOG_V("This is a single frame\n"); 746 747 /* Okay, we only have one frame */ 748 if (g_queue_is_empty(self->packed_stream_queue)) { 749 /* If the packed_stream_queue is empty, everything is fine */ 750 picture_data = &(data->picture_data[0]); 751 752 LOG_V("There's no packed frame not processed yet\n"); 753 754 } else { 755 /* The packed_stream_queue is not empty, is this frame N-VOP? */ 756 picture_data = &(data->picture_data[0]); 757 if (picture_data->vop_coded != 0) { 758 759 LOG_V("The packed frame queue is not empty, we will flush it\n"); 760 761 /* 762 * Unexpected! We flush the packed_stream_queue and begin to process the 763 * current frame if it is not a B frame 764 */ 765 mix_videoformat_mp42_flush_packed_stream_queue( 766 self->packed_stream_queue); 767 768 picture_param = &(picture_data->picture_param); 769 frame_type = picture_param->vop_fields.bits.vop_coding_type; 770 771 if (frame_type == MP4_VOP_TYPE_B) { 772 ret = MIX_RESULT_FAIL; 773 LOG_E("The frame right after packed frame is B frame!\n"); 774 goto cleanup; 775 } 776 777 } else { 778 /* This is N-VOP, process B frame from the packed_stream_queue */ 779 PackedStream *packed_stream = NULL; 780 781 LOG_V("N-VOP found, we ignore it and start to process the B frame from the packed frame queue\n"); 782 783 packed_stream = (PackedStream *) g_queue_pop_head( 784 self->packed_stream_queue); 785 picture_data = packed_stream->picture_data; 786 mix_buffer = packed_stream->mix_buffer; 787 g_free(packed_stream); 788 is_from_queued_data = TRUE; 789 } 790 } 791 } 792 793 picture_param = &(picture_data->picture_param); 794 iq_matrix_buffer = &(picture_data->iq_matrix_buffer); 795 796 if (picture_param == NULL) { 797 ret = MIX_RESULT_NULL_PTR; 798 LOG_E("picture_param == NULL\n"); 799 goto cleanup; 800 } 801 802 /* If the frame type is not I, P or B */ 803 frame_type = picture_param->vop_fields.bits.vop_coding_type; 804 if (frame_type != MP4_VOP_TYPE_I && frame_type != MP4_VOP_TYPE_P 805 && frame_type != MP4_VOP_TYPE_B) { 806 ret = MIX_RESULT_FAIL; 807 LOG_E("frame_type is not I, P or B. frame_type = %d\n", frame_type); 808 goto cleanup; 809 } 810 811 /* 812 * This is a skipped frame (vop_coded = 0) 813 * Please note that this is not a N-VOP (DivX). 814 */ 815 if (picture_data->vop_coded == 0) { 816 817 MixVideoFrame *skip_frame = NULL; 818 gulong frame_id = VA_INVALID_SURFACE; 819 820 LOG_V("vop_coded == 0\n"); 821 if (self->last_frame == NULL) { 822 LOG_W("Previous frame is NULL\n"); 823 824 /* 825 * We shouldn't get a skipped frame 826 * before we are able to get a real frame 827 */ 828 ret = MIX_RESULT_DROPFRAME; 829 goto cleanup; 830 } 831 832 skip_frame = mix_videoframe_new(); 833 ret = mix_videoframe_set_is_skipped(skip_frame, TRUE); 834 mix_videoframe_ref(self->last_frame); 835 836 ret = mix_videoframe_get_frame_id(self->last_frame, &frame_id); 837 ret = mix_videoframe_set_frame_id(skip_frame, frame_id); 838 ret = mix_videoframe_set_frame_type(skip_frame, MP4_VOP_TYPE_P); 839 ret = mix_videoframe_set_real_frame(skip_frame, self->last_frame); 840 ret = mix_videoframe_set_timestamp(skip_frame, timestamp); 841 ret = mix_videoframe_set_discontinuity(skip_frame, FALSE); 842 843 LOG_V("Processing skipped frame %x, frame_id set to %d, ts %"G_GINT64_FORMAT"\n", 844 (guint)skip_frame, (guint)frame_id, timestamp); 845 846 /* Release our input buffers */ 847 ret = mix_videofmt_mp42_release_input_buffers(mix, timestamp); 848 849 /* Enqueue the skipped frame using frame manager */ 850 ret = mix_framemanager_enqueue(mix->framemgr, skip_frame); 851 goto cleanup; 852 } 853 854 /* 855 * Decide the number of buffer to use 856 */ 857 858 buffer_id_number = picture_data->number_slices * 2 + 2; 859 LOG_V("number_slices is %d, allocating %d buffer_ids\n", 860 picture_data->number_slices, buffer_id_number); 861 862 /* 863 * Check for B frames after a seek 864 * We need to have both reference frames in hand before we can decode a B frame 865 * If we don't have both reference frames, we must return MIX_RESULT_DROPFRAME 866 */ 867 if (frame_type == MP4_VOP_TYPE_B) { 868 869 if (self->reference_frames[1] == NULL) { 870 LOG_W("Insufficient reference frames for B frame\n"); 871 ret = MIX_RESULT_DROPFRAME; 872 goto cleanup; 873 } 874 } 875 876 buffer_ids = g_malloc(sizeof(VABufferID) * buffer_id_number); 877 if (buffer_ids == NULL) { 878 ret = MIX_RESULT_NO_MEMORY; 879 LOG_E("Failed to allocate buffer_ids!\n"); 880 goto cleanup; 881 } 882 883 LOG_V("Getting a new surface\n");LOG_V("frame type is %d\n", frame_type); 884 885 /* Get a frame from the surface pool */ 886 ret = mix_surfacepool_get(mix->surfacepool, &frame); 887 if (ret != MIX_RESULT_SUCCESS) { 888 LOG_E("Failed to get frame from surface pool!\n"); 889 goto cleanup; 890 } 891 892 /* 893 * Set the frame type for the frame object (used in reordering by frame manager) 894 */ 895 ret = mix_videoframe_set_frame_type(frame, frame_type); 896 if (ret != MIX_RESULT_SUCCESS) { 897 LOG_E("Failed to set frame type!\n"); 898 goto cleanup; 899 } 900 901 /* If I or P frame, update the reference array */ 902 if ((frame_type == MP4_VOP_TYPE_I) || (frame_type == MP4_VOP_TYPE_P)) { 903 LOG_V("Updating forward/backward references for libva\n"); 904 905 self->last_vop_coding_type = frame_type; 906 mix_videofmt_mp42_handle_ref_frames(mix, frame_type, frame); 907 } 908 909 LOG_V("Setting reference frames in picparams, frame_type = %d\n", 910 frame_type); 911 912 switch (frame_type) { 913 case MP4_VOP_TYPE_I: 914 picture_param->forward_reference_picture = VA_INVALID_SURFACE; 915 picture_param->backward_reference_picture = VA_INVALID_SURFACE; 916 LOG_V("I frame, surface ID %u\n", (guint) frame->frame_id); 917 break; 918 case MP4_VOP_TYPE_P: 919 picture_param-> forward_reference_picture 920 = self->reference_frames[0]->frame_id; 921 picture_param-> backward_reference_picture = VA_INVALID_SURFACE; 922 923 LOG_V("P frame, surface ID %u, forw ref frame is %u\n", 924 (guint) frame->frame_id, 925 (guint) self->reference_frames[0]->frame_id); 926 break; 927 case MP4_VOP_TYPE_B: 928 929 picture_param->vop_fields.bits.backward_reference_vop_coding_type 930 = self->last_vop_coding_type; 931 932 picture_param->forward_reference_picture 933 = self->reference_frames[1]->frame_id; 934 picture_param->backward_reference_picture 935 = self->reference_frames[0]->frame_id; 936 937 LOG_V("B frame, surface ID %u, forw ref %d, back ref %d\n", 938 (guint) frame->frame_id, 939 (guint) picture_param->forward_reference_picture, 940 (guint) picture_param->backward_reference_picture); 941 break; 942 case MP4_VOP_TYPE_S: 943 LOG_W("MP4_VOP_TYPE_S, Will never reach here\n"); 944 break; 945 946 default: 947 LOG_W("default, Will never reach here\n"); 948 break; 949 950 } 951 952 /* Libva buffer set up */ 953 va_display = mix->va_display; 954 va_context = mix->va_context; 955 956 LOG_V("Creating libva picture parameter buffer\n"); 957 958 /* First the picture parameter buffer */ 959 buffer_id_cnt = 0; 960 va_ret = vaCreateBuffer(va_display, va_context, 961 VAPictureParameterBufferType, 962 sizeof(VAPictureParameterBufferMPEG4), 1, picture_param, 963 &buffer_ids[buffer_id_cnt]); 964 buffer_id_cnt++; 965 966 if (va_ret != VA_STATUS_SUCCESS) { 967 ret = MIX_RESULT_FAIL; 968 LOG_E("Failed to create va buffer of type VAPictureParameterBufferMPEG4!\n"); 969 goto cleanup; 970 } 971 972 LOG_V("Creating libva VAIQMatrixBufferMPEG4 buffer\n"); 973 974 if (picture_param->vol_fields.bits.quant_type) { 975 va_ret = vaCreateBuffer(va_display, va_context, VAIQMatrixBufferType, 976 sizeof(VAIQMatrixBufferMPEG4), 1, iq_matrix_buffer, 977 &buffer_ids[buffer_id_cnt]); 978 979 if (va_ret != VA_STATUS_SUCCESS) { 980 ret = MIX_RESULT_FAIL; 981 LOG_E("Failed to create va buffer of type VAIQMatrixBufferType!\n"); 982 goto cleanup; 983 } 984 buffer_id_cnt++; 985 } 986 987 /* Now for slices */ 988 for (jdx = 0; jdx < picture_data->number_slices; jdx++) { 989 990 slice_data = &(picture_data->slice_data[jdx]); 991 slice_param = &(slice_data->slice_param); 992 993 LOG_V( 994 "Creating libva slice parameter buffer, for slice %d\n", 995 jdx); 996 997 /* Do slice parameters */ 998 va_ret = vaCreateBuffer(va_display, va_context, 999 VASliceParameterBufferType, 1000 sizeof(VASliceParameterBufferMPEG4), 1, slice_param, 1001 &buffer_ids[buffer_id_cnt]); 1002 if (va_ret != VA_STATUS_SUCCESS) { 1003 ret = MIX_RESULT_FAIL; 1004 LOG_E("Failed to create va buffer of type VASliceParameterBufferMPEG4!\n"); 1005 goto cleanup; 1006 } 1007 buffer_id_cnt++; 1008 1009 /* Do slice data */ 1010 va_ret = vaCreateBuffer(va_display, va_context, VASliceDataBufferType, 1011 slice_data->slice_size, 1, slice_data->buffer_addr 1012 + slice_data->slice_offset, &buffer_ids[buffer_id_cnt]); 1013 if (va_ret != VA_STATUS_SUCCESS) { 1014 ret = MIX_RESULT_FAIL; 1015 LOG_E("Failed to create va buffer of type VASliceDataBufferType!\n"); 1016 goto cleanup; 1017 } 1018 buffer_id_cnt++; 1019 } 1020 1021 /* Get our surface ID from the frame object */ 1022 ret = mix_videoframe_get_frame_id(frame, &surface); 1023 if (ret != MIX_RESULT_SUCCESS) { 1024 LOG_E("Failed to get frame id: ret = 0x%x\n", ret); 1025 goto cleanup; 1026 } 1027 1028 LOG_V("Calling vaBeginPicture\n"); 1029 1030 /* Now we can begin the picture */ 1031 va_ret = vaBeginPicture(va_display, va_context, surface); 1032 if (va_ret != VA_STATUS_SUCCESS) { 1033 ret = MIX_RESULT_FAIL; 1034 LOG_E("Failed to vaBeginPicture(): va_ret = 0x%x\n", va_ret); 1035 goto cleanup; 1036 } 1037 1038 LOG_V("Calling vaRenderPicture\n"); 1039 1040 /* Render the picture */ 1041 va_ret = vaRenderPicture(va_display, va_context, buffer_ids, buffer_id_cnt); 1042 if (va_ret != VA_STATUS_SUCCESS) { 1043 ret = MIX_RESULT_FAIL; 1044 LOG_E("Failed to vaRenderPicture(): va_ret = 0x%x\n", va_ret); 1045 goto cleanup; 1046 } 1047 1048 LOG_V("Calling vaEndPicture\n"); 1049 1050 /* End picture */ 1051 va_ret = vaEndPicture(va_display, va_context); 1052 if (va_ret != VA_STATUS_SUCCESS) { 1053 ret = MIX_RESULT_FAIL; 1054 LOG_E("Failed to vaEndPicture(): va_ret = 0x%x\n", va_ret); 1055 goto cleanup; 1056 } 1057 1058 LOG_V("Calling vaSyncSurface\n"); 1059 1060 /* Decode the picture */ 1061 va_ret = vaSyncSurface(va_display, surface); 1062 if (va_ret != VA_STATUS_SUCCESS) { 1063 ret = MIX_RESULT_FAIL; 1064 LOG_E("Failed to vaSyncSurface(): va_ret = 0x%x\n", va_ret); 1065 goto cleanup; 1066 } 1067 1068 /* Set the discontinuity flag */ 1069 mix_videoframe_set_discontinuity(frame, discontinuity); 1070 1071 /* Set the timestamp */ 1072 mix_videoframe_set_timestamp(frame, timestamp); 1073 1074 LOG_V("Enqueueing the frame with frame manager, timestamp %"G_GINT64_FORMAT"\n", timestamp); 1075 1076 /* Enqueue the decoded frame using frame manager */ 1077 ret = mix_framemanager_enqueue(mix->framemgr, frame); 1078 if (ret != MIX_RESULT_SUCCESS) { 1079 LOG_E("Failed to mix_framemanager_enqueue()!\n"); 1080 goto cleanup; 1081 } 1082 1083 /* For I or P frames, save this frame off for skipped frame handling */ 1084 if ((frame_type == MP4_VOP_TYPE_I) || (frame_type == MP4_VOP_TYPE_P)) { 1085 if (self->last_frame != NULL) { 1086 mix_videoframe_unref(self->last_frame); 1087 } 1088 self->last_frame = frame; 1089 mix_videoframe_ref(frame); 1090 } 1091 1092 ret = MIX_RESULT_SUCCESS; 1093 1094 cleanup: 1095 1096 if (ret != MIX_RESULT_SUCCESS && frame != NULL) { 1097 mix_videoframe_unref(frame); 1098 } 1099 1100 if (ret != MIX_RESULT_SUCCESS) { 1101 mix_videoformat_mp42_flush_packed_stream_queue( 1102 self->packed_stream_queue); 1103 } 1104 1105 g_free(buffer_ids); 1106 mix_videofmt_mp42_release_input_buffers(mix, timestamp); 1107 1108 if (is_from_queued_data) { 1109 if (mix_buffer) { 1110 mix_buffer_unref(mix_buffer); 1111 } 1112 mix_videoformat_mp42_free_picture_data(picture_data); 1113 } 1114 1115 LOG_V("End\n"); 1116 1117 return ret; 1118 } 1119 1120 MIX_RESULT mix_videofmt_mp42_flush(MixVideoFormat *mix) { 1121 1122 MIX_RESULT ret = MIX_RESULT_SUCCESS; 1123 MixVideoFormat_MP42 *self = MIX_VIDEOFORMAT_MP42(mix); 1124 MixInputBufferEntry *bufentry = NULL; 1125 1126 LOG_V("Begin\n"); 1127 1128 g_mutex_lock(mix->objectlock); 1129 1130 mix_videoformat_mp42_flush_packed_stream_queue(self->packed_stream_queue); 1131 1132 /* 1133 * Clear the contents of inputbufqueue 1134 */ 1135 while (!g_queue_is_empty(mix->inputbufqueue)) { 1136 bufentry = (MixInputBufferEntry *) g_queue_pop_head(mix->inputbufqueue); 1137 if (bufentry == NULL) { 1138 continue; 1139 } 1140 1141 mix_buffer_unref(bufentry->buf); 1142 g_free(bufentry); 1143 } 1144 1145 /* 1146 * Clear parse_in_progress flag and current timestamp 1147 */ 1148 mix->parse_in_progress = FALSE; 1149 mix->discontinuity_frame_in_progress = FALSE; 1150 mix->current_timestamp = 0; 1151 1152 { 1153 gint idx = 0; 1154 for (idx = 0; idx < 2; idx++) { 1155 if (self->reference_frames[idx] != NULL) { 1156 mix_videoframe_unref(self->reference_frames[idx]); 1157 self->reference_frames[idx] = NULL; 1158 } 1159 } 1160 } 1161 1162 /* Call parser flush */ 1163 vbp_flush(mix->parser_handle); 1164 1165 g_mutex_unlock(mix->objectlock); 1166 1167 LOG_V("End\n"); 1168 1169 return ret; 1170 } 1171 1172 MIX_RESULT mix_videofmt_mp42_eos(MixVideoFormat *mix) { 1173 1174 MIX_RESULT ret = MIX_RESULT_SUCCESS; 1175 vbp_data_mp42 *data = NULL; 1176 uint32 vbp_ret = 0; 1177 1178 LOG_V("Begin\n"); 1179 1180 if (mix == NULL) { 1181 return MIX_RESULT_NULL_PTR; 1182 } 1183 1184 if (!MIX_IS_VIDEOFORMAT_MP42(mix)) { 1185 return MIX_RESULT_INVALID_PARAM; 1186 } 1187 1188 g_mutex_lock(mix->objectlock); 1189 1190 /* if a frame is in progress, process the frame */ 1191 if (mix->parse_in_progress) { 1192 /* query for data */ 1193 vbp_ret = vbp_query(mix->parser_handle, (void *) &data); 1194 LOG_V("vbp_query() returns 0x%x\n", vbp_ret); 1195 1196 if ((vbp_ret != VBP_OK) || (data == NULL)) { 1197 ret = MIX_RESULT_FAIL; 1198 LOG_E("vbp_ret != VBP_OK || data == NULL\n"); 1199 goto cleanup; 1200 } 1201 1202 /* process and decode data */ 1203 ret = mix_videofmt_mp42_process_decode(mix, data, 1204 mix->current_timestamp, mix->discontinuity_frame_in_progress); 1205 mix->parse_in_progress = FALSE; 1206 1207 } 1208 1209 ret = mix_framemanager_eos(mix->framemgr); 1210 1211 cleanup: 1212 1213 g_mutex_unlock(mix->objectlock); 1214 1215 LOG_V("End\n"); 1216 1217 return ret; 1218 } 1219 1220 MIX_RESULT mix_videofmt_mp42_deinitialize(MixVideoFormat *mix) { 1221 1222 /* 1223 * We do the all the cleanup in _finalize 1224 */ 1225 1226 MIX_RESULT ret = MIX_RESULT_FAIL; 1227 1228 LOG_V("Begin\n"); 1229 1230 if (mix == NULL) { 1231 LOG_V("mix is NULL\n"); 1232 return MIX_RESULT_NULL_PTR; 1233 } 1234 1235 if (!MIX_IS_VIDEOFORMAT_MP42(mix)) { 1236 LOG_V("mix is not mixvideoformat_mp42\n"); 1237 return MIX_RESULT_INVALID_PARAM; 1238 } 1239 1240 if (parent_class->deinitialize) { 1241 ret = parent_class->deinitialize(mix); 1242 } 1243 1244 LOG_V("End\n"); 1245 return ret; 1246 } 1247 1248 MIX_RESULT mix_videofmt_mp42_handle_ref_frames(MixVideoFormat *mix, 1249 enum _picture_type frame_type, MixVideoFrame * current_frame) { 1250 1251 MixVideoFormat_MP42 *self = MIX_VIDEOFORMAT_MP42(mix); 1252 1253 LOG_V("Begin\n"); 1254 1255 if (mix == NULL || current_frame == NULL) { 1256 return MIX_RESULT_NULL_PTR; 1257 } 1258 1259 switch (frame_type) { 1260 case MP4_VOP_TYPE_I: 1261 case MP4_VOP_TYPE_P: 1262 LOG_V("Refing reference frame %x\n", (guint) current_frame); 1263 1264 mix_videoframe_ref(current_frame); 1265 1266 /* should only happen on first frame */ 1267 if (self->reference_frames[0] == NULL) { 1268 self->reference_frames[0] = current_frame; 1269 /* should only happen on second frame */ 1270 } else if (self->reference_frames[1] == NULL) { 1271 self->reference_frames[1] = current_frame; 1272 } else { 1273 LOG_V("Releasing reference frame %x\n", 1274 (guint) self->reference_frames[0]); 1275 mix_videoframe_unref(self->reference_frames[0]); 1276 self->reference_frames[0] = self->reference_frames[1]; 1277 self->reference_frames[1] = current_frame; 1278 } 1279 break; 1280 case MP4_VOP_TYPE_B: 1281 case MP4_VOP_TYPE_S: 1282 default: 1283 break; 1284 1285 } 1286 1287 LOG_V("End\n"); 1288 1289 return MIX_RESULT_SUCCESS; 1290 } 1291 1292 MIX_RESULT mix_videofmt_mp42_release_input_buffers(MixVideoFormat *mix, 1293 guint64 timestamp) { 1294 1295 MixInputBufferEntry *bufentry = NULL; 1296 gboolean done = FALSE; 1297 1298 LOG_V("Begin\n"); 1299 1300 if (mix == NULL) { 1301 return MIX_RESULT_NULL_PTR; 1302 } 1303 1304 /* Dequeue and release all input buffers for this frame */ 1305 LOG_V("Releasing all the MixBuffers for this frame\n"); 1306 1307 /* 1308 * While the head of the queue has timestamp == current ts 1309 * dequeue the entry, unref the MixBuffer, and free the struct 1310 */ 1311 done = FALSE; 1312 while (!done) { 1313 bufentry 1314 = (MixInputBufferEntry *) g_queue_peek_head(mix->inputbufqueue); 1315 if (bufentry == NULL) { 1316 break; 1317 } 1318 1319 LOG_V("head of queue buf %x, timestamp %"G_GINT64_FORMAT", buffer timestamp %"G_GINT64_FORMAT"\n", 1320 (guint)bufentry->buf, timestamp, bufentry->timestamp); 1321 1322 if (bufentry->timestamp != timestamp) { 1323 LOG_V("buf %x, timestamp %"G_GINT64_FORMAT", buffer timestamp %"G_GINT64_FORMAT"\n", 1324 (guint)bufentry->buf, timestamp, bufentry->timestamp); 1325 1326 done = TRUE; 1327 break; 1328 } 1329 1330 bufentry = (MixInputBufferEntry *) g_queue_pop_head(mix->inputbufqueue); 1331 LOG_V("Unref this MixBuffers %x\n", (guint) bufentry->buf); 1332 1333 mix_buffer_unref(bufentry->buf); 1334 g_free(bufentry); 1335 } 1336 1337 LOG_V("End\n"); 1338 1339 return MIX_RESULT_SUCCESS; 1340 } 1341 1342 vbp_picture_data_mp42 *mix_videoformat_mp42_clone_picture_data( 1343 vbp_picture_data_mp42 *picture_data) { 1344 1345 gboolean succ = FALSE; 1346 1347 if (!picture_data) { 1348 return NULL; 1349 } 1350 1351 if (picture_data->number_slices == 0) { 1352 return NULL; 1353 } 1354 1355 vbp_picture_data_mp42 *cloned_picture_data = g_try_new0( 1356 vbp_picture_data_mp42, 1); 1357 if (cloned_picture_data == NULL) { 1358 goto cleanup; 1359 } 1360 1361 memcpy(cloned_picture_data, picture_data, sizeof(vbp_picture_data_mp42)); 1362 1363 cloned_picture_data->number_slices = picture_data->number_slices; 1364 cloned_picture_data->slice_data = g_try_new0(vbp_slice_data_mp42, 1365 picture_data->number_slices); 1366 if (cloned_picture_data->slice_data == NULL) { 1367 goto cleanup; 1368 } 1369 1370 memcpy(cloned_picture_data->slice_data, picture_data->slice_data, 1371 sizeof(vbp_slice_data_mp42) * (picture_data->number_slices)); 1372 1373 succ = TRUE; 1374 1375 cleanup: 1376 1377 if (!succ) { 1378 mix_videoformat_mp42_free_picture_data(cloned_picture_data); 1379 return NULL; 1380 } 1381 1382 return cloned_picture_data; 1383 } 1384 1385 void mix_videoformat_mp42_free_picture_data(vbp_picture_data_mp42 *picture_data) { 1386 if (picture_data) { 1387 if (picture_data->slice_data) { 1388 g_free(picture_data->slice_data); 1389 } 1390 g_free(picture_data); 1391 } 1392 } 1393 1394 void mix_videoformat_mp42_flush_packed_stream_queue(GQueue *packed_stream_queue) { 1395 1396 PackedStream *packed_stream = NULL; 1397 1398 if (packed_stream_queue == NULL) { 1399 return; 1400 } 1401 while (!g_queue_is_empty(packed_stream_queue)) { 1402 packed_stream = (PackedStream *) g_queue_pop_head(packed_stream_queue); 1403 if (packed_stream == NULL) { 1404 continue; 1405 } 1406 1407 if (packed_stream->picture_data) { 1408 mix_videoformat_mp42_free_picture_data(packed_stream->picture_data); 1409 } 1410 1411 if (packed_stream->mix_buffer) { 1412 mix_buffer_unref(packed_stream->mix_buffer); 1413 } 1414 g_free(packed_stream); 1415 } 1416 } 1417