基于android平台的libyuv库接口使用方法

不管现实多么惨不忍睹,都要持之以恒地相信,这只是黎明前短暂的黑暗而已。不要惶恐眼前的难关迈不过去,不要担心此刻的付出没有回报,别再花时间等待天降好运。真诚做人,努力做事!你想要的,岁月都会给你。基于android平台的libyuv库接口使用方法,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

1,Camera nv12格式数据实现镜像旋转

该操作即实现图像的左右翻转

步骤:

1.1根据width和height来计算stride跨距,和内存空间大小。

1.2NV12格式转换成I420格式,即分离出u和v plane。

1.3将I420格式数据镜像旋转。

1.4镜像旋转后,在转换格式为NV12即可。

代码示例

void HdmiRxStreamBuffer::LibyuvMirror_NV12(int buffer_width, int buffer_height, char* src_y_frame, char* src_uv_frame){
	
    //y stride
    int plane1_stride = buffer_width;
    //uv stride
    int plane2_stride = buffer_width;
    //y height
    int plane1_height = buffer_height;
    //uv height
    int plane2_height = buffer_height / 2;
    //y_size
    int32_t plane1_size = plane1_stride * plane1_height;
    //uv_size
    int32_t plane2_size = plane2_stride * plane2_height;
    //yuv_size(内存空间)
    int32_t frame_size = plane1_size + plane2_size;
	
	// 1.NV12转换为I420
    // 开辟buffer_frame大小的内存空间用于存放转换好的i420数据
    uint8_t* buffer_y = (unsigned char *)malloc(frame_size);
    uint8_t* buffer_u = buffer_y + plane1_size;
    uint8_t* buffer_v = buffer_u + plane1_size / 4;

    libyuv::NV12ToI420(/*const uint8 *src_y*/ (uint8_t *)src_y_frame,
                       /*int src_stride_y*/ plane1_stride,
                       /*const uint8 *src_uv*/ (uint8_t *)src_uv_frame,
                       /*int src_stride_uv*/ plane2_stride,
                       /*uint8 *dst_y*/ buffer_y,
                       /*int dst_stride_y*/ plane1_stride,
                       /*uint8 *dst_u*/ buffer_u,
                       /*int dst_stride_u*/ plane1_stride >> 1,
                       /*uint8 *dst_v*/ buffer_v,
                       /*int dst_stride_v*/ plane1_stride >> 1,
                       /*int width*/ buffer_width,
                       /*int height*/ buffer_height);
    
    uint8_t* mirror_y = (unsigned char *)malloc(frame_size);
    uint8_t* mirror_u = mirror_y + plane1_size;
    uint8_t* mirror_v = mirror_u + plane1_size / 4;
    
    libyuv::I420Mirror(/*const uint8* src_y*/buffer_y,
                       /*int src_stride_y*/plane1_stride,
                       /*const uint8* src_u*/buffer_u,
                       /*int src_stride_u*/plane1_stride >> 1,
                       /*const uint8* src_v*/buffer_v,
                       /*int src_stride_v*/plane1_stride >> 1,
                       /*uint8* dst_y*/mirror_y,
                       /*int dst_stride_y*/plane1_stride,
                       /*uint8* dst_u*/mirror_u,
                       /*int dst_stride_u*/plane1_stride >> 1,
                       /*uint8* dst_v*/mirror_v,
                       /*int dst_stride_v*/plane1_stride >> 1,
                       /*int width*/buffer_width,
                       /*int height*/buffer_height);
    
    free(buffer_y);
    
    uint8_t *nv12_y = (uint8_t *)malloc(frame_size);
    uint8_t* nv12_uv = nv12_y + plane1_stride * plane1_height;
    
    libyuv::I420ToNV12(/*const uint8 *src_y*/ mirror_y,
                       /*int src_stride_y*/ plane1_stride,
                       /*const uint8 *src_u*/ mirror_u,
                       /*int src_stride_u*/ plane1_stride >> 1,
                       /*const uint8 *src_v*/ mirror_v,
                       /*int src_stride_v*/ plane1_stride >> 1,
                       /*uint8 *dst_y*/ nv12_y,
                       /*int dst_stride_y*/ plane1_stride,
                       /*uint8 *dst_uv*/ nv12_uv,
                       /*int dst_stride_uv*/ plane1_stride,
                       /*int width*/ buffer_width,
                       /*int height*/ buffer_height);
    
    free(mirror_y); 

	memcpy(src_y_frame, nv12_y, plane1_size);
	memcpy(src_uv_frame, nv12_uv, plane2_size);
	
	free(nv12_y); 
}

