Merge "Encoder: add support for PSNR export"

This commit is contained in:
Treehugger Robot 2022-08-19 15:52:16 +00:00 • committed by Gerrit Code Review
commit ab6bce7870
11 changed files with 246 additions and 3 deletions

View file

@ -415,6 +415,7 @@ cc_library_static {
"encoder/ime.c",
"encoder/ime_distortion_metrics.c",
"encoder/ih264e_sei.c",
"encoder/psnr.c",
],
arch: {

View file

@ -2873,6 +2873,7 @@ static WORD32 ih264e_set_default_params(cfg_params_t *ps_cfg)
ps_cfg->u4_max_level = DEFAULT_MAX_LEVEL;
ps_cfg->e_inp_color_fmt = IV_YUV_420SP_UV;
ps_cfg->u4_enable_recon = DEFAULT_RECON_ENABLE;
ps_cfg->u4_enable_quality_metrics = DEFAULT_QUALITY_METRICS_ENABLE;
ps_cfg->e_recon_color_fmt = IV_YUV_420P;
ps_cfg->u4_enc_speed_preset = IVE_FASTEST;
ps_cfg->e_rc_mode = DEFAULT_RC;
@ -3045,6 +3046,8 @@ static WORD32 ih264e_init(codec_t *ps_codec)
/* Process thread created status */
memset(ps_codec->ai4_process_thread_created, 0, MAX_PROCESS_THREADS);
memset(&ps_codec->s_global_quality_stats, 0, sizeof(ps_codec->s_global_quality_stats));
/* Number of MBs processed together */
ps_codec->i4_proc_nmb = 8;

View file

@ -205,6 +205,7 @@
/* Generic declarations */
#define DEFAULT_MAX_LEVEL 40
#define DEFAULT_RECON_ENABLE 0
#define DEFAULT_QUALITY_METRICS_ENABLE 0
#define DEFAULT_RC IVE_RC_STORAGE
#define DEFAULT_MAX_FRAMERATE 120000
#define DEFAULT_MAX_BITRATE 240000000
@ -267,6 +268,8 @@
/** Number of buffers Needed for SUBPEL and BIPRED computation */
#define SUBPEL_BUFF_CNT 4
/** Mask value for PSNR. Needed when quality metrics is enabled */
#define QUALITY_MASK_PSNR 0x1
/**
*****************************************************************************
* Macro to compute total size required to hold on set of scaling matrices

View file

@ -531,6 +531,12 @@ WORD32 ih264e_encode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
ih264_list_reset(ps_codec->pv_proc_jobq);
ih264_list_reset(ps_codec->pv_entropy_jobq);
if (ps_codec->s_cfg.u4_enable_quality_metrics & QUALITY_MASK_PSNR)
{
ih264e_compute_quality_stats(ps_proc);
}
}
@ -566,6 +572,7 @@ WORD32 ih264e_encode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
IH264_ERROR_T ret = IH264_SUCCESS;
pic_buf_t *ps_pic_buf = NULL;
WORD32 i4_buf_status, i4_curr_poc = 32768;
WORD8 buf_idx = -1;
/* In case of skips we return recon, but indicate that buffer is zero size */
if (ps_codec->s_rate_control.post_encode_skip[ctxt_sel]
@ -593,6 +600,17 @@ WORD32 ih264e_encode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
{
ps_pic_buf = ps_codec->as_ref_set[i].ps_pic_buf;
i4_curr_poc = ps_codec->as_ref_set[i].i4_poc;
buf_idx = i;
}
}
if ((ps_codec->s_cfg.u4_enable_quality_metrics & QUALITY_MASK_PSNR)
&& buf_idx >= 0)
{
UWORD8 comp;
for(comp = 0; comp < 3; comp++)
{
DEBUG("PSNR[%d]: %f\n", comp,
ps_codec->as_ref_set[buf_idx].s_pic_quality_stats.total_psnr[comp]);
}
}

View file

@ -60,6 +60,23 @@
*/
void ih264e_join_threads(codec_t *ps_codec);
/**
******************************************************************************
*
* @brief
* This function calculates various quality metrics; the initial one is PSNR.
*
* @par Description
*
* @param[in] ps_codec
* pointer to process context
*
* @returns none
*
******************************************************************************
*/
void ih264e_compute_quality_stats(process_ctxt_t *ps_proc);
/**
******************************************************************************
*

View file

@ -1260,6 +1260,7 @@ IH264E_ERROR_T ih264e_init_proc_ctxt(process_ctxt_t *ps_proc)
convert_uv_only = 1;
if (u4_pad_bottom_sz || u4_pad_right_sz ||
ps_codec->s_cfg.e_inp_color_fmt == IV_YUV_422ILE ||
ps_codec->s_cfg.u4_enable_quality_metrics & QUALITY_MASK_PSNR ||
ps_proc->i4_mb_y == (ps_proc->i4_ht_mbs - 1))
{
if (ps_proc->i4_mb_y == ps_proc->i4_ht_mbs - 1)
@ -1279,6 +1280,7 @@ IH264E_ERROR_T ih264e_init_proc_ctxt(process_ctxt_t *ps_proc)
if (ps_codec->s_cfg.e_inp_color_fmt == IV_YUV_422ILE ||
ps_codec->s_cfg.e_inp_color_fmt == IV_YUV_420P ||
ps_proc->i4_mb_y == (ps_proc->i4_ht_mbs - 1) ||
ps_codec->s_cfg.u4_enable_quality_metrics & QUALITY_MASK_PSNR ||
u4_pad_bottom_sz || u4_pad_right_sz)
{
if ((ps_codec->s_cfg.e_inp_color_fmt == IV_YUV_420SP_UV) ||
@ -2070,7 +2072,8 @@ WORD32 ih264e_process(process_ctxt_t *ps_proc)
* 2. dump recon for bit stream sanity check
*/
ps_proc->u4_compute_recon = ps_codec->u4_is_curr_frm_ref ||
ps_codec->s_cfg.u4_enable_recon;
ps_codec->s_cfg.u4_enable_recon ||
ps_codec->s_cfg.u4_enable_quality_metrics & QUALITY_MASK_PSNR;
/* Encode 'n' macroblocks,
* 'n' being the number of mbs dictated by current proc ctxt */

View file

@ -369,9 +369,12 @@ typedef struct
/** Input color format */
IV_COLOR_FORMAT_T e_inp_color_fmt;
/** Flag to enable/disable - To be used only for debugging/testing */
/** Flag to enable/disable recon */
UWORD32 u4_enable_recon;
/** Flag to enable/disable quality metrics */
UWORD32 u4_enable_quality_metrics;
/** Recon color format */
IV_COLOR_FORMAT_T e_recon_color_fmt;
@ -626,6 +629,22 @@ typedef struct
} job_t;
/**
*****************************************************************************
* @brief Structure to store psnr of the sequence
*****************************************************************************
*/
typedef struct {
UWORD64 total_sse[3];
double global_psnr[3]; // total_sse / total_samples
double total_psnr[3]; // sum (per_frame_sse / per_frame_samples)
double avg_psnr[3]; // total_psnr / total_frames
UWORD32 total_samples[3];
WORD32 total_frames;
} quality_stats_t;
/**
* Structure to represent a MV Bank buffer
*/
@ -669,6 +688,9 @@ typedef struct
*/
typedef struct
{
/** Per pic PSNR */
quality_stats_t s_pic_quality_stats;
/** Picture count */
WORD32 i4_pic_cnt;
@ -2473,6 +2495,11 @@ struct _codec_t
*/
void *apv_proc_thread_handle[MAX_PROCESS_THREADS];
/**
* Structure for global PSNR
*/
quality_stats_t s_global_quality_stats;
/**
* Thread created flag for each of the processing threads
*/

View file

@ -70,6 +70,7 @@
#include "ime_distortion_metrics.h"
#include "ime_defs.h"
#include "ime_structs.h"
#include "psnr.h"
#include "ih264_error.h"
#include "ih264_structs.h"
#include "ih264_trans_quant_itrans_iquant.h"
@ -2204,3 +2205,77 @@ IH264E_ERROR_T ih264e_pic_init(codec_t *ps_codec, inp_buf_t *ps_inp_buf)
return error_status;
}
/**
*******************************************************************************
*
* @brief
* Calculate the per-pic and global PSNR
*
* @par Description:
* This function takes the source and recon luma/chroma buffer pointers from the
* codec context and calculates the per-pic and global PSNR for the current encoding
* frame.
*
* @param[in] ps_codec
* Pointer to process context
*
* @returns none
*
* @remarks
*
*
*******************************************************************************
*/
void ih264e_compute_quality_stats(process_ctxt_t *ps_proc)
{
codec_t *ps_codec = ps_proc->ps_codec;
WORD32 wd = ps_codec->s_cfg.u4_wd;
WORD32 ht = ps_codec->s_cfg.u4_ht;
WORD32 disp_wd = ps_codec->s_cfg.u4_disp_wd;
WORD32 disp_ht = ps_codec->s_cfg.u4_disp_ht;
WORD32 src_strds = ps_proc->i4_src_strd;
WORD32 rec_strds = ps_proc->i4_rec_strd;
quality_stats_t *ps_pic_quality_stats = NULL;
double sum_squared_error[3] = {0.0, 0.0, 0.0};
double total_samples[3];
WORD32 i;
for (i = 0; i < ps_codec->i4_ref_buf_cnt; i++)
{
if (ps_codec->as_ref_set[i].i4_pic_cnt != -1 &&
ps_codec->as_ref_set[i].i4_poc == ps_codec->i4_poc)
{
ps_pic_quality_stats = &ps_codec->as_ref_set[i].s_pic_quality_stats;
break;
}
}
if(ps_pic_quality_stats == NULL) return;
get_sse(
ps_proc->pu1_src_buf_luma_base, ps_proc->pu1_rec_buf_luma_base,
ps_proc->pu1_src_buf_chroma_base, ps_proc->pu1_rec_buf_chroma_base,
src_strds, rec_strds, wd, ht, sum_squared_error);
total_samples[0] = disp_wd * disp_ht;
total_samples[1] = total_samples[2] = total_samples[0] / 4;
ps_pic_quality_stats->total_frames = 1;
ps_codec->s_global_quality_stats.total_frames += 1;
for (i = 0; i < 3; i++)
{
double psnr = sse_to_psnr(total_samples[i], sum_squared_error[i]);
ps_pic_quality_stats->total_samples[i] = total_samples[i];
ps_pic_quality_stats->total_sse[i] = sum_squared_error[i];
ps_pic_quality_stats->global_psnr[i] = ps_pic_quality_stats->avg_psnr[i] =
ps_pic_quality_stats->total_psnr[i] = psnr;
ps_codec->s_global_quality_stats.total_sse[i] += sum_squared_error[i];
ps_codec->s_global_quality_stats.global_psnr[i] =
sse_to_psnr(ps_codec->s_global_quality_stats.total_samples[i],
ps_codec->s_global_quality_stats.total_sse[i]);
ps_codec->s_global_quality_stats.total_psnr[i] += psnr;
ps_codec->s_global_quality_stats.avg_psnr[i] =
ps_codec->s_global_quality_stats.total_psnr[i] /
ps_codec->s_global_quality_stats.total_frames;
}
}

