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