1 /*
2 INTEL CONFIDENTIAL
3 Copyright 2009 Intel Corporation All Rights Reserved.
4 The source code contained or described herein and all documents related to the source code ("Material") are owned by Intel Corporation or its suppliers or licensors. Title to the Material remains with Intel Corporation or its suppliers and licensors. The Material contains trade secrets and proprietary and confidential information of Intel or its suppliers and licensors. The Material is protected by worldwide copyright and trade secret laws and treaty provisions. No part of the Material may be used, copied, reproduced, modified, published, uploaded, posted, transmitted, distributed, or disclosed in any way without Intel’s prior express written permission.
5
6 No license under any patent, copyright, trade secret or other intellectual property right is granted to or conferred upon you by disclosure or delivery of the Materials, either expressly, by implication, inducement, estoppel or otherwise. Any license under such intellectual property rights must be express and approved by Intel in writing.
7 */
8 #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
mix_videoformat_mp42_init(MixVideoFormat_MP42 * self)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
mix_videoformat_mp42_class_init(MixVideoFormat_MP42Class * klass)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
mix_videoformat_mp42_new(void)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
mix_videoformat_mp42_finalize(GObject * obj)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 *
mix_videoformat_mp42_ref(MixVideoFormat_MP42 * mix)168 mix_videoformat_mp42_ref(MixVideoFormat_MP42 * mix) {
169 return (MixVideoFormat_MP42 *) g_object_ref(G_OBJECT(mix));
170 }
171
172 /* MP42 vmethods implementation */
mix_videofmt_mp42_getcaps(MixVideoFormat * mix,GString * msg)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
mix_videofmt_mp42_initialize(MixVideoFormat * mix,MixVideoConfigParamsDec * config_params,MixFrameManager * frame_mgr,MixBufferPool * input_buf_pool,MixSurfacePool ** surface_pool,VADisplay va_display)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
mix_videofmt_mp42_decode(MixVideoFormat * mix,MixBuffer * bufin[],gint bufincnt,MixVideoDecodeParams * decode_params)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
mix_videofmt_mp42_process_decode(MixVideoFormat * mix,vbp_data_mp42 * data,guint64 timestamp,gboolean discontinuity)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
mix_videofmt_mp42_flush(MixVideoFormat * mix)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
mix_videofmt_mp42_eos(MixVideoFormat * mix)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
mix_videofmt_mp42_deinitialize(MixVideoFormat * mix)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
mix_videofmt_mp42_handle_ref_frames(MixVideoFormat * mix,enum _picture_type frame_type,MixVideoFrame * current_frame)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
mix_videofmt_mp42_release_input_buffers(MixVideoFormat * mix,guint64 timestamp)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
mix_videoformat_mp42_clone_picture_data(vbp_picture_data_mp42 * picture_data)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
mix_videoformat_mp42_free_picture_data(vbp_picture_data_mp42 * picture_data)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
mix_videoformat_mp42_flush_packed_stream_queue(GQueue * packed_stream_queue)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