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