关于libyuv格式转换、图像裁剪说明

2023-12-14 18:10

本文主要是介绍关于libyuv格式转换、图像裁剪说明,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

项目源代码https://github.com/liluojun/PlayVideo

关联文章https://blog.csdn.net/hjt505694246/article/details/105046233Android硬编、硬解h264

https://blog.csdn.net/hjt505694246/article/details/105047729FFmpeg解码裸H264数据

         Android相机输出的是yuv数据、yuv数据格式太多了如420p、420sp等,我们经常会需要对yuv数据做处理,最原始的使用java for循环的方式耗时太多不合算,libyuv是由google开源的一个针对yuv数据处理的库,其效率比使用java处理的方式快太多了,故比较推荐使用。

public class NativeMethod {public native void nv21ToI420(byte[] src, byte[] dst, int w, int h, byte[] y, byte[] u, byte[] v);public native void nv21ToNv12(byte[] src, byte[] dst, int w, int h, byte[] y, byte[] u, byte[] v);public native void nv21CutterToI420(byte[] src, byte[] dst, int cutter_w, int cutter_h, int w, int h, byte[] y, byte[] u, byte[] v);public native void nv21CutterToNv12(byte[] src, byte[] dst, int cutter_w, int cutter_h, int w, int h, byte[] y, byte[] u, byte[] v);
}

我在项目中提供了4个方法示例前两个是nv21转420p和420sp,后两个是转的过程中做出裁剪。

参数说明:byte[] src 源数据

                  byte[] dst转换后的输出数据

                  int cutter_w裁剪的宽度

                  int cutter_h裁剪的高度

                  int w原宽度

                  int h原高度

                 byte[] y, byte[] u, byte[] v裁剪后yuv三个分量的数据,由于我用的是yuv渲染故需要这些值,没需求的可以不用理会。

jni层代码

