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 <string.h>
10 #include <stdlib.h>
11
12 #include "mixvideolog.h"
13
14 #include "mixvideoformatenc_h264.h"
15 #include "mixvideoconfigparamsenc_h264.h"
16
17 #define MDEBUG
18 #undef SHOW_SRC
19
20 #ifdef SHOW_SRC
21 Window win = 0;
22 #endif /* SHOW_SRC */
23
24
25 /* The parent class. The pointer will be saved
26 * in this class's initialization. The pointer
27 * can be used for chaining method call if needed.
28 */
29 static MixVideoFormatEncClass *parent_class = NULL;
30
31 static void mix_videoformatenc_h264_finalize(GObject * obj);
32
33 /*
34 * Please note that the type we pass to G_DEFINE_TYPE is MIX_TYPE_VIDEOFORMATENC
35 */
36 G_DEFINE_TYPE (MixVideoFormatEnc_H264, mix_videoformatenc_h264, MIX_TYPE_VIDEOFORMATENC);
37
mix_videoformatenc_h264_init(MixVideoFormatEnc_H264 * self)38 static void mix_videoformatenc_h264_init(MixVideoFormatEnc_H264 * self) {
39 MixVideoFormatEnc *parent = MIX_VIDEOFORMATENC(self);
40
41 /* TODO: public member initialization */
42
43 /* TODO: private member initialization */
44 self->encoded_frames = 0;
45 self->pic_skipped = FALSE;
46 self->is_intra = TRUE;
47 self->cur_fame = NULL;
48 self->ref_fame = NULL;
49 self->rec_fame = NULL;
50
51 self->ci_shared_surfaces = NULL;
52 self->surfaces= NULL;
53 self->surface_num = 0;
54
55 parent->initialized = FALSE;
56 }
57
mix_videoformatenc_h264_class_init(MixVideoFormatEnc_H264Class * klass)58 static void mix_videoformatenc_h264_class_init(
59 MixVideoFormatEnc_H264Class * klass) {
60
61 /* root class */
62 GObjectClass *gobject_class = (GObjectClass *) klass;
63
64 /* direct parent class */
65 MixVideoFormatEncClass *video_formatenc_class =
66 MIX_VIDEOFORMATENC_CLASS(klass);
67
68 /* parent class for later use */
69 parent_class = g_type_class_peek_parent(klass);
70
71 /* setup finializer */
72 gobject_class->finalize = mix_videoformatenc_h264_finalize;
73
74 /* setup vmethods with base implementation */
75 /* TODO: decide if we need to override the parent's methods */
76 video_formatenc_class->getcaps = mix_videofmtenc_h264_getcaps;
77 video_formatenc_class->initialize = mix_videofmtenc_h264_initialize;
78 video_formatenc_class->encode = mix_videofmtenc_h264_encode;
79 video_formatenc_class->flush = mix_videofmtenc_h264_flush;
80 video_formatenc_class->eos = mix_videofmtenc_h264_eos;
81 video_formatenc_class->deinitialize = mix_videofmtenc_h264_deinitialize;
82 video_formatenc_class->getmaxencodedbufsize = mix_videofmtenc_h264_get_max_encoded_buf_size;
83 }
84
85 MixVideoFormatEnc_H264 *
mix_videoformatenc_h264_new(void)86 mix_videoformatenc_h264_new(void) {
87 MixVideoFormatEnc_H264 *ret =
88 g_object_new(MIX_TYPE_VIDEOFORMATENC_H264, NULL);
89
90 return ret;
91 }
92
mix_videoformatenc_h264_finalize(GObject * obj)93 void mix_videoformatenc_h264_finalize(GObject * obj) {
94 /* clean up here. */
95
96 /*MixVideoFormatEnc_H264 *mix = MIX_VIDEOFORMATENC_H264(obj); */
97 GObjectClass *root_class = (GObjectClass *) parent_class;
98
99 LOG_V( "\n");
100
101 /* Chain up parent */
102 if (root_class->finalize) {
103 root_class->finalize(obj);
104 }
105 }
106
107 MixVideoFormatEnc_H264 *
mix_videoformatenc_h264_ref(MixVideoFormatEnc_H264 * mix)108 mix_videoformatenc_h264_ref(MixVideoFormatEnc_H264 * mix) {
109 return (MixVideoFormatEnc_H264 *) g_object_ref(G_OBJECT(mix));
110 }
111
112 /*H.264 vmethods implementation */
mix_videofmtenc_h264_getcaps(MixVideoFormatEnc * mix,GString * msg)113 MIX_RESULT mix_videofmtenc_h264_getcaps(MixVideoFormatEnc *mix, GString *msg) {
114
115 /* TODO: add codes for H.264 */
116
117 /* TODO: decide if we need to chainup parent method.
118 * if we do, the following is the code:
119 */
120
121 LOG_V( "mix_videofmtenc_h264_getcaps\n");
122
123 if (mix == NULL) {
124 LOG_E( "mix == NULL\n");
125 return MIX_RESULT_NULL_PTR;
126 }
127
128
129 if (parent_class->getcaps) {
130 return parent_class->getcaps(mix, msg);
131 }
132 return MIX_RESULT_SUCCESS;
133 }
134
mix_videofmtenc_h264_initialize(MixVideoFormatEnc * mix,MixVideoConfigParamsEnc * config_params_enc,MixFrameManager * frame_mgr,MixBufferPool * input_buf_pool,MixSurfacePool ** surface_pool,VADisplay va_display)135 MIX_RESULT mix_videofmtenc_h264_initialize(MixVideoFormatEnc *mix,
136 MixVideoConfigParamsEnc * config_params_enc,
137 MixFrameManager * frame_mgr,
138 MixBufferPool * input_buf_pool,
139 MixSurfacePool ** surface_pool,
140 VADisplay va_display ) {
141
142 MIX_RESULT ret = MIX_RESULT_SUCCESS;
143 MixVideoFormatEnc *parent = NULL;
144 MixVideoConfigParamsEncH264 * config_params_enc_h264;
145
146 VAStatus va_status = VA_STATUS_SUCCESS;
147 VASurfaceID * surfaces;
148
149 gint va_max_num_profiles, va_max_num_entrypoints, va_max_num_attribs;
150 gint va_num_profiles, va_num_entrypoints;
151
152 VAProfile *va_profiles = NULL;
153 VAEntrypoint *va_entrypoints = NULL;
154 VAConfigAttrib va_attrib[2];
155 guint index;
156
157
158 /*frame_mgr and input_buf_pool is reservered for future use*/
159
160 if (mix == NULL || config_params_enc == NULL || va_display == NULL) {
161 LOG_E(
162 "mix == NULL || config_params_enc == NULL || va_display == NULL\n");
163 return MIX_RESULT_NULL_PTR;
164 }
165
166 LOG_V( "begin\n");
167
168
169 //TODO additional parameter checking
170
171 /* Chainup parent method. */
172 #if 1
173 if (parent_class->initialize) {
174 ret = parent_class->initialize(mix, config_params_enc,
175 frame_mgr, input_buf_pool, surface_pool,
176 va_display);
177 }
178
179 if (ret != MIX_RESULT_SUCCESS)
180 {
181 return ret;
182 }
183
184 #endif //disable it currently
185
186 if (MIX_IS_VIDEOFORMATENC_H264(mix))
187 {
188 parent = MIX_VIDEOFORMATENC(&(mix->parent));
189 MixVideoFormatEnc_H264 *self = MIX_VIDEOFORMATENC_H264(mix);
190
191 if (MIX_IS_VIDEOCONFIGPARAMSENC_H264 (config_params_enc)) {
192 config_params_enc_h264 =
193 MIX_VIDEOCONFIGPARAMSENC_H264 (config_params_enc);
194 } else {
195 LOG_V(
196 "mix_videofmtenc_h264_initialize: no h264 config params found\n");
197 return MIX_RESULT_FAIL;
198 }
199
200 g_mutex_lock(parent->objectlock);
201
202 LOG_V(
203 "Start to get properities from h.264 params\n");
204
205 /* get properties from H264 params Object, which is special to H264 format*/
206 ret = mix_videoconfigparamsenc_h264_get_bus (config_params_enc_h264,
207 &self->basic_unit_size);
208
209 if (ret != MIX_RESULT_SUCCESS) {
210 //TODO cleanup
211 LOG_E(
212 "Failed to mix_videoconfigparamsenc_h264_get_bus\n");
213 g_mutex_unlock(parent->objectlock);
214 return MIX_RESULT_FAIL;
215 }
216
217
218 ret = mix_videoconfigparamsenc_h264_get_dlk (config_params_enc_h264,
219 &self->disable_deblocking_filter_idc);
220
221 if (ret != MIX_RESULT_SUCCESS) {
222 //TODO cleanup
223 LOG_E(
224 "Failed to mix_videoconfigparamsenc_h264_get_dlk\n");
225 g_mutex_unlock(parent->objectlock);
226 return MIX_RESULT_FAIL;
227 }
228
229
230 ret = mix_videoconfigparamsenc_h264_get_slice_num (config_params_enc_h264,
231 &self->slice_num);
232
233 if (ret != MIX_RESULT_SUCCESS) {
234 //TODO cleanup
235 LOG_E(
236 "Failed to mix_videoconfigparamsenc_h264_get_slice_num\n");
237 g_mutex_unlock(parent->objectlock);
238 return MIX_RESULT_FAIL;
239 }
240
241 ret = mix_videoconfigparamsenc_h264_get_delimiter_type (config_params_enc_h264,
242 &self->delimiter_type);
243
244 if (ret != MIX_RESULT_SUCCESS) {
245 //TODO cleanup
246 LOG_E (
247 "Failed to mix_videoconfigparamsenc_h264_get_delimiter_type\n");
248 g_mutex_unlock(parent->objectlock);
249 return MIX_RESULT_FAIL;
250 }
251
252 LOG_V(
253 "======H264 Encode Object properities======:\n");
254
255 LOG_I( "self->basic_unit_size = %d\n",
256 self->basic_unit_size);
257 LOG_I( "self->disable_deblocking_filter_idc = %d\n",
258 self->disable_deblocking_filter_idc);
259 LOG_I( "self->slice_num = %d\n",
260 self->slice_num);
261 LOG_I ("self->delimiter_type = %d\n",
262 self->delimiter_type);
263
264 LOG_V(
265 "Get properities from params done\n");
266
267
268 //display = XOpenDisplay(NULL);
269 //va_display = vaGetDisplay (videoencobj->display);
270
271 parent->va_display = va_display;
272
273 LOG_V( "Get Display\n");
274 LOG_I( "Display = 0x%08x\n",
275 (guint)va_display);
276
277 //va_status = vaInitialize(va_display, &va_major_ver, &va_minor_ver);
278 //g_print ("vaInitialize va_status = %d\n", va_status);
279
280
281 #if 0
282 /* query the vender information, can ignore*/
283 va_vendor = vaQueryVendorString (va_display);
284 LOG_I( "Vendor = %s\n",
285 va_vendor);
286 #endif
287
288 /*get the max number for profiles/entrypoints/attribs*/
289 va_max_num_profiles = vaMaxNumProfiles(va_display);
290 LOG_I( "va_max_num_profiles = %d\n",
291 va_max_num_profiles);
292
293 va_max_num_entrypoints = vaMaxNumEntrypoints(va_display);
294 LOG_I( "va_max_num_entrypoints = %d\n",
295 va_max_num_entrypoints);
296
297 va_max_num_attribs = vaMaxNumConfigAttributes(va_display);
298 LOG_I( "va_max_num_attribs = %d\n",
299 va_max_num_attribs);
300
301 va_profiles = g_malloc(sizeof(VAProfile)*va_max_num_profiles);
302 va_entrypoints = g_malloc(sizeof(VAEntrypoint)*va_max_num_entrypoints);
303
304 if (va_profiles == NULL || va_entrypoints ==NULL)
305 {
306 LOG_E(
307 "!va_profiles || !va_entrypoints\n");
308 g_mutex_unlock(parent->objectlock);
309 return MIX_RESULT_NO_MEMORY;
310 }
311
312 LOG_I(
313 "va_profiles = 0x%08x\n", (guint)va_profiles);
314
315 LOG_V( "vaQueryConfigProfiles\n");
316
317
318 va_status = vaQueryConfigProfiles (va_display, va_profiles, &va_num_profiles);
319
320 if (va_status != VA_STATUS_SUCCESS)
321 {
322 LOG_E(
323 "Failed to call vaQueryConfigProfiles\n");
324 g_free(va_profiles);
325 g_free (va_entrypoints);
326 g_mutex_unlock(parent->objectlock);
327 return MIX_RESULT_FAIL;
328 }
329
330 LOG_V( "vaQueryConfigProfiles Done\n");
331
332
333
334 /*check whether profile is supported*/
335 for(index= 0; index < va_num_profiles; index++) {
336 if(parent->va_profile == va_profiles[index])
337 break;
338 }
339
340 if(index == va_num_profiles)
341 {
342 LOG_E( "Profile not supported\n");
343 g_free(va_profiles);
344 g_free (va_entrypoints);
345 g_mutex_unlock(parent->objectlock);
346 return MIX_RESULT_FAIL; //Todo, add error handling here
347 }
348
349 LOG_V( "vaQueryConfigEntrypoints\n");
350
351
352 /*Check entry point*/
353 va_status = vaQueryConfigEntrypoints(va_display,
354 parent->va_profile,
355 va_entrypoints, &va_num_entrypoints);
356
357 if (va_status != VA_STATUS_SUCCESS)
358 {
359 LOG_E(
360 "Failed to call vaQueryConfigEntrypoints\n");
361 g_free(va_profiles);
362 g_free (va_entrypoints);
363 g_mutex_unlock(parent->objectlock);
364 return MIX_RESULT_FAIL;
365 }
366
367 for (index = 0; index < va_num_entrypoints; index ++) {
368 if (va_entrypoints[index] == VAEntrypointEncSlice) {
369 break;
370 }
371 }
372
373 if (index == va_num_entrypoints) {
374 LOG_E( "Entrypoint not found\n");
375 g_free(va_profiles);
376 g_free (va_entrypoints);
377 g_mutex_unlock(parent->objectlock);
378 return MIX_RESULT_FAIL; //Todo, add error handling here
379 }
380
381
382 /*free profiles and entrypoints*/
383 g_free(va_profiles);
384 g_free (va_entrypoints);
385
386 va_attrib[0].type = VAConfigAttribRTFormat;
387 va_attrib[1].type = VAConfigAttribRateControl;
388
389 LOG_V( "vaGetConfigAttributes\n");
390
391 va_status = vaGetConfigAttributes(va_display, parent->va_profile,
392 parent->va_entrypoint,
393 &va_attrib[0], 2);
394
395 if (va_status != VA_STATUS_SUCCESS)
396 {
397 LOG_E(
398 "Failed to call vaGetConfigAttributes\n");
399 g_mutex_unlock(parent->objectlock);
400 return MIX_RESULT_FAIL;
401 }
402
403 if ((va_attrib[0].value & parent->va_format) == 0) {
404 LOG_E( "Matched format not found\n");
405 g_mutex_unlock(parent->objectlock);
406 return MIX_RESULT_FAIL; //Todo, add error handling here
407 }
408
409
410 if ((va_attrib[1].value & parent->va_rcmode) == 0) {
411 LOG_E( "RC mode not found\n");
412 g_mutex_unlock(parent->objectlock);
413 return MIX_RESULT_FAIL; //Todo, add error handling here
414 }
415
416 va_attrib[0].value = parent->va_format; //VA_RT_FORMAT_YUV420;
417 va_attrib[1].value = parent->va_rcmode;
418
419 LOG_V( "======VA Configuration======\n");
420
421 LOG_I( "profile = %d\n",
422 parent->va_profile);
423 LOG_I( "va_entrypoint = %d\n",
424 parent->va_entrypoint);
425 LOG_I( "va_attrib[0].type = %d\n",
426 va_attrib[0].type);
427 LOG_I( "va_attrib[1].type = %d\n",
428 va_attrib[1].type);
429 LOG_I( "va_attrib[0].value (Format) = %d\n",
430 va_attrib[0].value);
431 LOG_I( "va_attrib[1].value (RC mode) = %d\n",
432 va_attrib[1].value);
433
434 LOG_V( "vaCreateConfig\n");
435
436 va_status = vaCreateConfig(va_display, parent->va_profile,
437 parent->va_entrypoint,
438 &va_attrib[0], 2, &(parent->va_config));
439
440 if (va_status != VA_STATUS_SUCCESS)
441 {
442 LOG_E( "Failed vaCreateConfig\n");
443 g_mutex_unlock(parent->objectlock);
444 return MIX_RESULT_FAIL;
445 }
446
447 /*TODO: compute the surface number*/
448 int numSurfaces;
449
450 if (parent->share_buf_mode) {
451 numSurfaces = 2;
452 }
453 else {
454 numSurfaces = 8;
455 parent->ci_frame_num = 0;
456 }
457
458 self->surface_num = numSurfaces + parent->ci_frame_num;
459
460 surfaces = g_malloc(sizeof(VASurfaceID)*numSurfaces);
461
462 if (surfaces == NULL)
463 {
464 LOG_E(
465 "Failed allocate surface\n");
466 g_mutex_unlock(parent->objectlock);
467 return MIX_RESULT_NO_MEMORY;
468 }
469
470 LOG_V( "vaCreateSurfaces\n");
471
472 va_status = vaCreateSurfaces(va_display, parent->picture_width,
473 parent->picture_height, parent->va_format,
474 numSurfaces, surfaces);
475 //TODO check vret and return fail if needed
476
477 if (va_status != VA_STATUS_SUCCESS)
478 {
479 LOG_E(
480 "Failed vaCreateSurfaces\n");
481 g_mutex_unlock(parent->objectlock);
482 return MIX_RESULT_FAIL;
483 }
484
485 if (parent->share_buf_mode) {
486
487 LOG_V(
488 "We are in share buffer mode!\n");
489 self->ci_shared_surfaces =
490 g_malloc(sizeof(VASurfaceID) * parent->ci_frame_num);
491
492 if (self->ci_shared_surfaces == NULL)
493 {
494 LOG_E(
495 "Failed allocate shared surface\n");
496 g_mutex_unlock(parent->objectlock);
497 return MIX_RESULT_NO_MEMORY;
498 }
499
500 guint index;
501 for(index = 0; index < parent->ci_frame_num; index++) {
502
503 LOG_I( "ci_frame_id = %lu\n",
504 parent->ci_frame_id[index]);
505
506 LOG_V(
507 "vaCreateSurfaceFromCIFrame\n");
508
509 va_status = vaCreateSurfaceFromCIFrame(va_display,
510 (gulong) (parent->ci_frame_id[index]),
511 &self->ci_shared_surfaces[index]);
512 if (va_status != VA_STATUS_SUCCESS)
513 {
514 LOG_E(
515 "Failed to vaCreateSurfaceFromCIFrame\n");
516 g_mutex_unlock(parent->objectlock);
517 return MIX_RESULT_FAIL;
518 }
519 }
520
521 LOG_V(
522 "vaCreateSurfaceFromCIFrame Done\n");
523
524 }// if (parent->share_buf_mode)
525
526 self->surfaces = g_malloc(sizeof(VASurfaceID) * self->surface_num);
527
528 if (self->surfaces == NULL)
529 {
530 LOG_E(
531 "Failed allocate private surface\n");
532 g_free (surfaces);
533 g_mutex_unlock(parent->objectlock);
534 return MIX_RESULT_NO_MEMORY;
535 }
536
537 if (parent->share_buf_mode) {
538 /*shared surfaces should be put in pool first,
539 * because we will get it accoring to CI index*/
540 for(index = 0; index < parent->ci_frame_num; index++)
541 self->surfaces[index] = self->ci_shared_surfaces[index];
542 }
543
544 for(index = 0; index < numSurfaces; index++) {
545 self->surfaces[index + parent->ci_frame_num] = surfaces[index];
546 }
547
548 LOG_V( "assign surface Done\n");
549 LOG_I( "Created %d libva surfaces\n",
550 numSurfaces + parent->ci_frame_num);
551
552 #if 0 //current put this in gst
553 images = g_malloc(sizeof(VAImage)*numSurfaces);
554 if (images == NULL)
555 {
556 g_mutex_unlock(parent->objectlock);
557 return MIX_RESULT_FAIL;
558 }
559
560 for (index = 0; index < numSurfaces; index++) {
561 //Derive an VAImage from an existing surface.
562 //The image buffer can then be mapped/unmapped for CPU access
563 va_status = vaDeriveImage(va_display, surfaces[index],
564 &images[index]);
565 }
566 #endif
567
568 LOG_V( "mix_surfacepool_new\n");
569
570 parent->surfacepool = mix_surfacepool_new();
571 if (surface_pool)
572 *surface_pool = parent->surfacepool;
573 //which is useful to check before encode
574
575 if (parent->surfacepool == NULL)
576 {
577 LOG_E(
578 "Failed to mix_surfacepool_new\n");
579 g_free (surfaces);
580 g_mutex_unlock(parent->objectlock);
581 return MIX_RESULT_FAIL;
582 }
583
584 LOG_V(
585 "mix_surfacepool_initialize\n");
586
587 ret = mix_surfacepool_initialize(parent->surfacepool,
588 self->surfaces, parent->ci_frame_num + numSurfaces);
589
590 switch (ret)
591 {
592 case MIX_RESULT_SUCCESS:
593 break;
594 case MIX_RESULT_ALREADY_INIT:
595 //TODO cleanup and/or retry
596 g_free (surfaces);
597 g_mutex_unlock(parent->objectlock);
598 return MIX_RESULT_FAIL;
599 default:
600 break;
601 }
602
603
604 //Initialize and save the VA context ID
605 LOG_V( "vaCreateContext\n");
606
607 va_status = vaCreateContext(va_display, parent->va_config,
608 parent->picture_width, parent->picture_height,
609 0, self->surfaces, parent->ci_frame_num + numSurfaces,
610 &(parent->va_context));
611
612 LOG_I(
613 "Created libva context width %d, height %d\n",
614 parent->picture_width, parent->picture_height);
615
616 if (va_status != VA_STATUS_SUCCESS)
617 {
618 LOG_E(
619 "Failed to vaCreateContext\n");
620 LOG_I( "va_status = %d\n",
621 (guint)va_status);
622 g_free (surfaces);
623 g_mutex_unlock(parent->objectlock);
624 return MIX_RESULT_FAIL;
625 }
626
627 guint max_size = 0;
628 ret = mix_videofmtenc_h264_get_max_encoded_buf_size (parent, &max_size);
629 if (ret != MIX_RESULT_SUCCESS)
630 {
631 LOG_E(
632 "Failed to mix_videofmtenc_h264_get_max_encoded_buf_size\n");
633 g_free (surfaces);
634 g_mutex_unlock(parent->objectlock);
635 return MIX_RESULT_FAIL;
636
637 }
638
639 /*Create coded buffer for output*/
640 va_status = vaCreateBuffer (va_display, parent->va_context,
641 VAEncCodedBufferType,
642 self->coded_buf_size, //
643 1, NULL,
644 &self->coded_buf);
645
646 if (va_status != VA_STATUS_SUCCESS)
647 {
648 LOG_E(
649 "Failed to vaCreateBuffer: VAEncCodedBufferType\n");
650 g_free (surfaces);
651 g_mutex_unlock(parent->objectlock);
652 return MIX_RESULT_FAIL;
653 }
654
655 #ifdef SHOW_SRC
656 Display * display = XOpenDisplay (NULL);
657
658 LOG_I( "display = 0x%08x\n",
659 (guint) display);
660 win = XCreateSimpleWindow(display, RootWindow(display, 0), 0, 0,
661 parent->picture_width, parent->picture_height, 0, 0,
662 WhitePixel(display, 0));
663 XMapWindow(display, win);
664 XSelectInput(display, win, KeyPressMask | StructureNotifyMask);
665
666 XSync(display, False);
667 LOG_I( "va_display = 0x%08x\n",
668 (guint) va_display);
669
670 #endif /* SHOW_SRC */
671
672 parent->initialized = TRUE;
673
674 g_mutex_unlock(parent->objectlock);
675 g_free (surfaces);
676
677 }
678 else
679 {
680 LOG_E(
681 "not H264 video encode Object\n");
682 return MIX_RESULT_FAIL;
683
684 }
685
686 LOG_V( "end\n");
687
688 return MIX_RESULT_SUCCESS;
689 }
690
mix_videofmtenc_h264_encode(MixVideoFormatEnc * mix,MixBuffer * bufin[],gint bufincnt,MixIOVec * iovout[],gint iovoutcnt,MixVideoEncodeParams * encode_params)691 MIX_RESULT mix_videofmtenc_h264_encode(MixVideoFormatEnc *mix, MixBuffer * bufin[],
692 gint bufincnt, MixIOVec * iovout[], gint iovoutcnt,
693 MixVideoEncodeParams * encode_params) {
694
695 MIX_RESULT ret = MIX_RESULT_SUCCESS;
696 MixVideoFormatEnc *parent = NULL;
697
698 LOG_V( "Begin\n");
699
700 /*currenly only support one input and output buffer*/
701 //TODO: params i
702
703 if (bufincnt != 1 || iovoutcnt != 1) {
704 LOG_E(
705 "buffer count not equel to 1\n");
706 LOG_E(
707 "maybe some exception occurs\n");
708 }
709
710 if (mix == NULL ||bufin[0] == NULL || iovout[0] == NULL) {
711 LOG_E(
712 "!mix || !bufin[0] ||!iovout[0]\n");
713 return MIX_RESULT_NULL_PTR;
714 }
715
716 //TODO: encode_params is reserved here for future usage.
717
718 /* TODO: decide if we need to chainup parent method.
719 * * * if we do, the following is the code:
720 * */
721
722 #if 0
723 if (parent_class->encode) {
724 return parent_class->encode(mix, bufin, bufincnt, iovout,
725 iovoutcnt, encode_params);
726 }
727 #endif
728
729 if (MIX_IS_VIDEOFORMATENC_H264(mix))
730 {
731
732 parent = MIX_VIDEOFORMATENC(&(mix->parent));
733 MixVideoFormatEnc_H264 *self = MIX_VIDEOFORMATENC_H264 (mix);
734
735 LOG_V( "Locking\n");
736 g_mutex_lock(parent->objectlock);
737
738
739 //TODO: also we could move some encode Preparation work to here
740
741 LOG_V(
742 "mix_videofmtenc_h264_process_encode\n");
743
744 ret = mix_videofmtenc_h264_process_encode (self,
745 bufin[0], iovout[0]);
746 if (ret != MIX_RESULT_SUCCESS)
747 {
748 LOG_E(
749 "Failed mix_videofmtenc_h264_process_encode\n");
750 g_mutex_unlock(parent->objectlock);
751 return MIX_RESULT_FAIL;
752 }
753
754
755 LOG_V( "UnLocking\n");
756
757 g_mutex_unlock(parent->objectlock);
758 }
759 else
760 {
761 LOG_E(
762 "not H264 video encode Object\n");
763 return MIX_RESULT_FAIL;
764 }
765
766 LOG_V( "end\n");
767
768 return MIX_RESULT_SUCCESS;
769 }
770
mix_videofmtenc_h264_flush(MixVideoFormatEnc * mix)771 MIX_RESULT mix_videofmtenc_h264_flush(MixVideoFormatEnc *mix) {
772
773 //MIX_RESULT ret = MIX_RESULT_SUCCESS;
774
775 LOG_V( "Begin\n");
776
777 if (mix == NULL) {
778 LOG_E( "mix == NULL\n");
779 return MIX_RESULT_NULL_PTR;
780 }
781
782
783 /*not chain to parent flush func*/
784 #if 0
785 if (parent_class->flush) {
786 return parent_class->flush(mix, msg);
787 }
788 #endif
789
790 MixVideoFormatEnc_H264 *self = MIX_VIDEOFORMATENC_H264(mix);
791
792 g_mutex_lock(mix->objectlock);
793
794 #if 0
795 /*unref the current source surface*/
796 if (self->cur_fame != NULL)
797 {
798 mix_videoframe_unref (self->cur_fame);
799 self->cur_fame = NULL;
800 }
801 #endif
802
803 /*unref the reconstructed surface*/
804 if (self->rec_fame != NULL)
805 {
806 mix_videoframe_unref (self->rec_fame);
807 self->rec_fame = NULL;
808 }
809
810 /*unref the reference surface*/
811 if (self->ref_fame != NULL)
812 {
813 mix_videoframe_unref (self->ref_fame);
814 self->ref_fame = NULL;
815 }
816
817 /*reset the properities*/
818 self->encoded_frames = 0;
819 self->pic_skipped = FALSE;
820 self->is_intra = TRUE;
821
822 g_mutex_unlock(mix->objectlock);
823
824 LOG_V( "end\n");
825
826 return MIX_RESULT_SUCCESS;
827 }
828
mix_videofmtenc_h264_eos(MixVideoFormatEnc * mix)829 MIX_RESULT mix_videofmtenc_h264_eos(MixVideoFormatEnc *mix) {
830
831 /* TODO: add codes for H.264 */
832
833 /* TODO: decide if we need to chainup parent method.
834 * if we do, the following is the code:
835 */
836
837 LOG_V( "\n");
838
839 if (mix == NULL) {
840 LOG_E( "mix == NULL\n");
841 return MIX_RESULT_NULL_PTR;
842 }
843
844 if (parent_class->eos) {
845 return parent_class->eos(mix);
846 }
847 return MIX_RESULT_SUCCESS;
848 }
849
mix_videofmtenc_h264_deinitialize(MixVideoFormatEnc * mix)850 MIX_RESULT mix_videofmtenc_h264_deinitialize(MixVideoFormatEnc *mix) {
851
852 MixVideoFormatEnc *parent = NULL;
853 VAStatus va_status;
854
855 LOG_V( "Begin\n");
856
857 if (mix == NULL) {
858 LOG_E( "mix == NULL\n");
859 return MIX_RESULT_NULL_PTR;
860 }
861
862 parent = MIX_VIDEOFORMATENC(&(mix->parent));
863 MixVideoFormatEnc_H264 *self = MIX_VIDEOFORMATENC_H264(mix);
864
865 LOG_V( "Release frames\n");
866
867 g_mutex_lock(parent->objectlock);
868
869 #if 0
870 /*unref the current source surface*/
871 if (self->cur_fame != NULL)
872 {
873 mix_videoframe_unref (self->cur_fame);
874 self->cur_fame = NULL;
875 }
876 #endif
877
878 /*unref the reconstructed surface*/
879 if (self->rec_fame != NULL)
880 {
881 mix_videoframe_unref (self->rec_fame);
882 self->rec_fame = NULL;
883 }
884
885 /*unref the reference surface*/
886 if (self->ref_fame != NULL)
887 {
888 mix_videoframe_unref (self->ref_fame);
889 self->ref_fame = NULL;
890 }
891
892 LOG_V( "Release surfaces\n");
893
894 if (self->ci_shared_surfaces)
895 {
896 g_free (self->ci_shared_surfaces);
897 self->ci_shared_surfaces = NULL;
898 }
899
900 if (self->surfaces)
901 {
902 g_free (self->surfaces);
903 self->surfaces = NULL;
904 }
905
906 LOG_V( "vaDestroyContext\n");
907
908 va_status = vaDestroyContext (parent->va_display, parent->va_context);
909 if (va_status != VA_STATUS_SUCCESS)
910 {
911 LOG_E(
912 "Failed vaDestroyContext\n");
913 g_mutex_unlock(parent->objectlock);
914 return MIX_RESULT_FAIL;
915 }
916
917 LOG_V( "vaDestroyConfig\n");
918
919 va_status = vaDestroyConfig (parent->va_display, parent->va_config);
920 if (va_status != VA_STATUS_SUCCESS)
921 {
922 LOG_E(
923 "Failed vaDestroyConfig\n");
924 g_mutex_unlock(parent->objectlock);
925 return MIX_RESULT_FAIL;
926 }
927
928 parent->initialized = TRUE;
929
930 g_mutex_unlock(parent->objectlock);
931
932 #if 1
933 if (parent_class->deinitialize) {
934 return parent_class->deinitialize(mix);
935 }
936 #endif
937
938 //Most stuff is cleaned up in parent_class->finalize()
939
940 LOG_V( "end\n");
941
942 return MIX_RESULT_SUCCESS;
943 }
944
mix_videofmtenc_h264_send_seq_params(MixVideoFormatEnc_H264 * mix)945 MIX_RESULT mix_videofmtenc_h264_send_seq_params (MixVideoFormatEnc_H264 *mix)
946 {
947
948 VAStatus va_status;
949 VAEncSequenceParameterBufferH264 h264_seq_param;
950
951 MixVideoFormatEnc *parent = NULL;
952
953 if (mix == NULL)
954 return MIX_RESULT_NULL_PTR;
955
956 LOG_V( "Begin\n\n");
957
958 if (MIX_IS_VIDEOFORMATENC_H264(mix))
959 {
960 parent = MIX_VIDEOFORMATENC(&(mix->parent));
961
962 /*set up the sequence params for HW*/
963 h264_seq_param.level_idc = 30; //TODO, hard code now
964 h264_seq_param.intra_period = parent->intra_period;
965 h264_seq_param.picture_width_in_mbs = parent->picture_width / 16;
966 h264_seq_param.picture_height_in_mbs = parent->picture_height/ 16;
967 h264_seq_param.bits_per_second = parent->bitrate;
968 h264_seq_param.frame_rate =
969 (unsigned int) (parent->frame_rate_num + parent->frame_rate_denom /2 ) / parent->frame_rate_denom;
970 h264_seq_param.initial_qp = parent->initial_qp;
971 h264_seq_param.min_qp = parent->min_qp;
972 h264_seq_param.basic_unit_size = mix->basic_unit_size; //for rate control usage
973 h264_seq_param.intra_period = parent->intra_period;
974 //h264_seq_param.vui_flag = 248;
975 //h264_seq_param.seq_parameter_set_id = 176;
976
977 LOG_V(
978 "===h264 sequence params===\n");
979
980 LOG_I( "seq_parameter_set_id = %d\n",
981 (guint)h264_seq_param.seq_parameter_set_id);
982 LOG_I( "level_idc = %d\n",
983 (guint)h264_seq_param.level_idc);
984 LOG_I( "intra_period = %d\n",
985 h264_seq_param.intra_period);
986 LOG_I( "picture_width_in_mbs = %d\n",
987 h264_seq_param.picture_width_in_mbs);
988 LOG_I( "picture_height_in_mbs = %d\n",
989 h264_seq_param.picture_height_in_mbs);
990 LOG_I( "bitrate = %d\n",
991 h264_seq_param.bits_per_second);
992 LOG_I( "frame_rate = %d\n",
993 h264_seq_param.frame_rate);
994 LOG_I( "initial_qp = %d\n",
995 h264_seq_param.initial_qp);
996 LOG_I( "min_qp = %d\n",
997 h264_seq_param.min_qp);
998 LOG_I( "basic_unit_size = %d\n",
999 h264_seq_param.basic_unit_size);
1000 LOG_I( "vui_flag = %d\n\n",
1001 h264_seq_param.vui_flag);
1002
1003 va_status = vaCreateBuffer(parent->va_display, parent->va_context,
1004 VAEncSequenceParameterBufferType,
1005 sizeof(h264_seq_param),
1006 1, &h264_seq_param,
1007 &mix->seq_param_buf);
1008 if (va_status != VA_STATUS_SUCCESS)
1009 {
1010 LOG_E(
1011 "Failed to vaCreateBuffer\n");
1012 return MIX_RESULT_FAIL;
1013 }
1014
1015 va_status = vaRenderPicture(parent->va_display, parent->va_context,
1016 &mix->seq_param_buf, 1);
1017 if (va_status != VA_STATUS_SUCCESS)
1018 {
1019 LOG_E(
1020 "Failed to vaRenderPicture\n");
1021 return MIX_RESULT_FAIL;
1022 }
1023 }
1024 else
1025 {
1026 LOG_E(
1027 "not H264 video encode Object\n");
1028 return MIX_RESULT_FAIL;
1029 }
1030
1031 LOG_V( "end\n");
1032
1033 return MIX_RESULT_SUCCESS;
1034
1035
1036 }
1037
mix_videofmtenc_h264_send_picture_parameter(MixVideoFormatEnc_H264 * mix)1038 MIX_RESULT mix_videofmtenc_h264_send_picture_parameter (MixVideoFormatEnc_H264 *mix)
1039 {
1040 VAStatus va_status;
1041 VAEncPictureParameterBufferH264 h264_pic_param;
1042 MixVideoFormatEnc *parent = NULL;
1043
1044 if (mix == NULL)
1045 return MIX_RESULT_NULL_PTR;
1046
1047 LOG_V( "Begin\n\n");
1048
1049 #if 0 //not needed currently
1050 MixVideoConfigParamsEncH264 * params_h264
1051 = MIX_VIDEOCONFIGPARAMSENC_H264 (config_params_enc);
1052 #endif
1053
1054 if (MIX_IS_VIDEOFORMATENC_H264(mix)) {
1055
1056 parent = MIX_VIDEOFORMATENC(&(mix->parent));
1057
1058 /*set picture params for HW*/
1059 h264_pic_param.reference_picture = mix->ref_fame->frame_id;
1060 h264_pic_param.reconstructed_picture = mix->rec_fame->frame_id;
1061 h264_pic_param.coded_buf = mix->coded_buf;
1062 h264_pic_param.picture_width = parent->picture_width;
1063 h264_pic_param.picture_height = parent->picture_height;
1064 h264_pic_param.last_picture = 0;
1065
1066
1067 LOG_V(
1068 "======h264 picture params======\n");
1069 LOG_I( "reference_picture = 0x%08x\n",
1070 h264_pic_param.reference_picture);
1071 LOG_I( "reconstructed_picture = 0x%08x\n",
1072 h264_pic_param.reconstructed_picture);
1073 LOG_I( "coded_buf = 0x%08x\n",
1074 h264_pic_param.coded_buf);
1075 LOG_I( "picture_width = %d\n",
1076 h264_pic_param.picture_width);
1077 LOG_I( "picture_height = %d\n\n",
1078 h264_pic_param.picture_height);
1079
1080 va_status = vaCreateBuffer(parent->va_display, parent->va_context,
1081 VAEncPictureParameterBufferType,
1082 sizeof(h264_pic_param),
1083 1,&h264_pic_param,
1084 &mix->pic_param_buf);
1085
1086 if (va_status != VA_STATUS_SUCCESS)
1087 {
1088 LOG_E(
1089 "Failed to vaCreateBuffer\n");
1090 return MIX_RESULT_FAIL;
1091 }
1092
1093
1094 va_status = vaRenderPicture(parent->va_display, parent->va_context,
1095 &mix->pic_param_buf, 1);
1096
1097 if (va_status != VA_STATUS_SUCCESS)
1098 {
1099 LOG_E(
1100 "Failed to vaRenderPicture\n");
1101 return MIX_RESULT_FAIL;
1102 }
1103 }
1104 else
1105 {
1106 LOG_E(
1107 "not H264 video encode Object\n");
1108 return MIX_RESULT_FAIL;
1109 }
1110
1111 LOG_V( "end\n");
1112 return MIX_RESULT_SUCCESS;
1113
1114 }
1115
1116
mix_videofmtenc_h264_send_slice_parameter(MixVideoFormatEnc_H264 * mix)1117 MIX_RESULT mix_videofmtenc_h264_send_slice_parameter (MixVideoFormatEnc_H264 *mix)
1118 {
1119 VAStatus va_status;
1120
1121 guint slice_num;
1122 guint slice_height;
1123 guint slice_index;
1124 guint slice_height_in_mb;
1125
1126 if (mix == NULL)
1127 return MIX_RESULT_NULL_PTR;
1128
1129 LOG_V( "Begin\n\n");
1130
1131
1132 MixVideoFormatEnc *parent = NULL;
1133
1134 if (MIX_IS_VIDEOFORMATENC_H264(mix))
1135 {
1136 parent = MIX_VIDEOFORMATENC(&(mix->parent));
1137
1138 slice_num = mix->slice_num;
1139 slice_height = parent->picture_height / slice_num;
1140
1141 slice_height += 15;
1142 slice_height &= (~15);
1143
1144 #if 1
1145 va_status = vaCreateBuffer (parent->va_display, parent->va_context,
1146 VAEncSliceParameterBufferType,
1147 sizeof(VAEncSliceParameterBuffer),
1148 slice_num, NULL,
1149 &mix->slice_param_buf);
1150
1151 if (va_status != VA_STATUS_SUCCESS)
1152 {
1153 LOG_E(
1154 "Failed to vaCreateBuffer\n");
1155 return MIX_RESULT_FAIL;
1156 }
1157
1158 VAEncSliceParameterBuffer *slice_param, *current_slice;
1159
1160 va_status = vaMapBuffer(parent->va_display,
1161 mix->slice_param_buf,
1162 (void **)&slice_param);
1163
1164 if (va_status != VA_STATUS_SUCCESS)
1165 {
1166 LOG_E(
1167 "Failed to vaMapBuffer\n");
1168 return MIX_RESULT_FAIL;
1169 }
1170
1171 current_slice = slice_param;
1172
1173
1174 for (slice_index = 0; slice_index < slice_num; slice_index++) {
1175 current_slice = slice_param + slice_index;
1176 slice_height_in_mb =
1177 min (slice_height, parent->picture_height
1178 - slice_index * slice_height) / 16;
1179
1180 // starting MB row number for this slice
1181 current_slice->start_row_number = slice_index * slice_height / 16;
1182 // slice height measured in MB
1183 current_slice->slice_height = slice_height_in_mb;
1184 current_slice->slice_flags.bits.is_intra = mix->is_intra;
1185 current_slice->slice_flags.bits.disable_deblocking_filter_idc
1186 = mix->disable_deblocking_filter_idc;
1187
1188 LOG_V(
1189 "======h264 slice params======\n");
1190
1191 LOG_I( "slice_index = %d\n",
1192 (gint) slice_index);
1193 LOG_I( "start_row_number = %d\n",
1194 (gint) current_slice->start_row_number);
1195 LOG_I( "slice_height_in_mb = %d\n",
1196 (gint) current_slice->slice_height);
1197 LOG_I( "slice.is_intra = %d\n",
1198 (gint) current_slice->slice_flags.bits.is_intra);
1199 LOG_I(
1200 "disable_deblocking_filter_idc = %d\n\n",
1201 (gint) mix->disable_deblocking_filter_idc);
1202
1203 }
1204
1205 va_status = vaUnmapBuffer(parent->va_display, mix->slice_param_buf);
1206
1207 if (va_status != VA_STATUS_SUCCESS)
1208 {
1209 LOG_E(
1210 "Failed to vaUnmapBuffer\n");
1211 return MIX_RESULT_FAIL;
1212 }
1213 #endif
1214
1215 #if 0
1216 VAEncSliceParameterBuffer slice_param;
1217 slice_index = 0;
1218 slice_height_in_mb = slice_height / 16;
1219 slice_param.start_row_number = 0;
1220 slice_param.slice_height = slice_height / 16;
1221 slice_param.slice_flags.bits.is_intra = mix->is_intra;
1222 slice_param.slice_flags.bits.disable_deblocking_filter_idc
1223 = mix->disable_deblocking_filter_idc;
1224
1225 va_status = vaCreateBuffer (parent->va_display, parent->va_context,
1226 VAEncSliceParameterBufferType,
1227 sizeof(slice_param),
1228 slice_num, &slice_param,
1229 &mix->slice_param_buf);
1230
1231 if (va_status != VA_STATUS_SUCCESS)
1232 {
1233 LOG_E(
1234 "Failed to vaCreateBuffer\n");
1235 return MIX_RESULT_FAIL;
1236 }
1237 #endif
1238
1239 va_status = vaRenderPicture(parent->va_display, parent->va_context,
1240 &mix->slice_param_buf, 1);
1241
1242 if (va_status != VA_STATUS_SUCCESS)
1243 {
1244 LOG_E(
1245 "Failed to vaRenderPicture\n");
1246 return MIX_RESULT_FAIL;
1247 }
1248
1249 }
1250 else
1251 {
1252 LOG_E(
1253 "not H264 video encode Object\n");
1254 return MIX_RESULT_FAIL;
1255 }
1256
1257 LOG_V( "end\n");
1258
1259 return MIX_RESULT_SUCCESS;
1260 }
1261
mix_videofmtenc_h264_process_encode(MixVideoFormatEnc_H264 * mix,MixBuffer * bufin,MixIOVec * iovout)1262 MIX_RESULT mix_videofmtenc_h264_process_encode (MixVideoFormatEnc_H264 *mix,
1263 MixBuffer * bufin, MixIOVec * iovout)
1264 {
1265
1266 MIX_RESULT ret = MIX_RESULT_SUCCESS;
1267 VAStatus va_status = VA_STATUS_SUCCESS;
1268 VADisplay va_display = NULL;
1269 VAContextID va_context;
1270 gulong surface = 0;
1271 guint16 width, height;
1272
1273 MixVideoFrame * tmp_fame;
1274 guint8 *buf;
1275
1276 if ((mix == NULL) || (bufin == NULL) || (iovout == NULL)) {
1277 LOG_E(
1278 "mix == NUL) || bufin == NULL || iovout == NULL\n");
1279 return MIX_RESULT_NULL_PTR;
1280 }
1281
1282 LOG_V( "Begin\n");
1283
1284 if (MIX_IS_VIDEOFORMATENC_H264(mix))
1285 {
1286
1287 MixVideoFormatEnc *parent = MIX_VIDEOFORMATENC(&(mix->parent));
1288
1289 va_display = parent->va_display;
1290 va_context = parent->va_context;
1291 width = parent->picture_width;
1292 height = parent->picture_height;
1293
1294
1295 LOG_I( "encoded_frames = %d\n",
1296 mix->encoded_frames);
1297 LOG_I( "is_intra = %d\n",
1298 mix->is_intra);
1299 LOG_I( "ci_frame_id = 0x%08x\n",
1300 (guint) parent->ci_frame_id);
1301
1302 /* determine the picture type*/
1303 if ((mix->encoded_frames % parent->intra_period) == 0) {
1304 mix->is_intra = TRUE;
1305 } else {
1306 mix->is_intra = FALSE;
1307 }
1308
1309 LOG_I( "is_intra_picture = %d\n",
1310 mix->is_intra);
1311
1312 LOG_V(
1313 "Get Surface from the pool\n");
1314
1315 /*current we use one surface for source data,
1316 * one for reference and one for reconstructed*/
1317 /*TODO, could be refine here*/
1318
1319 if (!parent->share_buf_mode) {
1320 LOG_V(
1321 "We are NOT in share buffer mode\n");
1322
1323 if (mix->ref_fame == NULL)
1324 {
1325 ret = mix_surfacepool_get(parent->surfacepool, &mix->ref_fame);
1326 if (ret != MIX_RESULT_SUCCESS) //#ifdef SLEEP_SURFACE not used
1327 {
1328 LOG_E(
1329 "Failed to mix_surfacepool_get\n");
1330 return MIX_RESULT_FAIL;
1331 }
1332 }
1333
1334 if (mix->rec_fame == NULL)
1335 {
1336 ret = mix_surfacepool_get(parent->surfacepool, &mix->rec_fame);
1337 if (ret != MIX_RESULT_SUCCESS)
1338 {
1339 LOG_E(
1340 "Failed to mix_surfacepool_get\n");
1341 return MIX_RESULT_FAIL;
1342 }
1343 }
1344
1345 if (parent->need_display) {
1346 mix->cur_fame = NULL;
1347 }
1348
1349 if (mix->cur_fame == NULL)
1350 {
1351 ret = mix_surfacepool_get(parent->surfacepool, &mix->cur_fame);
1352 if (ret != MIX_RESULT_SUCCESS)
1353 {
1354 LOG_E(
1355 "Failed to mix_surfacepool_get\n");
1356 return MIX_RESULT_FAIL;
1357 }
1358 }
1359
1360 LOG_V( "Get Surface Done\n");
1361
1362
1363 VAImage src_image;
1364 guint8 *pvbuf;
1365 guint8 *dst_y;
1366 guint8 *dst_uv;
1367 int i,j;
1368
1369 LOG_V(
1370 "map source data to surface\n");
1371
1372 ret = mix_videoframe_get_frame_id(mix->cur_fame, &surface);
1373 if (ret != MIX_RESULT_SUCCESS)
1374 {
1375 LOG_E(
1376 "Failed to mix_videoframe_get_frame_id\n");
1377 return MIX_RESULT_FAIL;
1378 }
1379
1380
1381 LOG_I(
1382 "surface id = 0x%08x\n", (guint) surface);
1383
1384 va_status = vaDeriveImage(va_display, surface, &src_image);
1385 //need to destroy
1386
1387 if (va_status != VA_STATUS_SUCCESS)
1388 {
1389 LOG_E(
1390 "Failed to vaDeriveImage\n");
1391 return MIX_RESULT_FAIL;
1392 }
1393
1394 VAImage *image = &src_image;
1395
1396 LOG_V( "vaDeriveImage Done\n");
1397
1398
1399 va_status = vaMapBuffer (va_display, image->buf, (void **)&pvbuf);
1400 if (va_status != VA_STATUS_SUCCESS)
1401 {
1402 LOG_E( "Failed to vaMapBuffer\n");
1403 return MIX_RESULT_FAIL;
1404 }
1405
1406 LOG_V(
1407 "vaImage information\n");
1408 LOG_I(
1409 "image->pitches[0] = %d\n", image->pitches[0]);
1410 LOG_I(
1411 "image->pitches[1] = %d\n", image->pitches[1]);
1412 LOG_I(
1413 "image->offsets[0] = %d\n", image->offsets[0]);
1414 LOG_I(
1415 "image->offsets[1] = %d\n", image->offsets[1]);
1416 LOG_I(
1417 "image->num_planes = %d\n", image->num_planes);
1418 LOG_I(
1419 "image->width = %d\n", image->width);
1420 LOG_I(
1421 "image->height = %d\n", image->height);
1422
1423 LOG_I(
1424 "input buf size = %d\n", bufin->size);
1425
1426 guint8 *inbuf = bufin->data;
1427
1428 /*need to convert YUV420 to NV12*/
1429 dst_y = pvbuf +image->offsets[0];
1430
1431 for (i = 0; i < height; i ++) {
1432 memcpy (dst_y, inbuf + i * width, width);
1433 dst_y += image->pitches[0];
1434 }
1435
1436 dst_uv = pvbuf + image->offsets[1];
1437
1438 for (i = 0; i < height / 2; i ++) {
1439 for (j = 0; j < width; j+=2) {
1440 dst_uv [j] = inbuf [width * height + i * width / 2 + j / 2];
1441 dst_uv [j + 1] =
1442 inbuf [width * height * 5 / 4 + i * width / 2 + j / 2];
1443 }
1444 dst_uv += image->pitches[1];
1445 }
1446
1447 vaUnmapBuffer(va_display, image->buf);
1448 if (va_status != VA_STATUS_SUCCESS)
1449 {
1450 LOG_E(
1451 "Failed to vaUnmapBuffer\n");
1452 return MIX_RESULT_FAIL;
1453 }
1454
1455 va_status = vaDestroyImage(va_display, src_image.image_id);
1456 if (va_status != VA_STATUS_SUCCESS)
1457 {
1458 LOG_E(
1459 "Failed to vaDestroyImage\n");
1460 return MIX_RESULT_FAIL;
1461 }
1462
1463 LOG_V(
1464 "Map source data to surface done\n");
1465
1466 }
1467
1468 else {//if (!parent->share_buf_mode)
1469
1470 MixVideoFrame * frame = mix_videoframe_new();
1471
1472 if (mix->ref_fame == NULL)
1473 {
1474 ret = mix_videoframe_set_ci_frame_idx (frame, mix->surface_num - 1);
1475
1476 ret = mix_surfacepool_get_frame_with_ci_frameidx
1477 (parent->surfacepool, &mix->ref_fame, frame);
1478 if (ret != MIX_RESULT_SUCCESS) //#ifdef SLEEP_SURFACE not used
1479 {
1480 LOG_E(
1481 "get reference surface from pool failed\n");
1482 return MIX_RESULT_FAIL;
1483 }
1484 }
1485
1486 if (mix->rec_fame == NULL)
1487 {
1488 ret = mix_videoframe_set_ci_frame_idx (frame, mix->surface_num - 2);
1489
1490 ret = mix_surfacepool_get_frame_with_ci_frameidx
1491 (parent->surfacepool, &mix->rec_fame, frame);
1492
1493 if (ret != MIX_RESULT_SUCCESS)
1494 {
1495 LOG_E(
1496 "get recontructed surface from pool failed\n");
1497 return MIX_RESULT_FAIL;
1498 }
1499 }
1500
1501 //mix_videoframe_unref (mix->cur_fame);
1502
1503 if (parent->need_display) {
1504 mix->cur_fame = NULL;
1505 }
1506
1507 if (mix->cur_fame == NULL)
1508 {
1509 guint ci_idx;
1510 memcpy (&ci_idx, bufin->data, bufin->size);
1511
1512 LOG_I(
1513 "surface_num = %d\n", mix->surface_num);
1514 LOG_I(
1515 "ci_frame_idx = %d\n", ci_idx);
1516
1517 if (ci_idx > mix->surface_num - 2) {
1518 LOG_E(
1519 "the CI frame idx is too bigger than CI frame number\n");
1520 return MIX_RESULT_FAIL;
1521 }
1522
1523
1524 ret = mix_videoframe_set_ci_frame_idx (frame, ci_idx);
1525
1526 ret = mix_surfacepool_get_frame_with_ci_frameidx
1527 (parent->surfacepool, &mix->cur_fame, frame);
1528
1529 if (ret != MIX_RESULT_SUCCESS)
1530 {
1531 LOG_E(
1532 "get current working surface from pool failed\n");
1533 return MIX_RESULT_FAIL;
1534 }
1535 }
1536
1537 ret = mix_videoframe_get_frame_id(mix->cur_fame, &surface);
1538
1539 }
1540
1541 LOG_V( "vaBeginPicture\n");
1542 LOG_I( "va_context = 0x%08x\n",(guint)va_context);
1543 LOG_I( "surface = 0x%08x\n",(guint)surface);
1544 LOG_I( "va_display = 0x%08x\n",(guint)va_display);
1545
1546 va_status = vaBeginPicture(va_display, va_context, surface);
1547 if (va_status != VA_STATUS_SUCCESS)
1548 {
1549 LOG_E( "Failed vaBeginPicture\n");
1550 return MIX_RESULT_FAIL;
1551 }
1552
1553 LOG_V( "mix_videofmtenc_h264_send_seq_params\n");
1554
1555 if (mix->encoded_frames == 0) {
1556 mix_videofmtenc_h264_send_seq_params (mix);
1557 if (ret != MIX_RESULT_SUCCESS)
1558 {
1559 LOG_E(
1560 "Failed mix_videofmtenc_h264_send_seq_params\n");
1561 return MIX_RESULT_FAIL;
1562 }
1563 }
1564
1565 ret = mix_videofmtenc_h264_send_picture_parameter (mix);
1566
1567 if (ret != MIX_RESULT_SUCCESS)
1568 {
1569 LOG_E(
1570 "Failed mix_videofmtenc_h264_send_picture_parameter\n");
1571 return MIX_RESULT_FAIL;
1572 }
1573
1574 ret = mix_videofmtenc_h264_send_slice_parameter (mix);
1575 if (ret != MIX_RESULT_SUCCESS)
1576 {
1577 LOG_E(
1578 "Failed mix_videofmtenc_h264_send_slice_parameter\n");
1579 return MIX_RESULT_FAIL;
1580 }
1581
1582 LOG_V( "before vaEndPicture\n");
1583
1584 va_status = vaEndPicture (va_display, va_context);
1585 if (va_status != VA_STATUS_SUCCESS)
1586 {
1587 LOG_E( "Failed vaEndPicture\n");
1588 return MIX_RESULT_FAIL;
1589 }
1590
1591
1592 LOG_V( "vaSyncSurface\n");
1593
1594 va_status = vaSyncSurface(va_display, surface);
1595 if (va_status != VA_STATUS_SUCCESS)
1596 {
1597 LOG_E( "Failed vaSyncSurface\n");
1598 return MIX_RESULT_FAIL;
1599 }
1600
1601
1602 LOG_V(
1603 "Start to get encoded data\n");
1604
1605 /*get encoded data from the VA buffer*/
1606 va_status = vaMapBuffer (va_display, mix->coded_buf, (void **)&buf);
1607 if (va_status != VA_STATUS_SUCCESS)
1608 {
1609 LOG_E( "Failed vaMapBuffer\n");
1610 return MIX_RESULT_FAIL;
1611 }
1612
1613 // first 4 bytes is the size of the buffer
1614 memcpy (&(iovout->data_size), (void*)buf, 4);
1615 //size = (guint*) buf;
1616
1617 guint size = iovout->data_size + 100;
1618
1619 iovout->buffer_size = size;
1620
1621 //We will support two buffer mode, one is application allocates the buffer and passes to encode,
1622 //the other is encode allocate memory
1623
1624 if (iovout->data == NULL) { //means app doesn't allocate the buffer, so _encode will allocate it.
1625 iovout->data = g_malloc (size); // In case we have lots of 0x000001 start code, and we replace them with 4 bytes length prefixed
1626 if (iovout->data == NULL) {
1627 return MIX_RESULT_NO_MEMORY;
1628 }
1629 }
1630
1631 if (mix->delimiter_type == MIX_DELIMITER_ANNEXB) {
1632 memcpy (iovout->data, buf + 16, iovout->data_size); //parload is started from 17th byte
1633 size = iovout->data_size;
1634 } else {
1635
1636 guint pos = 0;
1637 guint zero_byte_count = 0;
1638 guint prefix_length = 0;
1639 guint8 nal_unit_type = 0;
1640 guint8 * payload = buf + 16;
1641
1642 while ((payload[pos++] == 0x00)) {
1643 zero_byte_count ++;
1644 if (pos >= iovout->data_size) //to make sure the buffer to be accessed is valid
1645 break;
1646 }
1647
1648 nal_unit_type = (guint8)(payload[pos] & 0x1f);
1649 prefix_length = zero_byte_count + 1;
1650
1651 LOG_I ("nal_unit_type = %d\n", nal_unit_type);
1652 LOG_I ("zero_byte_count = %d\n", zero_byte_count);
1653
1654 if ((payload [pos - 1] & 0x01) && mix->slice_num == 1 && nal_unit_type == 1) {
1655 size = iovout->data_size;
1656 iovout->data[0] = ((size - prefix_length) >> 24) & 0xff;
1657 iovout->data[1] = ((size - prefix_length) >> 16) & 0xff;
1658 iovout->data[2] = ((size - prefix_length) >> 8) & 0xff;
1659 iovout->data[3] = (size - prefix_length) & 0xff;
1660 // use 4 bytes to indicate the NALU length
1661 memcpy (iovout->data + 4, buf + 16 + prefix_length, size - prefix_length);
1662 LOG_V ("We only have one start code, copy directly\n");
1663 }
1664 else {
1665 ret = mix_videofmtenc_h264_AnnexB_to_length_prefixed (buf + 16, iovout->data_size, iovout->data, &size);
1666 if (ret != MIX_RESULT_SUCCESS)
1667 {
1668 LOG_E (
1669 "Failed mix_videofmtenc_h264_AnnexB_to_length_prefixed\n");
1670 return MIX_RESULT_FAIL;
1671 }
1672 }
1673 }
1674
1675 iovout->data_size = size;
1676 LOG_I(
1677 "out size is = %d\n", iovout->data_size);
1678
1679 va_status = vaUnmapBuffer (va_display, mix->coded_buf);
1680 if (va_status != VA_STATUS_SUCCESS)
1681 {
1682 LOG_E( "Failed vaUnmapBuffer\n");
1683 return MIX_RESULT_FAIL;
1684 }
1685
1686 LOG_V( "get encoded data done\n");
1687 #if 0
1688 if (parent->drawable) {
1689 va_status = vaPutSurface(va_display, surface, (Drawable)parent->drawable,
1690 0,0, width, height,
1691 0,0, width, height,
1692 NULL,0,0);
1693 }
1694
1695 #ifdef SHOW_SRC
1696 else {
1697
1698 va_status = vaPutSurface(va_display, surface, win,
1699 0,0, width, height,
1700 0,0, width, height,
1701 NULL,0,0);
1702 }
1703 #endif //SHOW_SRC
1704 #endif
1705
1706 VASurfaceStatus status;
1707
1708 /*query the status of current surface*/
1709 va_status = vaQuerySurfaceStatus(va_display, surface, &status);
1710 if (va_status != VA_STATUS_SUCCESS)
1711 {
1712 LOG_E(
1713 "Failed vaQuerySurfaceStatus\n");
1714 return MIX_RESULT_FAIL;
1715 }
1716 mix->pic_skipped = status & VASurfaceSkipped;
1717
1718 if (parent->need_display) {
1719 ret = mix_framemanager_enqueue(parent->framemgr, mix->cur_fame);
1720 if (ret != MIX_RESULT_SUCCESS)
1721 {
1722 LOG_E(
1723 "Failed mix_framemanager_enqueue\n");
1724 return MIX_RESULT_FAIL;
1725 }
1726 }
1727
1728
1729 /*update the reference surface and reconstructed surface */
1730 if (!mix->pic_skipped) {
1731 tmp_fame = mix->rec_fame;
1732 mix->rec_fame= mix->ref_fame;
1733 mix->ref_fame = tmp_fame;
1734 }
1735
1736 #if 0
1737 if (mix->ref_fame != NULL)
1738 mix_videoframe_unref (mix->ref_fame);
1739 mix->ref_fame = mix->rec_fame;
1740
1741 mix_videoframe_unref (mix->cur_fame);
1742 #endif
1743
1744 if (!(parent->need_display)) {
1745 mix_videoframe_unref (mix->cur_fame);
1746 mix->cur_fame = NULL;
1747 }
1748
1749 mix->encoded_frames ++;
1750 }
1751 else
1752 {
1753 LOG_E(
1754 "not H264 video encode Object\n");
1755 return MIX_RESULT_FAIL;
1756 }
1757
1758
1759 LOG_V( "end\n");
1760
1761 return MIX_RESULT_SUCCESS;
1762 }
1763
mix_videofmtenc_h264_get_max_encoded_buf_size(MixVideoFormatEnc * mix,guint * max_size)1764 MIX_RESULT mix_videofmtenc_h264_get_max_encoded_buf_size (
1765 MixVideoFormatEnc *mix, guint *max_size)
1766 {
1767
1768 MixVideoFormatEnc *parent = NULL;
1769
1770 if (mix == NULL || max_size == NULL)
1771 {
1772 LOG_E(
1773 "mix == NULL || max_size == NULL\n");
1774 return MIX_RESULT_NULL_PTR;
1775 }
1776
1777 parent = MIX_VIDEOFORMATENC(mix);
1778 MixVideoFormatEnc_H264 *self = MIX_VIDEOFORMATENC_H264(mix);
1779
1780 LOG_V( "Begin\n");
1781
1782 if (MIX_IS_VIDEOFORMATENC_H264(self)) {
1783
1784 if (self->coded_buf_size > 0) {
1785 *max_size = self->coded_buf_size;
1786 LOG_V ("Already calculate the max encoded size, get the value directly");
1787 return MIX_RESULT_SUCCESS;
1788 }
1789
1790 /*base on the rate control mode to calculate the defaule encoded buffer size*/
1791 if (self->va_rcmode == VA_RC_NONE) {
1792 self->coded_buf_size =
1793 (parent->picture_width* parent->picture_height * 400) / (16 * 16);
1794 // set to value according to QP
1795 }
1796 else {
1797 self->coded_buf_size = parent->bitrate/ 4;
1798 }
1799
1800 self->coded_buf_size =
1801 max (self->coded_buf_size ,
1802 (parent->picture_width* parent->picture_height * 400) / (16 * 16));
1803
1804 /*in case got a very large user input bit rate value*/
1805 self->coded_buf_size =
1806 min(self->coded_buf_size,
1807 (parent->picture_width * parent->picture_height * 1.5 * 8));
1808 self->coded_buf_size = (self->coded_buf_size + 15) &(~15);
1809 }
1810 else
1811 {
1812 LOG_E(
1813 "not H264 video encode Object\n");
1814 return MIX_RESULT_FAIL;
1815 }
1816
1817 *max_size = self->coded_buf_size;
1818
1819 return MIX_RESULT_SUCCESS;
1820 }
1821
mix_videofmtenc_h264_AnnexB_to_length_prefixed(guint8 * bufin,guint bufin_len,guint8 * bufout,guint * bufout_len)1822 MIX_RESULT mix_videofmtenc_h264_AnnexB_to_length_prefixed (
1823 guint8 * bufin, guint bufin_len, guint8* bufout, guint * bufout_len)
1824 {
1825
1826 guint pos = 0;
1827 guint last_pos = 0;
1828
1829 guint zero_byte_count = 0;
1830 guint nal_size = 0;
1831 guint prefix_length = 0;
1832 guint size_copied = 0;
1833 guint leading_zero_count = 0;
1834
1835 if (bufin == NULL || bufout == NULL || bufout_len == NULL) {
1836
1837 LOG_E(
1838 "bufin == NULL || bufout == NULL || bufout_len = NULL\n");
1839 return MIX_RESULT_NULL_PTR;
1840 }
1841
1842 if (bufin_len <= 0 || *bufout_len <= 0) {
1843 LOG_E(
1844 "bufin_len <= 0 || *bufout_len <= 0\n");
1845 return MIX_RESULT_FAIL;
1846 }
1847
1848 LOG_V ("Begin\n");
1849
1850 while ((bufin[pos++] == 0x00)) {
1851 zero_byte_count ++;
1852 if (pos >= bufin_len) //to make sure the buffer to be accessed is valid
1853 break;
1854 }
1855
1856 if (bufin[pos - 1] != 0x01 || zero_byte_count < 2)
1857 {
1858 LOG_E("The stream is not AnnexB format \n");
1859 return MIX_RESULT_FAIL; ; //not AnnexB, we won't process it
1860 }
1861
1862 zero_byte_count = 0;
1863 last_pos = pos;
1864
1865 while (pos < bufin_len) {
1866
1867 while (bufin[pos++] == 0) {
1868 zero_byte_count ++;
1869 if (pos >= bufin_len) //to make sure the buffer to be accessed is valid
1870 break;
1871 }
1872
1873 if (bufin[pos - 1] == 0x01 && zero_byte_count >= 2) {
1874 if (zero_byte_count == 2) {
1875 prefix_length = 3;
1876 }
1877 else {
1878 prefix_length = 4;
1879 leading_zero_count = zero_byte_count - 3;
1880 }
1881
1882 LOG_I("leading_zero_count = %d\n", leading_zero_count);
1883
1884 nal_size = pos - last_pos - prefix_length - leading_zero_count;
1885 if (nal_size < 0) {
1886 LOG_E ("something wrong in the stream\n");
1887 return MIX_RESULT_FAIL; //not AnnexB, we won't process it
1888 }
1889
1890 if (*bufout_len < (size_copied + nal_size + 4)) {
1891 LOG_E ("The length of destination buffer is too small\n");
1892 return MIX_RESULT_FAIL;
1893 }
1894
1895 LOG_I ("nal_size = %d\n", nal_size);
1896
1897 /*We use 4 bytes length prefix*/
1898 bufout [size_copied] = nal_size >> 24 & 0xff;
1899 bufout [size_copied + 1] = nal_size >> 16 & 0xff;
1900 bufout [size_copied + 2] = nal_size >> 8 & 0xff;
1901 bufout [size_copied + 3] = nal_size & 0xff;
1902
1903 size_copied += 4; //4 bytes length prefix
1904 memcpy (bufout + size_copied, bufin + last_pos, nal_size);
1905 size_copied += nal_size;
1906
1907 LOG_I ("size_copied = %d\n", size_copied);
1908
1909 zero_byte_count = 0;
1910 leading_zero_count = 0;
1911 last_pos = pos;
1912 }
1913
1914 else if (pos == bufin_len) {
1915
1916 LOG_V ("Last NALU in this frame\n");
1917
1918 nal_size = pos - last_pos;
1919
1920 if (*bufout_len < (size_copied + nal_size + 4)) {
1921 LOG_E ("The length of destination buffer is too small\n");
1922 return MIX_RESULT_FAIL;
1923 }
1924
1925 /*We use 4 bytes length prefix*/
1926 bufout [size_copied] = nal_size >> 24 & 0xff;
1927 bufout [size_copied + 1] = nal_size >> 16 & 0xff;
1928 bufout [size_copied + 2] = nal_size >> 8 & 0xff;
1929 bufout [size_copied + 3] = nal_size & 0xff;
1930
1931 size_copied += 4; //4 bytes length prefix
1932 memcpy (bufout + size_copied, bufin + last_pos, nal_size);
1933 size_copied += nal_size;
1934
1935 LOG_I ("size_copied = %d\n", size_copied);
1936 }
1937
1938 else {
1939 zero_byte_count = 0;
1940 leading_zero_count = 0;
1941 }
1942
1943 }
1944
1945 if (size_copied != *bufout_len) {
1946 *bufout_len = size_copied;
1947 }
1948
1949 LOG_V ("End\n");
1950
1951 return MIX_RESULT_SUCCESS;
1952
1953 }
1954
1955