将ISP DMA写到DDR的数据unpack成可被7yuv预览的RAW图

背景

上篇博客埋了个坑,就是如何将ISP DMA写到DDR的数据unpack成可被7yuv等软件预览的RAW图。跟通用DMA这种源端目的端均以字节对齐访问不通,ISP DMA通常有一端是非字节对齐的,即流式(stream)访问——不需要指定访问地址,而另一端是字节对齐的,即对齐(aligned)访问,这就导致对齐端写入DDR的像素,是紧密排列的,如果像素位宽不是8的整数,则想要用7yuv等软件查看raw图内容,就需要unpack操作——给紧密排列的像素的高位补零,从而让其对齐到8bit或16bit甚至32bit。

思路

因为ISP DMA每行写到DDR的内存布局是一样的,因此问题可以简化成如何unpack一行像素,又因为ISP写入每行像素时是以beat为单位的(通常就是AXI_data总线的宽度),所以问题进一步简化成如何unpack一个beat内包含的像素,并保留好被beat截断的首尾像素残值,考虑到要拆分像素必然要用到移位操作,而PC机的移位只能作用于32位的int或64位的long long类型,但是AXI_data的宽度是可以到128位甚至256位的,为了实现的简单(反正被beat截断和被int截断都要考虑如何恢复像素残值),将问题变换成如何unpack一个blk内包含的像素,并保留好被blk截断的首尾像素残值,这里blk即block,表示用户选择的32位或64位整型,通常对应DDR里的4字节或8字节。

实现细节

关键结构体

图像宽高、像素位宽和总线位宽

为了支持任意宽度的像素,和任意宽度的总线位宽,我们定义下面的结构体,以存储此类全局信息

typedef struct _raw_info_s {
    unsigned char pix_width;
    unsigned char bus_width;
    unsigned short img_width;
    unsigned short img_height;
} raw_info_t;

像素截断和恢复信息

为了记录截断信息,定义下面的结构体

typedef struct _unpack_ctx_s {
    unsigned short* dst_pix_buf;
    unsigned short pix_num_unpacked;
    unsigned short left_bits_of_last_blk;
    unsigned short last_pix_val;
} unpack_ctx_t;

注意,像素恢复操作统一在blk开始进行,blk末尾不做处理,以避免重复。

通过移位操作分离单个像素

        tmp = blk & ((1 << info->pix_width) - 1);   // 提取blk内单个完整像素
        ctx->dst_pix_buf[ctx->pix_num_unpacked++] = tmp;  // 将提取出来的像素放到int16或int32
        blk >>= info->pix_width;   // 将已提取的完整像素通过移位操作丢弃,同时将下一个像素挪到blk的最低位
        bits_left -= info->pix_width;  // 将已提取的像素所占bit数 从 blk剩余bit数 里减去

通过截断上下文信息恢复被截断像素

    if (ctx->left_bits_of_last_blk > 0) {  // 上一个blk有残余像素
        miss_bits_of_last_blk = info->pix_width - ctx->left_bits_of_last_blk; // 算出残余像素遗留在本blk的bit数
        tmp = blk & ((1 << miss_bits_of_last_blk) - 1);  // 获取残余像素在本blk的高位像素值,存在tmp的低位
        tmp <<= ctx->left_bits_of_last_blk; // 将残余像素的高位值移到正确的位置
        tmp |= ctx->last_pix_val; // 将残余像素的低位值放到tmp的低位,从而拼凑出完整的被截像素
        ctx->dst_pix_buf[ctx->pix_num_unpacked++] = tmp; // 将被截像素放到int16或int32
        blk >>= miss_bits_of_last_blk;  // 将已提取的被截像素通过移位操作丢弃,同时将下一个像素挪到blk的最低位
        bits_left -= miss_bits_of_last_blk;  // 将已提取的被截像素所占bit数 从 blk剩余bit数 里减去
    }
    while (bits_left > info->pix_width) {
    	// 通过移位操作分离单个像素
    }
    if (bits_left > 0) {  // 本blk也留下残余像素了-_-!
        ctx->left_bits_of_last_blk = bits_left;  // 将残余像素的bit数存到ctx
        tmp = blk & ((1 << bits_left) - 1);  // 将残余像素的低位像素值存到tmp
        ctx->last_pix_val = tmp;  // 将上一步的tmp存到ctx
    }

总结

想获取完整可编译运行代码,访问此github地址,命令行使用方法:

rawpeck img_width img_height pixel_width bus_width path_of_packed_raw path_of_unpacked_raw
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值