2 wang xin 1992 wang_xin_1992 于 2014.03.31 23:50 提问

从camera preview获取数据流问题求教!

本人android开发新人,以下是我为了从预览数据流抓取图片并存储而编写的代码。网上说“从camera读取到的预览(preview)图像流一定要输出到一个可见的(Visible)SurfaceView上,然后通过Camera.PreviewCallback的public void onPreviewFrame(byte[] data, Camera camera)函数来获得图像帧数据的拷贝。”那么显示在SurfaceView上的数据流还是完整的吧,不会出现预览停顿的现象吧?为什么我的程序运行之后,预览一闪而过,然后程序重启,如此反复三遍,报出进程意外停止呢?而且也没有保存到图像。这个程序会以什么频率保存图片啊?onPreviewFrame(byte[] data, Camera camera)是每一帧都保存吗?如何控制保存频率?
求大神细心讲解,在线求教!或者QQ:851391489,隐身状态。拜谢!

package com.android.silentcamera;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;

import android.app.Activity;
import android.content.ContentValues;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.PreviewCallback;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.provider.MediaStore.Images.Media;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class SilentCameraActivity extends Activity
implements Camera.PreviewCallback, SurfaceHolder.Callback
{

SurfaceView mSurfaceView;
SurfaceHolder mSurfaceHolder;
Camera mCamera;

public void onCreate(Bundle savedInstanceState) 
{ 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 

    mSurfaceView = (SurfaceView) this.findViewById(R.id.surfaceview); 
    mSurfaceHolder = mSurfaceView.getHolder(); 
    mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    mSurfaceHolder.addCallback(this);
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    // TODO Auto-generated method stub
    mCamera.stopPreview();
    mCamera.release();
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
    // TODO Auto-generated method stub
    //打开前置摄像头 
    mCamera = Camera.open(CameraInfo.CAMERA_FACING_FRONT);

    //开始预览
    try 
    {
        //设置哪个surfaceView显示图片
        mCamera.setPreviewDisplay(mSurfaceHolder);
    }
    catch (IOException e)
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    //设置预览帧的接口,就是通过这个接口,我们来获得预览帧的数据的
    mCamera.setPreviewCallback(SilentCameraActivity.this); 
    mCamera.startPreview();
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
        int height) {
    // TODO Auto-generated method stub
    mCamera.startPreview();
}

    //拍照+退出 
    public void onPreviewFrame(byte[] data, Camera camera) 
    { 
        int w = camera.getParameters().getPreviewSize().width; 
        int h = camera.getParameters().getPreviewSize().height; 
        save(w,h,data); 
        finish(); 
    } 

    static public void decodeYUV420SP(int[] rgb, byte[] yuv420sp, int width, int height) {
        final int frameSize = 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);
        }
    }
}

    //保存 
    public void save(int w,int h,byte[] data){ 
        //预览编码为YUV420SP的视频流,需转换为RGB编码 
        int[] RGBData = new int[w* h]; 
        byte[] mYUVData = new byte[data.length]; 

        System.arraycopy(data,0, mYUVData, 0,data.length); 
        decodeYUV420SP(RGBData,mYUVData,w,h);

        //图片保存到sdcard 
        final Bitmap bitmap = Bitmap.createBitmap(w,h, Bitmap.Config.ARGB_8888); 
        try 
        { 
            FileOutputStream outputStream = new FileOutputStream(Environment.getExternalStorageDirectory().getPath() + UUID.randomUUID() + ".png"); 
            bitmap.compress(CompressFormat.PNG, 50, outputStream); 
            outputStream.close(); 
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }

}

7个回答

wangyaninglm
wangyaninglm   Ds   Rxr 2015.01.19 22:12
u011120188
u011120188   2015.08.19 16:24

楼主请问你的视频流的数据可以获取的到吗?

jinzengh6
jinzengh6   2015.10.23 15:24

请问楼主,上面的程序中 final Bitmap bitmap = Bitmap.createBitmap(w,h, Bitmap.Config.ARGB_8888); 在try{}块里, bitmap.compress(CompressFormat.PNG, 50, outputStream); 并没有保存图像的数据,请问该如何解决?

jinzengh6
jinzengh6   2015.10.23 15:24

请问楼主,上面的程序中 final Bitmap bitmap = Bitmap.createBitmap(w,h, Bitmap.Config.ARGB_8888); 在try{}块里, bitmap.compress(CompressFormat.PNG, 50, outputStream); 并没有保存图像的数据,请问该如何解决?

jinzengh6
jinzengh6   2015.10.23 15:24

请问楼主,上面的程序中 final Bitmap bitmap = Bitmap.createBitmap(w,h, Bitmap.Config.ARGB_8888); 在try{}块里, bitmap.compress(CompressFormat.PNG, 50, outputStream); 并没有保存图像的数据,请问该如何解决?

jinzengh6
jinzengh6   2015.10.23 15:22

请问楼主,上面的程序中 final Bitmap bitmap = Bitmap.createBitmap(w,h, Bitmap.Config.ARGB_8888); 在try{}块里, bitmap.compress(CompressFormat.PNG, 50, outputStream); 并没有保存图像的数据,请问该如何解决?

limin13215
limin13215 在createBitmap语句后面,执行bitmap.setPixels(。。。)方法
3 个月之前 回复
liuxia0017
liuxia0017   2017.02.25 16:45

我觉得大概是因为
FileOutputStream outputStream = new FileOutputStream(Environment.getExternalStorageDirectory().getPath() + UUID.randomUUID() + ".png");
这里是不是少了个“/”
Environment.getExternalStorageDirectory().getPath() +“/”+ UUID.randomUUID() + ".png"
文件目录是这个

Csdn user default icon
上传中...
上传图片
插入图片
准确详细的回答,更有利于被提问者采纳,从而获得C币。复制、灌水、广告等回答会被删除,是时候展现真正的技术了!