1、基于Socket的Android手机视频实时传输基于Socket的Android手机视频实时传输基于Socket的Android手机视频实时传输肖泽云首先,简单介绍一下原理。主要是在手机客户端(Android)通过实现Camera.PreviewCallback接口,在其onPreviewFrame重载函数里面获取摄像头当前图像数据,然后通过Socket将图像数据和相关的用户名、命令等数据传输到服务器程序中。服务器端(PC端)采用C#编写,通过监听相应的端口,在获取数据后进行相应的命令解析和图像数据还原,然后将图像数据传递至PictureBox控件中用于显示,这样就实现了手机摄像头的视频数据实
2、时传输到服务器上。如果需要将这些视频进行转发,通过服务器再将这些数据复制转发即可。效果如下:对于Android客户端上主要有几个地方需要注意,第一个就是Socket通信。Socket通信可以通过Socket类来实现,直接结合PrintWriter来写入命令,如下定义的一个专门用于发送命令的线程类,当要连接到服务器和与服务器断开时,都需要发送命令通知服务器,此外在进行其他文字传输时也可以采用该方法,具体代码如下: /*发送命令线程*/ class MySendCommondThread extends Thread private String commond; public MySendCom
3、mondThread(String commond) mond=commond; public void run() /实例化Socket try Socket socket=new Socket(serverUrl,serverPort); PrintWriter out = new PrintWriter(socket.getOutputStream(); out.println(commond); out.flush(); catch (UnknownHostException e) catch (IOException e) 如果是采用Socket发送文件,则可以通过OutputStr
4、eam将ByteArrayInputStream数据流读入,而文件数据流则转换为ByteArrayOutputStream。如果需要在前面添加文字,同样也需要转换为byte,然后写入OutputStream。同样也可以通过定义一个线程类发送文件,如下: /*发送文件线程*/ class MySendFileThread extends Thread private String username; private String ipname; private int port; private byte byteBuffer = new byte1024; private OutputStre
5、am outsocket; private ByteArrayOutputStream myoutputstream; public MySendFileThread(ByteArrayOutputStream myoutputstream,String username,String ipname,int port) this.myoutputstream = myoutputstream; this.username=username; this.ipname = ipname; this.port=port; try myoutputstream.close(); catch (IOEx
6、ception e) e.printStackTrace(); public void run() try /将图像数据通过Socket发送出去 Socket tempSocket = new Socket(ipname, port); outsocket = tempSocket.getOutputStream(); /写入头部数据信息 String msg=.URLEncoder.encode(PHONEVIDEO|+username+|,utf-8); byte buffer= msg.getBytes(); outsocket.write(buffer); ByteArrayInput
7、Stream inputstream = new ByteArrayInputStream(myoutputstream.toByteArray(); int amount; while (amount = inputstream.read(byteBuffer) != -1) outsocket.write(byteBuffer, 0, amount); myoutputstream.flush(); myoutputstream.close(); tempSocket.close(); catch (IOException e) e.printStackTrace(); 而获取摄像头当前图
8、像的关键在于onPreviewFrame()重载函数里面,该函数里面有两个参数,第一个参数为byte,为摄像头当前图像数据,通过YuvImage可以将该数据转换为图片文件,同时还可用对该图片进行压缩和裁剪,将图片进行压缩转换后转换为 ByteArrayOutputStream数据,即前面发送文件线程类中所需的文件数据,然后采用线程发送文件,如下代码: Override public void onPreviewFrame(byte data, Camera camera) / TODO Auto-generated method stub /如果没有指令传输视频,就先不传 if(!startS
9、endVideo) return; if(tempPreRateVideoPreRate) tempPreRate+; return; tempPreRate=0; try if(data!=null) YuvImage image = new YuvImage(data,VideoFormatIndex, VideoWidth, VideoHeight,null); if(image!=null) ByteArrayOutputStream outstream = new ByteArrayOutputStream(); /在此设置图片的尺寸和质量 pressToJpeg(new Rect(
10、0, 0, (int)(VideoWidthRatio*VideoWidth), (int)(VideoHeightRatio*VideoHeight), VideoQuality, outstream); outstream.flush(); /启用线程将图像数据发送出去 Thread th = new MySendFileThread(outstream,pUsername,serverUrl,serverPort); th.start(); catch (IOException e) e.printStackTrace(); 值得注意的是,在调试中YuvImage可能找不到,在模拟机上无
11、法执行该过程,但是编译后在真机中可以通过。此外,以上传输文字字符都是采用UTF编码,在服务器端接收时进行解析时需要采用对应的编码进行解析,否则可能会出现错误解析。Android客户端中关键的部分主要就这些,新建一个Android项目(项目名称为SocketCamera),在main布局中添加一个SurfaceView和两个按钮,如下图所示:然后在SocketCameraActivity.java中添加代码,具体如下:package com.xzy;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;i
12、mport java.io.IOException;import java.io.OutputStream;import java.io.PrintWriter;import .Socket;import .UnknownHostException;import android.app.Activity;import android.app.AlertDialog;import android.content.DialogInterface;import android.content.Intent;import android.content.SharedPreferences;import
13、 android.graphics.Rect;import android.graphics.YuvImage;import android.hardware.Camera;import android.hardware.Camera.Size;import android.os.Bundle;import android.preference.PreferenceManager;import android.view.Menu;import android.view.MenuItem;import android.view.SurfaceHolder;import android.view.
14、SurfaceView;import android.view.View;import android.view.WindowManager;import android.view.View.OnClickListener;import android.widget.Button;public class SocketCameraActivity extends Activity implements SurfaceHolder.Callback,Camera.PreviewCallback private SurfaceView mSurfaceview = null; / SurfaceV
15、iew对象:(视图组件)视频显示 private SurfaceHolder mSurfaceHolder = null; / SurfaceHolder对象:(抽象接口)SurfaceView支持类 private Camera mCamera = null; / Camera对象,相机预览 /*服务器地址*/ private String pUsername=XZY; /*服务器地址*/ private String serverUrl=192.168.1.100; /*服务器端口*/ private int serverPort=8888; /*视频刷新间隔*/ private int
16、VideoPreRate=1; /*当前视频序号*/ private int tempPreRate=0; /*视频质量*/ private int VideoQuality=85; /*发送视频宽度比例*/ private float VideoWidthRatio=1; /*发送视频高度比例*/ private float VideoHeightRatio=1; /*发送视频宽度*/ private int VideoWidth=320; /*发送视频高度*/ private int VideoHeight=240; /*视频格式索引*/ private int VideoFormatIn
17、dex=0; /*是否发送视频*/ private boolean startSendVideo=false; /*是否连接主机*/ private boolean connectedServer=false; private Button myBtn01, myBtn02; /* Called when the activity is first created. */ Override public void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState); setContentView(R.la
18、yout.main); /禁止屏幕休眠 getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); mSurfaceview = (SurfaceView) findViewById(R.id.camera_preview); myBtn01=(Button)findViewById(R.id.button1); myBtn02=(Button)findViewById(R.id.button2); /开始连接主机按钮
19、myBtn01.setOnClickListener(new OnClickListener() public void onClick(View v) /Common.SetGPSConnected(LoginActivity.this, false); if(connectedServer)/停止连接主机,同时断开传输 startSendVideo=false; connectedServer=false; myBtn02.setEnabled(false); myBtn01.setText(开始连接); myBtn02.setText(开始传输); /断开连接 Thread th = n
20、ew MySendCommondThread(PHONEDISCONNECT|+pUsername+|); th.start(); else/连接主机 /启用线程发送命令PHONECONNECT Thread th = new MySendCommondThread(PHONECONNECT|+pUsername+|); th.start(); connectedServer=true; myBtn02.setEnabled(true); myBtn01.setText(停止连接); ); myBtn02.setEnabled(false); myBtn02.setOnClickListene
21、r(new OnClickListener() public void onClick(View v) if(startSendVideo)/停止传输视频 startSendVideo=false; myBtn02.setText(开始传输); else / 开始传输视频 startSendVideo=true; myBtn02.setText(停止传输); ); Override public void onStart()/重新启动的时候 mSurfaceHolder = mSurfaceview.getHolder(); / 绑定SurfaceView,取得SurfaceHolder对象
22、mSurfaceHolder.addCallback(this); / SurfaceHolder加入回调接口 mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);/ 设置显示器类型,setType必须设置 /读取配置文件 SharedPreferences preParas = PreferenceManager.getDefaultSharedPreferences(SocketCameraActivity.this); pUsername=preParas.getString(Username, XZY); se
23、rverUrl=preParas.getString(ServerUrl, 192.168.0.100); String tempStr=preParas.getString(ServerPort, 8888); serverPort=Integer.parseInt(tempStr); tempStr=preParas.getString(VideoPreRate, 1); VideoPreRate=Integer.parseInt(tempStr); tempStr=preParas.getString(VideoQuality, 85); VideoQuality=Integer.par
24、seInt(tempStr); tempStr=preParas.getString(VideoWidthRatio, 100); VideoWidthRatio=Integer.parseInt(tempStr); tempStr=preParas.getString(VideoHeightRatio, 100); VideoHeightRatio=Integer.parseInt(tempStr); VideoWidthRatio=VideoWidthRatio/100f; VideoHeightRatio=VideoHeightRatio/100f; super.onStart(); O
25、verride protected void onResume() super.onResume(); InitCamera(); /*初始化摄像头*/ private void InitCamera() try mCamera = Camera.open(); catch (Exception e) e.printStackTrace(); Override protected void onPause() super.onPause(); try if (mCamera != null) mCamera.setPreviewCallback(null); / !这个必须在前,不然退出出错
26、mCamera.stopPreview(); mCamera.release(); mCamera = null; catch (Exception e) e.printStackTrace(); Override public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) / TODO Auto-generated method stub if (mCamera = null) return; mCamera.stopPreview(); mCamera.setPreviewCallback(thi
27、s); mCamera.setDisplayOrientation(90); /设置横行录制 /获取摄像头参数 Camera.Parameters parameters = mCamera.getParameters(); Size size = parameters.getPreviewSize(); VideoWidth=size.width; VideoHeight=size.height; VideoFormatIndex=parameters.getPreviewFormat(); mCamera.startPreview(); Override public void surfac
28、eCreated(SurfaceHolder holder) / TODO Auto-generated method stub try if (mCamera != null) mCamera.setPreviewDisplay(mSurfaceHolder); mCamera.startPreview(); catch (IOException e) e.printStackTrace(); Override public void surfaceDestroyed(SurfaceHolder holder) / TODO Auto-generated method stub if (nu
29、ll != mCamera) mCamera.setPreviewCallback(null); / !这个必须在前,不然退出出错 mCamera.stopPreview(); mCamera.release(); mCamera = null; Override public void onPreviewFrame(byte data, Camera camera) / TODO Auto-generated method stub /如果没有指令传输视频,就先不传 if(!startSendVideo) return; if(tempPreRateVideoPreRate) tempPreRate+; retur
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1