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

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

         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

#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的目录。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,265评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,078评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,852评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,408评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,445评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,772评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,921评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,688评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,130评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,467评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,617评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,276评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,882评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,740评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,967评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,315评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,486评论 2 348

推荐阅读更多精彩内容