2,Camera NV12格式数据实现缩放

即实现不同分辨率的差值,实现放大或者缩小。ScalePlane中算法参数kFilterNone执行速度快,但是图像模糊,尤其是小文本字体。如果使用kFilterBox算法,执行速度相对会变慢10ms左右。但是图像效果很清晰。

步骤:

2.1根据width和height计算stride等。

2.2对y plane实现缩放。

2.3分离uvplane成独立的u和vplane

2.4分别对u和vplane实现缩放

2.5再把u和vplane实现merge操作即可

参考代码:

void HdmiRxStreamBuffer::LibyuvResize_NV12(const Buffer *src,
                             Buffer *dst) {
  uint32_t src_halfheight = SUBSAMPLE(src->height, 1, 1);
  uint32_t src_halfwidth = SUBSAMPLE(src->width, 1, 1);
  dst->stride[0] = dst->width;
  dst->stride[1] = dst->width;
  dst->stride[2] = 0;
  dst->color = src->color;
  // resize y_plane
  libyuv::ScalePlane(src->data[0], src->stride[0], 
                        src->width, src->height, 
                        dst->data[0], dst->stride[0],
                        dst->width, dst->height,
                        /*libyuv::FilterMode::kFilterNone*/libyuv::FilterMode::kFilterBox);
  // Split VUplane
  uint8_t* uv_data = new uint8_t[src->width * src->height / 2];
  uint8_t* u_data = uv_data;
  uint8_t* v_data = uv_data + src->width * src->height / 4;
  //malloc memory to store temp u v 
  uint8_t* temp_uv_data = new uint8_t[dst->width * dst->height / 2];
  uint8_t* temp_u_data = temp_uv_data;
  uint8_t* temp_v_data = temp_uv_data + dst->width * dst->height / 4;
  libyuv::SplitUVPlane(src->data[1], src->stride[1],
                       u_data, src->stride[1] >> 1,
                       v_data, src->stride[1] >> 1,
                       src_halfwidth, src_halfheight);
  // resize u and v
  libyuv::ScalePlane(u_data, src->stride[1] >> 1,
                    src->width >> 1, src_halfheight,
                    temp_u_data, dst->stride[1] >> 1,
                    dst->width >> 1, dst->height >> 1,
                    /*libyuv::FilterMode::kFilterNone*/libyuv::FilterMode::kFilterBox);

  libyuv::ScalePlane(v_data, src->stride[1] >> 1,
                    src->width >> 1, src_halfheight,
                    temp_v_data, dst->stride[1] >> 1,
                    dst->width >> 1, dst->height >> 1,
                    /*libyuv::FilterMode::kFilterNone*/libyuv::FilterMode::kFilterBox);
                    
  libyuv::MergeUVPlane(temp_u_data, dst->stride[1] >> 1,
                       temp_v_data, dst->stride[1] >> 1, 
                       dst->data[1], dst->stride[1],
                       dst->width >> 1, dst->height >> 1);
  delete[] uv_data;
  u_data = v_data = uv_data = nullptr;
  delete[] temp_uv_data;
  temp_u_data = temp_v_data = temp_uv_data = nullptr;
}

3,将yuv422(UYVY)格式数据转换成NV12

3.1主要是计算好width和height,及跨距,就可以实现转换。转换后图像效果也很清晰,颜色上相差不大。也可以自行实现,隔行对uvplane读取就行,但是图像效果差很多。

参考代码:

libyuv::UYVYToNV12(mCache,
               1920 * 2,
               mHdmi_y_data,
               1920,
               mHdmi_uv_data,
               1920,
               1920,
               1080);

3.2自行实现yuv422格式数据转换成nv12格式,主要思路是对u和v隔行读取即可,代码参考:

        for (i = 0; i < 1920 * 1080 * 2; i += 4) {
			// copy y channel
			mHdmi_y_data[ycount++] = *(mCache + i + 1);
			mHdmi_y_data[ycount++] = *(mCache + i + 3);
			if (0 == i % pixels_in_a_row) {
				++lines;
			}
			if (lines % 2) { // extract the UV value of odd rows
				// copy uv channel
				mHdmi_uv_data[ucount++] = *(mCache + i);
				mHdmi_uv_data[ucount++] = *(mCache + i + 2);
			}
		}

4,总结

yuv格式的转换,旋转,缩放等操作都可以通过libyuv库接口实现。libyuv库有很多封装接口效率高,图像变换的效果对比相差不大。

android系统中libyuv接口路径:external\libyuv\files\source

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/182003.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!