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