#define  LOGE(...) __android_log_print(ANDROID_LOG_ERROR,"ffmpeg",__VA_ARGS__)
#ifndef _Included_media_jni_NativeMethod
#define _Included_media_jni_NativeMethod
#ifdef __cplusplus
extern "C" {
#include "libyuv.h"
#include <android/log.h>
#include "media_jni_NativeMethod.h"
#endif
void releaseByteArray(JNIEnv *env, jbyteArray array, uint8_t *elems, jint mode) {env->ReleaseByteArrayElements(array, (jbyte *) elems, mode);env->DeleteLocalRef(array);
}
/** Class:     media_jni_NativeMethod* Method:    nv21ToI420* Signature: ([B[BII)V*/
JNIEXPORT void JNICALL Java_media_jni_NativeMethod_nv21ToI420(JNIEnv *env, jobject job, jbyteArray src, jbyteArray dst, jint w, jint h, jbyteArray y,jbyteArray u, jbyteArray v) {uint8_t *srcArray = (uint8_t *) env->GetByteArrayElements(src, NULL);uint8_t *dstArray = (uint8_t *) env->GetByteArrayElements(dst, NULL);uint8_t *yArray = (uint8_t *) env->GetByteArrayElements(y, NULL);uint8_t *uArray = (uint8_t *) env->GetByteArrayElements(u, NULL);uint8_t *vArray = (uint8_t *) env->GetByteArrayElements(v, NULL);jint uvW = w >> 1;jint ySize = w * h;jint uSize = (uvW) * (h >> 1);uint8_t *y_src = srcArray;uint8_t *uv_src = srcArray + ySize;uint8_t *y_dst = dstArray;uint8_t *u_dst = dstArray + ySize;uint8_t *v_dst = dstArray + ySize + uSize;libyuv::NV21ToI420(y_src, w, uv_src, w, y_dst, w, u_dst, uvW, v_dst, uvW, w, h);memcpy(yArray, y_dst, ySize);memcpy(uArray, u_dst, (w * h) >> 2);memcpy(vArray, v_dst, (w * h) >> 2);//I420旋转方法注释但不能删除
//    yuv.libyuv::I420Rotate(y_tran, w, u_tran, w >> 1, v_tran, w >> 1, y_dst, h, u_dst, h >> 1, v_dst,
//                       h >> 1, h, w, yuv.libyuv::kRotate270);releaseByteArray(env, src, srcArray, 0);releaseByteArray(env, dst, dstArray, 0);releaseByteArray(env, y, yArray, 0);releaseByteArray(env, v, vArray, 0);releaseByteArray(env, u, uArray, 0);
} ;/** Class:     media_jni_NativeMethod* Method:    nv21ToNv12* Signature: ([B[BII)V*/
JNIEXPORT void JNICALL Java_media_jni_NativeMethod_nv21ToNv12(JNIEnv *env, jobject job, jbyteArray src, jbyteArray dst, jint w, jint h, jbyteArray y,jbyteArray u, jbyteArray v) {LOGE("111");uint8_t *srcArray = (uint8_t *) env->GetByteArrayElements(src, 0);uint8_t *dstArray = (uint8_t *) env->GetByteArrayElements(dst, 0);LOGE("222");uint8_t *yArray = (uint8_t *) env->GetByteArrayElements(y, NULL);uint8_t *uArray = (uint8_t *) env->GetByteArrayElements(u, NULL);uint8_t *vArray = (uint8_t *) env->GetByteArrayElements(v, NULL);jint ySize = w * h;jint uvSize = (w >> 1) * (h >> 1);uint8_t *y_src = srcArray;uint8_t *uv_src = srcArray + ySize;uint8_t *u_src = srcArray + ySize;uint8_t *v_src = srcArray + ySize + uvSize;uint8_t *y_dst = dstArray;uint8_t *uv_dst = dstArray + ySize;libyuv::NV21ToI420(y_src, w, uv_src, w, yArray, w, uArray, w >> 1, vArray, w >> 1, w,h);libyuv::I420ToNV12(yArray, w, uArray, w >> 1, vArray, w >> 1, y_dst, w, uv_dst, w, w, h);releaseByteArray(env, src, srcArray, 0);releaseByteArray(env, dst, dstArray, 0);releaseByteArray(env, y, yArray, 0);releaseByteArray(env, v, vArray, 0);releaseByteArray(env, u, uArray, 0);
} ;
/** Class:     media_jni_NativeMethod* Method:    nv21CutterToI420* Signature: ([B[BIIII)V*/
JNIEXPORT void JNICALL Java_media_jni_NativeMethod_nv21CutterToI420(JNIEnv *env, jobject job, jbyteArray src, jbyteArray dst, jint cw, jint ch, jint w,jint h, jbyteArray y,jbyteArray u, jbyteArray v) {uint8_t *srcArray = (uint8_t *) env->GetByteArrayElements(src, 0);uint8_t *dstArray = (uint8_t *) env->GetByteArrayElements(dst, 0);jbyteArray transitJbyteArray = env->NewByteArray(w * h * 3 / 2);uint8_t *transitArray = (uint8_t *) env->GetByteArrayElements(transitJbyteArray, 0);uint8_t *yArray = (uint8_t *) env->GetByteArrayElements(y, NULL);uint8_t *uArray = (uint8_t *) env->GetByteArrayElements(u, NULL);uint8_t *vArray = (uint8_t *) env->GetByteArrayElements(v, NULL);jint ySize = w * h;jint startx = (w - cw) / 2;jint starty = (h - ch) / 2;jint uvSize = (w >> 1) * (h >> 1);uint8_t *y_src = srcArray;uint8_t *uv_src = srcArray + ySize;uint8_t *y_transit = transitArray;uint8_t *u_transit = transitArray + ySize;uint8_t *v_transit = transitArray + ySize + uvSize;uint8_t *y_dst = dstArray;uint8_t *u_dst = dstArray + (cw * ch);uint8_t *v_dst = dstArray + (cw * ch) + ((cw * ch) >> 2);libyuv::NV21ToI420(y_src, w, uv_src, w, y_transit, w, u_transit, w >> 1, v_transit, w >> 1, w,h);libyuv::ConvertToI420(transitArray, ySize + uvSize, y_dst, cw, u_dst, cw >> 1,v_dst, cw >> 1,startx, starty, w, h, cw, ch, libyuv::kRotate0, libyuv::FOURCC_I420);memcpy(yArray, y_dst, cw * ch);memcpy(uArray, u_dst, (cw * ch) >> 2);memcpy(vArray, v_dst, (cw * ch) >> 2);releaseByteArray(env, transitJbyteArray, transitArray, 0);releaseByteArray(env, src, srcArray, 0);releaseByteArray(env, dst, dstArray, 0);releaseByteArray(env, y, yArray, 0);releaseByteArray(env, v, vArray, 0);releaseByteArray(env, u, uArray, 0);
} ;/** Class:     media_jni_NativeMethod* Method:    nv21CutterToNv12* Signature: ([B[BIIII)V*/
JNIEXPORT void JNICALL Java_media_jni_NativeMethod_nv21CutterToNv12(JNIEnv *env, jobject job, jbyteArray src, jbyteArray dst, jint cw, jint ch, jint w,jint h, jbyteArray y,jbyteArray u, jbyteArray v) {uint8_t *srcArray = (uint8_t *) env->GetByteArrayElements(src, 0);uint8_t *dstArray = (uint8_t *) env->GetByteArrayElements(dst, 0);uint8_t *yArray = (uint8_t *) env->GetByteArrayElements(y, NULL);uint8_t *uArray = (uint8_t *) env->GetByteArrayElements(u, NULL);uint8_t *vArray = (uint8_t *) env->GetByteArrayElements(v, NULL);jbyteArray transitJbyteArray = env->NewByteArray(w * h * 3 / 2);uint8_t *transitArray = (uint8_t *) env->GetByteArrayElements(transitJbyteArray, 0);jint ySize = w * h;jint startx = (w - cw) / 2;jint starty = (h - ch) / 2;jint uvSize = (w >> 1) * (h >> 1);uint8_t *y_src = srcArray;uint8_t *uv_src = srcArray + ySize;uint8_t *y_transit = transitArray;uint8_t *u_transit = transitArray + ySize;uint8_t *v_transit = transitArray + ySize + uvSize;uint8_t *y_dst = dstArray;uint8_t *uv_dst = dstArray + (cw * ch);libyuv::NV21ToI420(y_src, w, uv_src, w, y_transit, w, u_transit, w >> 1, v_transit, w >> 1, w,h);libyuv::ConvertToI420(transitArray, ySize + uvSize, yArray, cw, uArray, cw >> 1,vArray, cw >> 1,startx, starty, w, h, cw, ch, libyuv::kRotate0, libyuv::FOURCC_I420);libyuv::I420ToNV12(yArray, cw, uArray, cw >> 1, vArray, cw >> 1, y_dst, cw,uv_dst, cw, cw, ch);releaseByteArray(env, transitJbyteArray, transitArray, 0);releaseByteArray(env, src, srcArray, 0);releaseByteArray(env, dst, dstArray, 0);releaseByteArray(env, y, yArray, 0);releaseByteArray(env, v, vArray, 0);releaseByteArray(env, u, uArray, 0);
} ;
#ifdef __cplusplus
}
#endif
#endif以上就是jni层全部的代码基本上只涉及到数据转换和libyuv库的调用没啥太不好理解的地方。里面有注释旋转的代码有兴趣或者需求的童鞋可以恢复过来玩一玩。

