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
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_h264_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_H264, mix_videoformatenc_h264, MIX_TYPE_VIDEOFORMATENC);
37
38static 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
58static 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
85MixVideoFormatEnc_H264 *
86mix_videoformatenc_h264_new(void) {
87    MixVideoFormatEnc_H264 *ret =
88        g_object_new(MIX_TYPE_VIDEOFORMATENC_H264, NULL);
89
90    return ret;
91}
92
93void 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
107MixVideoFormatEnc_H264 *
108mix_videoformatenc_h264_ref(MixVideoFormatEnc_H264 * mix) {
109    return (MixVideoFormatEnc_H264 *) g_object_ref(G_OBJECT(mix));
110}
111
112/*H.264 vmethods implementation */
113MIX_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
135MIX_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
691MIX_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
771MIX_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
829MIX_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
850MIX_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
945MIX_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
1038MIX_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
1117MIX_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
1262MIX_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
1764MIX_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
1822MIX_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