2 * Copyright (c) 2012 Intel Corporation. All Rights Reserved.
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:
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial portions
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.
25 * Simple AVC encoder based on libVA.
28 * ./avcenc <width> <height> <input file> <output file> [qp]
39 #include <sys/types.h>
48 #include "va_display.h"
50 #define NAL_REF_IDC_NONE 0
51 #define NAL_REF_IDC_LOW 1
52 #define NAL_REF_IDC_MEDIUM 2
53 #define NAL_REF_IDC_HIGH 3
60 #define SLICE_TYPE_P 0
61 #define SLICE_TYPE_B 1
62 #define SLICE_TYPE_I 2
64 #define ENTROPY_MODE_CAVLC 0
65 #define ENTROPY_MODE_CABAC 1
67 #define PROFILE_IDC_BASELINE 66
68 #define PROFILE_IDC_MAIN 77
69 #define PROFILE_IDC_HIGH 100
71 #define CHECK_VASTATUS(va_status,func) \
72 if (va_status != VA_STATUS_SUCCESS) { \
73 fprintf(stderr,"%s:%s (%d) failed,exit\n", __func__, func, __LINE__); \
77 static VADisplay va_dpy;
79 static int picture_width, picture_width_in_mbs;
80 static int picture_height, picture_height_in_mbs;
81 static int frame_size;
82 static unsigned char *newImageBuffer = 0;
84 static int qp_value = 26;
86 static int intra_period = 30;
87 static int pb_period = 5;
88 static int frame_bit_rate = -1;
97 build_packed_pic_buffer(unsigned char **header_buffer);
100 build_packed_seq_buffer(unsigned char **header_buffer);
102 struct upload_thread_param
105 VASurfaceID surface_id;
109 upload_yuv_to_surface(FILE *yuv_fp, VASurfaceID surface_id);
111 struct packed_data_format
113 unsigned int length_in_bits;
115 unsigned char num_skip_bytes;
116 unsigned char pad[2];
120 VAEncSequenceParameterBufferH264Ext seq_param;
121 VAEncPictureParameterBufferH264Ext pic_param;
122 VAEncSliceParameterBufferH264Ext slice_param[MAX_SLICES];
123 VAEncH264DecRefPicMarkingBuffer dec_ref_pic_marking;
124 VAContextID context_id;
125 VAConfigID config_id;
126 VABufferID seq_param_buf_id; /* Sequence level parameter */
127 VABufferID pic_param_buf_id; /* Picture level parameter */
128 VABufferID slice_param_buf_id[MAX_SLICES]; /* Slice level parameter, multil slices */
129 VABufferID dec_ref_pic_marking_buf_id;
130 VABufferID codedbuf_buf_id; /* Output buffer, compressed data */
131 VABufferID packed_seq_buf_id;
132 VABufferID packed_pic_buf_id;
135 int codedbuf_pb_size;
136 int current_input_surface;
137 struct upload_thread_param upload_thread_param;
138 pthread_t upload_thread_id;
139 int upload_thread_value;
142 static void create_encode_pipe()
144 VAEntrypoint entrypoints[5];
145 int num_entrypoints,slice_entrypoint;
146 VAConfigAttrib attrib[2];
147 int major_ver, minor_ver;
150 va_dpy = va_open_display();
151 va_status = vaInitialize(va_dpy, &major_ver, &minor_ver);
152 CHECK_VASTATUS(va_status, "vaInitialize");
154 vaQueryConfigEntrypoints(va_dpy, VAProfileH264Baseline, entrypoints,
157 for (slice_entrypoint = 0; slice_entrypoint < num_entrypoints; slice_entrypoint++) {
158 if (entrypoints[slice_entrypoint] == VAEntrypointEncSlice)
162 if (slice_entrypoint == num_entrypoints) {
163 /* not find Slice entry point */
167 /* find out the format for the render target, and rate control mode */
168 attrib[0].type = VAConfigAttribRTFormat;
169 attrib[1].type = VAConfigAttribRateControl;
170 vaGetConfigAttributes(va_dpy, VAProfileH264Baseline, VAEntrypointEncSlice,
173 if ((attrib[0].value & VA_RT_FORMAT_YUV420) == 0) {
174 /* not find desired YUV420 RT format */
178 if ((attrib[1].value & VA_RC_VBR) == 0) {
179 /* Can't find matched RC mode */
180 printf("VBR mode doesn't found, exit\n");
184 attrib[0].value = VA_RT_FORMAT_YUV420; /* set to desired RT format */
185 attrib[1].value = VA_RC_VBR; /* set to desired RC mode */
187 va_status = vaCreateConfig(va_dpy, VAProfileH264Baseline, VAEntrypointEncSlice,
188 &attrib[0], 2,&avcenc_context.config_id);
189 CHECK_VASTATUS(va_status, "vaCreateConfig");
191 /* Create a context for this decode pipe */
192 va_status = vaCreateContext(va_dpy, avcenc_context.config_id,
193 picture_width, picture_height,
196 &avcenc_context.context_id);
197 CHECK_VASTATUS(va_status, "vaCreateContext");
200 static void destory_encode_pipe()
202 vaDestroyContext(va_dpy,avcenc_context.context_id);
203 vaDestroyConfig(va_dpy,avcenc_context.config_id);
205 va_close_display(va_dpy);
208 /***************************************************
210 * The encode pipe resource define
212 ***************************************************/
213 #define SID_INPUT_PICTURE_0 0
214 #define SID_INPUT_PICTURE_1 1
215 #define SID_REFERENCE_PICTURE_L0 2
216 #define SID_REFERENCE_PICTURE_L1 3
217 #define SID_RECON_PICTURE 4
218 #define SID_NUMBER SID_RECON_PICTURE + 1
219 static VASurfaceID surface_ids[SID_NUMBER];
221 static int frame_number;
222 static int enc_frame_number;
224 /***************************************************/
227 upload_thread_function(void *data)
229 struct upload_thread_param *param = data;
231 upload_yuv_to_surface(param->yuv_fp, param->surface_id);
236 static void alloc_encode_resource(FILE *yuv_fp)
241 va_status = vaCreateSurfaces(va_dpy, picture_width, picture_height,
242 VA_RT_FORMAT_YUV420, SID_NUMBER, &surface_ids[0]);
243 CHECK_VASTATUS(va_status, "vaCreateSurfaces");
245 newImageBuffer = (unsigned char *)malloc(frame_size);
247 /* firstly upload YUV data to SID_INPUT_PICTURE_1 */
248 avcenc_context.upload_thread_param.yuv_fp = yuv_fp;
249 avcenc_context.upload_thread_param.surface_id = surface_ids[SID_INPUT_PICTURE_1];
251 avcenc_context.upload_thread_value = pthread_create(&avcenc_context.upload_thread_id,
253 upload_thread_function,
254 (void*)&avcenc_context.upload_thread_param);
257 static void release_encode_resource()
259 pthread_join(avcenc_context.upload_thread_id, NULL);
260 free(newImageBuffer);
262 // Release all the surfaces resource
263 vaDestroySurfaces(va_dpy, &surface_ids[0], SID_NUMBER);
266 static void avcenc_update_picture_parameter(int slice_type, int frame_num, int display_num, int is_idr)
268 VAEncPictureParameterBufferH264Ext *pic_param;
272 pic_param = &avcenc_context.pic_param;
273 pic_param->CurrPic.picture_id = surface_ids[SID_RECON_PICTURE];
274 pic_param->CurrPic.TopFieldOrderCnt = display_num * 2;
275 pic_param->ReferenceFrames[0].picture_id = surface_ids[SID_REFERENCE_PICTURE_L0];
276 pic_param->ReferenceFrames[1].picture_id = surface_ids[SID_REFERENCE_PICTURE_L1];
277 pic_param->ReferenceFrames[2].picture_id = VA_INVALID_ID;
278 assert(avcenc_context.codedbuf_buf_id != VA_INVALID_ID);
279 pic_param->CodedBuf = avcenc_context.codedbuf_buf_id;
280 pic_param->frame_num = frame_num;
281 pic_param->pic_fields.bits.idr_pic_flag = !!is_idr;
282 pic_param->pic_fields.bits.reference_pic_flag = (slice_type != SLICE_TYPE_B);
284 va_status = vaCreateBuffer(va_dpy,
285 avcenc_context.context_id,
286 VAEncPictureParameterBufferExtType,
287 sizeof(*pic_param), 1, pic_param,
288 &avcenc_context.pic_param_buf_id);
289 CHECK_VASTATUS(va_status,"vaCreateBuffer");
292 static void upload_yuv_to_surface(FILE *yuv_fp, VASurfaceID surface_id)
294 VAImage surface_image;
296 void *surface_p = NULL;
297 unsigned char *y_src, *u_src, *v_src;
298 unsigned char *y_dst, *u_dst, *v_dst;
299 int y_size = picture_width * picture_height;
300 int u_size = (picture_width >> 1) * (picture_height >> 1);
305 n_items = fread(newImageBuffer, frame_size, 1, yuv_fp);
306 } while (n_items != 1);
308 va_status = vaDeriveImage(va_dpy, surface_id, &surface_image);
309 CHECK_VASTATUS(va_status,"vaDeriveImage");
311 vaMapBuffer(va_dpy, surface_image.buf, &surface_p);
312 assert(VA_STATUS_SUCCESS == va_status);
314 y_src = newImageBuffer;
315 u_src = newImageBuffer + y_size; /* UV offset for NV12 */
316 v_src = newImageBuffer + y_size + u_size;
318 y_dst = surface_p + surface_image.offsets[0];
319 u_dst = surface_p + surface_image.offsets[1]; /* UV offset for NV12 */
320 v_dst = surface_p + surface_image.offsets[2];
323 for (row = 0; row < surface_image.height; row++) {
324 memcpy(y_dst, y_src, surface_image.width);
325 y_dst += surface_image.pitches[0];
326 y_src += picture_width;
329 if (surface_image.format.fourcc == VA_FOURCC_NV12) { /* UV plane */
330 for (row = 0; row < surface_image.height / 2; row++) {
331 for (col = 0; col < surface_image.width / 2; col++) {
332 u_dst[col * 2] = u_src[col];
333 u_dst[col * 2 + 1] = v_src[col];
336 u_dst += surface_image.pitches[1];
337 u_src += (picture_width / 2);
338 v_src += (picture_width / 2);
341 /* FIXME: fix this later */
345 vaUnmapBuffer(va_dpy, surface_image.buf);
346 vaDestroyImage(va_dpy, surface_image.image_id);
349 static void avcenc_update_slice_parameter(int slice_type)
351 VAEncSliceParameterBufferH264Ext *slice_param;
357 slice_param = &avcenc_context.slice_param[i];
358 slice_param->start_row_number = 0;
359 slice_param->slice_height = picture_height_in_mbs/16; /* Measured by MB */
360 slice_param->pic_parameter_set_id = 0;
361 slice_param->slice_type = slice_type;
362 slice_param->direct_spatial_mv_pred_flag = 0;
363 slice_param->num_ref_idx_l0_active_minus1 = 0; /* FIXME: ??? */
364 slice_param->num_ref_idx_l1_active_minus1 = 0;
365 slice_param->cabac_init_idc = 0;
366 slice_param->slice_qp_delta = 0;
367 slice_param->disable_deblocking_filter_idc = 0;
368 slice_param->slice_alpha_c0_offset_div2 = 2;
369 slice_param->slice_beta_offset_div2 = 2;
370 slice_param->idr_pic_id = 0;
372 /* ref_pic_list_modification() */
373 slice_param->ref_pic_list_modification_flag_l0 = 0;
374 slice_param->ref_pic_list_modification_flag_l1 = 0;
375 /* FIXME: fill other fields */
377 va_status = vaCreateBuffer(va_dpy,
378 avcenc_context.context_id,
379 VAEncSliceParameterBufferExtType,
380 sizeof(*slice_param), 1, slice_param,
381 &avcenc_context.slice_param_buf_id[i]);
382 CHECK_VASTATUS(va_status,"vaCreateBuffer");;
386 avcenc_context.num_slices = i;
389 static int begin_picture(FILE *yuv_fp, int frame_num, int display_num, int slice_type, int is_idr)
393 if (avcenc_context.upload_thread_value != 0) {
394 fprintf(stderr, "FATAL error!!!\n");
398 pthread_join(avcenc_context.upload_thread_id, NULL);
400 avcenc_context.upload_thread_value = -1;
402 if (avcenc_context.current_input_surface == SID_INPUT_PICTURE_0)
403 avcenc_context.current_input_surface = SID_INPUT_PICTURE_1;
405 avcenc_context.current_input_surface = SID_INPUT_PICTURE_0;
407 if (frame_num == 0) {
408 unsigned char *packed_seq_buffer = NULL, *packed_pic_buffer = NULL;
409 int seq_length, pic_length;
411 assert(slice_type == SLICE_TYPE_I);
412 seq_length = build_packed_seq_buffer(&packed_seq_buffer);
413 va_status = vaCreateBuffer(va_dpy,
414 avcenc_context.context_id,
415 VAEncPackedSequenceParameterBufferType,
416 (seq_length + 7) / 8, 1, packed_seq_buffer,
417 &avcenc_context.packed_seq_buf_id);
418 CHECK_VASTATUS(va_status,"vaCreateBuffer");;
420 pic_length = build_packed_pic_buffer(&packed_pic_buffer);
421 va_status = vaCreateBuffer(va_dpy,
422 avcenc_context.context_id,
423 VAEncPackedPictureParameterBufferType,
424 (pic_length + 7) / 8 , 1, packed_pic_buffer,
425 &avcenc_context.packed_pic_buf_id);
426 CHECK_VASTATUS(va_status,"vaCreateBuffer");;
428 free(packed_seq_buffer);
429 free(packed_pic_buffer);
432 /* sequence parameter set */
433 VAEncSequenceParameterBufferH264Ext *seq_param = &avcenc_context.seq_param;
434 va_status = vaCreateBuffer(va_dpy,
435 avcenc_context.context_id,
436 VAEncSequenceParameterBufferExtType,
437 sizeof(*seq_param), 1, seq_param,
438 &avcenc_context.seq_param_buf_id);
439 CHECK_VASTATUS(va_status,"vaCreateBuffer");;
441 /* slice parameter */
442 avcenc_update_slice_parameter(slice_type);
447 int avcenc_render_picture()
450 VABufferID va_buffers[8];
451 unsigned int num_va_buffers = 0;
453 va_buffers[num_va_buffers++] = avcenc_context.seq_param_buf_id;
454 va_buffers[num_va_buffers++] = avcenc_context.pic_param_buf_id;
456 if (avcenc_context.dec_ref_pic_marking_buf_id != VA_INVALID_ID)
457 va_buffers[num_va_buffers++] = avcenc_context.dec_ref_pic_marking_buf_id;
459 if (avcenc_context.packed_seq_buf_id != VA_INVALID_ID)
460 va_buffers[num_va_buffers++] = avcenc_context.packed_seq_buf_id;
462 if (avcenc_context.packed_pic_buf_id != VA_INVALID_ID)
463 va_buffers[num_va_buffers++] = avcenc_context.packed_pic_buf_id;
465 va_status = vaBeginPicture(va_dpy,
466 avcenc_context.context_id,
467 surface_ids[avcenc_context.current_input_surface]);
468 CHECK_VASTATUS(va_status,"vaBeginPicture");
470 va_status = vaRenderPicture(va_dpy,
471 avcenc_context.context_id,
474 CHECK_VASTATUS(va_status,"vaRenderPicture");
476 va_status = vaRenderPicture(va_dpy,
477 avcenc_context.context_id,
478 &avcenc_context.slice_param_buf_id[0],
479 avcenc_context.num_slices);
480 CHECK_VASTATUS(va_status,"vaRenderPicture");
482 va_status = vaEndPicture(va_dpy, avcenc_context.context_id);
483 CHECK_VASTATUS(va_status,"vaEndPicture");
488 static int avcenc_destroy_buffers(VABufferID *va_buffers, unsigned int num_va_buffers)
493 for (i = 0; i < num_va_buffers; i++) {
494 if (va_buffers[i] != VA_INVALID_ID) {
495 va_status = vaDestroyBuffer(va_dpy, va_buffers[i]);
496 CHECK_VASTATUS(va_status,"vaDestroyBuffer");
497 va_buffers[i] = VA_INVALID_ID;
504 static void end_picture(int slice_type, int next_is_bpic)
508 /* Prepare for next picture */
509 tempID = surface_ids[SID_RECON_PICTURE];
511 if (slice_type != SLICE_TYPE_B) {
513 surface_ids[SID_RECON_PICTURE] = surface_ids[SID_REFERENCE_PICTURE_L1];
514 surface_ids[SID_REFERENCE_PICTURE_L1] = tempID;
516 surface_ids[SID_RECON_PICTURE] = surface_ids[SID_REFERENCE_PICTURE_L0];
517 surface_ids[SID_REFERENCE_PICTURE_L0] = tempID;
521 surface_ids[SID_RECON_PICTURE] = surface_ids[SID_REFERENCE_PICTURE_L0];
522 surface_ids[SID_REFERENCE_PICTURE_L0] = surface_ids[SID_REFERENCE_PICTURE_L1];
523 surface_ids[SID_REFERENCE_PICTURE_L1] = tempID;
527 avcenc_destroy_buffers(&avcenc_context.seq_param_buf_id, 1);
528 avcenc_destroy_buffers(&avcenc_context.pic_param_buf_id, 1);
529 avcenc_destroy_buffers(&avcenc_context.dec_ref_pic_marking_buf_id, 1);
530 avcenc_destroy_buffers(&avcenc_context.packed_seq_buf_id, 1);
531 avcenc_destroy_buffers(&avcenc_context.packed_pic_buf_id, 1);
532 avcenc_destroy_buffers(&avcenc_context.slice_param_buf_id[0], avcenc_context.num_slices);
533 avcenc_destroy_buffers(&avcenc_context.codedbuf_buf_id, 1);
534 memset(avcenc_context.slice_param, 0, sizeof(avcenc_context.slice_param));
535 avcenc_context.num_slices = 0;
538 #define BITSTREAM_ALLOCATE_STEPPING 4096
541 unsigned int *buffer;
543 int max_size_in_dword;
546 typedef struct __bitstream bitstream;
550 get_coded_bitsteam_length(unsigned char *buffer, int buffer_length)
554 for (i = 0; i < buffer_length - 3; i++) {
567 va_swap32(unsigned int val)
569 unsigned char *pval = (unsigned char *)&val;
571 return ((pval[0] << 24) |
578 bitstream_start(bitstream *bs)
580 bs->max_size_in_dword = BITSTREAM_ALLOCATE_STEPPING;
581 bs->buffer = calloc(bs->max_size_in_dword * sizeof(int), 1);
582 bs->bit_offset = sizeof(struct packed_data_format) * 8; /* the first 64 bits used for format */
586 bitstream_end(bitstream *bs)
588 int pos = (bs->bit_offset >> 5);
589 int bit_offset = (bs->bit_offset & 0x1f);
590 int bit_left = 32 - bit_offset;
591 struct packed_data_format *format;
594 bs->buffer[pos] = va_swap32((bs->buffer[pos] << bit_left));
597 format = (struct packed_data_format *)bs->buffer;
598 format->length_in_bits = bs->bit_offset - sizeof(struct packed_data_format) * 8;
600 format->num_skip_bytes = 5; /* ignore start code & nal type for emulation prevetion check */
604 bitstream_put_ui(bitstream *bs, unsigned int val, int size_in_bits)
606 int pos = (bs->bit_offset >> 5);
607 int bit_offset = (bs->bit_offset & 0x1f);
608 int bit_left = 32 - bit_offset;
613 bs->bit_offset += size_in_bits;
615 if (bit_left > size_in_bits) {
616 bs->buffer[pos] = (bs->buffer[pos] << size_in_bits | val);
618 size_in_bits -= bit_left;
619 bs->buffer[pos] = (bs->buffer[pos] << bit_left) | (val >> size_in_bits);
620 bs->buffer[pos] = va_swap32(bs->buffer[pos]);
622 if (pos + 1 == bs->max_size_in_dword) {
623 bs->max_size_in_dword += BITSTREAM_ALLOCATE_STEPPING;
624 bs->buffer = realloc(bs->buffer, bs->max_size_in_dword * sizeof(unsigned int));
627 bs->buffer[pos + 1] = val;
632 bitstream_put_ue(bitstream *bs, unsigned int val)
634 int size_in_bits = 0;
642 bitstream_put_ui(bs, 0, size_in_bits - 1); // leading zero
643 bitstream_put_ui(bs, val, size_in_bits);
647 bitstream_put_se(bitstream *bs, int val)
649 unsigned int new_val;
654 new_val = 2 * val - 1;
656 bitstream_put_ue(bs, new_val);
660 bitstream_byte_aligning(bitstream *bs, int bit)
662 int bit_offset = (bs->bit_offset & 0x7);
663 int bit_left = 8 - bit_offset;
669 assert(bit == 0 || bit == 1);
672 new_val = (1 << bit_left) - 1;
676 bitstream_put_ui(bs, new_val, bit_left);
680 rbsp_trailing_bits(bitstream *bs)
682 bitstream_put_ui(bs, 1, 1);
683 bitstream_byte_aligning(bs, 0);
686 static void nal_start_code_prefix(bitstream *bs)
688 bitstream_put_ui(bs, 0x00000001, 32);
691 static void nal_header(bitstream *bs, int nal_ref_idc, int nal_unit_type)
693 bitstream_put_ui(bs, 0, 1); /* forbidden_zero_bit: 0 */
694 bitstream_put_ui(bs, nal_ref_idc, 2);
695 bitstream_put_ui(bs, nal_unit_type, 5);
698 static void sps_rbsp(bitstream *bs)
700 VAEncSequenceParameterBufferH264Ext *seq_param = &avcenc_context.seq_param;
702 bitstream_put_ui(bs, seq_param->profile_idc, 8); /* profile_idc */
703 bitstream_put_ui(bs, 0, 1); /* constraint_set0_flag */
704 bitstream_put_ui(bs, 1, 1); /* constraint_set1_flag */
705 bitstream_put_ui(bs, 0, 1); /* constraint_set2_flag */
706 bitstream_put_ui(bs, 0, 1); /* constraint_set3_flag */
707 bitstream_put_ui(bs, 0, 4); /* reserved_zero_4bits */
708 bitstream_put_ui(bs, seq_param->level_idc, 8); /* level_idc */
709 bitstream_put_ue(bs, seq_param->seq_parameter_set_id); /* seq_parameter_set_id */
711 if (seq_param->profile_idc >= PROFILE_IDC_HIGH) {
712 /* FIXME: fix for high profile */
716 bitstream_put_ue(bs, seq_param->log2_max_frame_num_minus4); /* log2_max_frame_num_minus4 */
717 bitstream_put_ue(bs, seq_param->pic_order_cnt_type); /* pic_order_cnt_type */
719 if (seq_param->pic_order_cnt_type == 0)
720 bitstream_put_ue(bs, seq_param->log2_max_pic_order_cnt_lsb_minus4); /* log2_max_pic_order_cnt_lsb_minus4 */
725 bitstream_put_ue(bs, seq_param->max_num_ref_frames); /* num_ref_frames */
726 bitstream_put_ui(bs, 0, 1); /* gaps_in_frame_num_value_allowed_flag */
728 bitstream_put_ue(bs, seq_param->picture_width_in_mbs - 1); /* pic_width_in_mbs_minus1 */
729 bitstream_put_ue(bs, seq_param->picture_height_in_mbs - 1); /* pic_height_in_map_units_minus1 */
730 bitstream_put_ui(bs, seq_param->frame_mbs_only_flag, 1); /* frame_mbs_only_flag */
732 if (!seq_param->frame_mbs_only_flag) {
736 bitstream_put_ui(bs, seq_param->direct_8x8_inference_flag, 1); /* direct_8x8_inference_flag */
737 bitstream_put_ui(bs, seq_param->frame_cropping_flag, 1); /* frame_cropping_flag */
739 if (seq_param->frame_cropping_flag) {
740 bitstream_put_ue(bs, seq_param->frame_crop_left_offset); /* frame_crop_left_offset */
741 bitstream_put_ue(bs, seq_param->frame_crop_right_offset); /* frame_crop_right_offset */
742 bitstream_put_ue(bs, seq_param->frame_crop_top_offset); /* frame_crop_top_offset */
743 bitstream_put_ue(bs, seq_param->frame_crop_bottom_offset); /* frame_crop_bottom_offset */
746 bitstream_put_ui(bs, 0, 1); /* vui_parameters_present_flag */
747 rbsp_trailing_bits(bs); /* rbsp_trailing_bits */
751 static void build_nal_sps(FILE *avc_fp)
755 bitstream_start(&bs);
756 nal_start_code_prefix(&bs);
757 nal_header(&bs, NAL_REF_IDC_HIGH, NAL_SPS);
759 bitstream_end(&bs, avc_fp);
763 static void pps_rbsp(bitstream *bs)
765 VAEncPictureParameterBufferH264Ext *pic_param = &avcenc_context.pic_param;
767 bitstream_put_ue(bs, pic_param->pic_parameter_set_id); /* pic_parameter_set_id */
768 bitstream_put_ue(bs, pic_param->seq_parameter_set_id); /* seq_parameter_set_id */
770 bitstream_put_ui(bs, pic_param->pic_fields.bits.entropy_coding_mode_flag, 1); /* entropy_coding_mode_flag */
772 bitstream_put_ui(bs, 0, 1); /* pic_order_present_flag: 0 */
774 bitstream_put_ue(bs, 0); /* num_slice_groups_minus1 */
776 bitstream_put_ue(bs, pic_param->num_ref_idx_l0_active_minus1); /* num_ref_idx_l0_active_minus1 */
777 bitstream_put_ue(bs, pic_param->num_ref_idx_l1_active_minus1); /* num_ref_idx_l1_active_minus1 1 */
779 bitstream_put_ui(bs, pic_param->pic_fields.bits.weighted_pred_flag, 1); /* weighted_pred_flag: 0 */
780 bitstream_put_ui(bs, pic_param->pic_fields.bits.weighted_bipred_idc, 2); /* weighted_bipred_idc: 0 */
782 bitstream_put_se(bs, pic_param->pic_init_qp - 26); /* pic_init_qp_minus26 */
783 bitstream_put_se(bs, 0); /* pic_init_qs_minus26 */
784 bitstream_put_se(bs, 0); /* chroma_qp_index_offset */
786 bitstream_put_ui(bs, pic_param->pic_fields.bits.deblocking_filter_control_present_flag, 1); /* deblocking_filter_control_present_flag */
787 bitstream_put_ui(bs, 0, 1); /* constrained_intra_pred_flag */
788 bitstream_put_ui(bs, 0, 1); /* redundant_pic_cnt_present_flag */
790 rbsp_trailing_bits(bs);
794 static void build_nal_pps(FILE *avc_fp)
798 bitstream_start(&bs);
799 nal_start_code_prefix(&bs);
800 nal_header(&bs, NAL_REF_IDC_HIGH, NAL_PPS);
802 bitstream_end(&bs, avc_fp);
806 build_header(FILE *avc_fp)
808 build_nal_sps(avc_fp);
809 build_nal_pps(avc_fp);
814 build_packed_pic_buffer(unsigned char **header_buffer)
818 bitstream_start(&bs);
819 nal_start_code_prefix(&bs);
820 nal_header(&bs, NAL_REF_IDC_HIGH, NAL_PPS);
824 *header_buffer = (unsigned char *)bs.buffer;
825 return bs.bit_offset;
829 build_packed_seq_buffer(unsigned char **header_buffer)
833 bitstream_start(&bs);
834 nal_start_code_prefix(&bs);
835 nal_header(&bs, NAL_REF_IDC_HIGH, NAL_SPS);
839 *header_buffer = (unsigned char *)bs.buffer;
840 return bs.bit_offset;
846 slice_header(bitstream *bs, int frame_num, int display_frame, int slice_type, int nal_ref_idc, int is_idr)
848 VAEncSequenceParameterBufferH264Ext *seq_param = &avcenc_context.seq_param;
849 VAEncPictureParameterBufferH264Ext *pic_param = &avcenc_context.pic_param;
850 int is_cabac = (pic_param->pic_fields.bits.entropy_coding_mode_flag == ENTROPY_MODE_CABAC);
852 bitstream_put_ue(bs, 0); /* first_mb_in_slice: 0 */
853 bitstream_put_ue(bs, slice_type); /* slice_type */
854 bitstream_put_ue(bs, 0); /* pic_parameter_set_id: 0 */
855 bitstream_put_ui(bs, frame_num & 0x0F, seq_param->log2_max_frame_num_minus4 + 4); /* frame_num */
857 /* frame_mbs_only_flag == 1 */
858 if (!seq_param->frame_mbs_only_flag) {
864 bitstream_put_ue(bs, 0); /* idr_pic_id: 0 */
866 if (seq_param->pic_order_cnt_type == 0) {
867 bitstream_put_ui(bs, (display_frame*2) & 0x3F, seq_param->log2_max_pic_order_cnt_lsb_minus4 + 4);
868 /* only support frame */
874 /* redundant_pic_cnt_present_flag == 0 */
877 if (slice_type == SLICE_TYPE_P) {
878 bitstream_put_ui(bs, 0, 1); /* num_ref_idx_active_override_flag: 0 */
879 /* ref_pic_list_reordering */
880 bitstream_put_ui(bs, 0, 1); /* ref_pic_list_reordering_flag_l0: 0 */
881 } else if (slice_type == SLICE_TYPE_B) {
882 bitstream_put_ui(bs, 1, 1); /* direct_spatial_mv_pred: 1 */
883 bitstream_put_ui(bs, 0, 1); /* num_ref_idx_active_override_flag: 0 */
884 /* ref_pic_list_reordering */
885 bitstream_put_ui(bs, 0, 1); /* ref_pic_list_reordering_flag_l0: 0 */
886 bitstream_put_ui(bs, 0, 1); /* ref_pic_list_reordering_flag_l1: 0 */
889 /* weighted_pred_flag == 0 */
891 /* dec_ref_pic_marking */
892 if (nal_ref_idc != 0) {
894 bitstream_put_ui(bs, 0, 1); /* no_output_of_prior_pics_flag: 0 */
895 bitstream_put_ui(bs, 0, 1); /* long_term_reference_flag: 0 */
897 bitstream_put_ui(bs, 0, 1); /* adaptive_ref_pic_marking_mode_flag: 0 */
901 if (is_cabac && (slice_type != SLICE_TYPE_I))
902 bitstream_put_ue(bs, 0); /* cabac_init_idc: 0 */
904 bitstream_put_se(bs, 0); /* slice_qp_delta: 0 */
906 if (pic_param->pic_fields.bits.deblocking_filter_control_present_flag == 1) {
907 bitstream_put_ue(bs, 0); /* disable_deblocking_filter_idc: 0 */
908 bitstream_put_se(bs, 2); /* slice_alpha_c0_offset_div2: 2 */
909 bitstream_put_se(bs, 2); /* slice_beta_offset_div2: 2 */
914 slice_data(bitstream *bs)
916 VACodedBufferSegment *coded_buffer_segment;
917 unsigned char *coded_mem;
918 int i, slice_data_length;
920 VASurfaceStatus surface_status;
922 va_status = vaSyncSurface(va_dpy, surface_ids[avcenc_context.current_input_surface]);
923 CHECK_VASTATUS(va_status,"vaSyncSurface");
926 va_status = vaQuerySurfaceStatus(va_dpy, surface_ids[avcenc_context.current_input_surface], &surface_status);
927 CHECK_VASTATUS(va_status,"vaQuerySurfaceStatus");
929 va_status = vaMapBuffer(va_dpy, avcenc_context.codedbuf_buf_id, (void **)(&coded_buffer_segment));
930 CHECK_VASTATUS(va_status,"vaMapBuffer");
931 coded_mem = coded_buffer_segment->buf;
933 slice_data_length = get_coded_bitsteam_length(coded_mem, codedbuf_size);
935 for (i = 0; i < slice_data_length; i++) {
936 bitstream_put_ui(bs, *coded_mem, 8);
940 vaUnmapBuffer(va_dpy, avcenc_context.codedbuf_buf_id);
944 build_nal_slice(FILE *avc_fp, int frame_num, int display_frame, int slice_type, int is_idr)
948 bitstream_start(&bs);
950 bitstream_end(&bs, avc_fp);
956 store_coded_buffer(FILE *avc_fp, int slice_type)
958 VACodedBufferSegment *coded_buffer_segment;
959 unsigned char *coded_mem;
960 int slice_data_length;
962 VASurfaceStatus surface_status;
965 va_status = vaSyncSurface(va_dpy, surface_ids[avcenc_context.current_input_surface]);
966 CHECK_VASTATUS(va_status,"vaSyncSurface");
969 va_status = vaQuerySurfaceStatus(va_dpy, surface_ids[avcenc_context.current_input_surface], &surface_status);
970 CHECK_VASTATUS(va_status,"vaQuerySurfaceStatus");
972 va_status = vaMapBuffer(va_dpy, avcenc_context.codedbuf_buf_id, (void **)(&coded_buffer_segment));
973 CHECK_VASTATUS(va_status,"vaMapBuffer");
974 coded_mem = coded_buffer_segment->buf;
976 if (coded_buffer_segment->status & VA_CODED_BUF_STATUS_SLICE_OVERFLOW_MASK) {
977 if (slice_type == SLICE_TYPE_I)
978 avcenc_context.codedbuf_i_size *= 2;
980 avcenc_context.codedbuf_pb_size *= 2;
982 vaUnmapBuffer(va_dpy, avcenc_context.codedbuf_buf_id);
986 slice_data_length = coded_buffer_segment->size;
989 w_items = fwrite(coded_mem, slice_data_length, 1, avc_fp);
990 } while (w_items != 1);
992 if (slice_type == SLICE_TYPE_I) {
993 if (avcenc_context.codedbuf_i_size > slice_data_length * 3 / 2) {
994 avcenc_context.codedbuf_i_size = slice_data_length * 3 / 2;
997 if (avcenc_context.codedbuf_pb_size < slice_data_length) {
998 avcenc_context.codedbuf_pb_size = slice_data_length;
1001 if (avcenc_context.codedbuf_pb_size > slice_data_length * 3 / 2) {
1002 avcenc_context.codedbuf_pb_size = slice_data_length * 3 / 2;
1006 vaUnmapBuffer(va_dpy, avcenc_context.codedbuf_buf_id);
1012 encode_picture(FILE *yuv_fp, FILE *avc_fp,
1013 int frame_num, int display_num,
1015 int slice_type, int next_is_bpic,
1016 int next_display_num)
1019 int ret = 0, codedbuf_size;
1021 begin_picture(yuv_fp, frame_num, display_num, slice_type, is_idr);
1023 //if (next_display_num < frame_number) {
1027 /* prepare for next frame */
1028 if (avcenc_context.current_input_surface == SID_INPUT_PICTURE_0)
1029 index = SID_INPUT_PICTURE_1;
1031 index = SID_INPUT_PICTURE_0;
1032 if ( next_display_num >= frame_number )
1033 next_display_num = frame_number - 1;
1034 fseek(yuv_fp, frame_size * next_display_num, SEEK_SET);
1036 avcenc_context.upload_thread_param.yuv_fp = yuv_fp;
1037 avcenc_context.upload_thread_param.surface_id = surface_ids[index];
1039 avcenc_context.upload_thread_value = pthread_create(&avcenc_context.upload_thread_id,
1041 upload_thread_function,
1042 (void*)&avcenc_context.upload_thread_param);
1046 avcenc_destroy_buffers(&avcenc_context.codedbuf_buf_id, 1);
1047 avcenc_destroy_buffers(&avcenc_context.pic_param_buf_id, 1);
1050 if (SLICE_TYPE_I == slice_type) {
1051 codedbuf_size = avcenc_context.codedbuf_i_size;
1053 codedbuf_size = avcenc_context.codedbuf_pb_size;
1057 va_status = vaCreateBuffer(va_dpy,
1058 avcenc_context.context_id,
1059 VAEncCodedBufferType,
1060 codedbuf_size, 1, NULL,
1061 &avcenc_context.codedbuf_buf_id);
1062 CHECK_VASTATUS(va_status,"vaCreateBuffer");
1064 /* picture parameter set */
1065 avcenc_update_picture_parameter(slice_type, frame_num, display_num, is_idr);
1067 avcenc_render_picture();
1069 ret = store_coded_buffer(avc_fp, slice_type);
1072 end_picture(slice_type, next_is_bpic);
1075 static void encode_pb_pictures(FILE *yuv_fp, FILE *avc_fp, int f, int nbframes, int next_f)
1078 encode_picture(yuv_fp, avc_fp,
1079 enc_frame_number, f + nbframes,
1081 SLICE_TYPE_P, 1, f);
1083 for( i = 0; i < nbframes - 1; i++) {
1084 encode_picture(yuv_fp, avc_fp,
1085 enc_frame_number + 1, f + i,
1087 SLICE_TYPE_B, 1, f + i + 1);
1090 encode_picture(yuv_fp, avc_fp,
1091 enc_frame_number + 1, f + nbframes - 1,
1093 SLICE_TYPE_B, 0, next_f);
1096 static void show_help()
1098 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");
1101 static void avcenc_context_seq_param_init(VAEncSequenceParameterBufferH264Ext *seq_param,
1102 int width, int height)
1105 int width_in_mbs = (width + 15) / 16;
1106 int height_in_mbs = (height + 15) / 16;
1107 int frame_cropping_flag = 0;
1108 int frame_crop_bottom_offset = 0;
1110 seq_param->seq_parameter_set_id = 0;
1111 seq_param->profile_idc = PROFILE_IDC_MAIN;
1112 seq_param->level_idc = 41;
1113 seq_param->intra_period = intra_period;
1114 seq_param->ip_period = 0; /* FIXME: ??? */
1115 seq_param->max_num_ref_frames = 4;
1116 seq_param->picture_width_in_mbs = width_in_mbs;
1117 seq_param->picture_height_in_mbs = height_in_mbs;
1118 seq_param->frame_mbs_only_flag = 1;
1119 seq_param->target_usage = 1;
1121 /* 0:CBR, 1:VBR, 2:Constant QP */
1123 seq_param->rate_control_method = BR_CBR;
1124 else if (qp_value == -2)
1125 seq_param->rate_control_method = BR_VBR;
1127 assert(qp_value >= 0 && qp_value <= 51);
1128 seq_param->rate_control_method = BR_CQP;
1131 if (frame_bit_rate > 0)
1132 seq_param->bits_per_second = 30 * frame_bit_rate;
1134 seq_param->bits_per_second = 0;
1136 if (seq_param->rate_control_method == BR_VBR) {
1137 seq_param->max_bits_per_second = 0; /* FIXME: set it later */
1138 seq_param->min_bits_per_second = 0;
1141 seq_param->initial_hrd_buffer_fullness = 0; /* FIXME: ??? */
1142 seq_param->hrd_buffer_size = 0; /* FIXME: ??? */
1143 seq_param->time_scale = 900;
1144 seq_param->num_units_in_tick = 15;
1146 if (height_in_mbs * 16 - height) {
1147 frame_cropping_flag = 1;
1148 frame_crop_bottom_offset =
1149 (height_in_mbs * 16 - height) / (2 * (!seq_param->frame_mbs_only_flag + 1));
1152 seq_param->frame_cropping_flag = frame_cropping_flag;
1153 seq_param->frame_crop_left_offset = 0;
1154 seq_param->frame_crop_right_offset = 0;
1155 seq_param->frame_crop_top_offset = 0;
1156 seq_param->frame_crop_bottom_offset = frame_crop_bottom_offset;
1158 seq_param->pic_order_cnt_type = 0;
1159 seq_param->direct_8x8_inference_flag = 0;
1161 seq_param->log2_max_frame_num_minus4 = 0;
1162 seq_param->log2_max_pic_order_cnt_lsb_minus4 = 2;
1164 seq_param->vui_flag = 0;
1167 static void avcenc_context_pic_param_init(VAEncPictureParameterBufferH264Ext *pic_param)
1169 pic_param->seq_parameter_set_id = 0;
1170 pic_param->pic_parameter_set_id = 0;
1172 pic_param->last_picture = 0;
1173 pic_param->frame_num = 0;
1174 pic_param->coding_type = 0;
1176 pic_param->pic_init_qp = (qp_value >= 0 ? qp_value : 26);
1177 pic_param->num_ref_idx_l0_active_minus1 = 0;
1178 pic_param->num_ref_idx_l1_active_minus1 = 0;
1180 pic_param->pic_fields.bits.idr_pic_flag = 0;
1181 pic_param->pic_fields.bits.reference_pic_flag = 0;
1182 pic_param->pic_fields.bits.entropy_coding_mode_flag = ENTROPY_MODE_CABAC;
1183 pic_param->pic_fields.bits.weighted_pred_flag = 0;
1184 pic_param->pic_fields.bits.weighted_bipred_idc = 0;
1185 pic_param->pic_fields.bits.transform_8x8_mode_flag = 0;
1186 pic_param->pic_fields.bits.deblocking_filter_control_present_flag = 1;
1189 static void avcenc_context_init(int width, int height)
1192 memset(&avcenc_context, 0, sizeof(avcenc_context));
1193 avcenc_context.seq_param_buf_id = VA_INVALID_ID;
1194 avcenc_context.pic_param_buf_id = VA_INVALID_ID;
1195 avcenc_context.dec_ref_pic_marking_buf_id = VA_INVALID_ID;
1196 avcenc_context.packed_seq_buf_id = VA_INVALID_ID;
1197 avcenc_context.packed_pic_buf_id = VA_INVALID_ID;
1198 avcenc_context.codedbuf_buf_id = VA_INVALID_ID;
1199 avcenc_context.codedbuf_i_size = width * height;
1200 avcenc_context.codedbuf_pb_size = 0;
1201 avcenc_context.current_input_surface = SID_INPUT_PICTURE_0;
1202 avcenc_context.upload_thread_value = -1;
1204 for (i = 0; i < MAX_SLICES; i++) {
1205 avcenc_context.slice_param_buf_id[i] = VA_INVALID_ID;
1208 avcenc_context_seq_param_init(&avcenc_context.seq_param, width, height);
1209 avcenc_context_pic_param_init(&avcenc_context.pic_param);
1212 int main(int argc, char *argv[])
1218 int i_frame_only=0,i_p_frame_only=1;
1220 struct timeval tpstart,tpend;
1223 va_init_display_args(&argc, argv);
1225 //TODO may be we should using option analytics library
1226 if(argc != 5 && argc != 6 && argc != 7) {
1231 picture_width = atoi(argv[1]);
1232 picture_height = atoi(argv[2]);
1233 picture_width_in_mbs = (picture_width + 15) / 16;
1234 picture_height_in_mbs = (picture_height + 15) / 16;
1236 if (argc == 6 || argc == 7) {
1238 sscanf(argv[5], "qp=%d", &qp_value);
1239 if ( qp_value == -1 ) {
1240 frame_bit_rate = -1;
1241 sscanf(argv[5], "fb=%d", &frame_bit_rate);
1242 if ( frame_bit_rate == -1 ) {
1246 } else if (qp_value > 51) {
1248 } else if (qp_value < 0) {
1252 qp_value = 28; //default const QP mode
1255 sscanf(argv[6], "mode=%d", &mode_value);
1256 if ( mode_value == 0 ) {
1260 else if ( mode_value == 1) {
1264 else if ( mode_value == 2 ) {
1269 printf("mode_value=%d\n",mode_value);
1275 yuv_fp = fopen(argv[3],"rb");
1276 if ( yuv_fp == NULL){
1277 printf("Can't open input YUV file\n");
1280 fseek(yuv_fp,0l, SEEK_END);
1281 file_size = ftell(yuv_fp);
1282 frame_size = picture_width * picture_height + ((picture_width * picture_height) >> 1) ;
1284 if ( (file_size < frame_size) || (file_size % frame_size) ) {
1286 printf("The YUV file's size is not correct\n");
1289 frame_number = file_size / frame_size;
1290 fseek(yuv_fp, 0l, SEEK_SET);
1292 avc_fp = fopen(argv[4], "wb");
1293 if ( avc_fp == NULL) {
1295 printf("Can't open output avc file\n");
1298 gettimeofday(&tpstart,NULL);
1299 avcenc_context_init(picture_width, picture_height);
1300 create_encode_pipe();
1301 alloc_encode_resource(yuv_fp);
1303 enc_frame_number = 0;
1304 for ( f = 0; f < frame_number; ) { //picture level loop
1305 static int const frame_type_pattern[][2] = { {SLICE_TYPE_I,1},
1306 {SLICE_TYPE_P,3}, {SLICE_TYPE_P,3},{SLICE_TYPE_P,3},
1307 {SLICE_TYPE_P,3}, {SLICE_TYPE_P,3},{SLICE_TYPE_P,3},
1308 {SLICE_TYPE_P,3}, {SLICE_TYPE_P,3},{SLICE_TYPE_P,3},
1311 if ( i_frame_only ) {
1312 encode_picture(yuv_fp, avc_fp,enc_frame_number, f, f==0, SLICE_TYPE_I, 0, f+1);
1315 } else if ( i_p_frame_only ) {
1316 if ( (f % intra_period) == 0 ) {
1317 encode_picture(yuv_fp, avc_fp,enc_frame_number, f, f==0, SLICE_TYPE_I, 0, f+1);
1321 encode_picture(yuv_fp, avc_fp,enc_frame_number, f, f==0, SLICE_TYPE_P, 0, f+1);
1325 } else { // follow the i,p,b pattern
1326 static int fcurrent = 0;
1329 fcurrent = fcurrent % (sizeof(frame_type_pattern)/sizeof(int[2]));
1330 fnext = (fcurrent+1) % (sizeof(frame_type_pattern)/sizeof(int[2]));
1332 if ( frame_type_pattern[fcurrent][0] == SLICE_TYPE_I ) {
1333 encode_picture(yuv_fp, avc_fp,enc_frame_number, f, f==0, SLICE_TYPE_I, 0,
1334 f+frame_type_pattern[fnext][1]);
1338 encode_pb_pictures(yuv_fp, avc_fp, f, frame_type_pattern[fcurrent][1]-1,
1339 f + frame_type_pattern[fcurrent][1] + frame_type_pattern[fnext][1] -1 );
1340 f += frame_type_pattern[fcurrent][1];
1346 printf("\r %d/%d ...", f+1, frame_number);
1350 gettimeofday(&tpend,NULL);
1351 timeuse=1000000*(tpend.tv_sec-tpstart.tv_sec)+ tpend.tv_usec-tpstart.tv_usec;
1353 printf("\ndone!\n");
1354 printf("encode %d frames in %f secondes, FPS is %.1f\n",frame_number, timeuse, frame_number/timeuse);
1355 release_encode_resource();
1356 destory_encode_pipe();