Index: third_party/libva/test/encode/avcenc.c |
diff --git a/third_party/libva/test/encode/avcenc.c b/third_party/libva/test/encode/avcenc.c |
new file mode 100644 |
index 0000000000000000000000000000000000000000..17411d8f752cbe9fefa397c97a47064b5d7f5b77 |
--- /dev/null |
+++ b/third_party/libva/test/encode/avcenc.c |
@@ -0,0 +1,818 @@ |
+/* |
+ * Simple AVC encoder based on libVA. |
+ * |
+ * Usage: |
+ * ./avcenc <width> <height> <input file> <output file> [qp] |
+ */ |
+ |
+#include <stdio.h> |
+#include <string.h> |
+#include <stdlib.h> |
+#include <getopt.h> |
+#include <X11/Xlib.h> |
+ |
+#include <unistd.h> |
+ |
+#include <sys/types.h> |
+#include <sys/stat.h> |
+#include <fcntl.h> |
+#include <assert.h> |
+#include <time.h> |
+ |
+#include <va/va.h> |
+#include <va/va_x11.h> |
+ |
+#define NAL_REF_IDC_NONE 0 |
+#define NAL_REF_IDC_LOW 1 |
+#define NAL_REF_IDC_MEDIUM 2 |
+#define NAL_REF_IDC_HIGH 3 |
+ |
+#define NAL_NON_IDR 1 |
+#define NAL_IDR 5 |
+#define NAL_SPS 7 |
+#define NAL_PPS 8 |
+ |
+#define SLICE_TYPE_P 0 |
+#define SLICE_TYPE_B 1 |
+#define SLICE_TYPE_I 2 |
+ |
+#define ENTROPY_MODE_CAVLC 0 |
+#define ENTROPY_MODE_CABAC 1 |
+ |
+#define PROFILE_IDC_BASELINE 66 |
+#define PROFILE_IDC_MAIN 77 |
+#define PROFILE_IDC_HIGH 100 |
+ |
+#define CHECK_VASTATUS(va_status,func) \ |
+ if (va_status != VA_STATUS_SUCCESS) { \ |
+ fprintf(stderr,"%s:%s (%d) failed,exit\n", __func__, func, __LINE__); \ |
+ exit(1); \ |
+ } |
+ |
+static Display *x11_display; |
+static VADisplay va_dpy; |
+static VAContextID context_id; |
+static VAConfigID config_id; |
+ |
+static int picture_width, picture_width_in_mbs; |
+static int picture_height, picture_height_in_mbs; |
+static int frame_size; |
+static unsigned char *newImageBuffer = 0; |
+static int codedbuf_size; |
+ |
+static int qp_value = 26; |
+ |
+static int log2_max_frame_num_minus4 = 0; |
+static int pic_order_cnt_type = 0; |
+static int log2_max_pic_order_cnt_lsb_minus4 = 0; |
+static int entropy_coding_mode_flag = ENTROPY_MODE_CABAC; |
+static int deblocking_filter_control_present_flag = 1; |
+static int frame_mbs_only_flag = 1; |
+ |
+static void create_encode_pipe() |
+{ |
+ VAEntrypoint entrypoints[5]; |
+ int num_entrypoints,slice_entrypoint; |
+ VAConfigAttrib attrib[2]; |
+ int major_ver, minor_ver; |
+ VAStatus va_status; |
+ |
+ x11_display = XOpenDisplay(":0.0"); |
+ assert(x11_display); |
+ |
+ va_dpy = vaGetDisplay(x11_display); |
+ va_status = vaInitialize(va_dpy, &major_ver, &minor_ver); |
+ CHECK_VASTATUS(va_status, "vaInitialize"); |
+ |
+ vaQueryConfigEntrypoints(va_dpy, VAProfileH264Baseline, entrypoints, |
+ &num_entrypoints); |
+ |
+ for (slice_entrypoint = 0; slice_entrypoint < num_entrypoints; slice_entrypoint++) { |
+ if (entrypoints[slice_entrypoint] == VAEntrypointEncSlice) |
+ break; |
+ } |
+ |
+ if (slice_entrypoint == num_entrypoints) { |
+ /* not find Slice entry point */ |
+ assert(0); |
+ } |
+ |
+ /* find out the format for the render target, and rate control mode */ |
+ attrib[0].type = VAConfigAttribRTFormat; |
+ attrib[1].type = VAConfigAttribRateControl; |
+ vaGetConfigAttributes(va_dpy, VAProfileH264Baseline, VAEntrypointEncSlice, |
+ &attrib[0], 2); |
+ |
+ if ((attrib[0].value & VA_RT_FORMAT_YUV420) == 0) { |
+ /* not find desired YUV420 RT format */ |
+ assert(0); |
+ } |
+ |
+ if ((attrib[1].value & VA_RC_VBR) == 0) { |
+ /* Can't find matched RC mode */ |
+ printf("VBR mode doesn't found, exit\n"); |
+ assert(0); |
+ } |
+ |
+ attrib[0].value = VA_RT_FORMAT_YUV420; /* set to desired RT format */ |
+ attrib[1].value = VA_RC_VBR; /* set to desired RC mode */ |
+ |
+ va_status = vaCreateConfig(va_dpy, VAProfileH264Baseline, VAEntrypointEncSlice, |
+ &attrib[0], 2,&config_id); |
+ CHECK_VASTATUS(va_status, "vaCreateConfig"); |
+ |
+ /* Create a context for this decode pipe */ |
+ va_status = vaCreateContext(va_dpy, config_id, |
+ picture_width, picture_height, |
+ VA_PROGRESSIVE, |
+ 0, 0, |
+ &context_id); |
+ CHECK_VASTATUS(va_status, "vaCreateContext"); |
+} |
+ |
+static void destory_encode_pipe() |
+{ |
+ vaDestroyContext(va_dpy,context_id); |
+ vaDestroyConfig(va_dpy,config_id); |
+ vaTerminate(va_dpy); |
+ XCloseDisplay(x11_display); |
+} |
+ |
+/*************************************************** |
+ * |
+ * The encode pipe resource define |
+ * |
+ ***************************************************/ |
+static VABufferID seq_parameter = VA_INVALID_ID; /*Sequence level parameter*/ |
+static VABufferID pic_parameter = VA_INVALID_ID; /*Picture level parameter*/ |
+static VABufferID slice_parameter = VA_INVALID_ID; /*Slice level parameter, multil slices*/ |
+ |
+static VABufferID coded_buf; /*Output buffer, compressed data*/ |
+ |
+#define SID_NUMBER 3 |
+#define SID_INPUT_PICTURE 0 |
+#define SID_REFERENCE_PICTURE 1 |
+#define SID_RECON_PICTURE 2 |
+static VASurfaceID surface_ids[SID_NUMBER]; |
+ |
+/***************************************************/ |
+ |
+static void alloc_encode_resource() |
+{ |
+ VAStatus va_status; |
+ |
+ seq_parameter = VA_INVALID_ID; |
+ pic_parameter = VA_INVALID_ID; |
+ slice_parameter = VA_INVALID_ID; |
+ |
+ //1. Create sequence parameter set |
+ { |
+ VAEncSequenceParameterBufferH264 seq_h264 = {0}; |
+ |
+ seq_h264.level_idc = 30; |
+ seq_h264.picture_width_in_mbs = picture_width_in_mbs; |
+ seq_h264.picture_height_in_mbs = picture_height_in_mbs; |
+ |
+ seq_h264.bits_per_second = 384*1000; |
+ seq_h264.initial_qp = qp_value; |
+ seq_h264.min_qp = 3; |
+ |
+ va_status = vaCreateBuffer(va_dpy, context_id, |
+ VAEncSequenceParameterBufferType, |
+ sizeof(seq_h264),1,&seq_h264,&seq_parameter); |
+ CHECK_VASTATUS(va_status,"vaCreateBuffer");; |
+ } |
+ |
+ //2. Create surface |
+ va_status = vaCreateSurfaces(va_dpy, picture_width, picture_height, |
+ VA_RT_FORMAT_YUV420, SID_NUMBER, &surface_ids[0]); |
+ CHECK_VASTATUS(va_status, "vaCreateSurfaces"); |
+ |
+ //3. Create coded buffer |
+ { |
+ va_status = vaCreateBuffer(va_dpy,context_id,VAEncCodedBufferType, |
+ codedbuf_size, 1, NULL, &coded_buf); |
+ |
+ CHECK_VASTATUS(va_status,"vaBeginPicture"); |
+ } |
+ |
+ newImageBuffer = (unsigned char *)malloc(frame_size); |
+} |
+ |
+static void release_encode_resource() |
+{ |
+ free(newImageBuffer); |
+ |
+ //-3 Relese coded buffer |
+ vaDestroyBuffer(va_dpy, coded_buf); |
+ |
+ //-2 Release all the surfaces resource |
+ vaDestroySurfaces(va_dpy, &surface_ids[0], SID_NUMBER); |
+ |
+ //-1 Destory the sequence level parameter |
+ vaDestroyBuffer(va_dpy, seq_parameter); |
+} |
+ |
+static void begin_picture() |
+{ |
+ VAStatus va_status; |
+ va_status = vaBeginPicture(va_dpy, context_id, surface_ids[SID_INPUT_PICTURE]); |
+ CHECK_VASTATUS(va_status,"vaBeginPicture"); |
+} |
+ |
+static void upload_yuv_to_surface(FILE *yuv_fp, VASurfaceID surface_id) |
+{ |
+ VAImage surface_image; |
+ VAStatus va_status; |
+ void *surface_p = NULL; |
+ unsigned char *y_src, *u_src, *v_src; |
+ unsigned char *y_dst, *u_dst, *v_dst; |
+ int y_size = picture_width * picture_height; |
+ int u_size = (picture_width >> 1) * (picture_height >> 1); |
+ int row, col; |
+ size_t n_items; |
+ |
+ do { |
+ n_items = fread(newImageBuffer, frame_size, 1, yuv_fp); |
+ } while (n_items != 1); |
+ |
+ va_status = vaDeriveImage(va_dpy, surface_id, &surface_image); |
+ CHECK_VASTATUS(va_status,"vaDeriveImage"); |
+ |
+ vaMapBuffer(va_dpy, surface_image.buf, &surface_p); |
+ assert(VA_STATUS_SUCCESS == va_status); |
+ |
+ y_src = newImageBuffer; |
+ u_src = newImageBuffer + y_size; /* UV offset for NV12 */ |
+ v_src = newImageBuffer + y_size + u_size; |
+ |
+ y_dst = surface_p + surface_image.offsets[0]; |
+ u_dst = surface_p + surface_image.offsets[1]; /* UV offset for NV12 */ |
+ v_dst = surface_p + surface_image.offsets[2]; |
+ |
+ /* Y plane */ |
+ for (row = 0; row < surface_image.height; row++) { |
+ memcpy(y_dst, y_src, surface_image.width); |
+ y_dst += surface_image.pitches[0]; |
+ y_src += picture_width; |
+ } |
+ |
+ if (surface_image.format.fourcc == VA_FOURCC_NV12) { /* UV plane */ |
+ for (row = 0; row < surface_image.height / 2; row++) { |
+ for (col = 0; col < surface_image.width / 2; col++) { |
+ u_dst[col * 2] = u_src[col]; |
+ u_dst[col * 2 + 1] = v_src[col]; |
+ } |
+ |
+ u_dst += surface_image.pitches[1]; |
+ u_src += (picture_width / 2); |
+ v_src += (picture_width / 2); |
+ } |
+ } else { |
+ /* FIXME: fix this later */ |
+ assert(0); |
+ } |
+ |
+ vaUnmapBuffer(va_dpy, surface_image.buf); |
+ vaDestroyImage(va_dpy, surface_image.image_id); |
+} |
+ |
+static void prepare_input(FILE * yuv_fp, int intra_slice) |
+{ |
+ static VAEncPictureParameterBufferH264 pic_h264; |
+ static VAEncSliceParameterBuffer slice_h264; |
+ VAStatus va_status; |
+ VABufferID tempID; |
+ VACodedBufferSegment *coded_buffer_segment = NULL; |
+ unsigned char *coded_mem; |
+ |
+ // Sequence level |
+ va_status = vaRenderPicture(va_dpy, context_id, &seq_parameter, 1); |
+ CHECK_VASTATUS(va_status,"vaRenderPicture");; |
+ |
+ // Copy Image to target surface according input YUV data. |
+ upload_yuv_to_surface(yuv_fp, surface_ids[SID_INPUT_PICTURE]); |
+ |
+ // Picture level |
+ pic_h264.reference_picture = surface_ids[SID_REFERENCE_PICTURE]; |
+ pic_h264.reconstructed_picture = surface_ids[SID_RECON_PICTURE]; |
+ pic_h264.coded_buf = coded_buf; |
+ pic_h264.picture_width = picture_width; |
+ pic_h264.picture_height = picture_height; |
+ pic_h264.last_picture = 0; |
+ if (pic_parameter != VA_INVALID_ID) { |
+ vaDestroyBuffer(va_dpy, pic_parameter); |
+ } |
+ va_status = vaCreateBuffer(va_dpy, context_id,VAEncPictureParameterBufferType, |
+ sizeof(pic_h264),1,&pic_h264,&pic_parameter); |
+ CHECK_VASTATUS(va_status,"vaCreateBuffer"); |
+ va_status = vaRenderPicture(va_dpy,context_id, &pic_parameter, 1); |
+ CHECK_VASTATUS(va_status,"vaRenderPicture"); |
+ |
+ // clean old memory |
+ va_status = vaMapBuffer(va_dpy,coded_buf,(void **)(&coded_buffer_segment)); |
+ CHECK_VASTATUS(va_status,"vaMapBuffer"); |
+ coded_mem = coded_buffer_segment->buf; |
+ memset(coded_mem, 0, coded_buffer_segment->size); |
+ vaUnmapBuffer(va_dpy, coded_buf); |
+ |
+ // Slice level |
+ slice_h264.start_row_number = 0; |
+ slice_h264.slice_height = picture_height/16; /* Measured by MB */ |
+ slice_h264.slice_flags.bits.is_intra = intra_slice; |
+ slice_h264.slice_flags.bits.disable_deblocking_filter_idc = 0; |
+ if ( slice_parameter != VA_INVALID_ID){ |
+ vaDestroyBuffer(va_dpy, slice_parameter); |
+ } |
+ va_status = vaCreateBuffer(va_dpy,context_id,VAEncSliceParameterBufferType, |
+ sizeof(slice_h264),1,&slice_h264,&slice_parameter); |
+ CHECK_VASTATUS(va_status,"vaCreateBuffer");; |
+ va_status = vaRenderPicture(va_dpy,context_id, &slice_parameter, 1); |
+ CHECK_VASTATUS(va_status,"vaRenderPicture"); |
+ |
+ // Prepare for next picture |
+ tempID = surface_ids[SID_RECON_PICTURE]; |
+ surface_ids[SID_RECON_PICTURE] = surface_ids[SID_REFERENCE_PICTURE]; |
+ surface_ids[SID_REFERENCE_PICTURE] = tempID; |
+} |
+ |
+static void end_picture() |
+{ |
+ VAStatus va_status; |
+ |
+ va_status = vaEndPicture(va_dpy,context_id); |
+ CHECK_VASTATUS(va_status,"vaRenderPicture"); |
+} |
+ |
+#define BITSTREAM_ALLOCATE_STEPPING 4096 |
+ |
+struct __bitstream { |
+ unsigned int *buffer; |
+ int bit_offset; |
+ int max_size_in_dword; |
+}; |
+ |
+typedef struct __bitstream bitstream; |
+ |
+static int |
+get_coded_bitsteam_length(unsigned char *buffer, int buffer_length) |
+{ |
+ int i; |
+ |
+ for (i = buffer_length - 1; i >= 0; i--) { |
+ if (buffer[i]) |
+ break; |
+ } |
+ |
+ return i + 1; |
+} |
+ |
+static unsigned int |
+swap32(unsigned int val) |
+{ |
+ unsigned char *pval = (unsigned char *)&val; |
+ |
+ return ((pval[0] << 24) | |
+ (pval[1] << 16) | |
+ (pval[2] << 8) | |
+ (pval[3] << 0)); |
+} |
+ |
+static void |
+bitstream_start(bitstream *bs) |
+{ |
+ bs->max_size_in_dword = BITSTREAM_ALLOCATE_STEPPING; |
+ bs->buffer = calloc(bs->max_size_in_dword * sizeof(int), 1); |
+ bs->bit_offset = 0; |
+} |
+ |
+static void |
+bitstream_end(bitstream *bs, FILE *avc_fp) |
+{ |
+ int pos = (bs->bit_offset >> 5); |
+ int bit_offset = (bs->bit_offset & 0x1f); |
+ int bit_left = 32 - bit_offset; |
+ int length = (bs->bit_offset + 7) >> 3; |
+ size_t w_items; |
+ |
+ if (bit_offset) { |
+ bs->buffer[pos] = swap32((bs->buffer[pos] << bit_left)); |
+ } |
+ |
+ do { |
+ w_items = fwrite(bs->buffer, length, 1, avc_fp); |
+ } while (w_items != 1); |
+ |
+ free(bs->buffer); |
+} |
+ |
+static void |
+bitstream_put_ui(bitstream *bs, unsigned int val, int size_in_bits) |
+{ |
+ int pos = (bs->bit_offset >> 5); |
+ int bit_offset = (bs->bit_offset & 0x1f); |
+ int bit_left = 32 - bit_offset; |
+ |
+ if (!size_in_bits) |
+ return; |
+ |
+ bs->bit_offset += size_in_bits; |
+ |
+ if (bit_left > size_in_bits) { |
+ bs->buffer[pos] = (bs->buffer[pos] << size_in_bits | val); |
+ } else { |
+ size_in_bits -= bit_left; |
+ bs->buffer[pos] = (bs->buffer[pos] << bit_left) | (val >> size_in_bits); |
+ bs->buffer[pos] = swap32(bs->buffer[pos]); |
+ |
+ if (pos + 1 == bs->max_size_in_dword) { |
+ bs->max_size_in_dword += BITSTREAM_ALLOCATE_STEPPING; |
+ bs->buffer = realloc(bs->buffer, bs->max_size_in_dword * sizeof(unsigned int)); |
+ } |
+ |
+ bs->buffer[pos + 1] = val; |
+ } |
+} |
+ |
+static void |
+bitstream_put_ue(bitstream *bs, unsigned int val) |
+{ |
+ int size_in_bits = 0; |
+ int tmp_val = ++val; |
+ |
+ while (tmp_val) { |
+ tmp_val >>= 1; |
+ size_in_bits++; |
+ } |
+ |
+ bitstream_put_ui(bs, 0, size_in_bits - 1); // leading zero |
+ bitstream_put_ui(bs, val, size_in_bits); |
+} |
+ |
+static void |
+bitstream_put_se(bitstream *bs, int val) |
+{ |
+ unsigned int new_val; |
+ |
+ if (val <= 0) |
+ new_val = -2 * val; |
+ else |
+ new_val = 2 * val - 1; |
+ |
+ bitstream_put_ue(bs, new_val); |
+} |
+ |
+static void |
+bitstream_byte_aligning(bitstream *bs, int bit) |
+{ |
+ int bit_offset = (bs->bit_offset & 0x7); |
+ int bit_left = 8 - bit_offset; |
+ int new_val; |
+ |
+ if (!bit_offset) |
+ return; |
+ |
+ assert(bit == 0 || bit == 1); |
+ |
+ if (bit) |
+ new_val = (1 << bit_left) - 1; |
+ else |
+ new_val = 0; |
+ |
+ bitstream_put_ui(bs, new_val, bit_left); |
+} |
+ |
+static void |
+rbsp_trailing_bits(bitstream *bs) |
+{ |
+ bitstream_put_ui(bs, 1, 1); |
+ bitstream_byte_aligning(bs, 0); |
+} |
+ |
+static void nal_start_code_prefix(bitstream *bs) |
+{ |
+ bitstream_put_ui(bs, 0x00000001, 32); |
+} |
+ |
+static void nal_header(bitstream *bs, int nal_ref_idc, int nal_unit_type) |
+{ |
+ bitstream_put_ui(bs, 0, 1); /* forbidden_zero_bit: 0 */ |
+ bitstream_put_ui(bs, nal_ref_idc, 2); |
+ bitstream_put_ui(bs, nal_unit_type, 5); |
+} |
+ |
+static void sps_rbsp(bitstream *bs) |
+{ |
+ int mb_width, mb_height; |
+ int frame_cropping_flag = 0; |
+ int frame_crop_bottom_offset = 0; |
+ int profile_idc = PROFILE_IDC_MAIN; |
+ |
+ mb_width = picture_width_in_mbs; |
+ mb_height = picture_height_in_mbs; |
+ |
+ if (mb_height * 16 - picture_height) { |
+ frame_cropping_flag = 1; |
+ frame_crop_bottom_offset = |
+ (mb_height * 16 - picture_height) / (2 * (!frame_mbs_only_flag + 1)); |
+ } |
+ |
+ bitstream_put_ui(bs, profile_idc, 8); /* profile_idc */ |
+ bitstream_put_ui(bs, 0, 1); /* constraint_set0_flag */ |
+ bitstream_put_ui(bs, 1, 1); /* constraint_set1_flag */ |
+ bitstream_put_ui(bs, 0, 1); /* constraint_set2_flag */ |
+ bitstream_put_ui(bs, 0, 1); /* constraint_set3_flag */ |
+ bitstream_put_ui(bs, 0, 4); /* reserved_zero_4bits */ |
+ bitstream_put_ui(bs, 41, 8); /* level_idc */ |
+ bitstream_put_ue(bs, 0); /* seq_parameter_set_id */ |
+ |
+ if (profile_idc >= 100) { |
+ /* FIXME: fix for high profile */ |
+ assert(0); |
+ } |
+ |
+ bitstream_put_ue(bs, log2_max_frame_num_minus4); /* log2_max_frame_num_minus4 */ |
+ bitstream_put_ue(bs, pic_order_cnt_type); /* pic_order_cnt_type */ |
+ |
+ if (pic_order_cnt_type == 0) |
+ bitstream_put_ue(bs, log2_max_pic_order_cnt_lsb_minus4); /* log2_max_pic_order_cnt_lsb_minus4 */ |
+ else { |
+ assert(0); |
+ } |
+ |
+ bitstream_put_ue(bs, 1); /* num_ref_frames */ |
+ bitstream_put_ui(bs, 0, 1); /* gaps_in_frame_num_value_allowed_flag */ |
+ |
+ bitstream_put_ue(bs, mb_width - 1); /* pic_width_in_mbs_minus1 */ |
+ bitstream_put_ue(bs, mb_height - 1); /* pic_height_in_map_units_minus1 */ |
+ bitstream_put_ui(bs, frame_mbs_only_flag, 1); /* frame_mbs_only_flag */ |
+ |
+ if (!frame_mbs_only_flag) { |
+ assert(0); |
+ } |
+ |
+ bitstream_put_ui(bs, 0, 1); /* direct_8x8_inference_flag */ |
+ bitstream_put_ui(bs, frame_cropping_flag, 1); /* frame_cropping_flag */ |
+ |
+ if (frame_cropping_flag) { |
+ bitstream_put_ue(bs, 0); /* frame_crop_left_offset */ |
+ bitstream_put_ue(bs, 0); /* frame_crop_right_offset */ |
+ bitstream_put_ue(bs, 0); /* frame_crop_top_offset */ |
+ bitstream_put_ue(bs, frame_crop_bottom_offset); /* frame_crop_bottom_offset */ |
+ } |
+ |
+ bitstream_put_ui(bs, 0, 1); /* vui_parameters_present_flag */ |
+ rbsp_trailing_bits(bs); /* rbsp_trailing_bits */ |
+} |
+ |
+static void build_nal_sps(FILE *avc_fp) |
+{ |
+ bitstream bs; |
+ |
+ bitstream_start(&bs); |
+ nal_start_code_prefix(&bs); |
+ nal_header(&bs, NAL_REF_IDC_HIGH, NAL_SPS); |
+ sps_rbsp(&bs); |
+ bitstream_end(&bs, avc_fp); |
+} |
+ |
+static void pps_rbsp(bitstream *bs) |
+{ |
+ bitstream_put_ue(bs, 0); /* pic_parameter_set_id */ |
+ bitstream_put_ue(bs, 0); /* seq_parameter_set_id */ |
+ |
+ bitstream_put_ui(bs, entropy_coding_mode_flag, 1); /* entropy_coding_mode_flag */ |
+ |
+ bitstream_put_ui(bs, 0, 1); /* pic_order_present_flag: 0 */ |
+ |
+ bitstream_put_ue(bs, 0); /* num_slice_groups_minus1 */ |
+ |
+ bitstream_put_ue(bs, 0); /* num_ref_idx_l0_active_minus1 */ |
+ bitstream_put_ue(bs, 0); /* num_ref_idx_l1_active_minus1 1 */ |
+ |
+ bitstream_put_ui(bs, 0, 1); /* weighted_pred_flag: 0 */ |
+ bitstream_put_ui(bs, 0, 2); /* weighted_bipred_idc: 0 */ |
+ |
+ bitstream_put_se(bs, 0); /* pic_init_qp_minus26 */ |
+ bitstream_put_se(bs, 0); /* pic_init_qs_minus26 */ |
+ bitstream_put_se(bs, 0); /* chroma_qp_index_offset */ |
+ |
+ bitstream_put_ui(bs, 1, 1); /* deblocking_filter_control_present_flag */ |
+ bitstream_put_ui(bs, 0, 1); /* constrained_intra_pred_flag */ |
+ bitstream_put_ui(bs, 0, 1); /* redundant_pic_cnt_present_flag */ |
+ |
+ rbsp_trailing_bits(bs); |
+} |
+ |
+static void build_nal_pps(FILE *avc_fp) |
+{ |
+ bitstream bs; |
+ |
+ bitstream_start(&bs); |
+ nal_start_code_prefix(&bs); |
+ nal_header(&bs, NAL_REF_IDC_HIGH, NAL_PPS); |
+ pps_rbsp(&bs); |
+ bitstream_end(&bs, avc_fp); |
+} |
+ |
+static void |
+build_header(FILE *avc_fp) |
+{ |
+ build_nal_sps(avc_fp); |
+ build_nal_pps(avc_fp); |
+} |
+ |
+ |
+static void |
+slice_header(bitstream *bs, int frame_num, int slice_type, int is_idr) |
+{ |
+ int is_cabac = (entropy_coding_mode_flag == ENTROPY_MODE_CABAC); |
+ |
+ bitstream_put_ue(bs, 0); /* first_mb_in_slice: 0 */ |
+ bitstream_put_ue(bs, slice_type); /* slice_type */ |
+ bitstream_put_ue(bs, 0); /* pic_parameter_set_id: 0 */ |
+ bitstream_put_ui(bs, frame_num & 0x0F, log2_max_frame_num_minus4 + 4); /* frame_num */ |
+ |
+ /* frame_mbs_only_flag == 1 */ |
+ if (!frame_mbs_only_flag) { |
+ /* FIXME: */ |
+ assert(0); |
+ } |
+ |
+ if (is_idr) |
+ bitstream_put_ue(bs, 0); /* idr_pic_id: 0 */ |
+ |
+ if (pic_order_cnt_type == 0) { |
+ bitstream_put_ui(bs, (frame_num * 2) & 0x0F, log2_max_pic_order_cnt_lsb_minus4 + 4); |
+ /* only support frame */ |
+ } else { |
+ /* FIXME: */ |
+ assert(0); |
+ } |
+ |
+ /* redundant_pic_cnt_present_flag == 0 */ |
+ |
+ /* slice type */ |
+ if (slice_type == SLICE_TYPE_P) { |
+ bitstream_put_ui(bs, 0, 1); /* num_ref_idx_active_override_flag: 0 */ |
+ /* ref_pic_list_reordering */ |
+ bitstream_put_ui(bs, 0, 1); /* ref_pic_list_reordering_flag_l0: 0 */ |
+ } else if (slice_type == SLICE_TYPE_B) { |
+ /* FIXME */ |
+ assert(0); |
+ } |
+ |
+ /* weighted_pred_flag == 0 */ |
+ |
+ /* dec_ref_pic_marking */ |
+ if (is_idr) { |
+ bitstream_put_ui(bs, 0, 1); /* no_output_of_prior_pics_flag: 0 */ |
+ bitstream_put_ui(bs, 0, 1); /* long_term_reference_flag: 0 */ |
+ } else { |
+ bitstream_put_ui(bs, 0, 1); /* adaptive_ref_pic_marking_mode_flag: 0 */ |
+ } |
+ |
+ if (is_cabac && (slice_type != SLICE_TYPE_I)) |
+ bitstream_put_ue(bs, 0); /* cabac_init_idc: 0 */ |
+ |
+ bitstream_put_se(bs, 0); /* slice_qp_delta: 0 */ |
+ |
+ if (deblocking_filter_control_present_flag == 1) { |
+ bitstream_put_ue(bs, 0); /* disable_deblocking_filter_idc: 0 */ |
+ bitstream_put_se(bs, 2); /* slice_alpha_c0_offset_div2: 2 */ |
+ bitstream_put_se(bs, 2); /* slice_beta_offset_div2: 2 */ |
+ } |
+} |
+ |
+static void |
+slice_data(bitstream *bs) |
+{ |
+ VACodedBufferSegment *coded_buffer_segment; |
+ unsigned char *coded_mem; |
+ int i, slice_data_length; |
+ VAStatus va_status; |
+ VASurfaceStatus surface_status; |
+ int is_cabac = (entropy_coding_mode_flag == ENTROPY_MODE_CABAC); |
+ |
+ va_status = vaSyncSurface(va_dpy, surface_ids[SID_INPUT_PICTURE]); |
+ CHECK_VASTATUS(va_status,"vaSyncSurface"); |
+ |
+ surface_status = 0; |
+ va_status = vaQuerySurfaceStatus(va_dpy, surface_ids[SID_INPUT_PICTURE], &surface_status); |
+ CHECK_VASTATUS(va_status,"vaQuerySurfaceStatus"); |
+ |
+ va_status = vaMapBuffer(va_dpy, coded_buf, (void **)(&coded_buffer_segment)); |
+ CHECK_VASTATUS(va_status,"vaMapBuffer"); |
+ coded_mem = coded_buffer_segment->buf; |
+ |
+ if (is_cabac) { |
+ bitstream_byte_aligning(bs, 1); |
+ slice_data_length = get_coded_bitsteam_length(coded_mem, codedbuf_size); |
+ |
+ for (i = 0; i < slice_data_length; i++) { |
+ bitstream_put_ui(bs, *coded_mem, 8); |
+ coded_mem++; |
+ } |
+ } else { |
+ /* FIXME */ |
+ assert(0); |
+ } |
+ |
+ vaUnmapBuffer(va_dpy, coded_buf); |
+} |
+ |
+static void |
+build_nal_slice(FILE *avc_fp, int frame_num, int slice_type, int is_idr) |
+{ |
+ bitstream bs; |
+ |
+ bitstream_start(&bs); |
+ nal_start_code_prefix(&bs); |
+ nal_header(&bs, NAL_REF_IDC_HIGH, is_idr ? NAL_IDR : NAL_NON_IDR); |
+ slice_header(&bs, frame_num, slice_type, is_idr); |
+ slice_data(&bs); |
+ bitstream_end(&bs, avc_fp); |
+} |
+ |
+static void |
+store_coded_buffer(FILE *avc_fp, int frame_num, int is_intra, int is_idr) |
+{ |
+ build_nal_slice(avc_fp, frame_num, is_intra ? SLICE_TYPE_I : SLICE_TYPE_P, is_idr); |
+} |
+ |
+int main(int argc, char *argv[]) |
+{ |
+ int f; |
+ FILE *yuv_fp; |
+ FILE *avc_fp; |
+ int frame_number; |
+ long file_size; |
+ clock_t start_clock, end_clock; |
+ float encoding_time; |
+ |
+ if(argc != 5 && argc != 6) { |
+ printf("Usage: %s <width> <height> <input_yuvfile> <output_avcfile> [qp]\n", argv[0]); |
+ return -1; |
+ } |
+ |
+ picture_width = atoi(argv[1]); |
+ picture_height = atoi(argv[2]); |
+ picture_width_in_mbs = (picture_width + 15) / 16; |
+ picture_height_in_mbs = (picture_height + 15) / 16; |
+ |
+ if (argc == 6) |
+ qp_value = atoi(argv[5]); |
+ else |
+ qp_value = 26; |
+ |
+ yuv_fp = fopen(argv[3],"rb"); |
+ if ( yuv_fp == NULL){ |
+ printf("Can't open input YUV file\n"); |
+ return -1; |
+ } |
+ fseek(yuv_fp,0l, SEEK_END); |
+ file_size = ftell(yuv_fp); |
+ frame_size = picture_width * picture_height + ((picture_width * picture_height) >> 1) ; |
+ codedbuf_size = picture_width * picture_height * 1.5; |
+ |
+ if ( (file_size < frame_size) || (file_size % frame_size) ) { |
+ printf("The YUV file's size is not correct\n"); |
+ return -1; |
+ } |
+ frame_number = file_size / frame_size; |
+ fseek(yuv_fp, 0l, SEEK_SET); |
+ |
+ avc_fp = fopen(argv[4], "wb"); |
+ if ( avc_fp == NULL) { |
+ printf("Can't open output avc file\n"); |
+ return -1; |
+ } |
+ start_clock = clock(); |
+ build_header(avc_fp); |
+ |
+ create_encode_pipe(); |
+ alloc_encode_resource(); |
+ |
+ for ( f = 0; f < frame_number; f++ ) { //picture level loop |
+ int is_intra = (f % 30 == 0); |
+ int is_idr = (f == 0); |
+ |
+ begin_picture(); |
+ prepare_input(yuv_fp, is_intra); |
+ end_picture(); |
+ store_coded_buffer(avc_fp, f, is_intra, is_idr); |
+ |
+ printf("\r %d/%d ...", f+1, frame_number); |
+ fflush(stdout); |
+ } |
+ |
+ end_clock = clock(); |
+ printf("\ndone!\n"); |
+ encoding_time = (float)(end_clock-start_clock)/CLOCKS_PER_SEC; |
+ printf("encode %d frames in %f secondes, FPS is %.1f\n",frame_number, encoding_time, frame_number/encoding_time); |
+ |
+ release_encode_resource(); |
+ destory_encode_pipe(); |
+ |
+ return 0; |
+} |