这是yuv jni的目录。

这篇关于关于libyuv格式转换、图像裁剪说明的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/493507

相关文章

Linux中shell解析脚本的通配符、元字符、转义符说明

《Linux中shell解析脚本的通配符、元字符、转义符说明》:本文主要介绍shell通配符、元字符、转义符以及shell解析脚本的过程,通配符用于路径扩展,元字符用于多命令分割,转义符用于将特殊... 目录一、linux shell通配符(wildcard)二、shell元字符(特殊字符 Meta)三、s

Linux使用dd命令来复制和转换数据的操作方法

《Linux使用dd命令来复制和转换数据的操作方法》Linux中的dd命令是一个功能强大的数据复制和转换实用程序,它以较低级别运行,通常用于创建可启动的USB驱动器、克隆磁盘和生成随机数据等任务,本文... 目录简介功能和能力语法常用选项示例用法基础用法创建可启动www.chinasem.cn的 USB 驱动

java脚本使用不同版本jdk的说明介绍

《java脚本使用不同版本jdk的说明介绍》本文介绍了在Java中执行JavaScript脚本的几种方式,包括使用ScriptEngine、Nashorn和GraalVM,ScriptEngine适用... 目录Java脚本使用不同版本jdk的说明1.使用ScriptEngine执行javascript2.

