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
13enum {
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 */
23typedef struct _PackedStream PackedStream;
24struct _PackedStream {
25	vbp_picture_data_mp42 *picture_data;
26	MixBuffer *mix_buffer;
27};
28
29/*
30 * Clone and destroy vbp_picture_data_mp42
31 */
32static vbp_picture_data_mp42 *mix_videoformat_mp42_clone_picture_data(
33		vbp_picture_data_mp42 *picture_data);
34static void mix_videoformat_mp42_free_picture_data(
35		vbp_picture_data_mp42 *picture_data);
36static 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 */
43static MixVideoFormatClass *parent_class = NULL;
44
45static 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 */
50G_DEFINE_TYPE( MixVideoFormat_MP42, mix_videoformat_mp42, MIX_TYPE_VIDEOFORMAT);
51
52static 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
70static 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
93MixVideoFormat_MP42 *mix_videoformat_mp42_new(void) {
94	MixVideoFormat_MP42 *ret = g_object_new(MIX_TYPE_VIDEOFORMAT_MP42, NULL);
95
96	return ret;
97}
98
99void 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
167MixVideoFormat_MP42 *
168mix_videoformat_mp42_ref(MixVideoFormat_MP42 * mix) {
169	return (MixVideoFormat_MP42 *) g_object_ref(G_OBJECT(mix));
170}
171
172/*  MP42 vmethods implementation */
173MIX_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
186MIX_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
390MIX_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
586MIX_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
1120MIX_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
1172MIX_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
1220MIX_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
1248MIX_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
1292MIX_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
1342vbp_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
1385void 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
1394void 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