OSDN Git Service

test/encode/avcenc: Support B frame in MFC and VME.
[android-x86/hardware-intel-common-libva.git] / test / encode / avcenc.c
1 /*
2  * Copyright (c) 2012 Intel Corporation. All Rights Reserved.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sub license, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the
13  * next paragraph) shall be included in all copies or substantial portions
14  * of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
19  * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
20  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24 /*
25  * Simple AVC encoder based on libVA.
26  *
27  * Usage:
28  * ./avcenc <width> <height> <input file> <output file> [qp]
29  */  
30
31 #include "sysdeps.h"
32 #include <stdio.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <getopt.h>
36 #include <unistd.h>
37
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <fcntl.h>
41 #include <assert.h>
42 #include <time.h>
43
44 #include <va/va.h>
45 #include "va_display.h"
46
47 #define NAL_REF_IDC_NONE        0
48 #define NAL_REF_IDC_LOW         1
49 #define NAL_REF_IDC_MEDIUM      2
50 #define NAL_REF_IDC_HIGH        3
51
52 #define NAL_NON_IDR             1
53 #define NAL_IDR                 5
54 #define NAL_SPS                 7
55 #define NAL_PPS                 8
56
57 #define SLICE_TYPE_P            0
58 #define SLICE_TYPE_B            1
59 #define SLICE_TYPE_I            2
60
61 #define ENTROPY_MODE_CAVLC      0
62 #define ENTROPY_MODE_CABAC      1
63
64 #define PROFILE_IDC_BASELINE    66
65 #define PROFILE_IDC_MAIN        77
66 #define PROFILE_IDC_HIGH        100
67
68 #define CHECK_VASTATUS(va_status,func)                                  \
69     if (va_status != VA_STATUS_SUCCESS) {                               \
70         fprintf(stderr,"%s:%s (%d) failed,exit\n", __func__, func, __LINE__); \
71         exit(1);                                                        \
72     }
73
74 static VADisplay va_dpy;
75 static VAContextID context_id;
76 static VAConfigID config_id;
77
78 static int picture_width, picture_width_in_mbs;
79 static int picture_height, picture_height_in_mbs;
80 static int frame_size;
81 static unsigned char *newImageBuffer = 0;
82 static int codedbuf_size;
83
84 static int qp_value = 26;
85
86 static int log2_max_frame_num_minus4 = 0;
87 static int pic_order_cnt_type = 0;
88 static int log2_max_pic_order_cnt_lsb_minus4 = 2;
89 static int entropy_coding_mode_flag = ENTROPY_MODE_CABAC;
90 static int deblocking_filter_control_present_flag = 1;
91 static int frame_mbs_only_flag = 1;
92
93 static void create_encode_pipe()
94 {
95     VAEntrypoint entrypoints[5];
96     int num_entrypoints,slice_entrypoint;
97     VAConfigAttrib attrib[2];
98     int major_ver, minor_ver;
99     VAStatus va_status;
100
101     va_dpy = va_open_display();
102     va_status = vaInitialize(va_dpy, &major_ver, &minor_ver);
103     CHECK_VASTATUS(va_status, "vaInitialize");
104
105     vaQueryConfigEntrypoints(va_dpy, VAProfileH264Baseline, entrypoints, 
106                              &num_entrypoints);
107
108     for (slice_entrypoint = 0; slice_entrypoint < num_entrypoints; slice_entrypoint++) {
109         if (entrypoints[slice_entrypoint] == VAEntrypointEncSlice)
110             break;
111     }
112
113     if (slice_entrypoint == num_entrypoints) {
114         /* not find Slice entry point */
115         assert(0);
116     }
117
118     /* find out the format for the render target, and rate control mode */
119     attrib[0].type = VAConfigAttribRTFormat;
120     attrib[1].type = VAConfigAttribRateControl;
121     vaGetConfigAttributes(va_dpy, VAProfileH264Baseline, VAEntrypointEncSlice,
122                           &attrib[0], 2);
123
124     if ((attrib[0].value & VA_RT_FORMAT_YUV420) == 0) {
125         /* not find desired YUV420 RT format */
126         assert(0);
127     }
128
129     if ((attrib[1].value & VA_RC_VBR) == 0) {
130         /* Can't find matched RC mode */
131         printf("VBR mode doesn't found, exit\n");
132         assert(0);
133     }
134
135     attrib[0].value = VA_RT_FORMAT_YUV420; /* set to desired RT format */
136     attrib[1].value = VA_RC_VBR; /* set to desired RC mode */
137
138     va_status = vaCreateConfig(va_dpy, VAProfileH264Baseline, VAEntrypointEncSlice,
139                                &attrib[0], 2,&config_id);
140     CHECK_VASTATUS(va_status, "vaCreateConfig");
141
142     /* Create a context for this decode pipe */
143     va_status = vaCreateContext(va_dpy, config_id,
144                                 picture_width, picture_height,
145                                 VA_PROGRESSIVE, 
146                                 0, 0,
147                                 &context_id);
148     CHECK_VASTATUS(va_status, "vaCreateContext");
149 }
150
151 static void destory_encode_pipe()
152 {
153     vaDestroyContext(va_dpy,context_id);
154     vaDestroyConfig(va_dpy,config_id);
155     vaTerminate(va_dpy);
156     va_close_display(va_dpy);
157 }
158
159 /***************************************************
160  *
161  *  The encode pipe resource define 
162  *
163  ***************************************************/
164 static VABufferID seq_parameter = VA_INVALID_ID;                /*Sequence level parameter*/
165 static VABufferID pic_parameter = VA_INVALID_ID;                /*Picture level parameter*/
166 static VABufferID slice_parameter = VA_INVALID_ID;              /*Slice level parameter, multil slices*/
167
168 static VABufferID coded_buf;                                    /*Output buffer, compressed data*/
169
170 #define SID_INPUT_PICTURE                       0
171 #define SID_REFERENCE_PICTURE_L0                1
172 #define SID_REFERENCE_PICTURE_L1                                2
173 #define SID_RECON_PICTURE                       3
174 #define SID_NUMBER                              SID_RECON_PICTURE + 1
175 static  VASurfaceID surface_ids[SID_NUMBER];
176
177 /***************************************************/
178
179 static void alloc_encode_resource()
180 {
181     VAStatus va_status;
182
183     seq_parameter = VA_INVALID_ID;              
184     pic_parameter = VA_INVALID_ID;
185     slice_parameter = VA_INVALID_ID;
186
187     //1. Create sequence parameter set
188     {
189         VAEncSequenceParameterBufferH264Baseline seq_h264 = {0};
190
191         seq_h264.level_idc = 30;
192         seq_h264.picture_width_in_mbs = picture_width_in_mbs;
193         seq_h264.picture_height_in_mbs = picture_height_in_mbs;
194
195         seq_h264.bits_per_second = 384*1000;
196         seq_h264.initial_qp = qp_value;
197         seq_h264.min_qp = 3;
198
199         va_status = vaCreateBuffer(va_dpy, context_id,
200                                    VAEncSequenceParameterBufferType,
201                                    sizeof(seq_h264),1,&seq_h264,&seq_parameter);
202         CHECK_VASTATUS(va_status,"vaCreateBuffer");;
203     }
204
205     //2. Create surface
206     va_status = vaCreateSurfaces(va_dpy, picture_width, picture_height,
207                                  VA_RT_FORMAT_YUV420, SID_NUMBER, &surface_ids[0]);
208     CHECK_VASTATUS(va_status, "vaCreateSurfaces");
209
210     //3. Create coded buffer
211     {
212         va_status = vaCreateBuffer(va_dpy,context_id,VAEncCodedBufferType,
213                                    codedbuf_size, 1, NULL, &coded_buf);
214
215         CHECK_VASTATUS(va_status,"vaBeginPicture");
216     }
217
218     newImageBuffer = (unsigned char *)malloc(frame_size);
219 }
220
221 static void release_encode_resource()
222 {
223     free(newImageBuffer);
224
225     //-3 Relese coded buffer
226     vaDestroyBuffer(va_dpy, coded_buf);
227
228     //-2 Release all the surfaces resource
229     vaDestroySurfaces(va_dpy, &surface_ids[0], SID_NUMBER);     
230
231     //-1 Destory the sequence level parameter
232     vaDestroyBuffer(va_dpy, seq_parameter);
233 }
234
235 static void begin_picture()
236 {
237     VAStatus va_status;
238     va_status = vaBeginPicture(va_dpy, context_id, surface_ids[SID_INPUT_PICTURE]);
239     CHECK_VASTATUS(va_status,"vaBeginPicture");
240 }
241
242 static void upload_yuv_to_surface(FILE *yuv_fp, VASurfaceID surface_id)
243 {
244     VAImage surface_image;
245     VAStatus va_status;
246     void *surface_p = NULL;
247     unsigned char *y_src, *u_src, *v_src;
248     unsigned char *y_dst, *u_dst, *v_dst;
249     int y_size = picture_width * picture_height;
250     int u_size = (picture_width >> 1) * (picture_height >> 1);
251     int row, col;
252     size_t n_items;
253
254     do {
255         n_items = fread(newImageBuffer, frame_size, 1, yuv_fp);
256     } while (n_items != 1);
257
258     va_status = vaDeriveImage(va_dpy, surface_id, &surface_image);
259     CHECK_VASTATUS(va_status,"vaDeriveImage");
260
261     vaMapBuffer(va_dpy, surface_image.buf, &surface_p);
262     assert(VA_STATUS_SUCCESS == va_status);
263         
264     y_src = newImageBuffer;
265     u_src = newImageBuffer + y_size; /* UV offset for NV12 */
266     v_src = newImageBuffer + y_size + u_size;
267
268     y_dst = surface_p + surface_image.offsets[0];
269     u_dst = surface_p + surface_image.offsets[1]; /* UV offset for NV12 */
270     v_dst = surface_p + surface_image.offsets[2];
271
272     /* Y plane */
273     for (row = 0; row < surface_image.height; row++) {
274         memcpy(y_dst, y_src, surface_image.width);
275         y_dst += surface_image.pitches[0];
276         y_src += picture_width;
277     }
278
279     if (surface_image.format.fourcc == VA_FOURCC_NV12) { /* UV plane */
280         for (row = 0; row < surface_image.height / 2; row++) {
281             for (col = 0; col < surface_image.width / 2; col++) {
282                 u_dst[col * 2] = u_src[col];
283                 u_dst[col * 2 + 1] = v_src[col];
284             }
285
286             u_dst += surface_image.pitches[1];
287             u_src += (picture_width / 2);
288             v_src += (picture_width / 2);
289         }
290     } else {
291         /* FIXME: fix this later */
292         assert(0);
293     }
294
295     vaUnmapBuffer(va_dpy, surface_image.buf);
296     vaDestroyImage(va_dpy, surface_image.image_id);
297 }
298
299 static void render_picture_parameter()
300 {
301     VACodedBufferSegment *coded_buffer_segment = NULL; 
302         unsigned char *coded_mem;  
303         static VAEncPictureParameterBufferH264Ext pic_h264;
304     VAStatus va_status;
305
306         // Sequence level
307     va_status = vaRenderPicture(va_dpy, context_id, &seq_parameter, 1);
308     CHECK_VASTATUS(va_status,"vaRenderPicture");;
309         // Picture level
310         memset(&pic_h264, 0, sizeof(pic_h264));
311         pic_h264.CurrPic.picture_id = surface_ids[SID_RECON_PICTURE];
312         pic_h264.ReferenceFrames[0].picture_id = surface_ids[SID_REFERENCE_PICTURE_L0];
313         pic_h264.ReferenceFrames[1].picture_id = surface_ids[SID_REFERENCE_PICTURE_L1];
314         pic_h264.ReferenceFrames[2].picture_id = VA_INVALID_ID;
315         pic_h264.CodedBuf = coded_buf;
316          if (pic_parameter != VA_INVALID_ID) {  
317         vaDestroyBuffer(va_dpy, pic_parameter); 
318     }
319     va_status = vaCreateBuffer(va_dpy, context_id,VAEncPictureParameterBufferType,
320                                sizeof(pic_h264),1,&pic_h264,&pic_parameter);
321     CHECK_VASTATUS(va_status,"vaCreateBuffer");
322     va_status = vaRenderPicture(va_dpy,context_id, &pic_parameter, 1);
323     CHECK_VASTATUS(va_status,"vaRenderPicture");
324
325     // clean old memory
326     va_status = vaMapBuffer(va_dpy,coded_buf,(void **)(&coded_buffer_segment));
327     CHECK_VASTATUS(va_status,"vaMapBuffer");
328     coded_mem = coded_buffer_segment->buf;
329     memset(coded_mem, 0, coded_buffer_segment->size);
330     vaUnmapBuffer(va_dpy, coded_buf);
331 }
332
333 static void render_slice_parameter(int slice_type)
334 {
335     static VAEncSliceParameterBufferH264Ext slice_h264;
336         VAStatus va_status;
337         
338         // Slice level  
339     slice_h264.start_row_number = 0;
340     slice_h264.slice_height = picture_height/16; /* Measured by MB */
341         slice_h264.slice_type = slice_type;
342
343     if ( slice_parameter != VA_INVALID_ID){
344         vaDestroyBuffer(va_dpy, slice_parameter);
345     }
346     va_status = vaCreateBuffer(va_dpy,context_id,VAEncSliceParameterBufferType,
347                                sizeof(slice_h264),1,&slice_h264,&slice_parameter);
348     CHECK_VASTATUS(va_status,"vaCreateBuffer");;
349     va_status = vaRenderPicture(va_dpy,context_id, &slice_parameter, 1);
350     CHECK_VASTATUS(va_status,"vaRenderPicture");
351 }
352
353 static void prepare_input_pb(FILE *yuv_fp, int is_bslice)
354 {
355     VAStatus va_status;
356     VABufferID tempID;  
357
358     // Copy Image to target surface according input YUV data.
359         if ( is_bslice ) {
360                 upload_yuv_to_surface(yuv_fp, surface_ids[SID_INPUT_PICTURE]);
361                 fseek(yuv_fp, SEEK_CUR, frame_size);
362         } else {
363                 fseek(yuv_fp, SEEK_CUR, frame_size); 
364                 upload_yuv_to_surface(yuv_fp, surface_ids[SID_INPUT_PICTURE]);
365                 fseek(yuv_fp, SEEK_CUR, -2l * frame_size);
366         }
367         
368         // Render picture level parameters
369         render_picture_parameter();
370         
371         // Render slice level parameters
372         if ( is_bslice ) {
373                 render_slice_parameter(SLICE_TYPE_B);
374         } else {
375                 render_slice_parameter(SLICE_TYPE_P);
376         }
377         
378         if ( is_bslice == 1) {
379                 // Prepare for next I:P frame
380                 tempID = surface_ids[SID_RECON_PICTURE];  
381                 surface_ids[SID_RECON_PICTURE] = surface_ids[SID_REFERENCE_PICTURE_L0]; 
382                 surface_ids[SID_REFERENCE_PICTURE_L0] = surface_ids[SID_REFERENCE_PICTURE_L1];
383                 surface_ids[SID_REFERENCE_PICTURE_L1] = tempID;
384         } else {
385                 // Prepare for next B frame
386                 tempID = surface_ids[SID_RECON_PICTURE];  
387                 surface_ids[SID_RECON_PICTURE] = surface_ids[SID_REFERENCE_PICTURE_L1]; 
388                 surface_ids[SID_REFERENCE_PICTURE_L1] = tempID; 
389         }
390 }
391
392 static void prepare_input_ip(FILE * yuv_fp, int intra_slice)
393 {
394     VAStatus va_status;
395     VABufferID tempID;  
396     VACodedBufferSegment *coded_buffer_segment = NULL; 
397     unsigned char *coded_mem;
398
399     // Copy Image to target surface according input YUV data.
400     upload_yuv_to_surface(yuv_fp, surface_ids[SID_INPUT_PICTURE]);
401         
402         // Render picture level parameters
403         render_picture_parameter();
404         
405     // Slice level      
406         if ( intra_slice )
407                 render_slice_parameter(SLICE_TYPE_I);
408         else
409                 render_slice_parameter(SLICE_TYPE_P);
410
411     // Prepare for next picture
412     tempID = surface_ids[SID_RECON_PICTURE];  
413     surface_ids[SID_RECON_PICTURE] = surface_ids[SID_REFERENCE_PICTURE_L0]; 
414     surface_ids[SID_REFERENCE_PICTURE_L0] = tempID;
415 }
416
417 static void end_picture()
418 {       
419     VAStatus va_status;
420
421     va_status = vaEndPicture(va_dpy,context_id);
422     CHECK_VASTATUS(va_status,"vaRenderPicture");
423 }
424
425 #define BITSTREAM_ALLOCATE_STEPPING     4096
426
427 struct __bitstream {
428     unsigned int *buffer;
429     int bit_offset;
430     int max_size_in_dword;
431 };
432
433 typedef struct __bitstream bitstream;
434
435 static int 
436 get_coded_bitsteam_length(unsigned char *buffer, int buffer_length)
437 {
438     int i;
439
440     for (i = buffer_length - 1; i >= 0; i--) {
441         if (buffer[i])
442             break;
443     }
444
445     return i + 1;
446 }
447
448 static unsigned int 
449 va_swap32(unsigned int val)
450 {
451     unsigned char *pval = (unsigned char *)&val;
452
453     return ((pval[0] << 24)     |
454             (pval[1] << 16)     |
455             (pval[2] << 8)      |
456             (pval[3] << 0));
457 }
458
459 static void
460 bitstream_start(bitstream *bs)
461 {
462     bs->max_size_in_dword = BITSTREAM_ALLOCATE_STEPPING;
463     bs->buffer = calloc(bs->max_size_in_dword * sizeof(int), 1);
464     bs->bit_offset = 0;
465 }
466
467 static void
468 bitstream_end(bitstream *bs, FILE *avc_fp)
469 {
470     int pos = (bs->bit_offset >> 5);
471     int bit_offset = (bs->bit_offset & 0x1f);
472     int bit_left = 32 - bit_offset;
473     int length = (bs->bit_offset + 7) >> 3;
474     size_t w_items;
475
476     if (bit_offset) {
477         bs->buffer[pos] = va_swap32((bs->buffer[pos] << bit_left));
478     }
479
480     do {
481         w_items = fwrite(bs->buffer, length, 1, avc_fp);
482     } while (w_items != 1);
483
484     free(bs->buffer);
485 }
486  
487 static void
488 bitstream_put_ui(bitstream *bs, unsigned int val, int size_in_bits)
489 {
490     int pos = (bs->bit_offset >> 5);
491     int bit_offset = (bs->bit_offset & 0x1f);
492     int bit_left = 32 - bit_offset;
493
494     if (!size_in_bits)
495         return;
496
497     bs->bit_offset += size_in_bits;
498
499     if (bit_left > size_in_bits) {
500         bs->buffer[pos] = (bs->buffer[pos] << size_in_bits | val);
501     } else {
502         size_in_bits -= bit_left;
503         bs->buffer[pos] = (bs->buffer[pos] << bit_left) | (val >> size_in_bits);
504         bs->buffer[pos] = va_swap32(bs->buffer[pos]);
505
506         if (pos + 1 == bs->max_size_in_dword) {
507             bs->max_size_in_dword += BITSTREAM_ALLOCATE_STEPPING;
508             bs->buffer = realloc(bs->buffer, bs->max_size_in_dword * sizeof(unsigned int));
509         }
510
511         bs->buffer[pos + 1] = val;
512     }
513 }
514
515 static void
516 bitstream_put_ue(bitstream *bs, unsigned int val)
517 {
518     int size_in_bits = 0;
519     int tmp_val = ++val;
520
521     while (tmp_val) {
522         tmp_val >>= 1;
523         size_in_bits++;
524     }
525
526     bitstream_put_ui(bs, 0, size_in_bits - 1); // leading zero
527     bitstream_put_ui(bs, val, size_in_bits);
528 }
529
530 static void
531 bitstream_put_se(bitstream *bs, int val)
532 {
533     unsigned int new_val;
534
535     if (val <= 0)
536         new_val = -2 * val;
537     else
538         new_val = 2 * val - 1;
539
540     bitstream_put_ue(bs, new_val);
541 }
542
543 static void
544 bitstream_byte_aligning(bitstream *bs, int bit)
545 {
546     int bit_offset = (bs->bit_offset & 0x7);
547     int bit_left = 8 - bit_offset;
548     int new_val;
549
550     if (!bit_offset)
551         return;
552
553     assert(bit == 0 || bit == 1);
554
555     if (bit)
556         new_val = (1 << bit_left) - 1;
557     else
558         new_val = 0;
559
560     bitstream_put_ui(bs, new_val, bit_left);
561 }
562
563 static void 
564 rbsp_trailing_bits(bitstream *bs)
565 {
566     bitstream_put_ui(bs, 1, 1);
567     bitstream_byte_aligning(bs, 0);
568 }
569
570 static void nal_start_code_prefix(bitstream *bs)
571 {
572     bitstream_put_ui(bs, 0x00000001, 32);
573 }
574
575 static void nal_header(bitstream *bs, int nal_ref_idc, int nal_unit_type)
576 {
577     bitstream_put_ui(bs, 0, 1);                /* forbidden_zero_bit: 0 */
578     bitstream_put_ui(bs, nal_ref_idc, 2);
579     bitstream_put_ui(bs, nal_unit_type, 5);
580 }
581
582 static void sps_rbsp(bitstream *bs)
583 {
584     int mb_width, mb_height;
585     int frame_cropping_flag = 0;
586     int frame_crop_bottom_offset = 0;
587     int profile_idc = PROFILE_IDC_MAIN;
588
589     mb_width = picture_width_in_mbs;
590     mb_height = picture_height_in_mbs;
591
592     if (mb_height * 16 - picture_height) {
593         frame_cropping_flag = 1;
594         frame_crop_bottom_offset = 
595             (mb_height * 16 - picture_height) / (2 * (!frame_mbs_only_flag + 1));
596     }
597
598     bitstream_put_ui(bs, profile_idc, 8);               /* profile_idc */
599     bitstream_put_ui(bs, 0, 1);                         /* constraint_set0_flag */
600     bitstream_put_ui(bs, 1, 1);                         /* constraint_set1_flag */
601     bitstream_put_ui(bs, 0, 1);                         /* constraint_set2_flag */
602     bitstream_put_ui(bs, 0, 1);                         /* constraint_set3_flag */
603     bitstream_put_ui(bs, 0, 4);                         /* reserved_zero_4bits */
604     bitstream_put_ui(bs, 41, 8);                        /* level_idc */
605     bitstream_put_ue(bs, 0);                            /* seq_parameter_set_id */
606
607     if (profile_idc >= 100) {
608         /* FIXME: fix for high profile */
609         assert(0);
610     }
611
612     bitstream_put_ue(bs, log2_max_frame_num_minus4);    /* log2_max_frame_num_minus4 */
613     bitstream_put_ue(bs, pic_order_cnt_type);           /* pic_order_cnt_type */
614
615     if (pic_order_cnt_type == 0)
616         bitstream_put_ue(bs, log2_max_pic_order_cnt_lsb_minus4);        /* log2_max_pic_order_cnt_lsb_minus4 */
617     else {
618         assert(0);
619     }
620
621     bitstream_put_ue(bs, 4);                            /* num_ref_frames */
622     bitstream_put_ui(bs, 0, 1);                         /* gaps_in_frame_num_value_allowed_flag */
623
624     bitstream_put_ue(bs, mb_width - 1);                 /* pic_width_in_mbs_minus1 */
625     bitstream_put_ue(bs, mb_height - 1);                /* pic_height_in_map_units_minus1 */
626     bitstream_put_ui(bs, frame_mbs_only_flag, 1);       /* frame_mbs_only_flag */
627
628     if (!frame_mbs_only_flag) {
629         assert(0);
630     }
631
632     bitstream_put_ui(bs, 0, 1);                         /* direct_8x8_inference_flag */
633     bitstream_put_ui(bs, frame_cropping_flag, 1);       /* frame_cropping_flag */
634
635     if (frame_cropping_flag) {
636         bitstream_put_ue(bs, 0);                        /* frame_crop_left_offset */
637         bitstream_put_ue(bs, 0);                        /* frame_crop_right_offset */
638         bitstream_put_ue(bs, 0);                        /* frame_crop_top_offset */
639         bitstream_put_ue(bs, frame_crop_bottom_offset); /* frame_crop_bottom_offset */
640     }
641
642     bitstream_put_ui(bs, 0, 1);                         /* vui_parameters_present_flag */
643     rbsp_trailing_bits(bs);                             /* rbsp_trailing_bits */
644 }
645
646 static void build_nal_sps(FILE *avc_fp)
647 {
648     bitstream bs;
649
650     bitstream_start(&bs);
651     nal_start_code_prefix(&bs);
652     nal_header(&bs, NAL_REF_IDC_HIGH, NAL_SPS);
653     sps_rbsp(&bs);
654     bitstream_end(&bs, avc_fp);
655 }
656
657 static void pps_rbsp(bitstream *bs)
658 {
659     bitstream_put_ue(bs, 0);                            /* pic_parameter_set_id */
660     bitstream_put_ue(bs, 0);                            /* seq_parameter_set_id */
661
662     bitstream_put_ui(bs, entropy_coding_mode_flag, 1);  /* entropy_coding_mode_flag */
663
664     bitstream_put_ui(bs, 0, 1);                         /* pic_order_present_flag: 0 */
665
666     bitstream_put_ue(bs, 0);                            /* num_slice_groups_minus1 */
667
668     bitstream_put_ue(bs, 0);                            /* num_ref_idx_l0_active_minus1 */
669     bitstream_put_ue(bs, 0);                            /* num_ref_idx_l1_active_minus1 1 */
670
671     bitstream_put_ui(bs, 0, 1);                         /* weighted_pred_flag: 0 */
672     bitstream_put_ui(bs, 0, 2);                         /* weighted_bipred_idc: 0 */
673
674     bitstream_put_se(bs, 0);                            /* pic_init_qp_minus26 */
675     bitstream_put_se(bs, 0);                            /* pic_init_qs_minus26 */
676     bitstream_put_se(bs, 0);                            /* chroma_qp_index_offset */
677
678     bitstream_put_ui(bs, 1, 1);                         /* deblocking_filter_control_present_flag */
679     bitstream_put_ui(bs, 0, 1);                         /* constrained_intra_pred_flag */
680     bitstream_put_ui(bs, 0, 1);                         /* redundant_pic_cnt_present_flag */
681
682     rbsp_trailing_bits(bs);
683 }
684
685 static void build_nal_pps(FILE *avc_fp)
686 {
687     bitstream bs;
688
689     bitstream_start(&bs);
690     nal_start_code_prefix(&bs);
691     nal_header(&bs, NAL_REF_IDC_HIGH, NAL_PPS);
692     pps_rbsp(&bs);
693     bitstream_end(&bs, avc_fp);
694 }
695
696 static void 
697 build_header(FILE *avc_fp)
698 {
699     build_nal_sps(avc_fp);
700     build_nal_pps(avc_fp);
701 }
702
703
704 static void 
705 slice_header(bitstream *bs, int frame_num, int display_frame, int slice_type, int nal_ref_idc, int is_idr)
706 {       
707     int is_cabac = (entropy_coding_mode_flag == ENTROPY_MODE_CABAC);
708
709     bitstream_put_ue(bs, 0);                   /* first_mb_in_slice: 0 */
710     bitstream_put_ue(bs, slice_type);          /* slice_type */
711     bitstream_put_ue(bs, 0);                   /* pic_parameter_set_id: 0 */
712     bitstream_put_ui(bs, frame_num & 0x0F, log2_max_frame_num_minus4 + 4);    /* frame_num */
713
714     /* frame_mbs_only_flag == 1 */
715     if (!frame_mbs_only_flag) {
716         /* FIXME: */
717         assert(0);
718     }
719
720     if (is_idr)
721         bitstream_put_ue(bs, 0);                /* idr_pic_id: 0 */
722
723     if (pic_order_cnt_type == 0) {
724                 bitstream_put_ui(bs, (display_frame*2) & 0x3F, log2_max_pic_order_cnt_lsb_minus4 + 4);
725         /* only support frame */
726     } else {
727         /* FIXME: */
728         assert(0);
729     }
730
731     /* redundant_pic_cnt_present_flag == 0 */
732     
733     /* slice type */
734         if (slice_type == SLICE_TYPE_P) {
735                 bitstream_put_ui(bs, 0, 1);            /* num_ref_idx_active_override_flag: 0 */
736                 /* ref_pic_list_reordering */
737                 bitstream_put_ui(bs, 0, 1);            /* ref_pic_list_reordering_flag_l0: 0 */
738         } else if (slice_type == SLICE_TYPE_B) {
739                 bitstream_put_ui(bs, 1, 1);            /* direct_spatial_mv_pred: 1 */
740                 bitstream_put_ui(bs, 0, 1);            /* num_ref_idx_active_override_flag: 0 */
741                 /* ref_pic_list_reordering */
742                 bitstream_put_ui(bs, 0, 1);            /* ref_pic_list_reordering_flag_l0: 0 */
743                 bitstream_put_ui(bs, 0, 1);            /* ref_pic_list_reordering_flag_l1: 0 */
744         } 
745
746     /* weighted_pred_flag == 0 */
747
748     /* dec_ref_pic_marking */
749         if (nal_ref_idc != 0) {
750                 if ( is_idr) {
751                         bitstream_put_ui(bs, 0, 1);            /* no_output_of_prior_pics_flag: 0 */
752                         bitstream_put_ui(bs, 0, 1);            /* long_term_reference_flag: 0 */
753                 } else {
754                         bitstream_put_ui(bs, 0, 1);            /* adaptive_ref_pic_marking_mode_flag: 0 */
755                 }
756         }
757
758     if (is_cabac && (slice_type != SLICE_TYPE_I))
759         bitstream_put_ue(bs, 0);               /* cabac_init_idc: 0 */
760
761     bitstream_put_se(bs, 0);                   /* slice_qp_delta: 0 */
762
763     if (deblocking_filter_control_present_flag == 1) {
764         bitstream_put_ue(bs, 0);               /* disable_deblocking_filter_idc: 0 */
765         bitstream_put_se(bs, 2);               /* slice_alpha_c0_offset_div2: 2 */
766         bitstream_put_se(bs, 2);               /* slice_beta_offset_div2: 2 */
767     }
768 }
769
770 static void 
771 slice_data(bitstream *bs)
772 {
773     VACodedBufferSegment *coded_buffer_segment;
774     unsigned char *coded_mem;
775     int i, slice_data_length;
776     VAStatus va_status;
777     VASurfaceStatus surface_status;
778     int is_cabac = (entropy_coding_mode_flag == ENTROPY_MODE_CABAC);
779
780     va_status = vaSyncSurface(va_dpy, surface_ids[SID_INPUT_PICTURE]);
781     CHECK_VASTATUS(va_status,"vaSyncSurface");
782
783     surface_status = 0;
784     va_status = vaQuerySurfaceStatus(va_dpy, surface_ids[SID_INPUT_PICTURE], &surface_status);
785     CHECK_VASTATUS(va_status,"vaQuerySurfaceStatus");
786
787     va_status = vaMapBuffer(va_dpy, coded_buf, (void **)(&coded_buffer_segment));
788     CHECK_VASTATUS(va_status,"vaMapBuffer");
789     coded_mem = coded_buffer_segment->buf;
790
791     if (is_cabac) {
792         bitstream_byte_aligning(bs, 1);
793         slice_data_length = get_coded_bitsteam_length(coded_mem, codedbuf_size);
794
795         for (i = 0; i < slice_data_length; i++) {
796             bitstream_put_ui(bs, *coded_mem, 8);
797             coded_mem++;
798         }
799     } else {
800         /* FIXME */
801         assert(0);
802     }
803
804     vaUnmapBuffer(va_dpy, coded_buf);
805 }
806
807 static void 
808 build_nal_slice(FILE *avc_fp, int frame_num, int display_frame, int slice_type, int is_idr)
809 {
810     bitstream bs;
811
812     bitstream_start(&bs);
813     nal_start_code_prefix(&bs);
814     if ( slice_type == SLICE_TYPE_I)
815                 nal_header(&bs, NAL_REF_IDC_HIGH, is_idr ? NAL_IDR : NAL_NON_IDR);
816         else if ( slice_type == SLICE_TYPE_P)
817                 nal_header(&bs, NAL_REF_IDC_MEDIUM, is_idr ? NAL_IDR : NAL_NON_IDR);
818         else
819                 nal_header(&bs, NAL_REF_IDC_NONE, is_idr ? NAL_IDR : NAL_NON_IDR);
820
821     if ( slice_type == SLICE_TYPE_I  ) {
822                 slice_header(&bs, frame_num, display_frame, slice_type, NAL_REF_IDC_HIGH, is_idr);
823         } else if ( slice_type == SLICE_TYPE_P ) {
824                 slice_header(&bs, frame_num, display_frame, slice_type, NAL_REF_IDC_MEDIUM, is_idr);
825         } else {
826                 slice_header(&bs, frame_num, display_frame, slice_type, NAL_REF_IDC_NONE,is_idr);
827         }
828
829         slice_data(&bs);
830     bitstream_end(&bs, avc_fp);
831 }
832
833 static void 
834 store_coded_buffer(FILE *avc_fp, int frame_num, int display_frame, int slice_type, int is_idr)
835 {
836     build_nal_slice(avc_fp, frame_num, display_frame, slice_type, is_idr);
837 }
838
839 static void encode_intra_slices(FILE *yuv_fp, FILE *avc_fp, int f, int is_idr)
840 {
841          begin_picture();
842          prepare_input_ip(yuv_fp, 1);
843          end_picture();
844          store_coded_buffer(avc_fp, f, f, SLICE_TYPE_I, is_idr);
845 }
846
847 static void encode_p_slices(FILE *yuv_fp, FILE *avc_fp, int f)
848 {
849          begin_picture();
850          prepare_input_ip(yuv_fp, 0);
851          end_picture();
852          store_coded_buffer(avc_fp, f, f, SLICE_TYPE_P, 0);
853 }
854
855 static void encode_pb_slices(FILE *yuv_fp, FILE *avc_fp, int f)
856 {
857         begin_picture();
858         prepare_input_pb(yuv_fp, 0);
859         end_picture();
860         store_coded_buffer(avc_fp, f, f+1, SLICE_TYPE_P, 0);
861
862         begin_picture();
863         prepare_input_pb(yuv_fp, 1);
864         end_picture();
865         store_coded_buffer(avc_fp, f+1, f, SLICE_TYPE_B, 0);
866 }
867
868 int main(int argc, char *argv[])
869 {
870     int f;
871     FILE *yuv_fp;
872     FILE *avc_fp;
873     int frame_number;
874     long file_size;
875     clock_t start_clock, end_clock;
876     float encoding_time;
877
878     va_init_display_args(&argc, argv);
879
880     if(argc != 5 && argc != 6) {
881         printf("Usage: %s <width> <height> <input_yuvfile> <output_avcfile> [qp]\n", argv[0]);
882         return -1;
883     }
884
885     picture_width = atoi(argv[1]);
886     picture_height = atoi(argv[2]);
887     picture_width_in_mbs = (picture_width + 15) / 16;
888     picture_height_in_mbs = (picture_height + 15) / 16;
889
890     if (argc == 6)
891         qp_value = atoi(argv[5]);
892     else
893         qp_value = 26;
894
895     yuv_fp = fopen(argv[3],"rb");
896     if ( yuv_fp == NULL){
897         printf("Can't open input YUV file\n");
898         return -1;
899     }
900     fseek(yuv_fp,0l, SEEK_END);
901     file_size = ftell(yuv_fp);
902     frame_size = picture_width * picture_height +  ((picture_width * picture_height) >> 1) ;
903     codedbuf_size = picture_width * picture_height * 1.5;
904
905     if ( (file_size < frame_size) || (file_size % frame_size) ) {
906         printf("The YUV file's size is not correct\n");
907         return -1;
908     }
909     frame_number = file_size / frame_size;
910     fseek(yuv_fp, 0l, SEEK_SET);
911
912     avc_fp = fopen(argv[4], "wb");      
913     if ( avc_fp == NULL) {
914         printf("Can't open output avc file\n");
915         return -1;
916     }   
917     start_clock = clock();
918     build_header(avc_fp);
919
920     create_encode_pipe();
921     alloc_encode_resource();
922
923     for ( f = 0; f < frame_number; ) {          //picture level loop
924         int is_intra = (f % 30 == 0);
925         int is_idr = (f == 0);
926                 int is_bslice = 0;
927                 
928                 if ( ! is_intra ) {
929                         is_bslice = (f % 5 == 0) && (f < frame_number - 1);     
930                 }
931         
932                 if ( is_intra ) {
933                         encode_intra_slices(yuv_fp, avc_fp, f, is_idr);
934                         f++;
935                 } else if ( is_bslice) {
936                         encode_pb_slices(yuv_fp, avc_fp, f);
937                         f+=2;
938                 } else {
939                         encode_p_slices(yuv_fp, avc_fp, f);
940                         f++;
941                 }
942        
943         printf("\r %d/%d ...", f+1, frame_number);
944         fflush(stdout);
945     }
946
947     end_clock = clock();
948     printf("\ndone!\n");
949     encoding_time = (float)(end_clock-start_clock)/CLOCKS_PER_SEC;
950     printf("encode %d frames in %f secondes, FPS is %.1f\n",frame_number, encoding_time, frame_number/encoding_time);
951
952     release_encode_resource();
953     destory_encode_pipe();
954
955     return 0;
956 }