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