Android使用surface直接显示yuv数据(三)
在本文中,Java创建UI和关节JNI经营层surface直接显示yuv数据(yv12)。发展环境Android 4.4,驰A23平台。
package com.example.myyuvviewer; import java.io.File;
import java.io.FileInputStream;
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView; public class MainActivity extends Activity { final private String TAG = "MyYUVViewer";
final private String FILE_NAME = "yuv_320_240.yuv";
private int width = 320;
private int height = 240;
private int size = width * height * 3/2; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
nativeTest();
SurfaceView surfaceview = (SurfaceView) findViewById(R.id.surfaceView);
SurfaceHolder holder = surfaceview.getHolder();
holder.addCallback(new Callback(){ @Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
Log.d(TAG,"surfaceCreated");
byte[]yuvArray = new byte[size];
readYUVFile(yuvArray, FILE_NAME);
nativeSetVideoSurface(holder.getSurface());
nativeShowYUV(yuvArray,width,height);
} @Override
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
// TODO Auto-generated method stub } @Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub }});
} private boolean readYUVFile(byte[] yuvArray,String filename){
try {
// 假设手机插入了SD卡,并且应用程序具有訪问SD的权限
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
// 获取SD卡相应的存储文件夹
File sdCardDir = Environment.getExternalStorageDirectory();
// 获取指定文件相应的输入流
FileInputStream fis = new FileInputStream(
sdCardDir.getCanonicalPath() +"/" + filename);
fis.read(yuvArray, 0, size);
fis.close();
return true;
} else {
return false;
}
}catch (Exception e) {
e.printStackTrace();
return false;
}
}
private native void nativeTest();
private native boolean nativeSetVideoSurface(Surface surface);
private native void nativeShowYUV(byte[] yuvArray,int width,int height);
static {
System.loadLibrary("showYUV");
}
}
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" > <SurfaceView
android:id="@+id/surfaceView"
android:layout_width="fill_parent"
android:layout_height="360dp" /> </LinearLayout>
JNI层。showYUV.cpp(libshowyuv.so)採用动态注冊JNI函数的方法.
#include <jni.h>
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_view_Surface.h>
#include <gui/Surface.h>
#include <assert.h>
#include <utils/Log.h>
#include <JNIHelp.h>
#include <media/stagefright/foundation/ADebug.h>
#include <ui/GraphicBufferMapper.h>
#include <cutils/properties.h>
using namespace android; static sp<Surface> surface; static int ALIGN(int x, int y) {
// y must be a power of 2.
return (x + y - 1) & ~(y - 1);
} static void render(
const void *data, size_t size, const sp<ANativeWindow> &nativeWindow,int width,int height) {
ALOGE("[%s]%d",__FILE__,__LINE__);
sp<ANativeWindow> mNativeWindow = nativeWindow;
int err;
int mCropWidth = width;
int mCropHeight = height; int halFormat = HAL_PIXEL_FORMAT_YV12;//颜色空间
int bufWidth = (mCropWidth + 1) & ~1;//按2对齐
int bufHeight = (mCropHeight + 1) & ~1; CHECK_EQ(0,
native_window_set_usage(
mNativeWindow.get(),
GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_OFTEN
| GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP)); CHECK_EQ(0,
native_window_set_scaling_mode(
mNativeWindow.get(),
NATIVE_WINDOW_SCALING_MODE_SCALE_CROP)); // Width must be multiple of 32?? ?
//非常重要,配置宽高和和指定颜色空间yuv420
//假设这里不配置好,以下deque_buffer仅仅能去申请一个默认宽高的图形缓冲区
CHECK_EQ(0, native_window_set_buffers_geometry(
mNativeWindow.get(),
bufWidth,
bufHeight,
halFormat)); ANativeWindowBuffer *buf;//描写叙述buffer
//申请一块空暇的图形缓冲区
if ((err = native_window_dequeue_buffer_and_wait(mNativeWindow.get(),
&buf)) != 0) {
ALOGW("Surface::dequeueBuffer returned error %d", err);
return;
} GraphicBufferMapper &mapper = GraphicBufferMapper::get(); Rect bounds(mCropWidth, mCropHeight); void *dst;
CHECK_EQ(0, mapper.lock(//用来锁定一个图形缓冲区并将缓冲区映射到用户进程
buf->handle, GRALLOC_USAGE_SW_WRITE_OFTEN, bounds, &dst));//dst就指向图形缓冲区首地址 if (true){
size_t dst_y_size = buf->stride * buf->height;
size_t dst_c_stride = ALIGN(buf->stride / 2, 16);//1行v/u的大小
size_t dst_c_size = dst_c_stride * buf->height / 2;//u/v的大小 memcpy(dst, data, dst_y_size + dst_c_size*2);//将yuv数据copy到图形缓冲区
} CHECK_EQ(0, mapper.unlock(buf->handle)); if ((err = mNativeWindow->queueBuffer(mNativeWindow.get(), buf,
-1)) != 0) {
ALOGW("Surface::queueBuffer returned error %d", err);
}
buf = NULL;
} static void nativeTest(){
ALOGE("[%s]%d",__FILE__,__LINE__);
} static jboolean
nativeSetVideoSurface(JNIEnv *env, jobject thiz, jobject jsurface){
ALOGE("[%s]%d",__FILE__,__LINE__);
surface = android_view_Surface_getSurface(env, jsurface);
if(android::Surface::isValid(surface)){
ALOGE("surface is valid ");
}else {
ALOGE("surface is invalid ");
return false;
}
ALOGE("[%s][%d]\n",__FILE__,__LINE__);
return true;
}
static void
nativeShowYUV(JNIEnv *env, jobject thiz,jbyteArray yuvData,jint width,jint height){
ALOGE("width = %d,height = %d",width,height);
jint len = env->GetArrayLength(yuvData);
ALOGE("len = %d",len);
jbyte *byteBuf = env->GetByteArrayElements(yuvData, 0);
render(byteBuf,len,surface,width,height);
}
static JNINativeMethod gMethods[] = {
{"nativeTest", "()V", (void *)nativeTest},
{"nativeSetVideoSurface", "(Landroid/view/Surface;)Z", (void *)nativeSetVideoSurface},
{"nativeShowYUV", "([BII)V", (void *)nativeShowYUV},
}; static const char* const kClassPathName = "com/example/myyuvviewer/MainActivity"; // This function only registers the native methods
static int register_com_example_myyuvviewer(JNIEnv *env)
{
ALOGE("[%s]%d",__FILE__,__LINE__);
return AndroidRuntime::registerNativeMethods(env,
kClassPathName, gMethods, NELEM(gMethods));
} jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
ALOGE("[%s]%d",__FILE__,__LINE__);
JNIEnv* env = NULL;
jint result = -1; if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
ALOGE("ERROR: GetEnv failed\n");
goto bail;
}
assert(env != NULL);
ALOGE("[%s]%d",__FILE__,__LINE__);
if (register_com_example_myyuvviewer(env) < 0) {
ALOGE("ERROR: MediaPlayer native registration failed\n");
goto bail;
} /* success -- return valid version number */
result = JNI_VERSION_1_4; bail:
return result;
}
Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS) LOCAL_SRC_FILES:= \
showYUV.cpp LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
libbinder \
libui \
libgui \
libandroid_runtime \
libstagefright_foundation LOCAL_MODULE:= libshowYUV LOCAL_MODULE_TAGS := tests include $(BUILD_SHARED_LIBRARY)
生成的so文件拷贝到Java项目里 与src并列的libs/armeabi文件夹下。没有就手动创建文件夹,
这样Eclipse会自己主动把so库打包进apk。
转载请注明出处:http://blog.csdn.net/tung214/article/details/37762487
yuvdata下载地址:点击打开链接
版权声明:本文博客原创文章。博客,未经同意,不得转载。
Android使用surface直接显示yuv数据(三)的更多相关文章
- Android用surface直接显示yuv数据(三)
本文用Java创建UI并联合JNI层操作surface来直接显示yuv数据(yv12),开发环境为Android 4.4,全志A23平台. package com.example.myyuvviewe ...
- Android用surface直接显示yuv数据(二)
上一篇文章主要是參照AwesomePlayer直接用SoftwareRenderer类来显示yuv,为了能用到这个类,不惜依赖了libstagefright.libstagefright_color_ ...
- Android上使用OpenGLES2.0显示YUV数据
在Android上用OpenGLES来显示YUV图像,之所以这样做,是因为: 1.Android本身也不能直接显示YUV图像,YUV转成RGB还是必要的: 2.YUV手动转RGB会占用大量的CPU资源 ...
- 每天进步一点点------入门视频采集与处理(显示YUV数据)
做视频采集与处理,自然少不了要学会分析YUV数据.因为从采集的角度来说,一般的视频采集芯片输出的码流一般都是YUV数据流的形式,而从视频处理(例如H.264.MPEG视频编解码)的角度来说,也是在原始 ...
- Android TextView里直接显示图片的三种方法
方法一:重写TextView的onDraw方法,也挺直观就是不太好控制显示完图片后再显示字体所占空间的位置关系.一般假设字体是在图片上重叠的推荐这样写.时间关系,这个不付源代码了. 方法二:利用Tex ...
- 使用DirectDraw直接显示YUV视频数据
最近在编写一个进行视频播放的ActiveX控件,工作已经接近尾声,现将其中显示YUV数据的使用DirectDraw的一些经验总结如下:(解码部分不是我编写的,我负责从网络接收数据,将数据传给解码器,并 ...
- Android显示YUV图像
需要流畅显示YUV图像需要使用Opengl库调用GPU资源,网上在这部分的资料很少.实际上Android已经为我们提供了相关的Opengl方法 主体过程如下: 1.建立GLSurfaceView 2. ...
- Android应用开发基础之三:数据存储和界面展现(三)
生成XML文件备份短信 创建几个虚拟的短信对象,存在list中 备份数据通常都是备份至sd卡 使用StringBuffer拼接字符串 把整个xml文件所有节点append到sb对象里 sb.appen ...
- Android初级教程理论知识(第三章测试&数据存储&界面展现)
首先介绍单元测试,我在javaweb部分有详细介绍单元测试框架的一篇文章. 可以先看在javaweb中的单元测试详解篇http://blog.csdn.net/qq_32059827/article/ ...
随机推荐
- Java 并发专题 : Semaphore 实现 互斥 与 连接池
继续并发方面的知识.今天介绍Semaphore,同样在java.util.concurrent包下. 本来准备通过例子,从自己实现到最后使用并发工具实现,但是貌似效果并不是很好,有点太啰嗦的感觉,所有 ...
- 部署IIS错误
- 重新想象 Windows 8 Store Apps (24) - 文件系统: Application Data 中的文件操作, Package 中的文件操作, 可移动存储中的文件操作
原文:重新想象 Windows 8 Store Apps (24) - 文件系统: Application Data 中的文件操作, Package 中的文件操作, 可移动存储中的文件操作 [源码下载 ...
- 【屌丝程序的口才逆袭演讲稿50篇】第十篇:程序猿们请看看外面的世界吧【张振华.Jack】
演讲稿主题:<程序猿们请看看外面的世界吧> --作者:张振华Jack 大家都知道我是一个程序猿.几年下来认识了最典型的三个程序猿. ...
- LCA 学习算法 (最近的共同祖先)poj 1330
Nearest Common Ancestors Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 20983 Accept ...
- Linux 下一个 Mysql error 2002 错误解决
Linux 下一个 Mysql error 2002 错误解决 首先查看 /etc/rc.d/init.d/mysqld status 查看mysql它已开始. 假设启动的的话,先将数 ...
- Memcached全面剖析–5. memcached的应用和兼容程序
作者:长野雅广(Masahiro Nagano) 原文链接:http://gihyo.jp/dev/feature/01/memcached/0005 我是Mixi的长野.memcached的连载最 ...
- 安装framework 3.5出现0x800F0922的解决方法
关闭Windows 防火墙,启动Windows model install服务 重启! 再安装 就ok了
- Java经典23结构模型的设计模式(三)------附加代理模式、适配器型号、Facade模式的差异
本文介绍了7样的结构模型中的其余2种:轻量级.代理模式. 一.享元模式FlyWeight 享元模式比較简单且重要,在非常多场合都被用到.仅仅只是封装起来了用户看不到.其概念:运用共享内存技术最大限度的 ...
- SQL Server 连接问题-TCP/IP
原文:SQL Server 连接问题-TCP/IP 出自:http://blogs.msdn.com/b/apgcdsd/archive/2012/02/24/ms-sql-server-tcp-ip ...