android 视频流采集

这个完全是站在巨人的肩膀上,网上流传甚广的一个帖子,只是他说他当时调通是基于1.5的系统在G3上调通的,我是在Nexus One上基于2.2的系统调通的。但是这里所指的调通只是指PC端为Windows的,我用的Ubuntu系统,在Ubuntu下就没有调通,在PC端运行出之后发送数据等等都很正常,但是就是不显示任何图像,很让人郁闷,不知道有没有那位大虾在Linux下调通的,欢迎交流!

    下面就贴代码了:
PC端(目前仅Windows下起作用):
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Transparency;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.PixelInterleavedSampleModel;
import java.awt.image.Raster;
import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Main extends Frame {
    private static final long serialVersionUID = 1L;

    private BufferedImage im;

    // 图像信息
    // private final int width = 480;
    // private final int height = 320;
    private static final int width = 240;

    private static final int height = 160;

    private static final int numBands = 3;

    private static final int dataLen = 57600;// 307200 OR 230400//57600 76800

    private static final int tt = 28800;// 14400;//28800;

    // 图像数组

    private byte[] byteArray = new byte[width * height * numBands];// 图像RGB数组

    private byte[] yuv420sp = new byte[dataLen];// 图像YUV数组

    private static final int[] bandOffsets = new int[] {
            0, 1, 2
    };

    private static final SampleModel sampleModel = new PixelInterleavedSampleModel(
            DataBuffer.TYPE_BYTE, width, height, 3, width * 3, bandOffsets);

    // ColorModel
    private static final ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);

    private static final ComponentColorModel cm = new ComponentColorModel(cs, false, false,
            Transparency.OPAQUE, DataBuffer.TYPE_BYTE);

    public Main() {
        super("Flushing");
        updateIM();
        setSize(480, 320);
        // 窗口关闭方法
        this.addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowClosing(java.awt.event.WindowEvent e) {
                System.exit(0);
            }
        });
        // 窗口居中
        this.setLocationRelativeTo(null);
        this.setResizable(false);
        this.setVisible(true);
        this.getData();
    }

    public void update(Graphics g) {
        paint(g);
    }

    public void paint(Graphics g) {
        g.drawImage(im, 0, 0, 480, 320, this);
    }

    public void getData() {
        try {
            System.out.print("等待连接……/n");
            ServerSocket server = new ServerSocket(8899);

            Socket socket = server.accept();
            System.out.print("已建立连接!/n");
            DataInputStream dis = new DataInputStream(socket.getInputStream());
            DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
            while (true) {
                for (int i = 0; i < dataLen / tt; i++) {
                    dis.read(yuv420sp, i * tt, tt);
                }
                // 得到数据之后立即更新显示
                updateIM();
                im.flush();
                repaint();

                dos.writeBoolean(true);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private void updateIM() {
        try {
            // 解析YUV成RGB格式
            decodeYUV420SP(byteArray, yuv420sp, width, height);
            DataBuffer dataBuffer = new DataBufferByte(byteArray, numBands);
            WritableRaster wr = Raster.createWritableRaster(sampleModel, dataBuffer,
                    new Point(0, 0));
            im = new BufferedImage(cm, wr, false, null);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private static void decodeYUV420SP(byte[] rgbBuf, byte[] yuv420sp, int width, int height) {
        final int frameSize = width * height;
        if (rgbBuf == null)
            throw new NullPointerException("buffer 'rgbBuf' is null");
        if (rgbBuf.length < frameSize * 3)
            throw new IllegalArgumentException("buffer 'rgbBuf' size " + rgbBuf.length
                    + " < minimum " + frameSize * 3);

        if (yuv420sp == null)
            throw new NullPointerException("buffer 'yuv420sp' is null");

        if (yuv420sp.length < frameSize * 3 / 2)
            throw new IllegalArgumentException("buffer 'yuv420sp' size " + yuv420sp.length
                    + " < minimum " + frameSize * 3 / 2);

        int i = 0, y = 0;
        int uvp = 0, u = 0, v = 0;
        int y1192 = 0, r = 0, g = 0, b = 0;

        for (int j = 0, yp = 0; j < height; j++) {
            uvp = frameSize + (j >> 1) * width;
            u = 0;
            v = 0;
            for (i = 0; i < width; i++, yp++) {
                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;
                }

                y1192 = 1192 * y;
                r = (y1192 + 1634 * v);
                g = (y1192 - 833 * v - 400 * u);
                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;

                rgbBuf[yp * 3] = (byte) (r >> 10);
                rgbBuf[yp * 3 + 1] = (byte) (g >> 10);
                rgbBuf[yp * 3 + 2] = (byte) (b >> 10);
            }
        }
    }

    public static void main(String[] args) {
        // Frame f =
        new Main();
    }
}

Android端:
Java代码:
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;

import android.app.Activity;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.SurfaceHolder.Callback;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;

public class MainActivity extends Activity implements Callback, OnClickListener {
    private SurfaceView mSurfaceView = null;

    private SurfaceHolder mSurfaceHolder = null;

    private Camera mCamera = null;

    private boolean mPreviewRunning = false;

    // 连接相关
    private EditText remoteIP = null;

    private Button connect = null;

    private String remoteIPStr = null;

    // 视频数据
    private StreamIt streamIt = null;

    public static Kit kit = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        getWindow().setFormat(PixelFormat.TRANSLUCENT);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);

        setContentView(R.layout.main);

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

        remoteIP = (EditText) this.findViewById(R.id.remoteIP);
        connect = (Button) this.findViewById(R.id.connect);
        connect.setOnClickListener(this);

    }

    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        if (mPreviewRunning) {
            mCamera.stopPreview();
        }
        Camera.Parameters p = mCamera.getParameters();
        p.setPreviewSize(width, height);
        streamIt = new StreamIt();
        kit = new Kit();
        mCamera.setPreviewCallback(streamIt);

        mCamera.setParameters(p);
        try {
            mCamera.setPreviewDisplay(holder);
        } catch (Exception ex) {
        }
        mCamera.startPreview();
        mPreviewRunning = true;
    }

    public void surfaceCreated(SurfaceHolder holder) {
        mCamera = Camera.open();
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        mCamera.stopPreview();
        mPreviewRunning = false;
        mCamera.release();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        try {
            super.onConfigurationChanged(newConfig);
            if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
            } else if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
            }
        } catch (Exception ex) {
        }
    }

    class Kit implements Runnable {
        private boolean run = true;

        // private final int dataLen=57600; //307200 OR 230400 76800 OR 57600
        private final int tt = 28800;

        public void run() {
            // TODO Auto-generated method stub
            try {
                Socket socket = new Socket("219.232.191.146", 8899);
                // Socket socket = new Socket("10.0.2.15", 8899);

                DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
                DataInputStream dis = new DataInputStream(socket.getInputStream());
                while (run) {
                    dos.write(streamIt.yuv420sp, 0, 28800);
                    dos.write(streamIt.yuv420sp, 28800, 28800);

                    dis.readBoolean();
                    Thread.sleep(155);
                }
            } catch (Exception ex) {
                run = false;
                ex.printStackTrace();
            }
        }

    }

    @Override
    public void onClick(View view) {
        // TODO Auto-generated method stub
        if (view == connect) {// 连接函数
            // remoteIPStr = remoteIP.getText().toString();
            new Thread(MainActivity.kit).start();
        }
    }
}

class StreamIt implements Camera.PreviewCallback {
    public byte[] yuv420sp = null;

    private boolean t = true;

    public void onPreviewFrame(byte[] data, Camera camera) {
        // TODO Auto-generated method stub
        // if(t){
        // t=false;
        // new Thread(AndroidVideo.kit).start();
        // }
        yuv420sp = data;
    }
}

布局文件:
<SurfaceView android:id="@+id/surface_camera"
android:layout_width="240px" android:layout_height="160px">
</SurfaceView>
还要记得在AndroidManifest.xml中添加如下的权限声明:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>

这样就可以跑通了,效果还是很不错的,我用的WIFI,所有绿屏的现象还是比较少的,比较流畅。
遗憾的是Ubuntu下没能调通。还需要努力阿!

你可能感兴趣的:(android 视频流采集)