Commit 0b8b9764 authored by Zhou Chang's avatar Zhou Chang Committed by Xiang, Haihao

test/encode/avcenc: a simple encoder based on VA API for H.264

Usage:
avcenc <width> <height> <input file> <output file> [qp]
Singed-off-by: default avatarZhou Chang <chang.zhou@intel.com>
Singed-off-by: default avatarLan Hai <hai.lan@intel.com>
Signed-off-by: default avatarXiang, Haihao <haihao.xiang@intel.com>
parent 54d2648b
......@@ -20,7 +20,7 @@
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
bin_PROGRAMS = h264encode
bin_PROGRAMS = h264encode avcenc
AM_CFLAGS = -I$(top_srcdir)/va -I$(top_srcdir)/src/x11
......@@ -29,6 +29,8 @@ TEST_LIBS = $(top_builddir)/va/$(libvabackendlib)
h264encode_LDADD = $(TEST_LIBS)
h264encode_SOURCES = h264encode.c
avcenc_LDADD= $(TEST_LIBS)
avcenc_SOURCES= avcenc.c
valgrind: $(bin_PROGRAMS)
for a in $(bin_PROGRAMS); do \
......
/*
* 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 <pciaccess.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;
static int picture_height;
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 / 16;
seq_h264.picture_height_in_mbs = picture_height / 16;
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 + 15) / 16;
mb_height = (picture_height + 15) / 16;
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]);
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;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment