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