`
phenom
  • 浏览: 409351 次
  • 性别: Icon_minigender_1
  • 来自: 福州
社区版块
存档分类
最新评论

Camera预览图解析

 
阅读更多
网上查询预览的问题,多数是由于 byte[]的数据无法解析成Bitmap,然后会有一引2.2系统的YuvImage类来处理,因为它是jni实现的,所以其它低版本无法直接引用。
搞了一天,只是预览的效果是是一堆看不清的像素,不是一张图片,今天换了个工程试了一次居然行了。。。

还没有找到为什么。先把代码放上,备份:
由于两个工程效果不同,所以把整段代码放上来,有需要的可以参考下。
解码是从网络上抄得的一段。
public static final String TAG = "CameraActivity";
    Camera mCamera;
    SurfaceView mRemoteView;
    Surface mLocalSurface;
    SurfaceView mLocalView;
    SurfaceHolder mLocalSurfaceHolder;

    SurfaceHolder mRemoteSurfaceHolder;
    ImageView imageView;

    boolean remoteVideoVisible=true;
    int previewWidth=240,previewHeight=240;

@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        final Window win = getWindow();

        win.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
            WindowManager.LayoutParams.FLAG_FULLSCREEN);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        setContentView(R.layout.camera_test);

        mRemoteView = (SurfaceView) findViewById(R.id.remoteView);
        mLocalView = (SurfaceView) findViewById(R.id.localView);

        mLocalSurfaceHolder = mLocalView.getHolder();
        mLocalSurfaceHolder.addCallback(this);
        mLocalSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        mLocalSurface = mLocalSurfaceHolder.getSurface();

        mRemoteSurfaceHolder = mRemoteView.getHolder();
        mRemoteSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
        //imageView= (ImageView) findViewById(R.id.iv);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        Log.i(TAG, "surfaceCreated");
        mCamera = Camera.open();
        mCamera.setPreviewCallback(this);
        try {
            mCamera.setPreviewDisplay(holder);
        } catch (IOException exception) {
            mCamera.release();
            mCamera = null;
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
        Log.i(TAG, "surfaceChanged");
        Camera.Parameters parameters = mCamera.getParameters();
        parameters.setPreviewSize(previewWidth, previewHeight);
        parameters.setPreviewFormat(PixelFormat.YCbCr_420_SP);
        parameters.setPreviewFrameRate(10);
        mCamera.setParameters(parameters);
        mCamera.startPreview();
    }

@Override
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
        Log.i(TAG, "surfaceDestroyed");
        if (mCamera != null) {
            mCamera.setPreviewCallback(null);
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }
    }

//如果只是实现预览下面这个方法就可以不使用了。但是我现在实现两个图像,一个是预览的图像,另一个也不知道是什么图像。
    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {
        Log.i(TAG, "onPreviewFrame.");

        if (remoteVideoVisible) {
            int w = camera.getParameters().getPreviewSize().width;
            int h = camera.getParameters().getPreviewSize().height;
            drawRemoteVideo(data,w,h);
        }
    }

private void drawRemoteVideo(final byte[] imageData, int width, int height) {
        //Log.i(TAG, "drawRemoteVideo");
        int[] rgb = decodeYUV420SP(imageData, width, height);
        Bitmap bmp = Bitmap.createBitmap(rgb, width, height, Bitmap.Config.ARGB_8888);
        Canvas canvas = mRemoteSurfaceHolder.lockCanvas();
        canvas.drawBitmap(bmp, 0, 0, null);
        mRemoteSurfaceHolder.unlockCanvasAndPost(canvas);

这里处理的图像大小会是截取部分的,因为remoteView的大小与取得的图像不同。所以如果要显示全像,要再处理图像的缩放:
bmp=Bitmap.createScaledBitmap(bmp,mRemoteView.getWidth(), mRemoteView.getHeight(),true);然后再用canvas画出来。
    }

这个解码方法是网上抄来的。
public int[] decodeYUV420SP(byte[] yuv420sp, int width, int height) {

        final int frameSize = width * height;

        int rgb[] = new int[width * height];
        for (int j = 0, yp = 0; j < height; j++) {
            int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;
            for (int i = 0; i < width; i++, yp++) {
                int y = (0xff & ((int) yuv420sp[yp])) - 16;
                if (y < 0) y = 0;
                if ((i & 1) == 0) {
                    v = (0xff & yuv420sp[uvp++]) - 128;
                    u = (0xff & yuv420sp[uvp++]) - 128;
                }

                int y1192 = 1192 * y;
                int r = (y1192 + 1634 * v);
                int g = (y1192 - 833 * v - 400 * u);
                int b = (y1192 + 2066 * u);

                if (r < 0) r = 0;
                else if (r > 262143) r = 262143;
                if (g < 0) g = 0;
                else if (g > 262143) g = 262143;
                if (b < 0) b = 0;
                else if (b > 262143) b = 262143;

                rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) &
                    0xff00) | ((b >> 10) & 0xff);

            }
        }
        return rgb;
    }

还需要实现一些接口: implements SurfaceHolder.Callback, Camera.PreviewCallback 这个接口就是onPreviewFrame方法覆盖实现的。
布局文件:<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/remoteView"
                 android:layout_height="100dip"
                 android:layout_width="100dip">
    </SurfaceView>

    <TextView
        android:id="@+id/txt" android:layout_height="wrap_content"
        android:layout_width="fill_parent" android:text="divdder"
        android:textColor="@color/red"/>

    <SurfaceView android:id="@+id/localView"
                 android:layout_height="200dip"
                 android:layout_width="200dip">
    </SurfaceView>
</LinearLayout>
运行后就可以看到两个图像了。一个大一个小的。
权限还是需要的
<uses-permission android:name="android.permission.CAMERA"/>
    <uses-feature android:name="android.hardware.camera"/>
    <uses-feature android:name="android.hardware.camera.autofocus"/>

关于int previewWidth=240,previewHeight=240;与decodeYUV420SP的问题:
Camera.Parameters parameters = mCamera.getParameters();
        parameters.setPreviewSize(previewWidth, previewHeight);
这个预览大小需要确定,似乎可以解释为码率,有一些固定值,如果不在这些固定值范围就会出错。比如176*144 是最小的,320*240,这个值可以查看的,如果实在无法查询,你随便设置一个,然后看log,会提示一些关于这些的值。
如果这个值太小了,解析出来的图像也小,然后在remoteView设置过大,又会出错(之前的程序会,也许不是这个问题),关于这个方法,也有见过不同的说法,我觉得实践后是正确的。
setPictureSize我想就是成像大小,比如拍照后保存的文件分辨率在这个方法设置。
上面的摄像头没有实现传感器监听,所以图像会倒置,这跟屏幕的方向似乎无关的。需要设置横屏的,但因为Android系统版本太多,不同厂商间的摄像头处理方式又不同,所以有较多的麻烦处
分享到:
评论
8 楼 phenom 2012-11-15  
ihopethatwell 写道
楼主,我加了:
int[] rgb = decodeYUV420SP(yuv420sp, width, height);

用mat 分析您这个代码有内存泄漏:
1:The class "android.content.res.Resources",

Keywords
java.lang.Object[]
android.content.res.Resources
Keywords
java.lang.Object[]
android.content.res.Resources
这三个问题怎样优化?

内存泄露不是我这段代码造成的。
你检查下是具体的位置,看下mat里面的关联。

我这篇文章只是提供decodeYUV420SP 从yuv转为rgb,重点不是摄像头的预览,如果你也做视频通话的客户端,看另一篇关于 如何缓存帧的。个人测试过,那一篇 里面没有出现内存泄露。但是要Activity中控制 好何时把线程停止了。


7 楼 ihopethatwell 2012-11-15  
楼主,我加了:
int[] rgb = decodeYUV420SP(yuv420sp, width, height);
Bitmap bmp = Bitmap.createBitmap(rgb, width, height,
Bitmap.Config.ARGB_8888);
rgb = null;
Canvas canvas = mRemoteSurfaceHolder.lockCanvas();
if (canvas != null)
{
canvas.drawBitmap(bmp, null, null);
mRemoteSurfaceHolder.unlockCanvasAndPost(canvas);
canvas = null;

}
if (!bmp.isRecycled())
{
bmp.recycle();
}
bmp = null;
}
用mat 分析您这个代码有内存泄漏:
1:The class "android.content.res.Resources", loaded by "<system class loader>", occupies 3,297,296 (39.79%) bytes. The memory is accumulated in one instance of "java.lang.Object[]" loaded by "<system class loader>".

Keywords
java.lang.Object[]
android.content.res.Resources
2:The class "android.content.res.Resources", loaded by "<system class loader>", occupies 3,297,296 (39.79%) bytes. The memory is accumulated in one instance of "java.lang.Object[]" loaded by "<system class loader>".

Keywords
java.lang.Object[]
android.content.res.Resources
3:The class "android.content.res.Resources", loaded by "<system class loader>", occupies 3,297,296 (39.79%) bytes. The memory is accumulated in one instance of "java.lang.Object[]" loaded by "<system class loader>".

Keywords
java.lang.Object[]
android.content.res.Resources
这三个问题怎样优化?
6 楼 ihopethatwell 2012-08-10  
楼主,我点击手机的返回键,如果是连着电脑调试的话,还能看到他在执行,并且我把SurfaceView mLocalView 设置width=1dip,height=1dip ,mRemoteView则是fill_parent 用FrameLayout 布的局,这样显示就会看到mRemoteView ,但是这样 onCreateOptionsMenu 点击menu时候一直弹出,要么等待 关闭的选项对话框,这个绘图有什么优化方式?
5 楼 ihopethatwell 2012-07-31  
嗯,去掉这个函数就可以了,手机不会滋滋响,不过我有个问题想请教:我只想显示:得到mLocalSurfaceHolder的数据然后绘图得到bimap,你这里是两个surfaceview 但是定义了mLocalSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);  我就不能得到数据并且在这个上面绘图了,有什么办法可以绘图? 总之就是界面只显示一个surfaceview 这个data 生成图片是我在上面画了图的 然后显示。怎么优化?
4 楼 phenom 2012-07-26  
Camera.Parameters parameters = mCamera.getParameters(); 
        parameters.setPreviewSize(previewWidth, previewHeight); 
        parameters.setPreviewFormat(PixelFormat.YCbCr_420_SP); 
        parameters.setPreviewFrameRate(10);  //会不会是这句有问题。
        mCamera.setParameters(parameters); 
是参数的问题,仔细设置参数,看看日志有没有错误信息,
android就是个蛋疼的货。
3 楼 ihopethatwell 2012-07-26  
嗯,对了楼主,你这个例子我在手机上运行正常运行但ste手机会滋滋的响声。
请教一个问题:用htc的手机调用onPreviewFrame()这个方法 ,我调试看到Camera.open()得到的camera对象不为null,但手机屏幕会显示黑屏,ste 手机和中信的没问题,360camera装在htc手机上可以开启摄像头,像我们这种开启摄像头预览就是黑屏,不知道楼主有什么建议解决或者遇到过?
2 楼 phenom 2012-07-25  
yuv420 to rgb格式转换用的,但是通常会在c写用jni连接java.
ffmpeg有yuv2rgb.c
1 楼 ihopethatwell 2012-07-24  
楼主,你这个解码的是万能还是怎么?里面有些数值代表什么?能解释一下或者发一下原址?

相关推荐

    camera preview test sample

    《Camera预览测试样本解析》 在Android应用开发中,Camera功能是不可或缺的一部分,它使得开发者能够构建丰富的图像处理和拍摄应用。本篇将详细解析一个名为"camera preview test sample"的项目,该项目旨在帮助...

    android 原生人脸识别Camera和Camera2的示例

    6. **处理人脸数据**:在`CaptureCallback`的`onCaptureCompleted()`或`onFrameAvailable()`方法中,获取`TotalCaptureResult`,从中解析出人脸信息。 7. **更新界面**:将检测到的人脸信息转换为UI元素,例如在屏幕...

    android camera 拍照流程图

    首先,我们要理解Android Camera API的三个主要版本:Camera、Camera2以及Camera3。每个版本都有其特定的特性和使用场景: 1. **Camera API**(旧版):这是早期Android系统中提供的相机接口,简单易用,但功能相对...

    FAQ_Camera

    它可以帮助用户快速读取和解析条形码中的信息。在移动设备中,这种功能通常集成在相机应用中。 ### 14. 名片识别死机(拍非名片的场景)的分析方法 当遇到在拍摄非名片场景时出现死机的情况,可以通过以下步骤进行...

    Android Camera2 API

    《深入解析Android Camera2 API》 在Android平台上,相机功能是开发者和用户都非常关注的部分,尤其是在移动设备上,高质量的拍照体验对用户来说至关重要。随着Android系统的不断演进,Camera API也经历了从早期的...

    Android VideoCamera MediaRecorder 解析PPT

    本文将深入解析MediaRecorder的生命周期、使用方法以及需要注意的事项。 首先,让我们了解MediaRecorder的状态机。MediaRecorder有以下几种状态: 1. **Initial**:初始状态,这是刚创建MediaRecorder对象时的状态...

    opencamera

    《OpenCamera:深入解析开源相机应用的开发》 OpenCamera是一款开源的Android相机应用程序,它提供了丰富的拍照和录像功能,同时也为开发者提供了深入定制和扩展的可能性。本文将围绕"opencamera相机开发"这一主题...

    Android_Camera_Demo

    3. **设置预览Surface**: 为了显示相机预览,你需要创建一个SurfaceView或者TextureView,并将其Surface传递给Camera对象。这一步涉及`setPreviewDisplay(SurfaceHolder holder)`方法。 4. **配置参数**: 使用`...

    Android camera架构介绍

    ### Android Camera 架构深入解析 #### 一、Android Camera 概述 Android Camera 模块作为移动设备上的核心功能之一,在系统架构设计上显得尤为重要。为了更好地理解其内部工作原理,我们首先需要对它的整体架构有...

    Qt 使用QWidget调用QML打开安卓摄像头可以实时预览

    `Camera`组件负责管理相机设备,而`CameraPreview`则用来显示预览图像。在QML代码中,配置这些组件可能如下所示: ```qml import QtQuick 2.0 import QtMultimedia 5.0 Camera { id: camera captureMode: Camera...

    CameraApp摄像头调用和设备

    关于写JSON文档,JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。在本案例中,可能是为了记录或传输摄像头设备的信息。创建JSON文档,可以使用JSON库...

    brew camera service overview

    ### Brew平台Camera服务概述知识点解析 #### 一、Brew平台简介 Brew(Binary Runtime Environment for Wireless)是由高通公司开发的一种无线应用平台。它主要用于移动设备上应用程序的开发和部署,支持多种功能,...

    图片选择器及预览删除

    在移动应用开发中,"图片选择器及预览删除"是一个常见的功能模块,它主要用于让用户在应用程序内方便地选择图片,同时提供预览和删除图片的功能。这一特性在社交、相册管理、个人资料编辑等多种场景下都有广泛的应用...

    AndroidCamera2BasicApp.zip

    《Android Camera2基础应用解析》 在移动设备领域,Android操作系统以其开放性和强大的定制性深受开发者喜爱。在Android系统中,相机功能是不可或缺的一部分,而Camera2 API是Google推出的一个重要更新,它为开发者...

    高通Camera 面试题

    在ISP(Image Signal Processor)处理后,数据会根据需求分流,如capture(拍照)、preview(预览)和video(录像)等。以零快门延迟(ZSL)拍照为例,通过发送请求获取capture stream数据流,编码压缩后传给APP完成拍照。 3...

    android-Camera2Basic-master源码

    《深入解析Android Camera2Basic-master源码》 在Android应用开发中,相机功能是一个不可或缺的部分。随着技术的发展,Android系统提供了Camera2 API,为开发者提供了更高级、更灵活的相机控制。本文将深入剖析...

    DualCamera.rar

    《双路USB摄像头同步视频预览技术解析》 在当今数字化时代,摄像头已经广泛应用于各种领域,如视频会议、远程教育、安防监控等。而针对需要同时使用两个或多个摄像头的场景,例如3D视频录制或者多角度监控,实现...

    Android Camera使用小结

    创建CameraCaptureSession,定义预览Surface和图片或视频的OutputSurface。设置CaptureRequest.Builder,通过setTargetRotation()处理屏幕旋转,设置曝光、对焦等参数,最后通过CaptureSession.capture()或...

    Android Studio Camera2的录像功能

    设置预览Surface,用于显示摄像头画面,同时设置另一个Surface用于MediaRecorder处理。 - **准备MediaRecorder**: 设置摄像头源(Camera2 API提供),音频源(默认为麦克风),并调用`MediaRecorder.prepare()`进行...

Global site tag (gtag.js) - Google Analytics