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
21Window 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 */
29static MixVideoFormatEncClass *parent_class = NULL;
30
31static 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 */
36G_DEFINE_TYPE (MixVideoFormatEnc_Preview, mix_videoformatenc_preview, MIX_TYPE_VIDEOFORMATENC);
37
38static 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
58static 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
84MixVideoFormatEnc_Preview *
85mix_videoformatenc_preview_new(void) {
86    MixVideoFormatEnc_Preview *ret =
87        g_object_new(MIX_TYPE_VIDEOFORMATENC_PREVIEW, NULL);
88
89    return ret;
90}
91
92void 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
106MixVideoFormatEnc_Preview *
107mix_videoformatenc_preview_ref(MixVideoFormatEnc_Preview * mix) {
108    return (MixVideoFormatEnc_Preview *) g_object_ref(G_OBJECT(mix));
109}
110
111/*Preview vmethods implementation */
112MIX_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
134MIX_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
619MIX_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
698MIX_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
756MIX_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
777MIX_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
873MIX_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