Home | History | Annotate | Download | only in src
      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 Intels 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 
     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 
     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 *
     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 
     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 *
    140 mix_videoformat_vc1_ref(MixVideoFormat_VC1 * mix) {
    141 	return (MixVideoFormat_VC1 *) g_object_ref(G_OBJECT(mix));
    142 }
    143 
    144 /*  VC1 vmethods implementation */
    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 
    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 
    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 
    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 
    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 
    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 
   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 
   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 
   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 
   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 
   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 
   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