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