View file

@ -39,7 +39,8 @@ list(
"${AVC_ROOT}/encoder/irc_rate_control_api.c"
"${AVC_ROOT}/encoder/irc_rd_model.c"
"${AVC_ROOT}/encoder/irc_vbr_storage_vbv.c"
"${AVC_ROOT}/encoder/irc_vbr_str_prms.c")
"${AVC_ROOT}/encoder/irc_vbr_str_prms.c"
"${AVC_ROOT}/encoder/psnr.c")
include_directories(${AVC_ROOT}/encoder)

65
encoder/psnr.c Normal file
View file

@ -0,0 +1,65 @@
/******************************************************************************
*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*****************************************************************************/
/* System Include Files */
#include <math.h>
#include "ih264_macros.h"
#include "ih264_typedefs.h"
#include "psnr.h"
void get_sse(UWORD8 *pu1_src_luma, UWORD8 *pu1_rec_luma, UWORD8 *pu1_src_chroma,
UWORD8 *pu1_rec_chroma, WORD32 src_strd, WORD32 rec_strd, WORD32 width, WORD32 height,
DOUBLE pd_sse[3])
{
WORD32 i, j;
for(j = 0; j < height; j++)
{
for(i = 0; i < width; i++)
{
WORD32 diff = pu1_src_luma[i] - pu1_rec_luma[i];
pd_sse[0] += diff * diff;
}
pu1_src_luma += src_strd;
pu1_rec_luma += rec_strd;
}
for(j = 0; j < height / 2; j++)
{
for(i = 0; i < width / 2; i++)
{
WORD32 diff = pu1_src_chroma[i * 2] - pu1_rec_chroma[i * 2];
pd_sse[1] += diff * diff;
diff = pu1_src_chroma[i * 2 + 1] - pu1_rec_chroma[i * 2 + 1];
pd_sse[2] += diff * diff;
}
pu1_src_chroma += src_strd;
pu1_rec_chroma += rec_strd;
}
}
DOUBLE sse_to_psnr(DOUBLE samples, DOUBLE sse)
{
DOUBLE psnr;
if(samples <= 0) return -1;
if (sse<=0) return MAX_PSNR;
psnr = 10.0 * (log10(samples) + 2*log10(255) - log10(sse));
psnr = MIN(MAX_PSNR, psnr);
return psnr;
}

30
encoder/psnr.h Normal file
View file

@ -0,0 +1,30 @@
/******************************************************************************
*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*****************************************************************************/
#ifndef __PSNR_H__
#define __PSNR_H__
#define MAX_PSNR 100.0
void get_sse(UWORD8 *pu1_src_luma, UWORD8 *pu1_rec_luma, UWORD8 *pu1_src_chroma,
UWORD8 *pu1_rec_chroma, WORD32 src_strd, WORD32 rec_strd, WORD32 width, WORD32 height,
DOUBLE *pd_sse);
DOUBLE sse_to_psnr(DOUBLE samples, DOUBLE sse);
#endif