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
15 static 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  */
22 static MixVideoFormatClass *parent_class = NULL;
23 
24 static 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  */
29 G_DEFINE_TYPE (MixVideoFormat_H264, mix_videoformat_h264, MIX_TYPE_VIDEOFORMAT);
30 
mix_videoformat_h264_init(MixVideoFormat_H264 * self)31 static 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 
mix_videoformat_h264_class_init(MixVideoFormat_H264Class * klass)46 static 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 
72 MixVideoFormat_H264 *
mix_videoformat_h264_new(void)73 mix_videoformat_h264_new(void) {
74 	MixVideoFormat_H264 *ret =
75 			g_object_new(MIX_TYPE_VIDEOFORMAT_H264, NULL);
76 
77 	return ret;
78 }
79 
mix_videoformat_h264_finalize(GObject * obj)80 void 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 
123 MixVideoFormat_H264 *
mix_videoformat_h264_ref(MixVideoFormat_H264 * mix)124 mix_videoformat_h264_ref(MixVideoFormat_H264 * mix) {
125 	return (MixVideoFormat_H264 *) g_object_ref(G_OBJECT(mix));
126 }
127 
128 /*  H.264 vmethods implementation */
mix_videofmt_h264_getcaps(MixVideoFormat * mix,GString * msg)129 MIX_RESULT mix_videofmt_h264_getcaps(MixVideoFormat *mix, GString *msg) {
130 
131 MIX_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 
mix_videofmt_h264_initialize(MixVideoFormat * mix,MixVideoConfigParamsDec * config_params,MixFrameManager * frame_mgr,MixBufferPool * input_buf_pool,MixSurfacePool ** surface_pool,VADisplay va_display)153 MIX_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 
mix_videofmt_h264_decode(MixVideoFormat * mix,MixBuffer * bufin[],gint bufincnt,MixVideoDecodeParams * decode_params)565 MIX_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 
mix_videofmt_h264_flush(MixVideoFormat * mix)780 MIX_RESULT mix_videofmt_h264_flush(MixVideoFormat *mix) {
781 
782 MIX_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 
mix_videofmt_h264_eos(MixVideoFormat * mix)841 MIX_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 
894 cleanup:
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 
mix_videofmt_h264_deinitialize(MixVideoFormat * mix)908 MIX_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
mix_videofmt_h264_hack_dpb(MixVideoFormat * mix,vbp_picture_data_h264 * pic_data)935 static 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 
mix_videofmt_h264_process_decode_picture(MixVideoFormat * mix,vbp_data_h264 * data,guint64 timestamp,gboolean discontinuity,int pic_index,MixVideoFrame * frame)1016 MIX_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 
mix_videofmt_h264_process_decode(MixVideoFormat * mix,vbp_data_h264 * data,guint64 timestamp,gboolean discontinuity)1397 MIX_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 
mix_videofmt_h264_handle_ref_frames(MixVideoFormat * mix,VAPictureParameterBufferH264 * pic_params,MixVideoFrame * current_frame)1453 MIX_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 
mix_videofmt_h264_get_poc(VAPictureH264 * pic)1552 guint 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 
mix_videofmt_h264_check_in_DPB(gpointer key,gpointer value,gpointer user_data)1570 gboolean 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 
mix_videofmt_h264_destroy_DPB_key(gpointer data)1596 void 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 
mix_videofmt_h264_destroy_DPB_value(gpointer data)1605 void 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 
mix_videofmt_h264_release_input_buffers(MixVideoFormat * mix,guint64 timestamp)1616 MIX_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