diff --git a/src/cli.c b/src/cli.c index 38b475f88..689f70a75 100644 --- a/src/cli.c +++ b/src/cli.c @@ -24,7 +24,6 @@ */ #include "cli.h" -#include "encoderstate.h" #include #include @@ -356,37 +355,26 @@ void print_help(void) } -void print_frame_info(encoder_state_t *state, double frame_psnr[3]) +void print_frame_info(const kvz_frame_info *const info, + const double frame_psnr[3], + const uint32_t bytes) { fprintf(stderr, "POC %4d QP %2d (%c-frame) %10d bits PSNR: %2.4f %2.4f %2.4f", - state->global->poc, - state->global->QP, - "BPI"[state->global->slicetype % 3], state->stats_bitstream_length << 3, + info->poc, + info->qp, + "BPI"[info->slice_type % 3], + bytes << 3, frame_psnr[0], frame_psnr[1], frame_psnr[2]); - // Print reference picture lists - if (state->global->slicetype != SLICE_I) { - int j, ref_list[2] = { 0, 0 }, ref_list_poc[2][16]; - // List all pocs of lists - for (j = 0; j < state->global->ref->used_size; j++) { - if (state->global->ref->pocs[j] < state->global->poc) { - ref_list_poc[0][ref_list[0]] = state->global->ref->pocs[j]; - ref_list[0]++; - } else { - ref_list_poc[1][ref_list[1]] = state->global->ref->pocs[j]; - ref_list[1]++; - } - } - kvz_encoder_ref_insertion_sort(ref_list_poc[0], ref_list[0]); - kvz_encoder_ref_insertion_sort(ref_list_poc[1], ref_list[1]); - + if (info->slice_type != KVZ_SLICE_I) { + // Print reference picture lists fprintf(stderr, " [L0 "); - for (j = ref_list[0] - 1; j >= 0; j--) { - fprintf(stderr, "%d ", ref_list_poc[0][j]); + for (int j = info->ref_list_len[0] - 1; j >= 0; j--) { + fprintf(stderr, "%d ", info->ref_list[0][j]); } fprintf(stderr, "] [L1 "); - for (j = 0; j < ref_list[1]; j++) { - fprintf(stderr, "%d ", ref_list_poc[1][j]); + for (int j = 0; j < info->ref_list_len[1]; j++) { + fprintf(stderr, "%d ", info->ref_list[1][j]); } fprintf(stderr, "]"); } diff --git a/src/cli.h b/src/cli.h index 190fe73fd..f2dc82a7a 100644 --- a/src/cli.h +++ b/src/cli.h @@ -49,6 +49,8 @@ void cmdline_opts_free(const kvz_api *api, cmdline_opts_t *opts); void print_version(void); void print_help(void); -void print_frame_info(encoder_state_t *state, double frame_psnr[3]); +void print_frame_info(const kvz_frame_info *const info, + const double frame_psnr[3], + const uint32_t bytes); #endif diff --git a/src/encmain.c b/src/encmain.c index 583fc2489..08177633e 100644 --- a/src/encmain.c +++ b/src/encmain.c @@ -40,10 +40,9 @@ #include "checkpoint.h" #include "global.h" -#include "config.h" #include "threadqueue.h" #include "encoder.h" -#include "encoderstate.h" +#include "videoframe.h" #include "cli.h" #include "yuv_io.h" @@ -211,8 +210,16 @@ int main(int argc, char *argv[]) kvz_data_chunk* chunks_out = NULL; kvz_picture *img_rec = NULL; + kvz_picture *img_src = NULL; uint32_t len_out = 0; - if (!api->encoder_encode(enc, img_in, &chunks_out, &len_out, &img_rec)) { + kvz_frame_info info_out; + if (!api->encoder_encode(enc, + img_in, + &chunks_out, + &len_out, + &img_rec, + &img_src, + &info_out)) { fprintf(stderr, "Failed to encode image.\n"); api->picture_free(img_in); goto exit_failure; @@ -244,14 +251,8 @@ int main(int argc, char *argv[]) // Compute and print stats. - // Number of the state that was finished is one less than - // enc->out_state_num. - encoder_state_t *state = &enc->states[ - (enc->out_state_num + enc->num_encoder_states - 1) % - enc->num_encoder_states - ]; double frame_psnr[3] = { 0.0, 0.0, 0.0 }; - kvz_encoder_compute_stats(state, frame_psnr); + kvz_videoframe_compute_psnr(img_src, img_rec, frame_psnr); if (recout) { // Since chunks_out was not NULL, img_rec should have been set. @@ -269,12 +270,13 @@ int main(int argc, char *argv[]) psnr_sum[1] += frame_psnr[1]; psnr_sum[2] += frame_psnr[2]; - print_frame_info(state, frame_psnr); + print_frame_info(&info_out, frame_psnr, len_out); } api->picture_free(img_in); api->chunk_free(chunks_out); api->picture_free(img_rec); + api->picture_free(img_src); } GET_TIME(&encoding_end_real_time); diff --git a/src/encoder_state-bitstream.c b/src/encoder_state-bitstream.c index 2622a1dfb..9307bc381 100644 --- a/src/encoder_state-bitstream.c +++ b/src/encoder_state-bitstream.c @@ -31,10 +31,10 @@ static void encoder_state_write_bitstream_aud(encoder_state_t * const state) { bitstream_t * const stream = &state->stream; - kvz_nal_write(stream, AUD_NUT, 0, 1); + kvz_nal_write(stream, KVZ_NAL_AUD_NUT, 0, 1); - uint8_t pic_type = state->global->slicetype == SLICE_I ? 0 - : state->global->slicetype == SLICE_P ? 1 + uint8_t pic_type = state->global->slicetype == KVZ_SLICE_I ? 0 + : state->global->slicetype == KVZ_SLICE_P ? 1 : 2; WRITE_U(stream, pic_type, 3, "pic_type"); @@ -654,8 +654,8 @@ void kvz_encoder_state_write_bitstream_slice_header(encoder_state_t * const stat #endif WRITE_U(stream, (state->slice->start_in_rs == 0), 1, "first_slice_segment_in_pic_flag"); - if (state->global->pictype >= NAL_BLA_W_LP - && state->global->pictype <= NAL_RSV_IRAP_VCL23) { + if (state->global->pictype >= KVZ_NAL_BLA_W_LP + && state->global->pictype <= KVZ_NAL_RSV_IRAP_VCL23) { WRITE_U(stream, 1, 1, "no_output_of_prior_pics_flag"); } @@ -674,8 +674,8 @@ void kvz_encoder_state_write_bitstream_slice_header(encoder_state_t * const stat //WRITE_U(stream, 1, 1, "pic_output_flag"); //end if //if( IdrPicFlag ) <- nal_unit_type == 5 - if (state->global->pictype != NAL_IDR_W_RADL - && state->global->pictype != NAL_IDR_N_LP) { + if (state->global->pictype != KVZ_NAL_IDR_W_RADL + && state->global->pictype != KVZ_NAL_IDR_N_LP) { int last_poc = 0; int poc_shift = 0; @@ -745,10 +745,10 @@ void kvz_encoder_state_write_bitstream_slice_header(encoder_state_t * const stat WRITE_U(stream, 1, 1, "slice_sao_chroma_flag"); } - if (state->global->slicetype != SLICE_I) { + if (state->global->slicetype != KVZ_SLICE_I) { WRITE_U(stream, 1, 1, "num_ref_idx_active_override_flag"); WRITE_UE(stream, ref_negative != 0 ? ref_negative - 1: 0, "num_ref_idx_l0_active_minus1"); - if (state->global->slicetype == SLICE_B) { + if (state->global->slicetype == KVZ_SLICE_B) { WRITE_UE(stream, ref_positive != 0 ? ref_positive - 1 : 0, "num_ref_idx_l1_active_minus1"); WRITE_U(stream, 0, 1, "mvd_l1_zero_flag"); } @@ -790,7 +790,7 @@ static void add_checksum(encoder_state_t * const state) uint32_t checksum_val; unsigned int i; - kvz_nal_write(stream, NAL_SUFFIT_SEI_NUT, 0, 0); + kvz_nal_write(stream, KVZ_NAL_SUFFIX_SEI_NUT, 0, 0); kvz_image_checksum(frame->rec, checksum, state->encoder_control->bitdepth); @@ -845,21 +845,21 @@ static void encoder_state_write_bitstream_main(encoder_state_t * const state) first_nal_in_au = false; // Video Parameter Set (VPS) - kvz_nal_write(stream, NAL_VPS_NUT, 0, 1); + kvz_nal_write(stream, KVZ_NAL_VPS_NUT, 0, 1); encoder_state_write_bitstream_vid_parameter_set(state); // Sequence Parameter Set (SPS) - kvz_nal_write(stream, NAL_SPS_NUT, 0, 1); + kvz_nal_write(stream, KVZ_NAL_SPS_NUT, 0, 1); encoder_state_write_bitstream_seq_parameter_set(state); // Picture Parameter Set (PPS) - kvz_nal_write(stream, NAL_PPS_NUT, 0, 1); + kvz_nal_write(stream, KVZ_NAL_PPS_NUT, 0, 1); encoder_state_write_bitstream_pic_parameter_set(state); } // Send Kvazaar version information only in the first frame. if (state->global->frame == 0 && state->encoder_control->cfg->add_encoder_info) { - kvz_nal_write(stream, PREFIX_SEI_NUT, 0, first_nal_in_au); + kvz_nal_write(stream, KVZ_NAL_PREFIX_SEI_NUT, 0, first_nal_in_au); encoder_state_write_bitstream_prefix_sei_version(state); // spec:sei_rbsp() rbsp_trailing_bits @@ -870,11 +870,11 @@ static void encoder_state_write_bitstream_main(encoder_state_t * const state) if (state->encoder_control->vui.frame_field_info_present_flag){ // These should be optional, needed for earlier versions // of HM decoder to accept bitstream - //kvz_nal_write(stream, PREFIX_SEI_NUT, 0, 0); + //kvz_nal_write(stream, KVZ_NAL_PREFIX_SEI_NUT, 0, 0); //encoder_state_write_active_parameter_sets_sei_message(state); //kvz_bitstream_rbsp_trailing_bits(stream); - kvz_nal_write(stream, PREFIX_SEI_NUT, 0, first_nal_in_au); + kvz_nal_write(stream, KVZ_NAL_PREFIX_SEI_NUT, 0, first_nal_in_au); encoder_state_write_picture_timing_sei_message(state); // spec:sei_rbsp() rbsp_trailing_bits @@ -882,7 +882,7 @@ static void encoder_state_write_bitstream_main(encoder_state_t * const state) } { - uint8_t nal_type = (state->global->is_idr_frame ? NAL_IDR_W_RADL : NAL_TRAIL_R); + uint8_t nal_type = (state->global->is_idr_frame ? KVZ_NAL_IDR_W_RADL : KVZ_NAL_TRAIL_R); kvz_nal_write(stream, nal_type, 0, first_nal_in_au); } diff --git a/src/encoderstate.c b/src/encoderstate.c index be7a5155b..01ac41680 100644 --- a/src/encoderstate.c +++ b/src/encoderstate.c @@ -369,7 +369,7 @@ static void encoder_state_encode_leaf(encoder_state_t * const state) { // once. The added dependancy is for the first LCU of each wavefront // row to depend on the reconstruction status of the row below in the // previous frame. - if (state->previous_encoder_state != state && state->previous_encoder_state->tqj_recon_done && state->global->slicetype != SLICE_I) { + if (state->previous_encoder_state != state && state->previous_encoder_state->tqj_recon_done && state->global->slicetype != KVZ_SLICE_I) { if (!lcu->left) { if (lcu->below) { kvz_threadqueue_job_dep_add(state->tile->wf_jobs[lcu->id], lcu->below->encoder_state->previous_encoder_state->tqj_recon_done); @@ -629,7 +629,7 @@ static void encoder_state_encode(encoder_state_t * const main_state) { } -void kvz_encoder_ref_insertion_sort(int reflist[16], int length) { +static void encoder_ref_insertion_sort(int reflist[16], int length) { for (uint8_t i = 1; i < length; ++i) { const int16_t cur_poc = reflist[i]; @@ -641,35 +641,60 @@ void kvz_encoder_ref_insertion_sort(int reflist[16], int length) { reflist[j] = cur_poc; } } -static void encoder_state_ref_sort(encoder_state_t *state) { - int j, ref_list[2] = { 0, 0 }, ref_list_poc[2][16]; + +/** + * \brief Return reference picture lists. + * + * \param state main encoder state + * \param ref_list_len_out Returns the lengths of the reference lists. + * \param ref_list_poc_out Returns two lists of POCs of the reference pictures. + */ +void kvz_encoder_get_ref_lists(const encoder_state_t *const state, + int ref_list_len_out[2], + int ref_list_poc_out[2][16]) +{ + FILL_ARRAY(ref_list_len_out, 0, 2); // List all pocs of lists + int j = 0; for (j = 0; j < state->global->ref->used_size; j++) { if (state->global->ref->pocs[j] < state->global->poc) { - ref_list_poc[0][ref_list[0]] = state->global->ref->pocs[j]; - ref_list[0]++; + ref_list_poc_out[0][ref_list_len_out[0]] = state->global->ref->pocs[j]; + ref_list_len_out[0]++; } else { - ref_list_poc[1][ref_list[1]] = state->global->ref->pocs[j]; - ref_list[1]++; + ref_list_poc_out[1][ref_list_len_out[1]] = state->global->ref->pocs[j]; + ref_list_len_out[1]++; } } - kvz_encoder_ref_insertion_sort(ref_list_poc[0], ref_list[0]); - kvz_encoder_ref_insertion_sort(ref_list_poc[1], ref_list[1]); + // Fill the rest of ref_list_poc_out array with -1s. + for (; j < 16; j++) { + ref_list_poc_out[0][j] = -1; + ref_list_poc_out[1][j] = -1; + } - for (j = 0; j < state->global->ref->used_size; j++) { + encoder_ref_insertion_sort(ref_list_poc_out[0], ref_list_len_out[0]); + encoder_ref_insertion_sort(ref_list_poc_out[1], ref_list_len_out[1]); +} + +static void encoder_state_ref_sort(encoder_state_t *state) { + int ref_list_len[2]; + int ref_list_poc[2][16]; + + kvz_encoder_get_ref_lists(state, ref_list_len, ref_list_poc); + + for (int j = 0; j < state->global->ref->used_size; j++) { if (state->global->ref->pocs[j] < state->global->poc) { - for (int ref_idx = 0; ref_idx < ref_list[0]; ref_idx++) { + for (int ref_idx = 0; ref_idx < ref_list_len[0]; ref_idx++) { if (ref_list_poc[0][ref_idx] == state->global->ref->pocs[j]) { - state->global->refmap[j].idx = ref_list[0] - ref_idx - 1; + state->global->refmap[j].idx = ref_list_len[0] - ref_idx - 1; break; } } state->global->refmap[j].list = 1; } else { - for (int ref_idx = 0; ref_idx < ref_list[1]; ref_idx++) { + for (int ref_idx = 0; ref_idx < ref_list_len[1]; ref_idx++) { if (ref_list_poc[1][ref_idx] == state->global->ref->pocs[j]) { state->global->refmap[j].idx = ref_idx; break; @@ -688,7 +713,7 @@ static void encoder_state_remove_refs(encoder_state_t *state) { if (encoder->cfg->gop_len) { refnumber = encoder->cfg->gop[state->global->gop_offset].ref_neg_count + encoder->cfg->gop[state->global->gop_offset].ref_pos_count; check_refs = 1; - } else if (state->global->slicetype == SLICE_I) { + } else if (state->global->slicetype == KVZ_SLICE_I) { refnumber = 0; } // Remove the ref pic (if present) @@ -758,14 +783,14 @@ static void encoder_state_new_frame(encoder_state_t * const state) { if (state->global->is_idr_frame) { encoder_state_reset_poc(state); - state->global->slicetype = SLICE_I; - state->global->pictype = NAL_IDR_W_RADL; + state->global->slicetype = KVZ_SLICE_I; + state->global->pictype = KVZ_NAL_IDR_W_RADL; } else { - state->global->slicetype = encoder->cfg->intra_period==1 ? SLICE_I : (state->encoder_control->cfg->gop_len?SLICE_B:SLICE_P); - state->global->pictype = NAL_TRAIL_R; + state->global->slicetype = encoder->cfg->intra_period==1 ? KVZ_SLICE_I : (state->encoder_control->cfg->gop_len?KVZ_SLICE_B:KVZ_SLICE_P); + state->global->pictype = KVZ_NAL_TRAIL_R; if (state->encoder_control->cfg->gop_len) { if (encoder->cfg->intra_period > 1 && (state->global->poc % encoder->cfg->intra_period) == 0) { - state->global->slicetype = SLICE_I; + state->global->slicetype = KVZ_SLICE_I; } } @@ -779,7 +804,7 @@ static void encoder_state_new_frame(encoder_state_t * const state) { lambda = kvz_select_picture_lambda(state); state->global->QP = kvz_lambda_to_QP(lambda); } else { - if (encoder->cfg->gop_len > 0 && state->global->slicetype != SLICE_I) { + if (encoder->cfg->gop_len > 0 && state->global->slicetype != KVZ_SLICE_I) { kvz_gop_config const * const gop = encoder->cfg->gop + state->global->gop_offset; state->global->QP = encoder->cfg->qp + gop->qp_offset; @@ -864,12 +889,6 @@ void kvz_encode_one_frame(encoder_state_t * const state) } -void kvz_encoder_compute_stats(encoder_state_t *state, double frame_psnr[3]) -{ - assert(state->frame_done); - kvz_videoframe_compute_psnr(state->tile->frame, frame_psnr); -} - void kvz_encoder_next_frame(encoder_state_t *state) { const encoder_control_t * const encoder = state->encoder_control; @@ -1011,7 +1030,7 @@ void kvz_encode_coding_tree(encoder_state_t * const state, // Encode skip flag - if (state->global->slicetype != SLICE_I) { + if (state->global->slicetype != KVZ_SLICE_I) { int8_t ctx_skip = 0; // uiCtxSkip = aboveskipped + leftskipped; int ui; int16_t num_cand = MRG_MAX_NUM_CANDS; @@ -1050,7 +1069,7 @@ void kvz_encode_coding_tree(encoder_state_t * const state, // ENDIF SKIP // Prediction mode - if (state->global->slicetype != SLICE_I) { + if (state->global->slicetype != KVZ_SLICE_I) { cabac->cur_ctx = &(cabac->ctx.cu_pred_mode_model); CABAC_BIN(cabac, (cur_cu->type == CU_INTRA), "PredMode"); } @@ -1106,7 +1125,7 @@ void kvz_encode_coding_tree(encoder_state_t * const state, } // Void TEncSbac::codeInterDir( TComDataCU* pcCU, UInt uiAbsPartIdx ) - if (state->global->slicetype == SLICE_B) + if (state->global->slicetype == KVZ_SLICE_B) { // Code Inter Dir uint8_t inter_dir = cur_cu->inter.mv_dir-1; diff --git a/src/encoderstate.h b/src/encoderstate.h index b1b05dbb4..edc7b33f7 100644 --- a/src/encoderstate.h +++ b/src/encoderstate.h @@ -81,7 +81,7 @@ typedef struct { bool is_idr_frame; uint8_t pictype; - uint8_t slicetype; + enum kvz_slice_type slicetype; //! Total number of bits written. uint64_t total_bits_coded; @@ -206,7 +206,6 @@ typedef struct encoder_state_t { void kvz_encode_one_frame(encoder_state_t *state); -void kvz_encoder_compute_stats(encoder_state_t *state, double psnr[3]); void kvz_encoder_next_frame(encoder_state_t *state); @@ -228,7 +227,9 @@ int kvz_encoder_state_match_children_of_previous_frame(encoder_state_t * const s coeff_scan_order_t kvz_get_scan_order(int8_t cu_type, int intra_mode, int depth); -void kvz_encoder_ref_insertion_sort(int reflist[16], int length); +void kvz_encoder_get_ref_lists(const encoder_state_t *const state, + int ref_list_len_out[2], + int ref_list_poc_out[2][16]); static const uint8_t g_group_idx[32] = { 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, diff --git a/src/filter.c b/src/filter.c index 6fcdcef23..465e3cce9 100644 --- a/src/filter.c +++ b/src/filter.c @@ -246,7 +246,7 @@ void kvz_filter_deblock_edge_luma(encoder_state_t * const state, } // B-slice related checks - if(!strength && state->global->slicetype == SLICE_B) { + if(!strength && state->global->slicetype == KVZ_SLICE_B) { // Zero all undefined motion vectors for easier usage if(!(cu_q->inter.mv_dir & 1)) { diff --git a/src/global.h b/src/global.h index dbf3252dd..f8016f71d 100644 --- a/src/global.h +++ b/src/global.h @@ -216,6 +216,5 @@ typedef int16_t coeff_t; //Constants typedef enum { COLOR_Y = 0, COLOR_U, COLOR_V, NUM_COLORS } color_t; -enum { SLICE_B = 0, SLICE_P = 1, SLICE_I = 2 }; #endif diff --git a/src/inter.c b/src/inter.c index c84b7166d..cd26486fb 100644 --- a/src/inter.c +++ b/src/inter.c @@ -763,7 +763,7 @@ uint8_t kvz_inter_get_merge_cand(const encoder_state_t * const state, int32_t x, } #endif - if (candidates < MRG_MAX_NUM_CANDS && state->global->slicetype == SLICE_B) { + if (candidates < MRG_MAX_NUM_CANDS && state->global->slicetype == KVZ_SLICE_B) { #define NUM_PRIORITY_LIST 12; static const uint8_t priorityList0[] = { 0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3 }; static const uint8_t priorityList1[] = { 1, 0, 2, 0, 2, 1, 3, 0, 3, 1, 3, 2 }; @@ -798,7 +798,7 @@ uint8_t kvz_inter_get_merge_cand(const encoder_state_t * const state, int32_t x, int num_ref = state->global->ref->used_size; - if (candidates < MRG_MAX_NUM_CANDS && state->global->slicetype == SLICE_B) { + if (candidates < MRG_MAX_NUM_CANDS && state->global->slicetype == KVZ_SLICE_B) { int j; int ref_negative = 0; int ref_positive = 0; @@ -819,7 +819,7 @@ uint8_t kvz_inter_get_merge_cand(const encoder_state_t * const state, int32_t x, mv_cand[candidates].ref[0] = (zero_idx>=num_ref-1)?0:zero_idx; mv_cand[candidates].ref[1] = mv_cand[candidates].ref[0]; mv_cand[candidates].dir = 1; - if (state->global->slicetype == SLICE_B) { + if (state->global->slicetype == KVZ_SLICE_B) { mv_cand[candidates].mv[1][0] = 0; mv_cand[candidates].mv[1][1] = 0; mv_cand[candidates].dir = 3; diff --git a/src/kvazaar.c b/src/kvazaar.c index 3643a29b4..651f934ad 100644 --- a/src/kvazaar.c +++ b/src/kvazaar.c @@ -113,15 +113,28 @@ static kvz_encoder * kvazaar_open(const kvz_config *cfg) } +static void set_frame_info(kvz_frame_info *const info, const encoder_state_t *const state) +{ + info->poc = state->global->poc, + info->qp = state->global->QP; + info->nal_unit_type = state->global->pictype; + info->slice_type = state->global->slicetype; + kvz_encoder_get_ref_lists(state, info->ref_list_len, info->ref_list); +} + + static int kvazaar_encode(kvz_encoder *enc, kvz_picture *pic_in, kvz_data_chunk **data_out, uint32_t *len_out, - kvz_picture **pic_out) + kvz_picture **pic_out, + kvz_picture **src_out, + kvz_frame_info *info_out) { if (data_out) *data_out = NULL; if (len_out) *len_out = 0; if (pic_out) *pic_out = NULL; + if (src_out) *src_out = NULL; encoder_state_t *state = &enc->states[enc->cur_state_num]; @@ -164,6 +177,8 @@ static int kvazaar_encode(kvz_encoder *enc, if (len_out) *len_out = kvz_bitstream_tell(&output_state->stream) / 8; if (data_out) *data_out = kvz_bitstream_take_chunks(&output_state->stream); if (pic_out) *pic_out = kvz_image_copy_ref(output_state->tile->frame->rec); + if (src_out) *src_out = kvz_image_copy_ref(output_state->tile->frame->source); + if (info_out) set_frame_info(info_out, output_state); output_state->frame_done = 1; output_state->prepared = 0; diff --git a/src/kvazaar.h b/src/kvazaar.h index 3f3122c05..117918618 100644 --- a/src/kvazaar.h +++ b/src/kvazaar.h @@ -191,6 +191,116 @@ typedef struct kvz_picture { int64_t dts; //!< \brief Decompression timestamp. } kvz_picture; +/** + * \brief NAL unit type codes. + * + * These are the nal_unit_type codes from Table 7-1 ITU-T H.265 v1.0. + */ +enum kvz_nal_unit_type { + + // Trailing pictures + + KVZ_NAL_TRAIL_N = 0, + KVZ_NAL_TRAIL_R = 1, + + KVZ_NAL_TSA_N = 2, + KVZ_NAL_TSA_R = 3, + + KVZ_NAL_STSA_N = 4, + KVZ_NAL_STSA_R = 5, + + // Leading pictures + + KVZ_NAL_RADL_N = 6, + KVZ_NAL_RADL_R = 7, + + KVZ_NAL_RASL_N = 8, + KVZ_NAL_RASL_R = 9, + + // Reserved non-IRAP RSV_VCL_N/R 10-15 + + // Intra random access point pictures + + KVZ_NAL_BLA_W_LP = 16, + KVZ_NAL_BLA_W_RADL = 17, + KVZ_NAL_BLA_N_LP = 18, + + KVZ_NAL_IDR_W_RADL = 19, + KVZ_NAL_IDR_N_LP = 20, + + KVZ_NAL_CRA_NUT = 21, + + // Reserved IRAP + + KVZ_NAL_RSV_IRAP_VCL22 = 22, + KVZ_NAL_RSV_IRAP_VCL23 = 23, + + // Reserved non-IRAP RSV_VCL 24-32 + + // non-VCL + + KVZ_NAL_VPS_NUT = 32, + KVZ_NAL_SPS_NUT = 33, + KVZ_NAL_PPS_NUT = 34, + + KVZ_NAL_AUD_NUT = 35, + KVZ_NAL_EOS_NUT = 36, + KVZ_NAL_EOB_NUT = 37, + KVZ_NAL_FD_NUT = 38, + + KVZ_NAL_PREFIX_SEI_NUT = 39, + KVZ_NAL_SUFFIX_SEI_NUT = 40, + + // Reserved RSV_NVCL 41-47 + // Unspecified UNSPEC 48-63 +}; + +enum kvz_slice_type { + KVZ_SLICE_B = 0, + KVZ_SLICE_P = 1, + KVZ_SLICE_I = 2, +}; + +/** + * \brief Other information about an encoded frame + */ +typedef struct kvz_frame_info { + + /** + * \brief Picture order count + */ + int32_t poc; + + /** + * \brief Quantization parameter + */ + int8_t qp; + + /** + * \brief Type of the NAL VCL unit + */ + enum kvz_nal_unit_type nal_unit_type; + + /** + * \brief Type of the slice + */ + enum kvz_slice_type slice_type; + + /** + * \brief Reference picture lists + * + * The first list contains the reference picture POCs that are less than the + * POC of this frame and the second one contains those that are greater. + */ + int ref_list[2][16]; + + /** + * \brief Lengths of the reference picture lists + */ + int ref_list_len[2]; + +} kvz_frame_info; + /** * \brief A linked list of chunks of data. * @@ -303,9 +413,9 @@ typedef struct kvz_api { * \brief Encode one frame. * * Add pic_in to the encoding pipeline. If an encoded frame is ready, return - * the bitstream, length of the bitstream and the reconstructed frame in - * data_out, len_out and pic_out, respectively. Otherwise, set the output - * parameters to NULL. + * the bitstream, length of the bitstream, the reconstructed frame, the + * original frame and frame info in data_out, len_out, pic_out, src_out and + * info_out, respectively. Otherwise, set the output parameters to NULL. * * After passing all of the input frames, the caller should keep calling this * function with pic_in set to NULL, until no more data is returned in the @@ -313,24 +423,29 @@ typedef struct kvz_api { * * The caller must not modify pic_in after passing it to this function. * - * If pic_out and data_out are set to non-NULL values, the caller is - * responsible for calling picture_free and chunk_free on them. + * If data_out, pic_out and src_out are set to non-NULL values, the caller is + * responsible for calling chunk_free and picture_free on them. * * A null pointer may be passed in place of any of the parameters data_out, - * len_out or pic_out to skip returning the corresponding value. + * len_out, pic_out, src_out or info_out to skip returning the corresponding + * value. * * \param encoder encoder * \param pic_in input frame or NULL * \param data_out Returns the encoded data. * \param len_out Returns number of bytes in the encoded data. * \param pic_out Returns the reconstructed picture. + * \param src_out Returns the original picture. + * \param info_out Returns information about the encoded picture. * \return 1 on success, 0 on error. */ int (*encoder_encode)(kvz_encoder *encoder, kvz_picture *pic_in, kvz_data_chunk **data_out, uint32_t *len_out, - kvz_picture **pic_out); + kvz_picture **pic_out, + kvz_picture **src_out, + kvz_frame_info *info_out); } kvz_api; // Append API version to the getters name to prevent linking against incompatible versions. diff --git a/src/kvazaar_version.h b/src/kvazaar_version.h index caa17fa63..9f4d2453c 100644 --- a/src/kvazaar_version.h +++ b/src/kvazaar_version.h @@ -21,6 +21,6 @@ ****************************************************************************/ // KVZ_API_VERSION is incremented every time the public api changes. -#define KVZ_API_VERSION 4 +#define KVZ_API_VERSION 7 #endif // KVAZAAR_VERSION_H_ diff --git a/src/nal.h b/src/nal.h index 7db5d3e27..5f94645c8 100644 --- a/src/nal.h +++ b/src/nal.h @@ -32,64 +32,6 @@ #include "image.h" #include "bitstream.h" - -////////////////////////////////////////////////////////////////////////// -// TYPES - -/** - * \brief NAL unit type codes. - * - * These are the nal_unit_type codes from Table 7-1 ITU-T H.265 v1.0. - * The type codes have been prefixed with "NAL_". - */ -enum { - NAL_TRAIL_N = 0, - NAL_TRAIL_R = 1, - - NAL_TSA_N = 2, - NAL_TSA_R = 3, - - NAL_STSA_N = 4, - NAL_STSA_R = 5, - - NAL_RADL_N = 6, - NAL_RADL_R = 7, - - NAL_RASL_N = 8, - NAL_RASL_R = 9, - - // Reserved RSV_VCL_ N/R 10-15 - - NAL_BLA_W_LP = 16, - NAL_BLA_W_RADL = 17, - NAL_BLA_N_LP = 18, - - NAL_IDR_W_RADL = 19, - NAL_IDR_N_LP = 20, - - NAL_CRA_NUT = 21, - - // Reserved RSV_IRAP_VCL 22-23 - NAL_RSV_IRAP_VCL23 = 23, - - // Reserved RSV_VCL 24-31 - - NAL_VPS_NUT = 32, - NAL_SPS_NUT = 33, - NAL_PPS_NUT = 34, - - AUD_NUT = 35, - EOS_NUT = 36, - EOB_NUT = 37, - FD_NUT = 38, - - PREFIX_SEI_NUT = 39, - NAL_SUFFIT_SEI_NUT = 40, - - // Reserved RSV_NVCL 41-47 - // Unspecified UNSPEC 48-63 -}; - #define SEI_HASH_MAX_LENGTH 4 ////////////////////////////////////////////////////////////////////////// diff --git a/src/rate_control.c b/src/rate_control.c index 7c5a0f582..7f8f6c7cd 100644 --- a/src/rate_control.c +++ b/src/rate_control.c @@ -160,7 +160,7 @@ double kvz_select_picture_lambda_from_qp(encoder_state_t const * const state) const double qp_temp = state->global->QP - 12; double qp_factor; - if (state->global->slicetype == SLICE_I) { + if (state->global->slicetype == KVZ_SLICE_I) { const double lambda_scale = 1.0 - CLIP(0.0, 0.5, 0.05 * gop_len); qp_factor = 0.57 * lambda_scale; } else if (gop_len > 0) { diff --git a/src/search.c b/src/search.c index 985601a2b..0017ce2f5 100644 --- a/src/search.c +++ b/src/search.c @@ -517,7 +517,7 @@ static double search_cu(encoder_state_t * const state, int x, int y, int depth, y + cu_width <= frame->height) { - if (state->global->slicetype != SLICE_I && + if (state->global->slicetype != KVZ_SLICE_I && WITHIN(depth, ctrl->pu_depth_inter.min, ctrl->pu_depth_inter.max)) { int mode_cost = kvz_search_cu_inter(state, x, y, depth, &work_tree[depth]); @@ -606,7 +606,7 @@ static double search_cu(encoder_state_t * const state, int x, int y, int depth, } // Recursively split all the way to max search depth. - if (depth < ctrl->pu_depth_intra.max || (depth < ctrl->pu_depth_inter.max && state->global->slicetype != SLICE_I)) { + if (depth < ctrl->pu_depth_intra.max || (depth < ctrl->pu_depth_inter.max && state->global->slicetype != KVZ_SLICE_I)) { int half_cu = cu_width / 2; // Using Cost = lambda * 9 to compensate on the price of the split double split_cost = state->global->cur_lambda_cost * CU_COST; diff --git a/src/search_inter.c b/src/search_inter.c index bb89909d4..29f4ed834 100644 --- a/src/search_inter.c +++ b/src/search_inter.c @@ -1052,7 +1052,7 @@ int kvz_search_cu_inter(const encoder_state_t * const state, int x, int y, int d } // Search bi-pred positions - if (state->global->slicetype == SLICE_B && state->encoder_control->cfg->bipred) { + if (state->global->slicetype == KVZ_SLICE_B && state->encoder_control->cfg->bipred) { lcu_t *templcu = MALLOC(lcu_t, 1); cost_pixel_nxn_func *satd = kvz_pixels_get_satd_func(LCU_WIDTH >> depth); #define NUM_PRIORITY_LIST 12; diff --git a/src/transform.c b/src/transform.c index e95387aa9..163b6273c 100644 --- a/src/transform.c +++ b/src/transform.c @@ -147,7 +147,7 @@ void kvz_quant(const encoder_state_t * const state, coeff_t *coef, coeff_t *q_co const int32_t *quant_coeff = encoder->scaling_list.quant_coeff[log2_tr_size-2][scalinglist_type][qp_scaled%6]; const int32_t transform_shift = MAX_TR_DYNAMIC_RANGE - encoder->bitdepth - log2_tr_size; //!< Represents scaling through forward transform const int32_t q_bits = QUANT_SHIFT + qp_scaled/6 + transform_shift; - const int32_t add = ((state->global->slicetype == SLICE_I) ? 171 : 85) << (q_bits - 9); + const int32_t add = ((state->global->slicetype == KVZ_SLICE_I) ? 171 : 85) << (q_bits - 9); const int32_t q_bits8 = q_bits - 8; uint32_t ac_sum = 0; diff --git a/src/videoframe.c b/src/videoframe.c index ac569ab9e..b69d78848 100644 --- a/src/videoframe.c +++ b/src/videoframe.c @@ -118,23 +118,31 @@ cu_info_t* kvz_videoframe_get_cu(videoframe_t * const frame, const unsigned int /** * \brief Calculates image PSNR value + * + * \param src source picture + * \param rec reconstructed picture + * \prama psnr returns the PSNR */ -void kvz_videoframe_compute_psnr(const videoframe_t * const frame, double psnr[NUM_COLORS]) +void kvz_videoframe_compute_psnr(const kvz_picture *const src, + const kvz_picture *const rec, + double psnr[NUM_COLORS]) { - int32_t pixels = frame->width * frame->height; - int32_t i, c; - - for (c = 0; c < NUM_COLORS; ++c) { + assert(src->width == rec->width); + assert(src->height == rec->height); + + int32_t pixels = src->width * src->height; + + for (int32_t c = 0; c < NUM_COLORS; ++c) { int32_t num_pixels = pixels; if (c != COLOR_Y) { num_pixels >>= 2; } psnr[c] = 0; - for (i = 0; i < num_pixels; ++i) { - const int32_t error = frame->source->data[c][i] - frame->rec->data[c][i]; + for (int32_t i = 0; i < num_pixels; ++i) { + const int32_t error = src->data[c][i] - rec->data[c][i]; psnr[c] += error * error; } - + // Avoid division by zero if (psnr[c] == 0) psnr[c] = 99.0; psnr[c] = 10 * log10((num_pixels * PSNRMAX) / ((double)psnr[c]));; diff --git a/src/videoframe.h b/src/videoframe.h index caa0303de..c5ed17376 100644 --- a/src/videoframe.h +++ b/src/videoframe.h @@ -62,7 +62,9 @@ void kvz_videoframe_set_poc(videoframe_t * frame, int32_t poc); const cu_info_t* kvz_videoframe_get_cu_const(const videoframe_t * const frame, unsigned int x_in_scu, unsigned int y_in_scu); cu_info_t* kvz_videoframe_get_cu(videoframe_t * const frame, const unsigned int x_in_scu, const unsigned int y_in_scu); -void kvz_videoframe_compute_psnr(const videoframe_t * const frame, double psnr[NUM_COLORS]); +void kvz_videoframe_compute_psnr(const kvz_picture *const src, + const kvz_picture *const rec, + double psnr[NUM_COLORS]); #endif