OpenVVC中SPS读取和处理功能

时间:2025-02-22 18:41:48

代码概述

这段代码是OpenVVC(一个符合ITU - T H.266 - MPEG - I - Part 3 VVC标准的开源实时软件解码器)中关于序列参数集(Sequence Parameter Set, SPS)读取和处理的实现。代码主要完成了SPS的读取、验证、存储和释放等功能,同时还处理了SPS中的各种子信息,如子图像信息、VUI(Video Usability Information)有效负载、HRD(Hypothetical Reference Decoder)定时参数等。

代码结构与功能模块

1. 头文件包含与版权声明
/**
 * ...版权声明...
 **/

#include <string.h>

#include "ovmem.h"
#include "overror.h"

#include "hls_structures.h"
#include "nvcl.h"
#include "nvcl_utils.h"
#include "nvcl_structures.h"
#include "nvcl_private.h"

//TODOgpm: do not init here
#include "rcn.h"

包含了必要的头文件,其中一些是自定义的头文件,用于提供内存管理、错误处理、HLS(High - Level Syntax)结构定义等功能。

2. 辅助函数
  • probe_sps_id:从OVNVCLReader中提取SPS ID。
static uint8_t
probe_sps_id(OVNVCLReader *const rdr)
{
    uint8_t sps_id = fetch_bits(rdr, 4);
    return sps_id;
}
  • storage_in_nvcl_ctx:根据SPS ID找到在OVNVCLCtx中存储SPS数据的位置。
static const union HLSData **
storage_in_nvcl_ctx(OVNVCLReader *const rdr, OVNVCLCtx *const nvcl_ctx)
{
    uint8_t id = probe_sps_id(rdr);
    OVSPS **list = nvcl_ctx->sps_list;
    const union HLSData **storage = (const union HLSData**)&list[id];

    return storage;
}
  • validate_sps:验证SPS数据的有效性,检查是否包含不支持的特性,如加权预测、子图像、WPP等。
static int
validate_sps(OVNVCLReader *rdr, const union HLSData *const data)
{
    const OVSPS *const sps =  (const OVSPS *)data;

    if (sps->sps_weighted_pred_flag || sps->sps_weighted_bipred_flag) {
        ov_log(NULL, OVLOG_ERROR, "Unsupported weighted pred\n");
        return OVVC_EINDATA;
    }
    // 其他检查...
    return 1;
}
  • free_sps:释放SPS数据占用的内存。
static void
free_sps(const union HLSData *const data)
{
    const OVSPS *const sps = (const OVSPS *)data;
    ov_free((void *)sps);
}
  • replace_sps:用新的SPS数据替换旧的SPS数据,并释放旧数据的内存。
static int
replace_sps(const struct HLSReader *const manager,
            const union HLSData **storage,
            const OVHLSData *const hls_data)
{
    const union HLSData *to_free = *storage;
    union HLSData *new = ov_malloc(manager->data_size);

    if (!new) {
        return OVVC_ENOMEM;
    }

    memcpy(new, hls_data, manager->data_size);

    *storage = new;

    if (to_free) {
        manager->free(to_free);
    }

    return 0;
}
3. 子信息处理函数
  • subpic_info:处理SPS中的子图像信息。
static void
subpic_info(OVNVCLReader *const rdr, OVSPS *const sps)
{
    // 读取子图像数量等信息
    sps->sps_num_subpics_minus1 = nvcl_read_u_expgolomb(rdr);
    if (sps->sps_num_subpics_minus1 > 0) {
        // 处理子图像的各种参数
        // ...
    }
    // 处理子图像ID映射等信息
    // ...
}
  • vui_payload:处理SPS中的VUI有效负载信息。
static void
vui_payload(OVNVCLReader *const rdr, struct OVVUI *vui)
{
    // 读取VUI的各种标志和参数
    vui->vui_progressive_source_flag        = nvcl_read_flag(rdr);
    vui->vui_interlaced_source_flag         = nvcl_read_flag(rdr);
    // ...
}
  • general_timing_hrd_parameters:处理SPS中的HRD一般定时参数。
static void
general_timing_hrd_parameters(OVNVCLReader *const rdr, struct HRDTiming *hrd)
{
    hrd->num_units_in_tick = nvcl_read_bits(rdr, 32);
    hrd->time_scale = nvcl_read_bits(rdr, 32);
    // ...
}
  • sublayer_hrd_parameters:处理SPS中的HRD子层参数。
static void
sublayer_hrd_parameters(OVNVCLReader *const rdr, const struct HRDTiming *const hrd, uint8_t i) {
    int j;
    for (j = 0; j <= hrd->hrd_cpb_cnt_minus1; ++j) {
        uint16_t bit_rate_value_minus1 = nvcl_read_u_expgolomb(rdr);
        uint16_t cpb_size_value_minus1 = nvcl_read_u_expgolomb(rdr);
        // ...
    }
}
  • ols_timing_hrd_parameters:处理SPS中的HRD层集定时参数。
static void
ols_timing_hrd_parameters(OVNVCLReader *const rdr, const struct HRDTiming *const hrd, uint8_t first_sublayer, uint8_t max_sublayer)
{
    int i;
    for (i = first_sublayer; i <= max_sublayer; ++i) {
        uint8_t fixed_pic_rate_general_flag = nvcl_read_flag(rdr);
        // ...
    }
}
4. SPS读取函数
  • nvcl_sps_read:读取SPS数据,调用上述子信息处理函数处理各种子信息。
int
nvcl_sps_read(OVNVCLReader *const rdr, OVHLSData *const hls_data,
              const OVNVCLCtx *const nvcl_ctx)
{
    OVSPS *const sps = &hls_data->sps;

    // 读取SPS的基本信息
    sps->sps_seq_parameter_set_id   = nvcl_read_bits(rdr, 4);
    sps->sps_video_parameter_set_id = nvcl_read_bits(rdr, 4);
    // ...

    // 处理各种子信息
    if (sps->sps_subpic_info_present_flag) {
        subpic_info(rdr, sps);
    }
    if (sps->sps_vui_parameters_present_flag) {
        vui_payload(rdr, &sps->vui);
    }
    // ...

    return 0;
}
5. SPS管理器
  • sps_manager:定义了一个HLSReader结构体,用于管理SPS的读取、验证、存储和释放等操作。
const struct HLSReader sps_manager =
{
    .name = "SPS",
    .data_size    = sizeof(struct OVSPS),
    .probe_id     = &probe_sps_id,
    .find_storage = &storage_in_nvcl_ctx,
    .read         = &nvcl_sps_read,
    .validate     = &validate_sps,
    .replace      = &replace_sps,
    .free         = &free_sps
};

代码问题与改进建议

  1. 代码注释:虽然代码中有一些注释,但部分注释可以更加详细,特别是一些复杂的逻辑部分,如子图像信息处理和HRD参数处理。
  2. 错误处理:在nvcl_sps_read函数中,当读取某些参数失败时,没有进行相应的错误处理,建议添加错误处理逻辑,提高代码的健壮性。
  3. 代码复用:部分代码存在重复,如在处理不同颜色分量的QP表时,可以考虑将重复的代码提取成函数,提高代码的可维护性。
  4. TODO标记:代码中存在一些TODO标记,如TODOgpm: do not init here,需要及时处理这些待办事项。

总结

这段代码实现了OpenVVC中SPS的读取和处理功能,通过一系列辅助函数和子信息处理函数,完成了SPS数据的解析和验证。同时,通过sps_manager结构体提供了统一的管理接口,方便后续的使用和扩展。

相关文章