IDEA如何将String类型转json格式

《IDEA如何将String类型转json格式》在Java中,字符串字面量中的转义字符会被自动转换,但通过网络获取的字符串可能不会自动转换,为了解决IDEA无法识别JSON字符串的问题,可以在本地对字... 目录问题描述问题原因解决方案总结问题描述最近做项目需要使用Ai生成json,可生成String类型

基于WinForm+Halcon实现图像缩放与交互功能

《基于WinForm+Halcon实现图像缩放与交互功能》本文主要讲述在WinForm中结合Halcon实现图像缩放、平移及实时显示灰度值等交互功能,包括初始化窗口的不同方式,以及通过特定事件添加相应... 目录前言初始化窗口添加图像缩放功能添加图像平移功能添加实时显示灰度值功能示例代码总结最后前言本文将

Python 标准库time时间的访问和转换问题小结

《Python标准库time时间的访问和转换问题小结》time模块为Python提供了处理时间和日期的多种功能,适用于多种与时间相关的场景,包括获取当前时间、格式化时间、暂停程序执行、计算程序运行时... 目录模块介绍使用场景主要类主要函数 - time()- sleep()- localtime()- g

JAVA中整型数组、字符串数组、整型数和字符串 的创建与转换的方法

《JAVA中整型数组、字符串数组、整型数和字符串的创建与转换的方法》本文介绍了Java中字符串、字符数组和整型数组的创建方法,以及它们之间的转换方法,还详细讲解了字符串中的一些常用方法,如index... 目录一、字符串、字符数组和整型数组的创建1、字符串的创建方法1.1 通过引用字符数组来创建字符串1.2

Linux内核之内核裁剪详解

《Linux内核之内核裁剪详解》Linux内核裁剪是通过移除不必要的功能和模块,调整配置参数来优化内核,以满足特定需求,裁剪的方法包括使用配置选项、模块化设计和优化配置参数,图形裁剪工具如makeme... 目录简介一、 裁剪的原因二、裁剪的方法三、图形裁剪工具四、操作说明五、make menuconfig

Redis分布式锁使用及说明

《Redis分布式锁使用及说明》本文总结了Redis和Zookeeper在高可用性和高一致性场景下的应用,并详细介绍了Redis的分布式锁实现方式,包括使用Lua脚本和续期机制,最后,提到了RedLo... 目录Redis分布式锁加锁方式怎么会解错锁?举个小案例吧解锁方式续期总结Redis分布式锁如果追求

结构体和联合体的区别及说明

《结构体和联合体的区别及说明》文章主要介绍了C语言中的结构体和联合体,结构体是一种自定义的复合数据类型,可以包含多个成员,每个成员可以是不同的数据类型,联合体是一种特殊的数据结构,可以在内存中共享同一... 目录结构体和联合体的区别1. 结构体(Struct)2. 联合体(Union)3. 联合体与结构体的