OSDN Git Service

avcenc: Fix constraint flag
[android-x86/hardware-intel-common-libva.git] / test / encode / avcenc.c
1 /*
2  * Copyright (c) 2012 Intel Corporation. All Rights Reserved.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sub license, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the
13  * next paragraph) shall be included in all copies or substantial portions
14  * of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
19  * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
20  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24 /*
25  * Simple AVC encoder based on libVA.
26  *
27  * Usage:
28  * ./avcenc <width> <height> <input file> <output file> [qp]
29  */  
30
31 #include "sysdeps.h"
32 #include <stdio.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <getopt.h>
36 #include <unistd.h>
37
38 #include <sys/time.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <fcntl.h>
42 #include <assert.h>
43 #include <time.h>
44
45 #include <pthread.h>
46
47 #include <va/va.h>
48 #include <va/va_enc_h264.h>
49 #include "va_display.h"
50
51 #define NAL_REF_IDC_NONE        0
52 #define NAL_REF_IDC_LOW         1
53 #define NAL_REF_IDC_MEDIUM      2
54 #define NAL_REF_IDC_HIGH        3
55
56 #define NAL_NON_IDR             1
57 #define NAL_IDR                 5
58 #define NAL_SPS                 7
59 #define NAL_PPS                 8
60
61 #define SLICE_TYPE_P            0
62 #define SLICE_TYPE_B            1
63 #define SLICE_TYPE_I            2
64
65 #define ENTROPY_MODE_CAVLC      0
66 #define ENTROPY_MODE_CABAC      1
67
68 #define PROFILE_IDC_BASELINE    66
69 #define PROFILE_IDC_MAIN        77
70 #define PROFILE_IDC_HIGH        100
71
72 #define CHECK_VASTATUS(va_status,func)                                  \
73     if (va_status != VA_STATUS_SUCCESS) {                               \
74         fprintf(stderr,"%s:%s (%d) failed,exit\n", __func__, func, __LINE__); \
75         exit(1);                                                        \
76     }
77
78 static VADisplay va_dpy;
79
80 static int picture_width, picture_width_in_mbs;
81 static int picture_height, picture_height_in_mbs;
82 static int frame_size;
83 static unsigned char *newImageBuffer = 0;
84
85 static int qp_value = 26;
86
87 static int intra_period = 30;
88 static int pb_period = 5;
89 static int frame_bit_rate = -1;
90
91 #define MAX_SLICES      32
92
93 static int
94 build_packed_pic_buffer(unsigned char **header_buffer);
95
96 static int
97 build_packed_seq_buffer(unsigned char **header_buffer);
98
99 struct upload_thread_param
100 {
101     FILE *yuv_fp;
102     VASurfaceID surface_id;
103 };
104
105 static void 
106 upload_yuv_to_surface(FILE *yuv_fp, VASurfaceID surface_id);
107
108 static struct {
109     VAProfile profile;
110     int constraint_set_flag;
111     VAEncSequenceParameterBufferH264 seq_param;
112     VAEncPictureParameterBufferH264 pic_param;
113     VAEncSliceParameterBufferH264 slice_param[MAX_SLICES];
114     VAContextID context_id;
115     VAConfigID config_id;
116     VABufferID seq_param_buf_id;                /* Sequence level parameter */
117     VABufferID pic_param_buf_id;                /* Picture level parameter */
118     VABufferID slice_param_buf_id[MAX_SLICES];  /* Slice level parameter, multil slices */
119     VABufferID codedbuf_buf_id;                 /* Output buffer, compressed data */
120     VABufferID packed_seq_header_param_buf_id;
121     VABufferID packed_seq_buf_id;
122     VABufferID packed_pic_header_param_buf_id;
123     VABufferID packed_pic_buf_id;
124     VABufferID misc_parameter_hrd_buf_id;
125
126     int num_slices;
127     int codedbuf_i_size;
128     int codedbuf_pb_size;
129     int current_input_surface;
130     int rate_control_method;
131     struct upload_thread_param upload_thread_param;
132     pthread_t upload_thread_id;
133     int upload_thread_value;
134 } avcenc_context;
135
136 static void create_encode_pipe()
137 {
138     VAEntrypoint entrypoints[5];
139     int num_entrypoints,slice_entrypoint;
140     VAConfigAttrib attrib[2];
141     int major_ver, minor_ver;
142     VAStatus va_status;
143
144     va_dpy = va_open_display();
145     va_status = vaInitialize(va_dpy, &major_ver, &minor_ver);
146     CHECK_VASTATUS(va_status, "vaInitialize");
147
148     vaQueryConfigEntrypoints(va_dpy, avcenc_context.profile, entrypoints, 
149                              &num_entrypoints);
150
151     for (slice_entrypoint = 0; slice_entrypoint < num_entrypoints; slice_entrypoint++) {
152         if (entrypoints[slice_entrypoint] == VAEntrypointEncSlice)
153             break;
154     }
155
156     if (slice_entrypoint == num_entrypoints) {
157         /* not find Slice entry point */
158         assert(0);
159     }
160
161     /* find out the format for the render target, and rate control mode */
162     attrib[0].type = VAConfigAttribRTFormat;
163     attrib[1].type = VAConfigAttribRateControl;
164     vaGetConfigAttributes(va_dpy, avcenc_context.profile, VAEntrypointEncSlice,
165                           &attrib[0], 2);
166
167     if ((attrib[0].value & VA_RT_FORMAT_YUV420) == 0) {
168         /* not find desired YUV420 RT format */
169         assert(0);
170     }
171
172     if ((attrib[1].value & avcenc_context.rate_control_method) == 0) {
173         /* Can't find matched RC mode */
174         printf("Can't find the desired RC mode, exit\n");
175         assert(0);
176     }
177
178     attrib[0].value = VA_RT_FORMAT_YUV420; /* set to desired RT format */
179     attrib[1].value = avcenc_context.rate_control_method; /* set to desired RC mode */
180
181     va_status = vaCreateConfig(va_dpy, avcenc_context.profile, VAEntrypointEncSlice,
182                                &attrib[0], 2,&avcenc_context.config_id);
183     CHECK_VASTATUS(va_status, "vaCreateConfig");
184
185     /* Create a context for this decode pipe */
186     va_status = vaCreateContext(va_dpy, avcenc_context.config_id,
187                                 picture_width, picture_height,
188                                 VA_PROGRESSIVE, 
189                                 0, 0,
190                                 &avcenc_context.context_id);
191     CHECK_VASTATUS(va_status, "vaCreateContext");
192 }
193
194 static void destory_encode_pipe()
195 {
196     vaDestroyContext(va_dpy,avcenc_context.context_id);
197     vaDestroyConfig(va_dpy,avcenc_context.config_id);
198     vaTerminate(va_dpy);
199     va_close_display(va_dpy);
200 }
201
202 /***************************************************
203  *
204  *  The encode pipe resource define 
205  *
206  ***************************************************/
207 #define SID_INPUT_PICTURE_0                     0
208 #define SID_INPUT_PICTURE_1                     1
209 #define SID_REFERENCE_PICTURE_L0                2
210 #define SID_REFERENCE_PICTURE_L1                3
211 #define SID_RECON_PICTURE                       4
212 #define SID_NUMBER                              SID_RECON_PICTURE + 1
213 static  VASurfaceID surface_ids[SID_NUMBER];
214
215 static int frame_number;
216 static int enc_frame_number;
217
218 /***************************************************/
219
220 static void *
221 upload_thread_function(void *data)
222 {
223     struct upload_thread_param *param = data;
224
225     upload_yuv_to_surface(param->yuv_fp, param->surface_id);
226
227     return NULL;
228 }
229
230 static void alloc_encode_resource(FILE *yuv_fp)
231 {
232     VAStatus va_status;
233
234     // Create surface
235     va_status = vaCreateSurfaces(va_dpy, picture_width, picture_height,
236                                  VA_RT_FORMAT_YUV420, SID_NUMBER, &surface_ids[0]);
237     CHECK_VASTATUS(va_status, "vaCreateSurfaces");
238
239     newImageBuffer = (unsigned char *)malloc(frame_size);
240
241     /* firstly upload YUV data to SID_INPUT_PICTURE_1 */
242     avcenc_context.upload_thread_param.yuv_fp = yuv_fp;
243     avcenc_context.upload_thread_param.surface_id = surface_ids[SID_INPUT_PICTURE_1];
244
245     avcenc_context.upload_thread_value = pthread_create(&avcenc_context.upload_thread_id,
246                                                         NULL,
247                                                         upload_thread_function, 
248                                                         (void*)&avcenc_context.upload_thread_param);
249 }
250
251 static void release_encode_resource()
252 {
253     pthread_join(avcenc_context.upload_thread_id, NULL);
254     free(newImageBuffer);
255
256     // Release all the surfaces resource
257     vaDestroySurfaces(va_dpy, &surface_ids[0], SID_NUMBER);     
258 }
259
260 static void avcenc_update_picture_parameter(int slice_type, int frame_num, int display_num, int is_idr)
261 {
262     VAEncPictureParameterBufferH264 *pic_param;
263     VAStatus va_status;
264
265     // Picture level
266     pic_param = &avcenc_context.pic_param;
267     pic_param->CurrPic.picture_id = surface_ids[SID_RECON_PICTURE];
268     pic_param->CurrPic.TopFieldOrderCnt = display_num * 2;
269     pic_param->ReferenceFrames[0].picture_id = surface_ids[SID_REFERENCE_PICTURE_L0];
270     pic_param->ReferenceFrames[1].picture_id = surface_ids[SID_REFERENCE_PICTURE_L1];
271     pic_param->ReferenceFrames[2].picture_id = VA_INVALID_ID;
272     assert(avcenc_context.codedbuf_buf_id != VA_INVALID_ID);
273     pic_param->coded_buf = avcenc_context.codedbuf_buf_id;
274     pic_param->frame_num = frame_num;
275     pic_param->pic_fields.bits.idr_pic_flag = !!is_idr;
276     pic_param->pic_fields.bits.reference_pic_flag = (slice_type != SLICE_TYPE_B);
277
278     va_status = vaCreateBuffer(va_dpy,
279                                avcenc_context.context_id,
280                                VAEncPictureParameterBufferType,
281                                sizeof(*pic_param), 1, pic_param,
282                                &avcenc_context.pic_param_buf_id);
283     CHECK_VASTATUS(va_status,"vaCreateBuffer");
284 }
285
286 #ifndef VA_FOURCC_I420
287 #define VA_FOURCC_I420          0x30323449
288 #endif
289
290 static void upload_yuv_to_surface(FILE *yuv_fp, VASurfaceID surface_id)
291 {
292     VAImage surface_image;
293     VAStatus va_status;
294     void *surface_p = NULL;
295     unsigned char *y_src, *u_src, *v_src;
296     unsigned char *y_dst, *u_dst, *v_dst;
297     int y_size = picture_width * picture_height;
298     int u_size = (picture_width >> 1) * (picture_height >> 1);
299     int row, col;
300     size_t n_items;
301
302     do {
303         n_items = fread(newImageBuffer, frame_size, 1, yuv_fp);
304     } while (n_items != 1);
305
306     va_status = vaDeriveImage(va_dpy, surface_id, &surface_image);
307     CHECK_VASTATUS(va_status,"vaDeriveImage");
308
309     vaMapBuffer(va_dpy, surface_image.buf, &surface_p);
310     assert(VA_STATUS_SUCCESS == va_status);
311         
312     y_src = newImageBuffer;
313     u_src = newImageBuffer + y_size; /* UV offset for NV12 */
314     v_src = newImageBuffer + y_size + u_size;
315
316     y_dst = surface_p + surface_image.offsets[0];
317     u_dst = surface_p + surface_image.offsets[1]; /* UV offset for NV12 */
318     v_dst = surface_p + surface_image.offsets[2];
319
320     /* Y plane */
321     for (row = 0; row < surface_image.height; row++) {
322         memcpy(y_dst, y_src, surface_image.width);
323         y_dst += surface_image.pitches[0];
324         y_src += picture_width;
325     }
326
327     if (surface_image.format.fourcc == VA_FOURCC_NV12) { /* UV plane */
328         for (row = 0; row < surface_image.height / 2; row++) {
329             for (col = 0; col < surface_image.width / 2; col++) {
330                 u_dst[col * 2] = u_src[col];
331                 u_dst[col * 2 + 1] = v_src[col];
332             }
333
334             u_dst += surface_image.pitches[1];
335             u_src += (picture_width / 2);
336             v_src += (picture_width / 2);
337         }
338     } else if (surface_image.format.fourcc == VA_FOURCC_YV12 ||
339                surface_image.format.fourcc == VA_FOURCC_I420) {
340         const int U = surface_image.format.fourcc == VA_FOURCC_I420 ? 1 : 2;
341         const int V = surface_image.format.fourcc == VA_FOURCC_I420 ? 2 : 1;
342
343         u_dst = surface_p + surface_image.offsets[U];
344         v_dst = surface_p + surface_image.offsets[V];
345
346         for (row = 0; row < surface_image.height / 2; row++) {
347             memcpy(u_dst, u_src, surface_image.width / 2);
348             memcpy(v_dst, v_src, surface_image.width / 2);
349             u_dst += surface_image.pitches[U];
350             v_dst += surface_image.pitches[V];
351             u_src += (picture_width / 2);
352             v_src += (picture_width / 2);
353         }
354     }
355
356     vaUnmapBuffer(va_dpy, surface_image.buf);
357     vaDestroyImage(va_dpy, surface_image.image_id);
358 }
359
360 static void avcenc_update_slice_parameter(int slice_type)
361 {
362     VAEncSliceParameterBufferH264 *slice_param;
363     VAStatus va_status;
364     int i;
365
366     // Slice level
367     i = 0;
368     slice_param = &avcenc_context.slice_param[i];
369     slice_param->macroblock_address = 0;
370     slice_param->num_macroblocks = picture_height_in_mbs * picture_width_in_mbs; 
371     slice_param->pic_parameter_set_id = 0;
372     slice_param->slice_type = slice_type;
373     slice_param->direct_spatial_mv_pred_flag = 0;
374     slice_param->num_ref_idx_l0_active_minus1 = 0;      /* FIXME: ??? */
375     slice_param->num_ref_idx_l1_active_minus1 = 0;
376     slice_param->cabac_init_idc = 0;
377     slice_param->slice_qp_delta = 0;
378     slice_param->disable_deblocking_filter_idc = 0;
379     slice_param->slice_alpha_c0_offset_div2 = 2;
380     slice_param->slice_beta_offset_div2 = 2;
381     slice_param->idr_pic_id = 0;
382
383     /* FIXME: fill other fields */
384
385     va_status = vaCreateBuffer(va_dpy,
386                                avcenc_context.context_id,
387                                VAEncSliceParameterBufferType,
388                                sizeof(*slice_param), 1, slice_param,
389                                &avcenc_context.slice_param_buf_id[i]);
390     CHECK_VASTATUS(va_status,"vaCreateBuffer");;
391     i++;
392
393 #if 0
394     slice_param = &avcenc_context.slice_param[i];
395     slice_param->macroblock_address = picture_height_in_mbs * picture_width_in_mbs / 2;
396     slice_param->num_macroblocks = picture_height_in_mbs * picture_width_in_mbs / 2;
397     slice_param->pic_parameter_set_id = 0;
398     slice_param->slice_type = slice_type;
399     slice_param->direct_spatial_mv_pred_flag = 0;
400     slice_param->num_ref_idx_l0_active_minus1 = 0;      /* FIXME: ??? */
401     slice_param->num_ref_idx_l1_active_minus1 = 0;
402     slice_param->cabac_init_idc = 0;
403     slice_param->slice_qp_delta = 0;
404     slice_param->disable_deblocking_filter_idc = 0;
405     slice_param->slice_alpha_c0_offset_div2 = 2;
406     slice_param->slice_beta_offset_div2 = 2;
407     slice_param->idr_pic_id = 0;
408
409     /* FIXME: fill other fields */
410
411     va_status = vaCreateBuffer(va_dpy,
412                                avcenc_context.context_id,
413                                VAEncSliceParameterBufferType,
414                                sizeof(*slice_param), 1, slice_param,
415                                &avcenc_context.slice_param_buf_id[i]);
416     CHECK_VASTATUS(va_status,"vaCreateBuffer");;
417     i++;
418 #endif
419
420     avcenc_context.num_slices = i;
421 }
422
423 static int begin_picture(FILE *yuv_fp, int frame_num, int display_num, int slice_type, int is_idr)
424 {
425     VAStatus va_status;
426
427     if (avcenc_context.upload_thread_value != 0) {
428         fprintf(stderr, "FATAL error!!!\n");
429         exit(1);
430     }
431     
432     pthread_join(avcenc_context.upload_thread_id, NULL);
433
434     avcenc_context.upload_thread_value = -1;
435
436     if (avcenc_context.current_input_surface == SID_INPUT_PICTURE_0)
437         avcenc_context.current_input_surface = SID_INPUT_PICTURE_1;
438     else
439         avcenc_context.current_input_surface = SID_INPUT_PICTURE_0;
440
441     if (frame_num == 0) {
442         VAEncPackedHeaderParameterBuffer packed_header_param_buffer;
443         unsigned int length_in_bits, offset_in_bytes;
444         unsigned char *packed_seq_buffer = NULL, *packed_pic_buffer = NULL;
445
446         assert(slice_type == SLICE_TYPE_I);
447         length_in_bits = build_packed_seq_buffer(&packed_seq_buffer);
448         offset_in_bytes = 0;
449         packed_header_param_buffer.type = VAEncPackedHeaderSequence;
450         packed_header_param_buffer.bit_length = length_in_bits;
451         packed_header_param_buffer.has_emulation_bytes = 0;
452         va_status = vaCreateBuffer(va_dpy,
453                                    avcenc_context.context_id,
454                                    VAEncPackedHeaderParameterBufferType,
455                                    sizeof(packed_header_param_buffer), 1, &packed_header_param_buffer,
456                                    &avcenc_context.packed_seq_header_param_buf_id);
457         CHECK_VASTATUS(va_status,"vaCreateBuffer");
458
459         va_status = vaCreateBuffer(va_dpy,
460                                    avcenc_context.context_id,
461                                    VAEncPackedHeaderDataBufferType,
462                                    (length_in_bits + 7) / 8, 1, packed_seq_buffer,
463                                    &avcenc_context.packed_seq_buf_id);
464         CHECK_VASTATUS(va_status,"vaCreateBuffer");
465
466         length_in_bits = build_packed_pic_buffer(&packed_pic_buffer);
467         offset_in_bytes = 0;
468         packed_header_param_buffer.type = VAEncPackedHeaderPicture;
469         packed_header_param_buffer.bit_length = length_in_bits;
470         packed_header_param_buffer.has_emulation_bytes = 0;
471
472         va_status = vaCreateBuffer(va_dpy,
473                                    avcenc_context.context_id,
474                                    VAEncPackedHeaderParameterBufferType,
475                                    sizeof(packed_header_param_buffer), 1, &packed_header_param_buffer,
476                                    &avcenc_context.packed_pic_header_param_buf_id);
477         CHECK_VASTATUS(va_status,"vaCreateBuffer");
478
479         va_status = vaCreateBuffer(va_dpy,
480                                    avcenc_context.context_id,
481                                    VAEncPackedHeaderDataBufferType,
482                                    (length_in_bits + 7) / 8, 1, packed_pic_buffer,
483                                    &avcenc_context.packed_pic_buf_id);
484         CHECK_VASTATUS(va_status,"vaCreateBuffer");
485
486         free(packed_seq_buffer);
487         free(packed_pic_buffer);
488     }
489
490     /* sequence parameter set */
491     VAEncSequenceParameterBufferH264 *seq_param = &avcenc_context.seq_param;
492     va_status = vaCreateBuffer(va_dpy,
493                                avcenc_context.context_id,
494                                VAEncSequenceParameterBufferType,
495                                sizeof(*seq_param), 1, seq_param,
496                                &avcenc_context.seq_param_buf_id);
497     CHECK_VASTATUS(va_status,"vaCreateBuffer");
498
499
500     /* hrd parameter */
501     VAEncMiscParameterBuffer *misc_param;
502     VAEncMiscParameterHRD *misc_hrd_param;
503     vaCreateBuffer(va_dpy,
504                    avcenc_context.context_id,
505                    VAEncMiscParameterBufferType,
506                    sizeof(VAEncMiscParameterBuffer) + sizeof(VAEncMiscParameterRateControl),
507                    1,
508                    NULL, 
509                    &avcenc_context.misc_parameter_hrd_buf_id);
510     CHECK_VASTATUS(va_status, "vaCreateBuffer");
511
512     vaMapBuffer(va_dpy,
513                 avcenc_context.misc_parameter_hrd_buf_id,
514                 (void **)&misc_param);
515     misc_param->type = VAEncMiscParameterTypeHRD;
516     misc_hrd_param = (VAEncMiscParameterHRD *)misc_param->data;
517
518     if (frame_bit_rate > 0) {
519         misc_hrd_param->initial_buffer_fullness = frame_bit_rate * 1024 * 4;
520         misc_hrd_param->buffer_size = frame_bit_rate * 1024 * 8;
521     } else {
522         misc_hrd_param->initial_buffer_fullness = 0;
523         misc_hrd_param->buffer_size = 0;
524     }
525
526     vaUnmapBuffer(va_dpy, avcenc_context.misc_parameter_hrd_buf_id);
527
528     /* slice parameter */
529     avcenc_update_slice_parameter(slice_type);
530
531     return 0;
532 }
533
534 int avcenc_render_picture()
535 {
536     VAStatus va_status;
537     VABufferID va_buffers[8];
538     unsigned int num_va_buffers = 0;
539     int i;
540
541     va_buffers[num_va_buffers++] = avcenc_context.seq_param_buf_id;
542     va_buffers[num_va_buffers++] = avcenc_context.pic_param_buf_id;
543
544     if (avcenc_context.packed_seq_header_param_buf_id != VA_INVALID_ID)
545         va_buffers[num_va_buffers++] = avcenc_context.packed_seq_header_param_buf_id;
546
547     if (avcenc_context.packed_seq_buf_id != VA_INVALID_ID)
548         va_buffers[num_va_buffers++] = avcenc_context.packed_seq_buf_id;
549
550     if (avcenc_context.packed_pic_header_param_buf_id != VA_INVALID_ID)
551         va_buffers[num_va_buffers++] = avcenc_context.packed_pic_header_param_buf_id;
552
553     if (avcenc_context.packed_pic_buf_id != VA_INVALID_ID)
554         va_buffers[num_va_buffers++] = avcenc_context.packed_pic_buf_id;
555
556     if (avcenc_context.misc_parameter_hrd_buf_id != VA_INVALID_ID)
557         va_buffers[num_va_buffers++] =  avcenc_context.misc_parameter_hrd_buf_id;
558
559     va_status = vaBeginPicture(va_dpy,
560                                avcenc_context.context_id,
561                                surface_ids[avcenc_context.current_input_surface]);
562     CHECK_VASTATUS(va_status,"vaBeginPicture");
563     
564     va_status = vaRenderPicture(va_dpy,
565                                 avcenc_context.context_id,
566                                 va_buffers,
567                                 num_va_buffers);
568     CHECK_VASTATUS(va_status,"vaRenderPicture");
569     
570     for(i = 0; i < avcenc_context.num_slices; i++) {
571         va_status = vaRenderPicture(va_dpy,
572                                 avcenc_context.context_id,
573                                 &avcenc_context.slice_param_buf_id[i],
574                                 1);
575         CHECK_VASTATUS(va_status,"vaRenderPicture");
576     }
577
578     va_status = vaEndPicture(va_dpy, avcenc_context.context_id);
579     CHECK_VASTATUS(va_status,"vaEndPicture");
580
581     return 0;
582 }
583
584 static int avcenc_destroy_buffers(VABufferID *va_buffers, unsigned int num_va_buffers)
585 {
586     VAStatus va_status;
587     unsigned int i;
588
589     for (i = 0; i < num_va_buffers; i++) {
590         if (va_buffers[i] != VA_INVALID_ID) {
591             va_status = vaDestroyBuffer(va_dpy, va_buffers[i]);
592             CHECK_VASTATUS(va_status,"vaDestroyBuffer");
593             va_buffers[i] = VA_INVALID_ID;
594         }
595     }
596
597     return 0;
598 }
599
600 static void end_picture(int slice_type, int next_is_bpic)
601 {
602     VABufferID tempID;
603
604     /* Prepare for next picture */
605     tempID = surface_ids[SID_RECON_PICTURE];  
606
607     if (slice_type != SLICE_TYPE_B) {
608         if (next_is_bpic) {
609             surface_ids[SID_RECON_PICTURE] = surface_ids[SID_REFERENCE_PICTURE_L1]; 
610             surface_ids[SID_REFERENCE_PICTURE_L1] = tempID;     
611         } else {
612             surface_ids[SID_RECON_PICTURE] = surface_ids[SID_REFERENCE_PICTURE_L0]; 
613             surface_ids[SID_REFERENCE_PICTURE_L0] = tempID;
614         }
615     } else {
616         if (!next_is_bpic) {
617             surface_ids[SID_RECON_PICTURE] = surface_ids[SID_REFERENCE_PICTURE_L0]; 
618             surface_ids[SID_REFERENCE_PICTURE_L0] = surface_ids[SID_REFERENCE_PICTURE_L1];
619             surface_ids[SID_REFERENCE_PICTURE_L1] = tempID;
620         }
621     }
622
623     avcenc_destroy_buffers(&avcenc_context.seq_param_buf_id, 1);
624     avcenc_destroy_buffers(&avcenc_context.pic_param_buf_id, 1);
625     avcenc_destroy_buffers(&avcenc_context.packed_seq_header_param_buf_id, 1);
626     avcenc_destroy_buffers(&avcenc_context.packed_seq_buf_id, 1);
627     avcenc_destroy_buffers(&avcenc_context.packed_pic_header_param_buf_id, 1);
628     avcenc_destroy_buffers(&avcenc_context.packed_pic_buf_id, 1);
629     avcenc_destroy_buffers(&avcenc_context.slice_param_buf_id[0], avcenc_context.num_slices);
630     avcenc_destroy_buffers(&avcenc_context.codedbuf_buf_id, 1);
631     avcenc_destroy_buffers(&avcenc_context.misc_parameter_hrd_buf_id, 1);
632
633     memset(avcenc_context.slice_param, 0, sizeof(avcenc_context.slice_param));
634     avcenc_context.num_slices = 0;
635 }
636
637 #define BITSTREAM_ALLOCATE_STEPPING     4096
638
639 struct __bitstream {
640     unsigned int *buffer;
641     int bit_offset;
642     int max_size_in_dword;
643 };
644
645 typedef struct __bitstream bitstream;
646
647 #if 0
648 static int 
649 get_coded_bitsteam_length(unsigned char *buffer, int buffer_length)
650 {
651     int i;
652
653     for (i = 0; i < buffer_length - 3; i++) {
654         if (!buffer[i] &&
655             !buffer[i + 1] &&
656             !buffer[i + 2] &&
657             !buffer[i + 3])
658             break;
659     }
660
661     return i;
662 }
663 #endif
664
665 static unsigned int 
666 va_swap32(unsigned int val)
667 {
668     unsigned char *pval = (unsigned char *)&val;
669
670     return ((pval[0] << 24)     |
671             (pval[1] << 16)     |
672             (pval[2] << 8)      |
673             (pval[3] << 0));
674 }
675
676 static void
677 bitstream_start(bitstream *bs)
678 {
679     bs->max_size_in_dword = BITSTREAM_ALLOCATE_STEPPING;
680     bs->buffer = calloc(bs->max_size_in_dword * sizeof(int), 1);
681     bs->bit_offset = 0;
682 }
683
684 static void
685 bitstream_end(bitstream *bs)
686 {
687     int pos = (bs->bit_offset >> 5);
688     int bit_offset = (bs->bit_offset & 0x1f);
689     int bit_left = 32 - bit_offset;
690
691     if (bit_offset) {
692         bs->buffer[pos] = va_swap32((bs->buffer[pos] << bit_left));
693     }
694 }
695  
696 static void
697 bitstream_put_ui(bitstream *bs, unsigned int val, int size_in_bits)
698 {
699     int pos = (bs->bit_offset >> 5);
700     int bit_offset = (bs->bit_offset & 0x1f);
701     int bit_left = 32 - bit_offset;
702
703     if (!size_in_bits)
704         return;
705
706     bs->bit_offset += size_in_bits;
707
708     if (bit_left > size_in_bits) {
709         bs->buffer[pos] = (bs->buffer[pos] << size_in_bits | val);
710     } else {
711         size_in_bits -= bit_left;
712         bs->buffer[pos] = (bs->buffer[pos] << bit_left) | (val >> size_in_bits);
713         bs->buffer[pos] = va_swap32(bs->buffer[pos]);
714
715         if (pos + 1 == bs->max_size_in_dword) {
716             bs->max_size_in_dword += BITSTREAM_ALLOCATE_STEPPING;
717             bs->buffer = realloc(bs->buffer, bs->max_size_in_dword * sizeof(unsigned int));
718         }
719
720         bs->buffer[pos + 1] = val;
721     }
722 }
723
724 static void
725 bitstream_put_ue(bitstream *bs, unsigned int val)
726 {
727     int size_in_bits = 0;
728     int tmp_val = ++val;
729
730     while (tmp_val) {
731         tmp_val >>= 1;
732         size_in_bits++;
733     }
734
735     bitstream_put_ui(bs, 0, size_in_bits - 1); // leading zero
736     bitstream_put_ui(bs, val, size_in_bits);
737 }
738
739 static void
740 bitstream_put_se(bitstream *bs, int val)
741 {
742     unsigned int new_val;
743
744     if (val <= 0)
745         new_val = -2 * val;
746     else
747         new_val = 2 * val - 1;
748
749     bitstream_put_ue(bs, new_val);
750 }
751
752 static void
753 bitstream_byte_aligning(bitstream *bs, int bit)
754 {
755     int bit_offset = (bs->bit_offset & 0x7);
756     int bit_left = 8 - bit_offset;
757     int new_val;
758
759     if (!bit_offset)
760         return;
761
762     assert(bit == 0 || bit == 1);
763
764     if (bit)
765         new_val = (1 << bit_left) - 1;
766     else
767         new_val = 0;
768
769     bitstream_put_ui(bs, new_val, bit_left);
770 }
771
772 static void 
773 rbsp_trailing_bits(bitstream *bs)
774 {
775     bitstream_put_ui(bs, 1, 1);
776     bitstream_byte_aligning(bs, 0);
777 }
778
779 static void nal_start_code_prefix(bitstream *bs)
780 {
781     bitstream_put_ui(bs, 0x00000001, 32);
782 }
783
784 static void nal_header(bitstream *bs, int nal_ref_idc, int nal_unit_type)
785 {
786     bitstream_put_ui(bs, 0, 1);                /* forbidden_zero_bit: 0 */
787     bitstream_put_ui(bs, nal_ref_idc, 2);
788     bitstream_put_ui(bs, nal_unit_type, 5);
789 }
790
791 static void sps_rbsp(bitstream *bs)
792 {
793     VAEncSequenceParameterBufferH264 *seq_param = &avcenc_context.seq_param;
794     int profile_idc = PROFILE_IDC_BASELINE;
795
796     if (avcenc_context.profile == VAProfileH264High)
797         profile_idc = PROFILE_IDC_HIGH;
798     else if (avcenc_context.profile == VAProfileH264Main)
799         profile_idc = PROFILE_IDC_MAIN;
800
801     bitstream_put_ui(bs, profile_idc, 8);               /* profile_idc */
802     bitstream_put_ui(bs, !!(avcenc_context.constraint_set_flag & 1), 1);                         /* constraint_set0_flag */
803     bitstream_put_ui(bs, !!(avcenc_context.constraint_set_flag & 2), 1);                         /* constraint_set1_flag */
804     bitstream_put_ui(bs, !!(avcenc_context.constraint_set_flag & 4), 1);                         /* constraint_set2_flag */
805     bitstream_put_ui(bs, !!(avcenc_context.constraint_set_flag & 8), 1);                         /* constraint_set3_flag */
806     bitstream_put_ui(bs, 0, 4);                         /* reserved_zero_4bits */
807     bitstream_put_ui(bs, seq_param->level_idc, 8);      /* level_idc */
808     bitstream_put_ue(bs, seq_param->seq_parameter_set_id);      /* seq_parameter_set_id */
809
810     if ( profile_idc == PROFILE_IDC_HIGH) {
811         bitstream_put_ue(bs, 1);        /* chroma_format_idc = 1, 4:2:0 */ 
812         bitstream_put_ue(bs, 0);        /* bit_depth_luma_minus8 */
813         bitstream_put_ue(bs, 0);        /* bit_depth_chroma_minus8 */
814         bitstream_put_ui(bs, 0, 1);     /* qpprime_y_zero_transform_bypass_flag */
815         bitstream_put_ui(bs, 0, 1);     /* seq_scaling_matrix_present_flag */
816     }
817
818     bitstream_put_ue(bs, seq_param->seq_fields.bits.log2_max_frame_num_minus4); /* log2_max_frame_num_minus4 */
819     bitstream_put_ue(bs, seq_param->seq_fields.bits.pic_order_cnt_type);        /* pic_order_cnt_type */
820
821     if (seq_param->seq_fields.bits.pic_order_cnt_type == 0)
822         bitstream_put_ue(bs, seq_param->seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4);     /* log2_max_pic_order_cnt_lsb_minus4 */
823     else {
824         assert(0);
825     }
826
827     bitstream_put_ue(bs, seq_param->max_num_ref_frames);        /* num_ref_frames */
828     bitstream_put_ui(bs, 0, 1);                                 /* gaps_in_frame_num_value_allowed_flag */
829
830     bitstream_put_ue(bs, seq_param->picture_width_in_mbs - 1);  /* pic_width_in_mbs_minus1 */
831     bitstream_put_ue(bs, seq_param->picture_height_in_mbs - 1); /* pic_height_in_map_units_minus1 */
832     bitstream_put_ui(bs, seq_param->seq_fields.bits.frame_mbs_only_flag, 1);    /* frame_mbs_only_flag */
833
834     if (!seq_param->seq_fields.bits.frame_mbs_only_flag) {
835         assert(0);
836     }
837
838     bitstream_put_ui(bs, seq_param->seq_fields.bits.direct_8x8_inference_flag, 1);      /* direct_8x8_inference_flag */
839     bitstream_put_ui(bs, seq_param->frame_cropping_flag, 1);            /* frame_cropping_flag */
840
841     if (seq_param->frame_cropping_flag) {
842         bitstream_put_ue(bs, seq_param->frame_crop_left_offset);        /* frame_crop_left_offset */
843         bitstream_put_ue(bs, seq_param->frame_crop_right_offset);       /* frame_crop_right_offset */
844         bitstream_put_ue(bs, seq_param->frame_crop_top_offset);         /* frame_crop_top_offset */
845         bitstream_put_ue(bs, seq_param->frame_crop_bottom_offset);      /* frame_crop_bottom_offset */
846     }
847     
848     if ( frame_bit_rate < 0 ) {
849         bitstream_put_ui(bs, 0, 1); /* vui_parameters_present_flag */
850     } else {
851         bitstream_put_ui(bs, 1, 1); /* vui_parameters_present_flag */
852         bitstream_put_ui(bs, 0, 1); /* aspect_ratio_info_present_flag */
853         bitstream_put_ui(bs, 0, 1); /* overscan_info_present_flag */
854         bitstream_put_ui(bs, 0, 1); /* video_signal_type_present_flag */
855         bitstream_put_ui(bs, 0, 1); /* chroma_loc_info_present_flag */
856         bitstream_put_ui(bs, 1, 1); /* timing_info_present_flag */
857         {
858             bitstream_put_ui(bs, 15, 32);
859             bitstream_put_ui(bs, 900, 32);
860             bitstream_put_ui(bs, 1, 1);
861         }
862         bitstream_put_ui(bs, 1, 1); /* nal_hrd_parameters_present_flag */
863         {
864             // hrd_parameters 
865             bitstream_put_ue(bs, 0);    /* cpb_cnt_minus1 */
866             bitstream_put_ui(bs, 4, 4); /* bit_rate_scale */
867             bitstream_put_ui(bs, 6, 4); /* cpb_size_scale */
868            
869             bitstream_put_ue(bs, frame_bit_rate - 1); /* bit_rate_value_minus1[0] */
870             bitstream_put_ue(bs, frame_bit_rate*8 - 1); /* cpb_size_value_minus1[0] */
871             bitstream_put_ui(bs, 1, 1);  /* cbr_flag[0] */
872
873             bitstream_put_ui(bs, 23, 5);   /* initial_cpb_removal_delay_length_minus1 */
874             bitstream_put_ui(bs, 23, 5);   /* cpb_removal_delay_length_minus1 */
875             bitstream_put_ui(bs, 23, 5);   /* dpb_output_delay_length_minus1 */
876             bitstream_put_ui(bs, 23, 5);   /* time_offset_length  */
877         }
878         bitstream_put_ui(bs, 0, 1);   /* vcl_hrd_parameters_present_flag */
879         bitstream_put_ui(bs, 0, 1);   /* low_delay_hrd_flag */ 
880
881         bitstream_put_ui(bs, 0, 1); /* pic_struct_present_flag */
882         bitstream_put_ui(bs, 0, 1); /* bitstream_restriction_flag */
883     }
884
885     rbsp_trailing_bits(bs);     /* rbsp_trailing_bits */
886 }
887
888 #if 0
889 static void build_nal_sps(FILE *avc_fp)
890 {
891     bitstream bs;
892
893     bitstream_start(&bs);
894     nal_start_code_prefix(&bs);
895     nal_header(&bs, NAL_REF_IDC_HIGH, NAL_SPS);
896     sps_rbsp(&bs);
897     bitstream_end(&bs, avc_fp);
898 }
899 #endif
900
901 static void pps_rbsp(bitstream *bs)
902 {
903     VAEncPictureParameterBufferH264 *pic_param = &avcenc_context.pic_param;
904
905     bitstream_put_ue(bs, pic_param->pic_parameter_set_id);      /* pic_parameter_set_id */
906     bitstream_put_ue(bs, pic_param->seq_parameter_set_id);      /* seq_parameter_set_id */
907
908     bitstream_put_ui(bs, pic_param->pic_fields.bits.entropy_coding_mode_flag, 1);  /* entropy_coding_mode_flag */
909
910     bitstream_put_ui(bs, 0, 1);                         /* pic_order_present_flag: 0 */
911
912     bitstream_put_ue(bs, 0);                            /* num_slice_groups_minus1 */
913
914     bitstream_put_ue(bs, pic_param->num_ref_idx_l0_active_minus1);      /* num_ref_idx_l0_active_minus1 */
915     bitstream_put_ue(bs, pic_param->num_ref_idx_l1_active_minus1);      /* num_ref_idx_l1_active_minus1 1 */
916
917     bitstream_put_ui(bs, pic_param->pic_fields.bits.weighted_pred_flag, 1);     /* weighted_pred_flag: 0 */
918     bitstream_put_ui(bs, pic_param->pic_fields.bits.weighted_bipred_idc, 2);    /* weighted_bipred_idc: 0 */
919
920     bitstream_put_se(bs, pic_param->pic_init_qp - 26);  /* pic_init_qp_minus26 */
921     bitstream_put_se(bs, 0);                            /* pic_init_qs_minus26 */
922     bitstream_put_se(bs, 0);                            /* chroma_qp_index_offset */
923
924     bitstream_put_ui(bs, pic_param->pic_fields.bits.deblocking_filter_control_present_flag, 1); /* deblocking_filter_control_present_flag */
925     bitstream_put_ui(bs, 0, 1);                         /* constrained_intra_pred_flag */
926     bitstream_put_ui(bs, 0, 1);                         /* redundant_pic_cnt_present_flag */
927     
928     /* more_rbsp_data */
929     bitstream_put_ui(bs, pic_param->pic_fields.bits.transform_8x8_mode_flag, 1);    /*transform_8x8_mode_flag */
930     bitstream_put_ui(bs, 0, 1);                         /* pic_scaling_matrix_present_flag */
931     bitstream_put_se(bs, pic_param->second_chroma_qp_index_offset );    /*second_chroma_qp_index_offset */
932
933     rbsp_trailing_bits(bs);
934 }
935
936 #if 0
937 static void build_nal_pps(FILE *avc_fp)
938 {
939     bitstream bs;
940
941     bitstream_start(&bs);
942     nal_start_code_prefix(&bs);
943     nal_header(&bs, NAL_REF_IDC_HIGH, NAL_PPS);
944     pps_rbsp(&bs);
945     bitstream_end(&bs, avc_fp);
946 }
947
948 static void 
949 build_header(FILE *avc_fp)
950 {
951     build_nal_sps(avc_fp);
952     build_nal_pps(avc_fp);
953 }
954 #endif
955
956 static int
957 build_packed_pic_buffer(unsigned char **header_buffer)
958 {
959     bitstream bs;
960
961     bitstream_start(&bs);
962     nal_start_code_prefix(&bs);
963     nal_header(&bs, NAL_REF_IDC_HIGH, NAL_PPS);
964     pps_rbsp(&bs);
965     bitstream_end(&bs);
966
967     *header_buffer = (unsigned char *)bs.buffer;
968     return bs.bit_offset;
969 }
970
971 static int
972 build_packed_seq_buffer(unsigned char **header_buffer)
973 {
974     bitstream bs;
975
976     bitstream_start(&bs);
977     nal_start_code_prefix(&bs);
978     nal_header(&bs, NAL_REF_IDC_HIGH, NAL_SPS);
979     sps_rbsp(&bs);
980     bitstream_end(&bs);
981
982     *header_buffer = (unsigned char *)bs.buffer;
983     return bs.bit_offset;
984 }
985
986
987 #if 0
988 static void 
989 slice_header(bitstream *bs, int frame_num, int display_frame, int slice_type, int nal_ref_idc, int is_idr)
990 {
991     VAEncSequenceParameterBufferH264 *seq_param = &avcenc_context.seq_param;
992     VAEncPictureParameterBufferH264 *pic_param = &avcenc_context.pic_param;
993     int is_cabac = (pic_param->pic_fields.bits.entropy_coding_mode_flag == ENTROPY_MODE_CABAC);
994
995     bitstream_put_ue(bs, 0);                   /* first_mb_in_slice: 0 */
996     bitstream_put_ue(bs, slice_type);          /* slice_type */
997     bitstream_put_ue(bs, 0);                   /* pic_parameter_set_id: 0 */
998     bitstream_put_ui(bs, frame_num & 0x0F, seq_param->seq_fields.bits.log2_max_frame_num_minus4 + 4);    /* frame_num */
999
1000     /* frame_mbs_only_flag == 1 */
1001     if (!seq_param->seq_fields.bits.frame_mbs_only_flag) {
1002         /* FIXME: */
1003         assert(0);
1004     }
1005
1006     if (is_idr)
1007         bitstream_put_ue(bs, 0);                /* idr_pic_id: 0 */
1008
1009     if (seq_param->seq_fields.bits.pic_order_cnt_type == 0) {
1010         bitstream_put_ui(bs, (display_frame*2) & 0x3F, seq_param->seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4 + 4);
1011         /* only support frame */
1012     } else {
1013         /* FIXME: */
1014         assert(0);
1015     }
1016
1017     /* redundant_pic_cnt_present_flag == 0 */
1018     
1019     /* slice type */
1020     if (slice_type == SLICE_TYPE_P) {
1021         bitstream_put_ui(bs, 0, 1);            /* num_ref_idx_active_override_flag: 0 */
1022         /* ref_pic_list_reordering */
1023         bitstream_put_ui(bs, 0, 1);            /* ref_pic_list_reordering_flag_l0: 0 */
1024     } else if (slice_type == SLICE_TYPE_B) {
1025         bitstream_put_ui(bs, 1, 1);            /* direct_spatial_mv_pred: 1 */
1026         bitstream_put_ui(bs, 0, 1);            /* num_ref_idx_active_override_flag: 0 */
1027         /* ref_pic_list_reordering */
1028         bitstream_put_ui(bs, 0, 1);            /* ref_pic_list_reordering_flag_l0: 0 */
1029         bitstream_put_ui(bs, 0, 1);            /* ref_pic_list_reordering_flag_l1: 0 */
1030     } 
1031
1032     /* weighted_pred_flag == 0 */
1033
1034     /* dec_ref_pic_marking */
1035     if (nal_ref_idc != 0) {
1036         if ( is_idr) {
1037             bitstream_put_ui(bs, 0, 1);            /* no_output_of_prior_pics_flag: 0 */
1038             bitstream_put_ui(bs, 0, 1);            /* long_term_reference_flag: 0 */
1039         } else {
1040             bitstream_put_ui(bs, 0, 1);            /* adaptive_ref_pic_marking_mode_flag: 0 */
1041         }
1042     }
1043
1044     if (is_cabac && (slice_type != SLICE_TYPE_I))
1045         bitstream_put_ue(bs, 0);               /* cabac_init_idc: 0 */
1046
1047     bitstream_put_se(bs, 0);                   /* slice_qp_delta: 0 */
1048
1049     if (pic_param->pic_fields.bits.deblocking_filter_control_present_flag == 1) {
1050         bitstream_put_ue(bs, 0);               /* disable_deblocking_filter_idc: 0 */
1051         bitstream_put_se(bs, 2);               /* slice_alpha_c0_offset_div2: 2 */
1052         bitstream_put_se(bs, 2);               /* slice_beta_offset_div2: 2 */
1053     }
1054 }
1055
1056 static void 
1057 slice_data(bitstream *bs)
1058 {
1059     VACodedBufferSegment *coded_buffer_segment;
1060     unsigned char *coded_mem;
1061     int i, slice_data_length;
1062     VAStatus va_status;
1063     VASurfaceStatus surface_status;
1064
1065     va_status = vaSyncSurface(va_dpy, surface_ids[avcenc_context.current_input_surface]);
1066     CHECK_VASTATUS(va_status,"vaSyncSurface");
1067
1068     surface_status = 0;
1069     va_status = vaQuerySurfaceStatus(va_dpy, surface_ids[avcenc_context.current_input_surface], &surface_status);
1070     CHECK_VASTATUS(va_status,"vaQuerySurfaceStatus");
1071
1072     va_status = vaMapBuffer(va_dpy, avcenc_context.codedbuf_buf_id, (void **)(&coded_buffer_segment));
1073     CHECK_VASTATUS(va_status,"vaMapBuffer");
1074     coded_mem = coded_buffer_segment->buf;
1075
1076     slice_data_length = get_coded_bitsteam_length(coded_mem, codedbuf_size);
1077
1078     for (i = 0; i < slice_data_length; i++) {
1079         bitstream_put_ui(bs, *coded_mem, 8);
1080         coded_mem++;
1081     }
1082
1083     vaUnmapBuffer(va_dpy, avcenc_context.codedbuf_buf_id);
1084 }
1085
1086 static void 
1087 build_nal_slice(FILE *avc_fp, int frame_num, int display_frame, int slice_type, int is_idr)
1088 {
1089     bitstream bs;
1090
1091     bitstream_start(&bs);
1092     slice_data(&bs);
1093     bitstream_end(&bs, avc_fp);
1094 }
1095
1096 #endif
1097
1098 static int
1099 store_coded_buffer(FILE *avc_fp, int slice_type)
1100 {
1101     VACodedBufferSegment *coded_buffer_segment;
1102     unsigned char *coded_mem;
1103     int slice_data_length;
1104     VAStatus va_status;
1105     VASurfaceStatus surface_status;
1106     size_t w_items;
1107
1108     va_status = vaSyncSurface(va_dpy, surface_ids[avcenc_context.current_input_surface]);
1109     CHECK_VASTATUS(va_status,"vaSyncSurface");
1110
1111     surface_status = 0;
1112     va_status = vaQuerySurfaceStatus(va_dpy, surface_ids[avcenc_context.current_input_surface], &surface_status);
1113     CHECK_VASTATUS(va_status,"vaQuerySurfaceStatus");
1114
1115     va_status = vaMapBuffer(va_dpy, avcenc_context.codedbuf_buf_id, (void **)(&coded_buffer_segment));
1116     CHECK_VASTATUS(va_status,"vaMapBuffer");
1117     coded_mem = coded_buffer_segment->buf;
1118
1119     if (coded_buffer_segment->status & VA_CODED_BUF_STATUS_SLICE_OVERFLOW_MASK) {
1120         if (slice_type == SLICE_TYPE_I)
1121             avcenc_context.codedbuf_i_size *= 2;
1122         else
1123             avcenc_context.codedbuf_pb_size *= 2;
1124
1125         vaUnmapBuffer(va_dpy, avcenc_context.codedbuf_buf_id);
1126         return -1;
1127     }
1128
1129     slice_data_length = coded_buffer_segment->size;
1130
1131     do {
1132         w_items = fwrite(coded_mem, slice_data_length, 1, avc_fp);
1133     } while (w_items != 1);
1134
1135     if (slice_type == SLICE_TYPE_I) {
1136         if (avcenc_context.codedbuf_i_size > slice_data_length * 3 / 2) {
1137             avcenc_context.codedbuf_i_size = slice_data_length * 3 / 2;
1138         }
1139         
1140         if (avcenc_context.codedbuf_pb_size < slice_data_length) {
1141             avcenc_context.codedbuf_pb_size = slice_data_length;
1142         }
1143     } else {
1144         if (avcenc_context.codedbuf_pb_size > slice_data_length * 3 / 2) {
1145             avcenc_context.codedbuf_pb_size = slice_data_length * 3 / 2;
1146         }
1147     }
1148
1149     vaUnmapBuffer(va_dpy, avcenc_context.codedbuf_buf_id);
1150
1151     return 0;
1152 }
1153
1154 static void
1155 encode_picture(FILE *yuv_fp, FILE *avc_fp,
1156                int frame_num, int display_num,
1157                int is_idr,
1158                int slice_type, int next_is_bpic,
1159                int next_display_num)
1160 {
1161     VAStatus va_status;
1162     int ret = 0, codedbuf_size;
1163     
1164     begin_picture(yuv_fp, frame_num, display_num, slice_type, is_idr);
1165
1166     //if (next_display_num < frame_number) {
1167     if (1) {
1168         int index;
1169
1170         /* prepare for next frame */
1171         if (avcenc_context.current_input_surface == SID_INPUT_PICTURE_0)
1172             index = SID_INPUT_PICTURE_1;
1173         else
1174             index = SID_INPUT_PICTURE_0;
1175         if ( next_display_num >= frame_number )
1176             next_display_num = frame_number - 1;
1177         fseek(yuv_fp, frame_size * next_display_num, SEEK_SET);
1178
1179         avcenc_context.upload_thread_param.yuv_fp = yuv_fp;
1180         avcenc_context.upload_thread_param.surface_id = surface_ids[index];
1181
1182         avcenc_context.upload_thread_value = pthread_create(&avcenc_context.upload_thread_id,
1183                                                             NULL,
1184                                                             upload_thread_function, 
1185                                                             (void*)&avcenc_context.upload_thread_param);
1186     }
1187
1188     do {
1189         avcenc_destroy_buffers(&avcenc_context.codedbuf_buf_id, 1);
1190         avcenc_destroy_buffers(&avcenc_context.pic_param_buf_id, 1);
1191
1192
1193         if (SLICE_TYPE_I == slice_type) {
1194             codedbuf_size = avcenc_context.codedbuf_i_size;
1195         } else {
1196             codedbuf_size = avcenc_context.codedbuf_pb_size;
1197         }
1198
1199         /* coded buffer */
1200         va_status = vaCreateBuffer(va_dpy,
1201                                    avcenc_context.context_id,
1202                                    VAEncCodedBufferType,
1203                                    codedbuf_size, 1, NULL,
1204                                    &avcenc_context.codedbuf_buf_id);
1205         CHECK_VASTATUS(va_status,"vaCreateBuffer");
1206
1207         /* picture parameter set */
1208         avcenc_update_picture_parameter(slice_type, frame_num, display_num, is_idr);
1209
1210         avcenc_render_picture();
1211
1212         ret = store_coded_buffer(avc_fp, slice_type);
1213     } while (ret);
1214
1215     end_picture(slice_type, next_is_bpic);
1216 }
1217
1218 static void encode_pb_pictures(FILE *yuv_fp, FILE *avc_fp, int f, int nbframes, int next_f)
1219 {
1220     int i;
1221     encode_picture(yuv_fp, avc_fp,
1222                    enc_frame_number, f + nbframes,
1223                    0,
1224                    SLICE_TYPE_P, 1, f);
1225
1226     for( i = 0; i < nbframes - 1; i++) {
1227         encode_picture(yuv_fp, avc_fp,
1228                        enc_frame_number + 1, f + i,
1229                        0,
1230                        SLICE_TYPE_B, 1, f + i + 1);
1231     }
1232     
1233     encode_picture(yuv_fp, avc_fp,
1234                    enc_frame_number + 1, f + nbframes - 1,
1235                    0,
1236                    SLICE_TYPE_B, 0, next_f);
1237 }
1238
1239 static void show_help()
1240 {
1241     printf("Usage: avnenc <width> <height> <input_yuvfile> <output_avcfile> [qp=qpvalue|fb=framebitrate] [mode=0(I frames only)/1(I and P frames)/2(I, P and B frames)\n");
1242 }
1243
1244 static void avcenc_context_seq_param_init(VAEncSequenceParameterBufferH264 *seq_param,
1245                                           int width, int height)
1246
1247 {
1248     int width_in_mbs = (width + 15) / 16;
1249     int height_in_mbs = (height + 15) / 16;
1250     int frame_cropping_flag = 0;
1251     int frame_crop_bottom_offset = 0;
1252
1253     seq_param->seq_parameter_set_id = 0;
1254     seq_param->level_idc = 41;
1255     seq_param->intra_period = intra_period;
1256     seq_param->ip_period = 0;   /* FIXME: ??? */
1257     seq_param->max_num_ref_frames = 4;
1258     seq_param->picture_width_in_mbs = width_in_mbs;
1259     seq_param->picture_height_in_mbs = height_in_mbs;
1260     seq_param->seq_fields.bits.frame_mbs_only_flag = 1;
1261     
1262     if (frame_bit_rate > 0)
1263         seq_param->bits_per_second = 1024 * frame_bit_rate; /* use kbps as input */
1264     else
1265         seq_param->bits_per_second = 0;
1266     
1267     seq_param->time_scale = 900;
1268     seq_param->num_units_in_tick = 15;                  /* Tc = num_units_in_tick / time_sacle */
1269
1270     if (height_in_mbs * 16 - height) {
1271         frame_cropping_flag = 1;
1272         frame_crop_bottom_offset = 
1273             (height_in_mbs * 16 - height) / (2 * (!seq_param->seq_fields.bits.frame_mbs_only_flag + 1));
1274     }
1275
1276     seq_param->frame_cropping_flag = frame_cropping_flag;
1277     seq_param->frame_crop_left_offset = 0;
1278     seq_param->frame_crop_right_offset = 0;
1279     seq_param->frame_crop_top_offset = 0;
1280     seq_param->frame_crop_bottom_offset = frame_crop_bottom_offset;
1281
1282     seq_param->seq_fields.bits.pic_order_cnt_type = 0;
1283     seq_param->seq_fields.bits.direct_8x8_inference_flag = 0;
1284     
1285     seq_param->seq_fields.bits.log2_max_frame_num_minus4 = 0;
1286     seq_param->seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4 = 2;
1287         
1288     if (frame_bit_rate > 0)
1289         seq_param->vui_parameters_present_flag = 1;     //HRD info located in vui
1290     else
1291         seq_param->vui_parameters_present_flag = 0;
1292 }
1293
1294 static void avcenc_context_pic_param_init(VAEncPictureParameterBufferH264 *pic_param)
1295 {
1296     pic_param->seq_parameter_set_id = 0;
1297     pic_param->pic_parameter_set_id = 0;
1298
1299     pic_param->last_picture = 0;
1300     pic_param->frame_num = 0;
1301     
1302     pic_param->pic_init_qp = (qp_value >= 0 ?  qp_value : 26);
1303     pic_param->num_ref_idx_l0_active_minus1 = 0;
1304     pic_param->num_ref_idx_l1_active_minus1 = 0;
1305
1306     pic_param->pic_fields.bits.idr_pic_flag = 0;
1307     pic_param->pic_fields.bits.reference_pic_flag = 0;
1308     pic_param->pic_fields.bits.entropy_coding_mode_flag = ENTROPY_MODE_CABAC;
1309     pic_param->pic_fields.bits.weighted_pred_flag = 0;
1310     pic_param->pic_fields.bits.weighted_bipred_idc = 0;
1311     
1312     if (avcenc_context.constraint_set_flag & 0x7)
1313         pic_param->pic_fields.bits.transform_8x8_mode_flag = 0;
1314     else
1315         pic_param->pic_fields.bits.transform_8x8_mode_flag = 1;
1316
1317     pic_param->pic_fields.bits.deblocking_filter_control_present_flag = 1;
1318 }
1319
1320 static void avcenc_context_init(int width, int height)
1321 {
1322     int i;
1323     memset(&avcenc_context, 0, sizeof(avcenc_context));
1324     avcenc_context.profile = VAProfileH264Main;
1325
1326     switch (avcenc_context.profile) {
1327     case VAProfileH264Baseline:
1328         avcenc_context.constraint_set_flag |= (1 << 0); /* Annex A.2.1 */
1329         break;
1330
1331     case VAProfileH264Main:
1332         avcenc_context.constraint_set_flag |= (1 << 1); /* Annex A.2.2 */
1333         break;
1334
1335     case VAProfileH264High:
1336         avcenc_context.constraint_set_flag |= (1 << 3); /* Annex A.2.4 */
1337         break;
1338         
1339     default:
1340         break;
1341     }
1342         
1343     avcenc_context.seq_param_buf_id = VA_INVALID_ID;
1344     avcenc_context.pic_param_buf_id = VA_INVALID_ID;
1345     avcenc_context.packed_seq_header_param_buf_id = VA_INVALID_ID;
1346     avcenc_context.packed_seq_buf_id = VA_INVALID_ID;
1347     avcenc_context.packed_pic_header_param_buf_id = VA_INVALID_ID;
1348     avcenc_context.packed_pic_buf_id = VA_INVALID_ID;
1349     avcenc_context.codedbuf_buf_id = VA_INVALID_ID;
1350     avcenc_context.misc_parameter_hrd_buf_id = VA_INVALID_ID;
1351     avcenc_context.codedbuf_i_size = width * height;
1352     avcenc_context.codedbuf_pb_size = 0;
1353     avcenc_context.current_input_surface = SID_INPUT_PICTURE_0;
1354     avcenc_context.upload_thread_value = -1;
1355
1356     if (qp_value == -1)
1357         avcenc_context.rate_control_method = VA_RC_CBR;
1358     else if (qp_value == -2)
1359         avcenc_context.rate_control_method = VA_RC_VBR;
1360     else {
1361         assert(qp_value >= 0 && qp_value <= 51);
1362         avcenc_context.rate_control_method = VA_RC_CQP;
1363     }
1364
1365     for (i = 0; i < MAX_SLICES; i++) {
1366         avcenc_context.slice_param_buf_id[i] = VA_INVALID_ID;
1367     }
1368
1369     avcenc_context_seq_param_init(&avcenc_context.seq_param, width, height);
1370     avcenc_context_pic_param_init(&avcenc_context.pic_param);
1371 }
1372
1373 int main(int argc, char *argv[])
1374 {
1375     int f;
1376     FILE *yuv_fp;
1377     FILE *avc_fp;
1378     long file_size;
1379     int i_frame_only=0,i_p_frame_only=1;
1380     int mode_value;
1381     struct timeval tpstart,tpend; 
1382     float  timeuse;
1383
1384     va_init_display_args(&argc, argv);
1385
1386     //TODO may be we should using option analytics library
1387     if(argc != 5 && argc != 6 && argc != 7) {
1388         show_help();
1389         return -1;
1390     }
1391
1392     picture_width = atoi(argv[1]);
1393     picture_height = atoi(argv[2]);
1394     picture_width_in_mbs = (picture_width + 15) / 16;
1395     picture_height_in_mbs = (picture_height + 15) / 16;
1396
1397     if (argc == 6 || argc == 7) {
1398         qp_value = -1;
1399         sscanf(argv[5], "qp=%d", &qp_value);
1400         if ( qp_value == -1 ) {
1401             frame_bit_rate = -1;
1402             sscanf(argv[5], "fb=%d", &frame_bit_rate);
1403             if (  frame_bit_rate == -1 ) {
1404                 show_help();
1405                 return -1;
1406             }
1407         } else if (qp_value > 51) {
1408             qp_value = 51;
1409         } else if (qp_value < 0) {
1410             qp_value = 0;
1411         }
1412     } else
1413         qp_value = 28;                          //default const QP mode
1414
1415     if (argc == 7) {
1416         sscanf(argv[6], "mode=%d", &mode_value);
1417         if ( mode_value == 0 ) {
1418                 i_frame_only = 1;
1419                 i_p_frame_only = 0;
1420         }
1421         else if ( mode_value == 1) {
1422                 i_frame_only = 0;
1423                 i_p_frame_only = 1;
1424         }
1425         else if ( mode_value == 2 ) {
1426                 i_frame_only = 0;
1427                 i_p_frame_only = 0;
1428         }
1429         else {
1430                 printf("mode_value=%d\n",mode_value);
1431                 show_help();
1432                 return -1;
1433         }
1434     }
1435
1436     yuv_fp = fopen(argv[3],"rb");
1437     if ( yuv_fp == NULL){
1438         printf("Can't open input YUV file\n");
1439         return -1;
1440     }
1441     fseek(yuv_fp,0l, SEEK_END);
1442     file_size = ftell(yuv_fp);
1443     frame_size = picture_width * picture_height +  ((picture_width * picture_height) >> 1) ;
1444
1445     if ( (file_size < frame_size) || (file_size % frame_size) ) {
1446         fclose(yuv_fp);
1447         printf("The YUV file's size is not correct\n");
1448         return -1;
1449     }
1450     frame_number = file_size / frame_size;
1451     fseek(yuv_fp, 0l, SEEK_SET);
1452
1453     avc_fp = fopen(argv[4], "wb");      
1454     if ( avc_fp == NULL) {
1455         fclose(yuv_fp);
1456         printf("Can't open output avc file\n");
1457         return -1;
1458     }   
1459     gettimeofday(&tpstart,NULL);        
1460     avcenc_context_init(picture_width, picture_height);
1461     create_encode_pipe();
1462     alloc_encode_resource(yuv_fp);
1463
1464     enc_frame_number = 0;
1465     for ( f = 0; f < frame_number; ) {          //picture level loop
1466         static int const frame_type_pattern[][2] = { {SLICE_TYPE_I,1}, 
1467                                                      {SLICE_TYPE_P,3}, {SLICE_TYPE_P,3},{SLICE_TYPE_P,3},
1468                                                      {SLICE_TYPE_P,3}, {SLICE_TYPE_P,3},{SLICE_TYPE_P,3},
1469                                                      {SLICE_TYPE_P,3}, {SLICE_TYPE_P,3},{SLICE_TYPE_P,3},
1470                                                      {SLICE_TYPE_P,2} };
1471
1472         if ( i_frame_only ) {
1473             encode_picture(yuv_fp, avc_fp,enc_frame_number, f, f==0, SLICE_TYPE_I, 0, f+1);
1474             f++;
1475             enc_frame_number++;
1476         } else if ( i_p_frame_only ) {
1477             if ( (f % intra_period) == 0 ) {
1478                 encode_picture(yuv_fp, avc_fp,enc_frame_number, f, f==0, SLICE_TYPE_I, 0, f+1);
1479                 f++;
1480                 enc_frame_number++;
1481             } else {
1482                 encode_picture(yuv_fp, avc_fp,enc_frame_number, f, f==0, SLICE_TYPE_P, 0, f+1);
1483                 f++;
1484                 enc_frame_number++;
1485             }
1486         } else { // follow the i,p,b pattern
1487             static int fcurrent = 0;
1488             int fnext;
1489             
1490             fcurrent = fcurrent % (sizeof(frame_type_pattern)/sizeof(int[2]));
1491             fnext = (fcurrent+1) % (sizeof(frame_type_pattern)/sizeof(int[2]));
1492             
1493             if ( frame_type_pattern[fcurrent][0] == SLICE_TYPE_I ) {
1494                 encode_picture(yuv_fp, avc_fp,enc_frame_number, f, f==0, SLICE_TYPE_I, 0, 
1495                         f+frame_type_pattern[fnext][1]);
1496                 f++;
1497                 enc_frame_number++;
1498             } else {
1499                 encode_pb_pictures(yuv_fp, avc_fp, f, frame_type_pattern[fcurrent][1]-1, 
1500                         f + frame_type_pattern[fcurrent][1] + frame_type_pattern[fnext][1] -1 );
1501                 f += frame_type_pattern[fcurrent][1];
1502                 enc_frame_number++;
1503             }
1504  
1505             fcurrent++;
1506         }
1507         printf("\r %d/%d ...", f+1, frame_number);
1508         fflush(stdout);
1509     }
1510
1511     gettimeofday(&tpend,NULL);
1512     timeuse=1000000*(tpend.tv_sec-tpstart.tv_sec)+ tpend.tv_usec-tpstart.tv_usec;
1513     timeuse/=1000000;
1514     printf("\ndone!\n");
1515     printf("encode %d frames in %f secondes, FPS is %.1f\n",frame_number, timeuse, frame_number/timeuse);
1516     release_encode_resource();
1517     destory_encode_pipe();
1518
1519     fclose(yuv_fp);
1520     fclose(avc_fp);
1521
1522     return 0;
1523 }