diff --git a/vaapi-recorder.cpp b/vaapi-recorder.cpp index 9800c18..ea48f23 100644 --- a/vaapi-recorder.cpp +++ b/vaapi-recorder.cpp @@ -507,7 +507,7 @@ encoder_update_slice_parameter(struct vaapi_recorder *r, int slice_type) { r->encoder.param.slice.RefPicList1[i].picture_id = VA_INVALID_ID; r->encoder.param.slice.RefPicList1[i].flags = VA_PICTURE_H264_INVALID; - r->encoder.param.slice.RefPicList0[i].frame_idx = 0; + r->encoder.param.slice.RefPicList1[i].frame_idx = 0; } if(r->frame_count) { diff --git a/vaapi_encoder_h264.h b/vaapi_encoder_h264.h new file mode 100644 index 0000000..4c870a0 --- /dev/null +++ b/vaapi_encoder_h264.h @@ -0,0 +1,475 @@ +#ifndef VAAPI_ENCODER_H264_H +#define VAAPI_ENCODER_H264_H +#include "vaapi_encoder.h" +#include +#include + +#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 NAL_SEI 6 + +#define SLICE_TYPE_P 0 +#define SLICE_TYPE_B 1 +#define SLICE_TYPE_I 2 +#define SLICE_TYPE_P_ONLY 5 + +#define H264_IS_P_SLICE(type) (SLICE_TYPE_P == (type) || SLICE_TYPE_P_ONLY == (type)) +#define H264_IS_B_SLICE(type) (SLICE_TYPE_B == (type)) +#define H264_IS_I_SLICE(type) (SLICE_TYPE_I == (type)) + + +#define ENTROPY_MODE_CAVLC 0 +#define ENTROPY_MODE_CABAC 1 + +#define H264_PROFILE_IDC_BASELINE 66 +#define H264_PROFILE_IDC_MAIN 77 +#define H264_PROFILE_IDC_HIGH 100 + +struct BaseBitstreamH264 : BaseBitstream<8> +{ + inline void NalStartCodePrefix() + { + PutUI(0x00000001, 32); + } + inline void NalHeader(int nal_ref_idc, int nal_unit_type) + { + PutUI(0, 1); + PutUI(nal_ref_idc, 2); + PutUI(nal_unit_type, 5); + } +}; + +struct PackedSPSH264 : BaseBitstreamH264 +{ + PackedSPSH264(const VAEncSequenceParameterBufferH264 *seq, int constraint_set_flag): BaseBitstreamH264() + { + int i; + NalStartCodePrefix(); + NalHeader(NAL_REF_IDC_HIGH, NAL_SPS); + + PutUI(H264_PROFILE_IDC_MAIN, 8); + + /* constraint_set[0-3] flag */ + for (i = 0; i < 4; i++) { + int set = (constraint_set_flag & (1 << i)) ? 1 : 0; + PutUI(set, 1); + } + + /* reserved_zero_4bits */ + PutUI(0, 4); + PutUI(seq->level_idc, 8); + PutUE(seq->seq_parameter_set_id); + + PutUE(seq->seq_fields.bits.log2_max_frame_num_minus4); + PutUE(seq->seq_fields.bits.pic_order_cnt_type); + if(seq->seq_fields.bits.pic_order_cnt_type != 2) + PutUE(seq->seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4); + + PutUE(seq->max_num_ref_frames); + + /* gaps_in_frame_num_value_allowed_flag */ + PutUI(0, 1); + + /* pic_width_in_mbs_minus1, pic_height_in_map_units_minus1 */ + PutUE(seq->picture_width_in_mbs - 1); + PutUE(seq->picture_height_in_mbs - 1); + + PutUI(seq->seq_fields.bits.frame_mbs_only_flag, 1); + PutUI(seq->seq_fields.bits.direct_8x8_inference_flag, 1); + + PutUI(seq->frame_cropping_flag, 1); + + if (seq->frame_cropping_flag) { + PutUE(seq->frame_crop_left_offset); + PutUE(seq->frame_crop_right_offset); + PutUE(seq->frame_crop_top_offset); + PutUE(seq->frame_crop_bottom_offset); + } + + /* vui_parameters_present_flag */ + PutUI(0, 1); + #if 0 + /* aspect_ratio_info_present_flag */ + PutUI(0, 1); + /* overscan_info_present_flag */ + PutUI(0, 1); + + /* video_signal_type_present_flag */ + PutUI(0, 1); + /* chroma_loc_info_present_flag */ + PutUI(0, 1); + + /* timing_info_present_flag */ + PutUI(1, 1); + PutUI(seq->num_units_in_tick, 32); + PutUI(seq->time_scale, 32); + /* fixed_frame_rate_flag */ + PutUI(1, 1); + + /* nal_hrd_parameters_present_flag */ + PutUI(0, 1); + + /* vcl_hrd_parameters_present_flag */ + PutUI(0, 1); + + /* low_delay_hrd_flag */ + PutUI(0, 1); + + /* pic_struct_present_flag */ + PutUI(0, 1); + /* bitstream_restriction_flag */ + PutUI(0, 1); + #endif + RBSPTrailingBits(); + End(); + } +}; + +struct PackedPPSH264 : BaseBitstreamH264 +{ + PackedPPSH264(const VAEncPictureParameterBufferH264 *pic): BaseBitstreamH264() + { + NalStartCodePrefix(); + NalHeader(NAL_REF_IDC_HIGH, NAL_PPS); + + /* pic_parameter_set_id, seq_parameter_set_id */ + PutUE(pic->pic_parameter_set_id); + PutUE(pic->seq_parameter_set_id); + + PutUI(pic->pic_fields.bits.entropy_coding_mode_flag, 1); + + /* pic_order_present_flag: 0 */ + PutUI(0, 1); + + /* num_slice_groups_minus1 */ + PutUE(0); + + PutUE(pic->num_ref_idx_l0_active_minus1); + PutUE(pic->num_ref_idx_l1_active_minus1); + + PutUI(pic->pic_fields.bits.weighted_pred_flag, 1); + PutUI(pic->pic_fields.bits.weighted_bipred_idc, 2); + + /* pic_init_qp_minus26, pic_init_qs_minus26, chroma_qp_index_offset */ + PutSE(pic->pic_init_qp - 26); + PutSE(0); + PutSE(0); + + PutUI(pic->pic_fields.bits.deblocking_filter_control_present_flag, 1); + + /* constrained_intra_pred_flag, redundant_pic_cnt_present_flag */ + PutUI(0, 1); + PutUI(0, 1); + + PutUI(pic->pic_fields.bits.transform_8x8_mode_flag, 1); + + /* pic_scaling_matrix_present_flag */ + PutUI(0, 1); + PutSE(pic->second_chroma_qp_index_offset ); + + RBSPTrailingBits(); + End(); + } +}; + + +template +struct PackedSliceH264: BaseBitstreamH264 +{ + PackedSliceH264(VAEncSequenceParameterBufferH264 *seq,VAEncPictureParameterBufferH264 *pic, VAEncSliceParameterBufferH264 *slice): BaseBitstreamH264() + { + constexpr bool is_idr = true; + constexpr bool is_ref = true; + NalStartCodePrefix(); + if constexpr(H264_IS_I_SLICE(slice_type)) + NalHeader(NAL_REF_IDC_HIGH, is_idr ? NAL_IDR : NAL_NON_IDR); + else if (H264_IS_P_SLICE(slice->slice_type)) + NalHeader(NAL_REF_IDC_MEDIUM, NAL_NON_IDR); + else + NalHeader(is_ref ? NAL_REF_IDC_LOW : NAL_REF_IDC_NONE, NAL_NON_IDR); + int first_mb_in_slice = slice->macroblock_address; + + PutUE(first_mb_in_slice); /* first_mb_in_slice: 0 */ + PutUE(slice->slice_type); /* slice_type */ + PutUE(slice->pic_parameter_set_id); /* pic_parameter_set_id: 0 */ + PutUI(pic->frame_num, seq->seq_fields.bits.log2_max_frame_num_minus4 + 4); /* frame_num */ + + /* frame_mbs_only_flag == 1 */ + if (!seq->seq_fields.bits.frame_mbs_only_flag) { + /* FIXME: */ + assert(0); + } + + if constexpr(H264_IS_I_SLICE(slice_type)) + if (pic->pic_fields.bits.idr_pic_flag) + PutUE(slice->idr_pic_id); /* idr_pic_id: 0 */ + + if (seq->seq_fields.bits.pic_order_cnt_type == 0) { + PutUI(pic->CurrPic.TopFieldOrderCnt, seq->seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4 + 4); + /* pic_order_present_flag == 0 */ + } else { + /* FIXME: */ + // assert(0); + } + + /* redundant_pic_cnt_present_flag == 0 */ + /* slice type */ + if constexpr(H264_IS_P_SLICE(slice_type)) { + PutUI(slice->num_ref_idx_active_override_flag, 1); /* num_ref_idx_active_override_flag: */ + + if (slice->num_ref_idx_active_override_flag) + PutUE(slice->num_ref_idx_l0_active_minus1); + + /* ref_pic_list_reordering */ + PutUI(0, 1); /* ref_pic_list_reordering_flag_l0: 0 */ + } else if (H264_IS_B_SLICE(slice_type)) { + PutUI(slice->direct_spatial_mv_pred_flag, 1); /* direct_spatial_mv_pred: 1 */ + + PutUI(slice->num_ref_idx_active_override_flag, 1); /* num_ref_idx_active_override_flag: */ + + if (slice->num_ref_idx_active_override_flag) { + PutUE(slice->num_ref_idx_l0_active_minus1); + PutUE(slice->num_ref_idx_l1_active_minus1); + } + + /* ref_pic_list_reordering */ + PutUI(0, 1); /* ref_pic_list_reordering_flag_l0: 0 */ + PutUI(0, 1); /* ref_pic_list_reordering_flag_l1: 0 */ + } + + if ((pic->pic_fields.bits.weighted_pred_flag && + H264_IS_P_SLICE(slice->slice_type)) || + ((pic->pic_fields.bits.weighted_bipred_idc == 1) && + H264_IS_B_SLICE(slice->slice_type))) { + /* FIXME: fill weight/offset table */ + assert(0); + } + + /* dec_ref_pic_marking */ + if (pic->pic_fields.bits.reference_pic_flag) { /* nal_ref_idc != 0 */ + unsigned char no_output_of_prior_pics_flag = 0; + unsigned char long_term_reference_flag = 0; + unsigned char adaptive_ref_pic_marking_mode_flag = 0; + + if (pic->pic_fields.bits.idr_pic_flag) { + PutUI(no_output_of_prior_pics_flag, 1); /* no_output_of_prior_pics_flag: 0 */ + PutUI(long_term_reference_flag, 1); /* long_term_reference_flag: 0 */ + } else { + PutUI(adaptive_ref_pic_marking_mode_flag, 1); /* adaptive_ref_pic_marking_mode_flag: 0 */ + } + } + + if (pic->pic_fields.bits.entropy_coding_mode_flag && + !H264_IS_I_SLICE(slice->slice_type)) + PutUE(slice->cabac_init_idc); /* cabac_init_idc: 0 */ + + PutSE(slice->slice_qp_delta); /* slice_qp_delta: 0 */ + + /* ignore for SP/SI */ + + if (pic->pic_fields.bits.deblocking_filter_control_present_flag) { + PutUE(slice->disable_deblocking_filter_idc); /* disable_deblocking_filter_idc: 0 */ + + if (slice->disable_deblocking_filter_idc != 1) { + PutSE(slice->slice_alpha_c0_offset_div2); /* slice_alpha_c0_offset_div2: 2 */ + PutSE(slice->slice_beta_offset_div2); /* slice_beta_offset_div2: 2 */ + } + } + + if (pic->pic_fields.bits.entropy_coding_mode_flag) { + ByteAligning(1); + } + End(); + } +}; + +struct VaapiEncoderH264: VaapiEncoder +{ + VAEncSequenceParameterBufferH264 seq; + VAEncPictureParameterBufferH264 pic; + VAEncSliceParameterBufferH264 slice; + void InitParameters() + { + int width_in_mbs, height_in_mbs; + int frame_cropping_flag = 0; + int frame_crop_bottom_offset = 0; + + width_in_mbs = (width + 15) / 16; + height_in_mbs = (height + 15) / 16; + + seq.level_idc = 60; + seq.intra_period = 32767; //r->encoder.intra_period; + seq.intra_idr_period = 32767; + seq.max_num_ref_frames = 1; + seq.picture_width_in_mbs = width_in_mbs; + seq.picture_height_in_mbs = height_in_mbs; + seq.seq_fields.bits.chroma_format_idc = 1; + seq.seq_fields.bits.frame_mbs_only_flag = 1; + seq.ip_period = 1; + + + /* Tc = num_units_in_tick / time_scale */ + seq.time_scale = 180; + seq.num_units_in_tick = 15; + + if (height_in_mbs * 16 - height > 0) { + frame_cropping_flag = 1; + frame_crop_bottom_offset = (height_in_mbs * 16 - height) / 2; + } + + seq.frame_cropping_flag = frame_cropping_flag; + seq.frame_crop_bottom_offset = frame_crop_bottom_offset; + + seq.seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4 = 0;//12; + seq.seq_fields.bits.log2_max_frame_num_minus4 = 4; + seq.seq_fields.bits.pic_order_cnt_type = 2; + + pic.pic_init_qp = 11; + + /* ENTROPY_MODE_CABAC */ + pic.pic_fields.bits.entropy_coding_mode_flag = 1; + + pic.pic_fields.bits.deblocking_filter_control_present_flag = 0; + pic.pic_fields.bits.reference_pic_flag = 1; + for(int i = 0; i < 16; i++) + { + pic.ReferenceFrames[i].picture_id = VA_INVALID_ID; + pic.ReferenceFrames[i].flags = VA_PICTURE_H264_INVALID; + pic.ReferenceFrames[i].frame_idx = 0; + } + + slice.num_macroblocks = width_in_mbs * height_in_mbs; + slice.macroblock_info = VA_INVALID_ID; + slice.direct_spatial_mv_pred_flag = 1; + for(int i = 0; i < 32; i++) + { + slice.RefPicList0[i].picture_id = VA_INVALID_ID; + slice.RefPicList0[i].flags = VA_PICTURE_H264_INVALID; + slice.RefPicList0[i].frame_idx = 0; + } + for(int i = 0; i < 32; i++) + { + slice.RefPicList1[i].picture_id = VA_INVALID_ID; + slice.RefPicList1[i].flags = VA_PICTURE_H264_INVALID; + slice.RefPicList1[i].frame_idx = 0; + } + } + + bool Setup(int drm_fd, int width, int height, const char *filename, int *dmabuf_fd, uint64_t *mod, uint32_t *size, uint32_t *offset, uint32_t *pitch1, uint32_t *pitch2, uint64_t *modifiers, int modifierscount, bool p010) + { + VAProfile profile = VAProfileH264Main; + uint32_t format = VA_RT_FORMAT_YUV420; + uint32_t fourcc = VA_FOURCC_NV12; + if(!SetupVA(profile, format, fourcc, drm_fd, width, height, filename, dmabuf_fd, mod, size, offset, pitch1, pitch2, modifiers, modifierscount)) + { + VaapiEncoder::Destroy(); + return false; + } + if(!CreateContext(profile, format, fourcc, VA_RC_CBR)) + { + VaapiEncoder::Destroy(); + return false; + } + InitParameters(); + + return true; + } + + inline void EncodeIDR(int idx) + { + VAStatus status = vaBeginPicture(dpy, ctx, inputFrames[idx]); + + VABufferID seqb = CreateParamererBuffer(VAEncSequenceParameterBufferType, seq); + slice.slice_type = SLICE_TYPE_I; + slice.RefPicList0[0].picture_id = VA_INVALID_ID; + slice.RefPicList0[0].flags = VA_PICTURE_H264_INVALID; + slice.RefPicList0[0].frame_idx = 0; + slice.pic_order_cnt_lsb = seq.seq_fields.bits.pic_order_cnt_type == 0? frame_count: 0; + VABufferID sliceb = CreateParamererBuffer(VAEncSliceParameterBufferType, slice); + VABufferID output = CreateOutputBuf(width * height); + + pic.CurrPic.picture_id = reference_picture[frame_count % 2]; + pic.CurrPic.frame_idx = frame_count; + pic.CurrPic.TopFieldOrderCnt = seq.seq_fields.bits.pic_order_cnt_type == 0? frame_count:0; + + pic.ReferenceFrames[0].picture_id = VA_INVALID_ID; + pic.ReferenceFrames[0].flags = VA_PICTURE_H264_INVALID; + pic.ReferenceFrames[0].frame_idx = 0; + pic.coded_buf = output; + pic.pic_fields.bits.idr_pic_flag = 1; + VABufferID picb = CreateParamererBuffer(VAEncPictureParameterBufferType, pic); + VABufferID fpsb = CreateMiscParameterBuffer(VAEncMiscParameterTypeFrameRate,VAEncMiscParameterFrameRate{.framerate = 90} ); + VABufferID hrdb = CreateMiscParameterBuffer(VAEncMiscParameterTypeHRD, VAEncMiscParameterHRD{}); + VABufferID rcb = CreateMiscParameterBuffer(VAEncMiscParameterTypeRateControl, VAEncMiscParameterRateControl{ + .bits_per_second = 150*1024*1024, + .target_percentage = 66, + .window_size = 1000, + .initial_qp = 25 + }); + VABufferID ppps[2]; + VABufferID psps[2]; + CreatePackedBuffer(psps[0], psps[1], VAEncPackedHeaderSequence, PackedSPSH264(&seq,(1 << 1) /* Annex A.2.2 */)); + CreatePackedBuffer(ppps[0], ppps[1], VAEncPackedHeaderPicture, PackedPPSH264(&pic)); + + VABufferID pslice[2]; + CreatePackedBuffer(pslice[0], pslice[1], VAEncPackedHeaderSlice, + PackedSliceH264(&seq, &pic, &slice)); + VABufferID buffers[] = {seqb, psps[0], psps[1], fpsb, hrdb, rcb, ppps[0], ppps[1], picb, pslice[0], pslice[1], sliceb }; + vaRenderPicture(dpy, ctx, buffers, sizeof(buffers) / sizeof(buffers[0]) ); + status = vaEndPicture(dpy, ctx); + if(status != VA_STATUS_SUCCESS) + abort(); + PushOutput(output); + /*status = vaSyncSurface(dpy, inputFrames[idx]); + status = vaSyncBuffer(dpy, output, 1000000000); + WriteOutput(output);*/ + for(int i = 0; i < sizeof(buffers) / sizeof(buffers[0]); i++) + vaDestroyBuffer(dpy, buffers[i]); + frame_count++; + } + + inline void EncodeP(int idx) + { + VAStatus status = vaBeginPicture(dpy, ctx, inputFrames[idx]); + // todo: chain slice/output buffers, patch POC in slice buffers??? + slice.slice_type = SLICE_TYPE_P; + slice.RefPicList0[0].frame_idx = frame_count - 1; + slice.RefPicList0[0].picture_id = reference_picture[(frame_count - 1)% 2]; + slice.RefPicList0[0].flags = VA_PICTURE_H264_SHORT_TERM_REFERENCE; + slice.pic_order_cnt_lsb = seq.seq_fields.bits.pic_order_cnt_type == 0? frame_count: 0; + VABufferID sliceb = CreateParamererBuffer(VAEncSliceParameterBufferType, slice); + VABufferID output = CreateOutputBuf(width * height); + pic.CurrPic.picture_id = reference_picture[frame_count % 2]; + pic.CurrPic.frame_idx = frame_count; + pic.CurrPic.TopFieldOrderCnt = seq.seq_fields.bits.pic_order_cnt_type == 0? frame_count:0; + pic.ReferenceFrames[0].picture_id = reference_picture[(frame_count + 1) % 2]; + pic.ReferenceFrames[0].flags = VA_PICTURE_H264_SHORT_TERM_REFERENCE; + pic.ReferenceFrames[0].frame_idx = frame_count - 1; + pic.coded_buf = output; + pic.pic_fields.bits.idr_pic_flag = 0; + VABufferID picb = CreateParamererBuffer(VAEncPictureParameterBufferType, pic); + VABufferID pslice[2]; + CreatePackedBuffer(pslice[0], pslice[1], VAEncPackedHeaderSlice, + PackedSliceH264(&seq, &pic, &slice)); + VABufferID buffers[] = {picb, pslice[0], pslice[1], sliceb }; + vaRenderPicture(dpy, ctx, buffers, sizeof(buffers) / sizeof(buffers[0]) ); + + status = vaEndPicture(dpy, ctx); + PushOutput(output); + /*status = vaSyncSurface(dpy, inputFrames[idx]); + status = vaSyncBuffer(dpy, output, 1000000000); + WriteOutput(output);*/ + for(int i = 0; i < sizeof(buffers) / sizeof(buffers[0]); i++) + vaDestroyBuffer(dpy, buffers[i]); + frame_count++; + } +}; + +#endif // VAAPI_ENCODER_H264_H diff --git a/vaapi_encoder_hevc.h b/vaapi_encoder_hevc.h index 2b51593..7d4d8e1 100644 --- a/vaapi_encoder_hevc.h +++ b/vaapi_encoder_hevc.h @@ -2,7 +2,7 @@ #define VAAPI_ENCODER_HEVC_H #include "vaapi_encoder.h" -#include +#include #include #define NAL_REF_IDC_NONE 0 @@ -16,16 +16,16 @@ enum { SLICE_P = 1, SLICE_I = 2, }; -#define IS_I_SLICE(type) (SLICE_I == (type)) -#define IS_P_SLICE(type) (SLICE_P == (type)) -#define IS_B_SLICE(type) (SLICE_B == (type)) +#define HEVC_IS_I_SLICE(type) (SLICE_I == (type)) +#define HEVC_IS_P_SLICE(type) (SLICE_P == (type)) +#define HEVC_IS_B_SLICE(type) (SLICE_B == (type)) #define ENTROPY_MODE_CAVLC 0 #define ENTROPY_MODE_CABAC 1 -#define PROFILE_IDC_MAIN 1 -#define PROFILE_IDC_MAIN10 2 +#define HEVC_PROFILE_IDC_MAIN 1 +#define HEVC_PROFILE_IDC_MAIN10 2 enum NALUType { NALU_TRAIL_N = 0x00, // Coded slice segment of a non-TSA, non-STSA trailing picture - slice_segment_layer_rbsp, VLC @@ -688,7 +688,7 @@ struct VaapiEncoderHEVC: VaapiEncoder // (none?) // profile seq.general_level_idc = 120; - seq.general_profile_idc = p010? PROFILE_IDC_MAIN10: PROFILE_IDC_MAIN; + seq.general_profile_idc = p010? HEVC_PROFILE_IDC_MAIN10: HEVC_PROFILE_IDC_MAIN; // pps pic.pic_fields.bits.dependent_slice_segments_enabled_flag = 1; // seens work both diff --git a/vkcompute.cpp b/vkcompute.cpp index 2126e9c..59bb0ab 100644 --- a/vkcompute.cpp +++ b/vkcompute.cpp @@ -36,8 +36,8 @@ #include #include //#include "vaapi-recorder.h" +#include "vaapi_encoder_h264.h" #include "vaapi_encoder_hevc.h" - struct DrmHelper { char *mapped_buffer; @@ -1328,7 +1328,8 @@ struct ComputeApplication { */ //VK_CHECK_RESULT(vkWaitForFences(device, 1, &fence, VK_TRUE, 100000000000)); } - void run() { + template + void run(bool p010, const char *filename) { // Buffer size of the storage buffer that will contain the rendered mandelbrot set. //bufferSize = sizeof(Pixel) * WIDTH * HEIGHT; @@ -1347,11 +1348,11 @@ struct ComputeApplication { uint32_t size, offset, pitch1, pitch2; int fd[CHAIN_SIZE]; uint64_t modifiers[32]; - bool p010 = true; int count = getAvailiableModifiersList(modifiers, 32, p010?VK_FORMAT_R16_UNORM:VK_FORMAT_R8_UNORM); //auto *r = vaapi_recorder_create5(drm_fd, WIDTH, HEIGHT, "out.264", fd, &mod, &size, &offset, &pitch1, &pitch2, modifiers, count); - VaapiEncoderHEVC enc = {}; - enc.Setup(drm_fd, WIDTH, HEIGHT, "out.265", fd, &mod, &size, &offset, &pitch1, &pitch2, modifiers, count, p010); + Codec enc = {}; + + enc.Setup(drm_fd, WIDTH, HEIGHT, filename, fd, &mod, &size, &offset, &pitch1, &pitch2, modifiers, count, p010); for(int i = 0; i < CHAIN_SIZE; i++) { createUBO(i); @@ -1464,10 +1465,17 @@ struct ComputeApplication { } }; -int main() { +int main(int argc, char **argv) { ComputeApplication app; - app.run(); + bool hevc = argc > 1; + bool p010 = false; + if(hevc) + p010 = atoi(argv[1]); + if(hevc) + app.run(p010, "out.265"); + else + app.run(false, "out.264"); return EXIT_SUCCESS; }