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_preview.h"
15 #include "mixvideoconfigparamsenc_preview.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_preview_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_Preview, mix_videoformatenc_preview, MIX_TYPE_VIDEOFORMATENC);
37 
mix_videoformatenc_preview_init(MixVideoFormatEnc_Preview * self)38 static void mix_videoformatenc_preview_init(MixVideoFormatEnc_Preview * 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_preview_class_init(MixVideoFormatEnc_PreviewClass * klass)58 static void mix_videoformatenc_preview_class_init(
59         MixVideoFormatEnc_PreviewClass * 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_preview_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_preview_getcaps;
77     video_formatenc_class->initialize = mix_videofmtenc_preview_initialize;
78     video_formatenc_class->encode = mix_videofmtenc_preview_encode;
79     video_formatenc_class->flush = mix_videofmtenc_preview_flush;
80     video_formatenc_class->eos = mix_videofmtenc_preview_eos;
81     video_formatenc_class->deinitialize = mix_videofmtenc_preview_deinitialize;
82 }
83 
84 MixVideoFormatEnc_Preview *
mix_videoformatenc_preview_new(void)85 mix_videoformatenc_preview_new(void) {
86     MixVideoFormatEnc_Preview *ret =
87         g_object_new(MIX_TYPE_VIDEOFORMATENC_PREVIEW, NULL);
88 
89     return ret;
90 }
91 
mix_videoformatenc_preview_finalize(GObject * obj)92 void mix_videoformatenc_preview_finalize(GObject * obj) {
93     /* clean up here. */
94 
95     /*MixVideoFormatEnc_Preview *mix = MIX_VIDEOFORMATENC_PREVIEW(obj); */
96     GObjectClass *root_class = (GObjectClass *) parent_class;
97 
98     LOG_V( "\n");
99 
100     /* Chain up parent */
101     if (root_class->finalize) {
102         root_class->finalize(obj);
103     }
104 }
105 
106 MixVideoFormatEnc_Preview *
mix_videoformatenc_preview_ref(MixVideoFormatEnc_Preview * mix)107 mix_videoformatenc_preview_ref(MixVideoFormatEnc_Preview * mix) {
108     return (MixVideoFormatEnc_Preview *) g_object_ref(G_OBJECT(mix));
109 }
110 
111 /*Preview vmethods implementation */
mix_videofmtenc_preview_getcaps(MixVideoFormatEnc * mix,GString * msg)112 MIX_RESULT mix_videofmtenc_preview_getcaps(MixVideoFormatEnc *mix, GString *msg) {
113 
114     /* TODO: add codes for Preview format */
115 
116     /* TODO: decide if we need to chainup parent method.
117      * if we do, the following is the code:
118      */
119 
120     LOG_V( "mix_videofmtenc_preview_getcaps\n");
121 
122     if (mix == NULL) {
123         LOG_E( "mix == NULL\n");
124         return MIX_RESULT_NULL_PTR;
125     }
126 
127 
128     if (parent_class->getcaps) {
129         return parent_class->getcaps(mix, msg);
130     }
131     return MIX_RESULT_SUCCESS;
132 }
133 
mix_videofmtenc_preview_initialize(MixVideoFormatEnc * mix,MixVideoConfigParamsEnc * config_params_enc,MixFrameManager * frame_mgr,MixBufferPool * input_buf_pool,MixSurfacePool ** surface_pool,VADisplay va_display)134 MIX_RESULT mix_videofmtenc_preview_initialize(MixVideoFormatEnc *mix,
135         MixVideoConfigParamsEnc * config_params_enc,
136         MixFrameManager * frame_mgr,
137         MixBufferPool * input_buf_pool,
138         MixSurfacePool ** surface_pool,
139         VADisplay va_display ) {
140 
141     MIX_RESULT ret = MIX_RESULT_SUCCESS;
142     MixVideoFormatEnc *parent = NULL;
143     MixVideoConfigParamsEncPreview * config_params_enc_preview;
144 
145     VAStatus va_status = VA_STATUS_SUCCESS;
146     VASurfaceID * surfaces;
147 
148     gint va_max_num_profiles, va_max_num_entrypoints, va_max_num_attribs;
149     gint va_num_profiles,  va_num_entrypoints;
150 
151     VAProfile *va_profiles = NULL;
152     VAEntrypoint *va_entrypoints = NULL;
153     VAConfigAttrib va_attrib[2];
154     guint index;
155 
156 
157     /*frame_mgr and input_buf_pool is reservered for future use*/
158 
159     if (mix == NULL || config_params_enc == NULL || va_display == NULL) {
160         LOG_E(
161                 "mix == NULL || config_params_enc == NULL || va_display == NULL\n");
162         return MIX_RESULT_NULL_PTR;
163     }
164 
165     LOG_V( "begin\n");
166 
167 
168     //TODO additional parameter checking
169 
170     /* Chainup parent method. */
171 #if 1
172     if (parent_class->initialize) {
173         ret = parent_class->initialize(mix, config_params_enc,
174                 frame_mgr, input_buf_pool, surface_pool,
175                 va_display);
176     }
177 
178     if (ret != MIX_RESULT_SUCCESS)
179     {
180         return ret;
181     }
182 
183 #endif //disable it currently
184 
185     if (MIX_IS_VIDEOFORMATENC_PREVIEW(mix))
186     {
187         parent = MIX_VIDEOFORMATENC(&(mix->parent));
188         MixVideoFormatEnc_Preview *self = MIX_VIDEOFORMATENC_PREVIEW(mix);
189 
190         if (MIX_IS_VIDEOCONFIGPARAMSENC_PREVIEW (config_params_enc)) {
191             config_params_enc_preview =
192                 MIX_VIDEOCONFIGPARAMSENC_PREVIEW (config_params_enc);
193         } else {
194             LOG_V(
195                     "mix_videofmtenc_preview_initialize:  no preview config params found\n");
196             return MIX_RESULT_FAIL;
197         }
198 
199         g_mutex_lock(parent->objectlock);
200 
201 
202         LOG_V(
203                 "Get properities from params done\n");
204 
205 
206     	//display = XOpenDisplay(NULL);
207      	//va_display = vaGetDisplay (videoencobj->display);
208 
209         parent->va_display = va_display;
210 
211         LOG_V( "Get Display\n");
212         LOG_I( "Display = 0x%08x\n",
213                 (guint)va_display);
214 
215         //va_status = vaInitialize(va_display, &va_major_ver, &va_minor_ver);
216         //g_print ("vaInitialize va_status = %d\n", va_status);
217 
218 
219 #if 0
220         /* query the vender information, can ignore*/
221         va_vendor = vaQueryVendorString (va_display);
222         LOG_I( "Vendor = %s\n",
223                 va_vendor);
224 #endif
225 
226         /*get the max number for profiles/entrypoints/attribs*/
227         va_max_num_profiles = vaMaxNumProfiles(va_display);
228         LOG_I( "va_max_num_profiles = %d\n",
229                 va_max_num_profiles);
230 
231         va_max_num_entrypoints = vaMaxNumEntrypoints(va_display);
232         LOG_I( "va_max_num_entrypoints = %d\n",
233                 va_max_num_entrypoints);
234 
235         va_max_num_attribs = vaMaxNumConfigAttributes(va_display);
236         LOG_I( "va_max_num_attribs = %d\n",
237                 va_max_num_attribs);
238 
239         va_profiles = g_malloc(sizeof(VAProfile)*va_max_num_profiles);
240         va_entrypoints = g_malloc(sizeof(VAEntrypoint)*va_max_num_entrypoints);
241 
242         if (va_profiles == NULL || va_entrypoints ==NULL)
243         {
244             LOG_E(
245                     "!va_profiles || !va_entrypoints\n");
246             g_mutex_unlock(parent->objectlock);
247             return MIX_RESULT_NO_MEMORY;
248         }
249 
250         LOG_I(
251                 "va_profiles = 0x%08x\n", (guint)va_profiles);
252 
253         LOG_V( "vaQueryConfigProfiles\n");
254 
255 
256         va_status = vaQueryConfigProfiles (va_display, va_profiles, &va_num_profiles);
257 
258         if (va_status != VA_STATUS_SUCCESS)
259         {
260             LOG_E(
261                     "Failed to call vaQueryConfigProfiles\n");
262             g_free(va_profiles);
263             g_free (va_entrypoints);
264             g_mutex_unlock(parent->objectlock);
265             return MIX_RESULT_FAIL;
266         }
267 
268         LOG_V( "vaQueryConfigProfiles Done\n");
269 
270 
271 
272         /*check whether profile is supported*/
273         for(index= 0; index < va_num_profiles; index++) {
274             if(parent->va_profile == va_profiles[index])
275                 break;
276         }
277 
278         if(index == va_num_profiles)
279         {
280             LOG_E( "Profile not supported\n");
281             g_free(va_profiles);
282             g_free (va_entrypoints);
283             g_mutex_unlock(parent->objectlock);
284             return MIX_RESULT_FAIL;  //Todo, add error handling here
285         }
286 
287         LOG_V( "vaQueryConfigEntrypoints\n");
288 
289 
290         /*Check entry point*/
291         va_status = vaQueryConfigEntrypoints(va_display,
292                 parent->va_profile,
293                 va_entrypoints, &va_num_entrypoints);
294 
295         if (va_status != VA_STATUS_SUCCESS)
296         {
297             LOG_E(
298                     "Failed to call vaQueryConfigEntrypoints\n");
299             g_free(va_profiles);
300             g_free (va_entrypoints);
301             g_mutex_unlock(parent->objectlock);
302             return MIX_RESULT_FAIL;
303         }
304 
305         for (index = 0; index < va_num_entrypoints; index ++) {
306             if (va_entrypoints[index] == VAEntrypointEncSlice) {
307                 break;
308             }
309         }
310 
311         if (index == va_num_entrypoints) {
312             LOG_E( "Entrypoint not found\n");
313             g_free(va_profiles);
314             g_free (va_entrypoints);
315             g_mutex_unlock(parent->objectlock);
316             return MIX_RESULT_FAIL;  //Todo, add error handling here
317         }
318 
319 
320         /*free profiles and entrypoints*/
321         g_free(va_profiles);
322         g_free (va_entrypoints);
323 
324         va_attrib[0].type = VAConfigAttribRTFormat;
325         va_attrib[1].type = VAConfigAttribRateControl;
326 
327         LOG_V( "vaGetConfigAttributes\n");
328 
329         va_status = vaGetConfigAttributes(va_display, parent->va_profile,
330                 parent->va_entrypoint,
331                 &va_attrib[0], 2);
332 
333         if (va_status != VA_STATUS_SUCCESS)
334         {
335             LOG_E(
336                     "Failed to call vaGetConfigAttributes\n");
337             g_mutex_unlock(parent->objectlock);
338             return MIX_RESULT_FAIL;
339         }
340 
341         if ((va_attrib[0].value & parent->va_format) == 0) {
342             LOG_E( "Matched format not found\n");
343             g_mutex_unlock(parent->objectlock);
344             return MIX_RESULT_FAIL;  //Todo, add error handling here
345         }
346 
347 
348         if ((va_attrib[1].value & parent->va_rcmode) == 0) {
349             LOG_E( "RC mode not found\n");
350             g_mutex_unlock(parent->objectlock);
351             return MIX_RESULT_FAIL;  //Todo, add error handling here
352         }
353 
354         va_attrib[0].value = parent->va_format; //VA_RT_FORMAT_YUV420;
355         va_attrib[1].value = parent->va_rcmode;
356 
357         LOG_V( "======VA Configuration======\n");
358 
359         LOG_I( "profile = %d\n",
360                 parent->va_profile);
361         LOG_I( "va_entrypoint = %d\n",
362                 parent->va_entrypoint);
363         LOG_I( "va_attrib[0].type = %d\n",
364                 va_attrib[0].type);
365         LOG_I( "va_attrib[1].type = %d\n",
366                 va_attrib[1].type);
367         LOG_I( "va_attrib[0].value (Format) = %d\n",
368                 va_attrib[0].value);
369         LOG_I( "va_attrib[1].value (RC mode) = %d\n",
370                 va_attrib[1].value);
371 
372         LOG_V( "vaCreateConfig\n");
373 
374         va_status = vaCreateConfig(va_display, parent->va_profile,
375                 parent->va_entrypoint,
376                 &va_attrib[0], 2, &(parent->va_config));
377 
378         if (va_status != VA_STATUS_SUCCESS)
379         {
380             LOG_E( "Failed vaCreateConfig\n");
381             g_mutex_unlock(parent->objectlock);
382             return MIX_RESULT_FAIL;
383         }
384 
385         /*TODO: compute the surface number*/
386         int numSurfaces;
387 
388         if (parent->share_buf_mode) {
389             numSurfaces = 2;
390         }
391         else {
392             numSurfaces = 8;
393             parent->ci_frame_num = 0;
394         }
395 
396         self->surface_num = numSurfaces + parent->ci_frame_num;
397 
398         surfaces = g_malloc(sizeof(VASurfaceID)*numSurfaces);
399 
400         if (surfaces == NULL)
401         {
402             LOG_E(
403                     "Failed allocate surface\n");
404             g_mutex_unlock(parent->objectlock);
405             return MIX_RESULT_NO_MEMORY;
406         }
407 
408         LOG_V( "vaCreateSurfaces\n");
409 
410         va_status = vaCreateSurfaces(va_display, parent->picture_width,
411                 parent->picture_height, parent->va_format,
412                 numSurfaces, surfaces);
413         //TODO check vret and return fail if needed
414 
415         if (va_status != VA_STATUS_SUCCESS)
416         {
417             LOG_E(
418                     "Failed vaCreateSurfaces\n");
419             g_mutex_unlock(parent->objectlock);
420             return MIX_RESULT_FAIL;
421         }
422 
423         if (parent->share_buf_mode) {
424 
425             LOG_V(
426                     "We are in share buffer mode!\n");
427             self->ci_shared_surfaces =
428                 g_malloc(sizeof(VASurfaceID) * parent->ci_frame_num);
429 
430             if (self->ci_shared_surfaces == NULL)
431             {
432                 LOG_E(
433                         "Failed allocate shared surface\n");
434                 g_mutex_unlock(parent->objectlock);
435                 return MIX_RESULT_NO_MEMORY;
436             }
437 
438             guint index;
439             for(index = 0; index < parent->ci_frame_num; index++) {
440 
441                 LOG_I( "ci_frame_id = %lu\n",
442                         parent->ci_frame_id[index]);
443 
444                 LOG_V(
445                         "vaCreateSurfaceFromCIFrame\n");
446 
447                 va_status = vaCreateSurfaceFromCIFrame(va_display,
448                         (gulong) (parent->ci_frame_id[index]),
449                         &self->ci_shared_surfaces[index]);
450                 if (va_status != VA_STATUS_SUCCESS)
451                 {
452                     LOG_E(
453                             "Failed to vaCreateSurfaceFromCIFrame\n");
454                     g_mutex_unlock(parent->objectlock);
455                     return MIX_RESULT_FAIL;
456                 }
457             }
458 
459             LOG_V(
460                     "vaCreateSurfaceFromCIFrame Done\n");
461 
462         }// if (parent->share_buf_mode)
463 
464         self->surfaces = g_malloc(sizeof(VASurfaceID) * self->surface_num);
465 
466         if (self->surfaces == NULL)
467         {
468             LOG_E(
469                     "Failed allocate private surface\n");
470             g_free (surfaces);
471             g_mutex_unlock(parent->objectlock);
472             return MIX_RESULT_NO_MEMORY;
473         }
474 
475         if (parent->share_buf_mode) {
476             /*shared surfaces should be put in pool first,
477              * because we will get it accoring to CI index*/
478             for(index = 0; index < parent->ci_frame_num; index++)
479                 self->surfaces[index] = self->ci_shared_surfaces[index];
480         }
481 
482         for(index = 0; index < numSurfaces; index++) {
483             self->surfaces[index + parent->ci_frame_num] = surfaces[index];
484         }
485 
486         LOG_V( "assign surface Done\n");
487         LOG_I( "Created %d libva surfaces\n",
488                 numSurfaces + parent->ci_frame_num);
489 
490 #if 0  //current put this in gst
491         images = g_malloc(sizeof(VAImage)*numSurfaces);
492         if (images == NULL)
493         {
494             g_mutex_unlock(parent->objectlock);
495             return MIX_RESULT_FAIL;
496         }
497 
498         for (index = 0; index < numSurfaces; index++) {
499             //Derive an VAImage from an existing surface.
500             //The image buffer can then be mapped/unmapped for CPU access
501             va_status = vaDeriveImage(va_display, surfaces[index],
502                     &images[index]);
503         }
504 #endif
505 
506         LOG_V( "mix_surfacepool_new\n");
507 
508         parent->surfacepool = mix_surfacepool_new();
509         if (surface_pool)
510             *surface_pool = parent->surfacepool;
511         //which is useful to check before encode
512 
513         if (parent->surfacepool == NULL)
514         {
515             LOG_E(
516                     "Failed to mix_surfacepool_new\n");
517             g_free (surfaces);
518             g_mutex_unlock(parent->objectlock);
519             return MIX_RESULT_FAIL;
520         }
521 
522         LOG_V(
523                 "mix_surfacepool_initialize\n");
524 
525         ret = mix_surfacepool_initialize(parent->surfacepool,
526                 self->surfaces, parent->ci_frame_num + numSurfaces);
527 
528         switch (ret)
529         {
530             case MIX_RESULT_SUCCESS:
531                 break;
532             case MIX_RESULT_ALREADY_INIT:
533                 //TODO cleanup and/or retry
534                 g_free (surfaces);
535                 g_mutex_unlock(parent->objectlock);
536                 return MIX_RESULT_FAIL;
537             default:
538                 break;
539         }
540 
541 
542         //Initialize and save the VA context ID
543         LOG_V( "vaCreateContext\n");
544 
545         va_status = vaCreateContext(va_display, parent->va_config,
546                 parent->picture_width, parent->picture_height,
547                 0, self->surfaces, parent->ci_frame_num + numSurfaces,
548                 &(parent->va_context));
549 
550         LOG_I(
551                 "Created libva context width %d, height %d\n",
552                 parent->picture_width, parent->picture_height);
553 
554         if (va_status != VA_STATUS_SUCCESS)
555         {
556             LOG_E(
557                     "Failed to vaCreateContext\n");
558             LOG_I( "va_status = %d\n",
559                     (guint)va_status);
560             g_free (surfaces);
561             g_mutex_unlock(parent->objectlock);
562             return MIX_RESULT_FAIL;
563         }
564 
565         self->coded_buf_size = 4;
566 
567         /*Create coded buffer for output*/
568         va_status = vaCreateBuffer (va_display, parent->va_context,
569                 VAEncCodedBufferType,
570                 self->coded_buf_size,  //
571                 1, NULL,
572                 &self->coded_buf);
573 
574         if (va_status != VA_STATUS_SUCCESS)
575         {
576             LOG_E(
577                     "Failed to vaCreateBuffer: VAEncCodedBufferType\n");
578             g_free (surfaces);
579             g_mutex_unlock(parent->objectlock);
580             return MIX_RESULT_FAIL;
581         }
582 
583 #ifdef SHOW_SRC
584         Display * display = XOpenDisplay (NULL);
585 
586         LOG_I( "display = 0x%08x\n",
587                 (guint) display);
588         win = XCreateSimpleWindow(display, RootWindow(display, 0), 0, 0,
589                 parent->picture_width,  parent->picture_height, 0, 0,
590                 WhitePixel(display, 0));
591         XMapWindow(display, win);
592         XSelectInput(display, win, KeyPressMask | StructureNotifyMask);
593 
594         XSync(display, False);
595         LOG_I( "va_display = 0x%08x\n",
596                 (guint) va_display);
597 
598 #endif /* SHOW_SRC */
599 
600         parent->initialized = TRUE;
601 
602         g_mutex_unlock(parent->objectlock);
603         g_free (surfaces);
604 
605     }
606     else
607     {
608         LOG_E(
609                 "not Preview video encode Object\n");
610         return MIX_RESULT_FAIL;
611 
612     }
613 
614     LOG_V( "end\n");
615 
616     return MIX_RESULT_SUCCESS;
617 }
618 
mix_videofmtenc_preview_encode(MixVideoFormatEnc * mix,MixBuffer * bufin[],gint bufincnt,MixIOVec * iovout[],gint iovoutcnt,MixVideoEncodeParams * encode_params)619 MIX_RESULT mix_videofmtenc_preview_encode(MixVideoFormatEnc *mix, MixBuffer * bufin[],
620         gint bufincnt, MixIOVec * iovout[], gint iovoutcnt,
621         MixVideoEncodeParams * encode_params) {
622 
623     MIX_RESULT ret = MIX_RESULT_SUCCESS;
624     MixVideoFormatEnc *parent = NULL;
625 
626     LOG_V( "Begin\n");
627 
628     /*currenly only support one input and output buffer*/
629     //TODO: params i
630 
631     if (bufincnt != 1 || iovoutcnt != 1) {
632         LOG_E(
633                 "buffer count not equel to 1\n");
634         LOG_E(
635                 "maybe some exception occurs\n");
636     }
637 
638     if (mix == NULL ||bufin[0] == NULL ||  iovout[0] == NULL) {
639         LOG_E(
640                 "!mix || !bufin[0] ||!iovout[0]\n");
641         return MIX_RESULT_NULL_PTR;
642     }
643 
644     //TODO: encode_params is reserved here for future usage.
645 
646     /* TODO: decide if we need to chainup parent method.
647      *      * * if we do, the following is the code:
648      * */
649 
650 #if 0
651     if (parent_class->encode) {
652         return parent_class->encode(mix, bufin, bufincnt, iovout,
653                 iovoutcnt, encode_params);
654     }
655 #endif
656 
657     if (MIX_IS_VIDEOFORMATENC_PREVIEW(mix))
658     {
659 
660         parent = MIX_VIDEOFORMATENC(&(mix->parent));
661         MixVideoFormatEnc_Preview *self = MIX_VIDEOFORMATENC_PREVIEW (mix);
662 
663         LOG_V( "Locking\n");
664         g_mutex_lock(parent->objectlock);
665 
666 
667         //TODO: also we could move some encode Preparation work to here
668 
669         LOG_V(
670                 "mix_videofmtenc_preview_process_encode\n");
671 
672         ret = mix_videofmtenc_preview_process_encode (self,
673                 bufin[0], iovout[0]);
674         if (ret != MIX_RESULT_SUCCESS)
675         {
676             LOG_E(
677                     "Failed mix_videofmtenc_preview_process_encode\n");
678             return MIX_RESULT_FAIL;
679         }
680 
681 
682         LOG_V( "UnLocking\n");
683 
684         g_mutex_unlock(parent->objectlock);
685     }
686     else
687     {
688         LOG_E(
689                 "not Preview video encode Object\n");
690         return MIX_RESULT_FAIL;
691     }
692 
693     LOG_V( "end\n");
694 
695     return MIX_RESULT_SUCCESS;
696 }
697 
mix_videofmtenc_preview_flush(MixVideoFormatEnc * mix)698 MIX_RESULT mix_videofmtenc_preview_flush(MixVideoFormatEnc *mix) {
699 
700     //MIX_RESULT ret = MIX_RESULT_SUCCESS;
701 
702     LOG_V( "Begin\n");
703 
704     if (mix == NULL) {
705         LOG_E( "mix == NULL\n");
706         return MIX_RESULT_NULL_PTR;
707     }
708 
709 
710     /*not chain to parent flush func*/
711 #if 0
712     if (parent_class->flush) {
713         return parent_class->flush(mix, msg);
714     }
715 #endif
716 
717     MixVideoFormatEnc_Preview *self = MIX_VIDEOFORMATENC_PREVIEW(mix);
718 
719     g_mutex_lock(mix->objectlock);
720 
721 #if 0
722     /*unref the current source surface*/
723     if (self->cur_fame != NULL)
724     {
725         mix_videoframe_unref (self->cur_fame);
726         self->cur_fame = NULL;
727     }
728 #endif
729 
730     /*unref the reconstructed surface*/
731     if (self->rec_fame != NULL)
732     {
733         mix_videoframe_unref (self->rec_fame);
734         self->rec_fame = NULL;
735     }
736 
737     /*unref the reference surface*/
738     if (self->ref_fame != NULL)
739     {
740         mix_videoframe_unref (self->ref_fame);
741         self->ref_fame = NULL;
742     }
743 
744     /*reset the properities*/
745     self->encoded_frames = 0;
746     self->pic_skipped = FALSE;
747     self->is_intra = TRUE;
748 
749     g_mutex_unlock(mix->objectlock);
750 
751     LOG_V( "end\n");
752 
753     return MIX_RESULT_SUCCESS;
754 }
755 
mix_videofmtenc_preview_eos(MixVideoFormatEnc * mix)756 MIX_RESULT mix_videofmtenc_preview_eos(MixVideoFormatEnc *mix) {
757 
758     /* TODO: add codes for preview */
759 
760     /* TODO: decide if we need to chainup parent method.
761      * if we do, the following is the code:
762      */
763 
764     LOG_V( "\n");
765 
766     if (mix == NULL) {
767         LOG_E( "mix == NULL\n");
768         return MIX_RESULT_NULL_PTR;
769     }
770 
771     if (parent_class->eos) {
772         return parent_class->eos(mix);
773     }
774     return MIX_RESULT_SUCCESS;
775 }
776 
mix_videofmtenc_preview_deinitialize(MixVideoFormatEnc * mix)777 MIX_RESULT mix_videofmtenc_preview_deinitialize(MixVideoFormatEnc *mix) {
778 
779     MixVideoFormatEnc *parent = NULL;
780     VAStatus va_status;
781 
782     LOG_V( "Begin\n");
783 
784     if (mix == NULL) {
785         LOG_E( "mix == NULL\n");
786         return MIX_RESULT_NULL_PTR;
787     }
788 
789     parent = MIX_VIDEOFORMATENC(&(mix->parent));
790     MixVideoFormatEnc_Preview *self = MIX_VIDEOFORMATENC_PREVIEW(mix);
791 
792     LOG_V( "Release frames\n");
793 
794     g_mutex_lock(parent->objectlock);
795 
796 #if 0
797     /*unref the current source surface*/
798     if (self->cur_fame != NULL)
799     {
800         mix_videoframe_unref (self->cur_fame);
801         self->cur_fame = NULL;
802     }
803 #endif
804 
805     /*unref the reconstructed surface*/
806     if (self->rec_fame != NULL)
807     {
808         mix_videoframe_unref (self->rec_fame);
809         self->rec_fame = NULL;
810     }
811 
812     /*unref the reference surface*/
813     if (self->ref_fame != NULL)
814     {
815         mix_videoframe_unref (self->ref_fame);
816         self->ref_fame = NULL;
817     }
818 
819     LOG_V( "Release surfaces\n");
820 
821     if (self->ci_shared_surfaces)
822     {
823         g_free (self->ci_shared_surfaces);
824         self->ci_shared_surfaces = NULL;
825     }
826 
827     if (self->surfaces)
828     {
829         g_free (self->surfaces);
830         self->surfaces = NULL;
831     }
832 
833     LOG_V( "vaDestroyContext\n");
834 
835     va_status = vaDestroyContext (parent->va_display, parent->va_context);
836     if (va_status != VA_STATUS_SUCCESS)
837     {
838         LOG_E(
839                 "Failed vaDestroyContext\n");
840         g_mutex_unlock(parent->objectlock);
841         return MIX_RESULT_FAIL;
842     }
843 
844     LOG_V( "vaDestroyConfig\n");
845 
846     va_status = vaDestroyConfig (parent->va_display, parent->va_config);
847     if (va_status != VA_STATUS_SUCCESS)
848     {
849         LOG_E(
850                 "Failed vaDestroyConfig\n");
851         g_mutex_unlock(parent->objectlock);
852         return MIX_RESULT_FAIL;
853     }
854 
855     parent->initialized = TRUE;
856 
857     g_mutex_unlock(parent->objectlock);
858 
859 #if 1
860     if (parent_class->deinitialize) {
861         return parent_class->deinitialize(mix);
862     }
863 #endif
864 
865     //Most stuff is cleaned up in parent_class->finalize()
866 
867     LOG_V( "end\n");
868 
869     return MIX_RESULT_SUCCESS;
870 }
871 
872 
mix_videofmtenc_preview_process_encode(MixVideoFormatEnc_Preview * mix,MixBuffer * bufin,MixIOVec * iovout)873 MIX_RESULT mix_videofmtenc_preview_process_encode (MixVideoFormatEnc_Preview *mix,
874         MixBuffer * bufin, MixIOVec * iovout)
875 {
876 
877     MIX_RESULT ret = MIX_RESULT_SUCCESS;
878     VAStatus va_status = VA_STATUS_SUCCESS;
879     VADisplay va_display = NULL;
880     VAContextID va_context;
881     gulong surface = 0;
882     guint16 width, height;
883 
884     //MixVideoFrame *  tmp_fame;
885     //guint8 *buf;
886 
887     if ((mix == NULL) || (bufin == NULL) || (iovout == NULL)) {
888         LOG_E(
889                 "mix == NUL) || bufin == NULL || iovout == NULL\n");
890         return MIX_RESULT_NULL_PTR;
891     }
892 
893     LOG_V( "Begin\n");
894 
895     if (MIX_IS_VIDEOFORMATENC_PREVIEW(mix))
896     {
897 
898         MixVideoFormatEnc *parent = MIX_VIDEOFORMATENC(&(mix->parent));
899 
900         va_display = parent->va_display;
901         va_context = parent->va_context;
902         width = parent->picture_width;
903         height = parent->picture_height;
904 
905 
906         LOG_I( "encoded_frames = %d\n",
907                 mix->encoded_frames);
908         LOG_I( "is_intra = %d\n",
909                 mix->is_intra);
910         LOG_I( "ci_frame_id = 0x%08x\n",
911                 (guint) parent->ci_frame_id);
912 
913         LOG_V(
914                 "Get Surface from the pool\n");
915 
916         /*current we use one surface for source data,
917          * one for reference and one for reconstructed*/
918         /*TODO, could be refine here*/
919 
920         if (!parent->share_buf_mode) {
921             LOG_V(
922                     "We are NOT in share buffer mode\n");
923 
924             if (mix->ref_fame == NULL)
925             {
926                 ret = mix_surfacepool_get(parent->surfacepool, &mix->ref_fame);
927                 if (ret != MIX_RESULT_SUCCESS)  //#ifdef SLEEP_SURFACE not used
928                 {
929                     LOG_E(
930                             "Failed to mix_surfacepool_get\n");
931                     return MIX_RESULT_FAIL;
932                 }
933             }
934 
935             if (mix->rec_fame == NULL)
936             {
937                 ret = mix_surfacepool_get(parent->surfacepool, &mix->rec_fame);
938                 if (ret != MIX_RESULT_SUCCESS)
939                 {
940                     LOG_E(
941                             "Failed to mix_surfacepool_get\n");
942                     return MIX_RESULT_FAIL;
943                 }
944             }
945 
946             if (parent->need_display) {
947                 mix->cur_fame = NULL;
948             }
949 
950             if (mix->cur_fame == NULL)
951             {
952                 ret = mix_surfacepool_get(parent->surfacepool, &mix->cur_fame);
953                 if (ret != MIX_RESULT_SUCCESS)
954                 {
955                     LOG_E(
956                             "Failed to mix_surfacepool_get\n");
957                     return MIX_RESULT_FAIL;
958                 }
959             }
960 
961             LOG_V( "Get Surface Done\n");
962 
963 
964             VAImage src_image;
965             guint8 *pvbuf;
966             guint8 *dst_y;
967             guint8 *dst_uv;
968             int i,j;
969 
970             LOG_V(
971                     "map source data to surface\n");
972 
973             ret = mix_videoframe_get_frame_id(mix->cur_fame, &surface);
974             if (ret != MIX_RESULT_SUCCESS)
975             {
976                 LOG_E(
977                         "Failed to mix_videoframe_get_frame_id\n");
978                 return MIX_RESULT_FAIL;
979             }
980 
981 
982             LOG_I(
983                     "surface id = 0x%08x\n", (guint) surface);
984 
985             va_status = vaDeriveImage(va_display, surface, &src_image);
986             //need to destroy
987 
988             if (va_status != VA_STATUS_SUCCESS)
989             {
990                 LOG_E(
991                         "Failed to vaDeriveImage\n");
992                 return MIX_RESULT_FAIL;
993             }
994 
995             VAImage *image = &src_image;
996 
997             LOG_V( "vaDeriveImage Done\n");
998 
999 
1000             va_status = vaMapBuffer (va_display, image->buf, (void **)&pvbuf);
1001             if (va_status != VA_STATUS_SUCCESS)
1002             {
1003                 LOG_E( "Failed to vaMapBuffer\n");
1004                 return MIX_RESULT_FAIL;
1005             }
1006 
1007             LOG_V(
1008                     "vaImage information\n");
1009             LOG_I(
1010                     "image->pitches[0] = %d\n", image->pitches[0]);
1011             LOG_I(
1012                     "image->pitches[1] = %d\n", image->pitches[1]);
1013             LOG_I(
1014                     "image->offsets[0] = %d\n", image->offsets[0]);
1015             LOG_I(
1016                     "image->offsets[1] = %d\n", image->offsets[1]);
1017             LOG_I(
1018                     "image->num_planes = %d\n", image->num_planes);
1019             LOG_I(
1020                     "image->width = %d\n", image->width);
1021             LOG_I(
1022                     "image->height = %d\n", image->height);
1023 
1024             LOG_I(
1025                     "input buf size = %d\n", bufin->size);
1026 
1027             guint8 *inbuf = bufin->data;
1028 
1029             /*need to convert YUV420 to NV12*/
1030             dst_y = pvbuf +image->offsets[0];
1031 
1032             for (i = 0; i < height; i ++) {
1033                 memcpy (dst_y, inbuf + i * width, width);
1034                 dst_y += image->pitches[0];
1035             }
1036 
1037             dst_uv = pvbuf + image->offsets[1];
1038 
1039             for (i = 0; i < height / 2; i ++) {
1040                 for (j = 0; j < width; j+=2) {
1041                     dst_uv [j] = inbuf [width * height + i * width / 2 + j / 2];
1042                     dst_uv [j + 1] =
1043                         inbuf [width * height * 5 / 4 + i * width / 2 + j / 2];
1044                 }
1045                 dst_uv += image->pitches[1];
1046             }
1047 
1048             vaUnmapBuffer(va_display, image->buf);
1049             if (va_status != VA_STATUS_SUCCESS)
1050             {
1051                 LOG_E(
1052                         "Failed to vaUnmapBuffer\n");
1053                 return MIX_RESULT_FAIL;
1054             }
1055 
1056             va_status = vaDestroyImage(va_display, src_image.image_id);
1057             if (va_status != VA_STATUS_SUCCESS)
1058             {
1059                 LOG_E(
1060                         "Failed to vaDestroyImage\n");
1061                 return MIX_RESULT_FAIL;
1062             }
1063 
1064             LOG_V(
1065                     "Map source data to surface done\n");
1066 
1067         }
1068 
1069         else {//if (!parent->share_buf_mode)
1070 
1071             MixVideoFrame * frame = mix_videoframe_new();
1072 
1073             if (mix->ref_fame == NULL)
1074             {
1075                 ret = mix_videoframe_set_ci_frame_idx (frame, mix->surface_num - 1);
1076 
1077                 ret = mix_surfacepool_get_frame_with_ci_frameidx
1078                     (parent->surfacepool, &mix->ref_fame, frame);
1079                 if (ret != MIX_RESULT_SUCCESS)  //#ifdef SLEEP_SURFACE not used
1080                 {
1081                     LOG_E(
1082                             "get reference surface from pool failed\n");
1083                     return MIX_RESULT_FAIL;
1084                 }
1085             }
1086 
1087             if (mix->rec_fame == NULL)
1088             {
1089                 ret = mix_videoframe_set_ci_frame_idx (frame, mix->surface_num - 2);
1090 
1091                 ret = mix_surfacepool_get_frame_with_ci_frameidx
1092                     (parent->surfacepool, &mix->rec_fame, frame);
1093 
1094                 if (ret != MIX_RESULT_SUCCESS)
1095                 {
1096                     LOG_E(
1097                             "get recontructed surface from pool failed\n");
1098                     return MIX_RESULT_FAIL;
1099                 }
1100             }
1101 
1102             //mix_videoframe_unref (mix->cur_fame);
1103 
1104             if (parent->need_display) {
1105                 mix->cur_fame = NULL;
1106             }
1107 
1108             if (mix->cur_fame == NULL)
1109             {
1110                 guint ci_idx;
1111                 memcpy (&ci_idx, bufin->data, bufin->size);
1112 
1113                 LOG_I(
1114                         "surface_num = %d\n", mix->surface_num);
1115                 LOG_I(
1116                         "ci_frame_idx = %d\n", ci_idx);
1117 
1118                 if (ci_idx > mix->surface_num - 2) {
1119                     LOG_E(
1120                             "the CI frame idx is too bigger than CI frame number\n");
1121                     return MIX_RESULT_FAIL;
1122                 }
1123 
1124 
1125                 ret = mix_videoframe_set_ci_frame_idx (frame, ci_idx);
1126 
1127                 ret = mix_surfacepool_get_frame_with_ci_frameidx
1128                     (parent->surfacepool, &mix->cur_fame, frame);
1129 
1130                 if (ret != MIX_RESULT_SUCCESS)
1131                 {
1132                     LOG_E(
1133                             "get current working surface from pool failed\n");
1134                     return MIX_RESULT_FAIL;
1135                 }
1136             }
1137 
1138             ret = mix_videoframe_get_frame_id(mix->cur_fame, &surface);
1139 
1140         }
1141 
1142         LOG_V( "vaBeginPicture\n");
1143         LOG_I( "va_context = 0x%08x\n",(guint)va_context);
1144         LOG_I( "surface = 0x%08x\n",(guint)surface);
1145         LOG_I( "va_display = 0x%08x\n",(guint)va_display);
1146 
1147         iovout->data_size = 4;
1148         iovout->data = g_malloc (iovout->data_size);
1149         if (iovout->data == NULL) {
1150             return MIX_RESULT_NO_MEMORY;
1151         }
1152 
1153         memset (iovout->data, 0, iovout->data_size);
1154 
1155         iovout->buffer_size = iovout->data_size;
1156 
1157 
1158         if (parent->need_display) {
1159             ret = mix_framemanager_enqueue(parent->framemgr, mix->cur_fame);
1160             if (ret != MIX_RESULT_SUCCESS)
1161             {
1162                 LOG_E(
1163                         "Failed mix_framemanager_enqueue\n");
1164                 return MIX_RESULT_FAIL;
1165             }
1166         }
1167 
1168 
1169         if (!(parent->need_display)) {
1170             mix_videoframe_unref (mix->cur_fame);
1171             mix->cur_fame = NULL;
1172         }
1173 
1174         mix->encoded_frames ++;
1175     }
1176     else
1177     {
1178         LOG_E(
1179                 "not Preview video encode Object\n");
1180         return MIX_RESULT_FAIL;
1181     }
1182 
1183 
1184     LOG_V( "end\n");
1185 
1186     return MIX_RESULT_SUCCESS;
1187 }
1188