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