基于Socket的Android手机视频实时传输.docx

上传人:b****5 文档编号:8363528 上传时间:2023-01-30 格式:DOCX 页数:27 大小:413.44KB
下载 相关 举报
基于Socket的Android手机视频实时传输.docx_第1页
第1页 / 共27页
基于Socket的Android手机视频实时传输.docx_第2页
第2页 / 共27页
基于Socket的Android手机视频实时传输.docx_第3页
第3页 / 共27页
基于Socket的Android手机视频实时传输.docx_第4页
第4页 / 共27页
基于Socket的Android手机视频实时传输.docx_第5页
第5页 / 共27页
点击查看更多>>
下载资源
资源描述

基于Socket的Android手机视频实时传输.docx

《基于Socket的Android手机视频实时传输.docx》由会员分享,可在线阅读,更多相关《基于Socket的Android手机视频实时传输.docx(27页珍藏版)》请在冰豆网上搜索。

基于Socket的Android手机视频实时传输.docx

基于Socket的Android手机视频实时传输

基于Socket的Android手机视频实时传输

基于Socket的Android手机视频实时传输

肖泽云

首先,简单介绍一下原理。

主要是在手机客户端(Android)通过实现Camera.PreviewCallback接口,在其onPreviewFrame重载函数里面获取摄像头当前图像数据,然后通过Socket将图像数据和相关的用户名、命令等数据传输到服务器程序中。

服务器端(PC端)采用C#编写,通过监听相应的端口,在获取数据后进行相应的命令解析和图像数据还原,然后将图像数据传递至PictureBox控件中用于显示,这样就实现了手机摄像头的视频数据实时传输到服务器上。

如果需要将这些视频进行转发,通过服务器再将这些数据复制转发即可。

效果如下:

对于Android客户端上主要有几个地方需要注意,第一个就是Socket通信。

Socket通信可以通过Socket类来实现,直接结合PrintWriter来写入命令,如下定义的一个专门用于发送命令的线程类,当要连接到服务器和与服务器断开时,都需要发送命令通知服务器,此外在进行其他文字传输时也可以采用该方法,具体代码如下:

/**发送命令线程*/

classMySendCommondThreadextendsThread{

privateStringcommond;

publicMySendCommondThread(Stringcommond){

mond=commond;

}

publicvoidrun(){

//实例化Socket

try{

Socketsocket=newSocket(serverUrl,serverPort);

PrintWriterout=newPrintWriter(socket.getOutputStream());

out.println(commond);

out.flush();

}catch(UnknownHostExceptione){

}catch(IOExceptione){

}

}

}

如果是采用Socket发送文件,则可以通过OutputStream将ByteArrayInputStream数据流读入,而文件数据流则转换为ByteArrayOutputStream。

如果需要在前面添加文字,同样也需要转换为byte,然后写入OutputStream。

同样也可以通过定义一个线程类发送文件,如下:

/**发送文件线程*/

classMySendFileThreadextendsThread{

privateStringusername;

privateStringipname;

privateintport;

privatebytebyteBuffer[]=newbyte[1024];

privateOutputStreamoutsocket;

privateByteArrayOutputStreammyoutputstream;

publicMySendFileThread(ByteArrayOutputStreammyoutputstream,Stringusername,Stringipname,intport){

this.myoutputstream=myoutputstream;

this.username=username;

this.ipname=ipname;

this.port=port;

try{

myoutputstream.close();

}catch(IOExceptione){

e.printStackTrace();

}

}

publicvoidrun(){

try{

//将图像数据通过Socket发送出去

SockettempSocket=newSocket(ipname,port);

outsocket=tempSocket.getOutputStream();

//写入头部数据信息

Stringmsg=.URLEncoder.encode("PHONEVIDEO|"+username+"|","utf-8");

byte[]buffer=msg.getBytes();

outsocket.write(buffer);

ByteArrayInputStreaminputstream=newByteArrayInputStream(myoutputstream.toByteArray());

intamount;

while((amount=inputstream.read(byteBuffer))!

=-1){

outsocket.write(byteBuffer,0,amount);

}

myoutputstream.flush();

myoutputstream.close();

tempSocket.close();

}catch(IOExceptione){

e.printStackTrace();

}

}

}

而获取摄像头当前图像的关键在于onPreviewFrame()重载函数里面,该函数里面有两个参数,第一个参数为byte[],为摄像头当前图像数据,通过YuvImage可以将该数据转换为图片文件,同时还可用对该图片进行压缩和裁剪,将图片进行压缩转换后转换为ByteArrayOutputStream数据,即前面发送文件线程类中所需的文件数据,然后采用线程发送文件,如下代码:

@Override

publicvoidonPreviewFrame(byte[]data,Cameracamera){

//TODOAuto-generatedmethodstub

//如果没有指令传输视频,就先不传

if(!

startSendVideo)

return;

if(tempPreRate

tempPreRate++;

return;

}

tempPreRate=0;

try{

if(data!

=null)

{

YuvImageimage=newYuvImage(data,VideoFormatIndex,VideoWidth,VideoHeight,null);

if(image!

=null)

{

ByteArrayOutputStreamoutstream=newByteArrayOutputStream();

//在此设置图片的尺寸和质量

pressToJpeg(newRect(0,0,(int)(VideoWidthRatio*VideoWidth),

(int)(VideoHeightRatio*VideoHeight)),VideoQuality,outstream);

outstream.flush();

//启用线程将图像数据发送出去

Threadth=newMySendFileThread(outstream,pUsername,serverUrl,serverPort);

th.start();

}

}

}catch(IOExceptione){

e.printStackTrace();

}

}

值得注意的是,在调试中YuvImage可能找不到,在模拟机上无法执行该过程,但是编译后在真机中可以通过。

此外,以上传输文字字符都是采用UTF编码,在服务器端接收时进行解析时需要采用对应的编码进行解析,否则可能会出现错误解析。

Android客户端中关键的部分主要就这些,新建一个Android项目(项目名称为SocketCamera),在main布局中添加一个SurfaceView和两个按钮,如下图所示:

然后在SocketCameraActivity.java中添加代码,具体如下:

packagecom.xzy;

importjava.io.ByteArrayInputStream;

importjava.io.ByteArrayOutputStream;

importjava.io.IOException;

importjava.io.OutputStream;

importjava.io.PrintWriter;

import.Socket;

import.UnknownHostException;

importandroid.app.Activity;

importandroid.app.AlertDialog;

importandroid.content.DialogInterface;

importandroid.content.Intent;

importandroid.content.SharedPreferences;

importandroid.graphics.Rect;

importandroid.graphics.YuvImage;

importandroid.hardware.Camera;

importandroid.hardware.Camera.Size;

importandroid.os.Bundle;

importandroid.preference.PreferenceManager;

importandroid.view.Menu;

importandroid.view.MenuItem;

importandroid.view.SurfaceHolder;

importandroid.view.SurfaceView;

importandroid.view.View;

importandroid.view.WindowManager;

importandroid.view.View.OnClickListener;

importandroid.widget.Button;

publicclassSocketCameraActivityextendsActivityimplementsSurfaceHolder.Callback,

Camera.PreviewCallback{

privateSurfaceViewmSurfaceview=null;//SurfaceView对象:

(视图组件)视频显示

privateSurfaceHoldermSurfaceHolder=null;//SurfaceHolder对象:

(抽象接口)SurfaceView支持类

privateCameramCamera=null;//Camera对象,相机预览

/**服务器地址*/

privateStringpUsername="XZY";

/**服务器地址*/

privateStringserverUrl="192.168.1.100";

/**服务器端口*/

privateintserverPort=8888;

/**视频刷新间隔*/

privateintVideoPreRate=1;

/**当前视频序号*/

privateinttempPreRate=0;

/**视频质量*/

privateintVideoQuality=85;

/**发送视频宽度比例*/

privatefloatVideoWidthRatio=1;

/**发送视频高度比例*/

privatefloatVideoHeightRatio=1;

/**发送视频宽度*/

privateintVideoWidth=320;

/**发送视频高度*/

privateintVideoHeight=240;

/**视频格式索引*/

privateintVideoFormatIndex=0;

/**是否发送视频*/

privatebooleanstartSendVideo=false;

/**是否连接主机*/

privatebooleanconnectedServer=false;

privateButtonmyBtn01,myBtn02;

/**Calledwhentheactivityisfirstcreated.*/

@Override

publicvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.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);

//开始连接主机按钮

myBtn01.setOnClickListener(newOnClickListener(){

publicvoidonClick(Viewv){

//Common.SetGPSConnected(LoginActivity.this,false);

if(connectedServer){//停止连接主机,同时断开传输

startSendVideo=false;

connectedServer=false;

myBtn02.setEnabled(false);

myBtn01.setText("开始连接");

myBtn02.setText("开始传输");

//断开连接

Threadth=newMySendCommondThread("PHONEDISCONNECT|"+pUsername+"|");

th.start();

}

else//连接主机

{

//启用线程发送命令PHONECONNECT

Threadth=newMySendCommondThread("PHONECONNECT|"+pUsername+"|");

th.start();

connectedServer=true;

myBtn02.setEnabled(true);

myBtn01.setText("停止连接");

}

}});

myBtn02.setEnabled(false);

myBtn02.setOnClickListener(newOnClickListener(){

publicvoidonClick(Viewv){

if(startSendVideo)//停止传输视频

{

startSendVideo=false;

myBtn02.setText("开始传输");

}

else{//开始传输视频

startSendVideo=true;

myBtn02.setText("停止传输");

}

}});

}

@Override

publicvoidonStart()//重新启动的时候

{

mSurfaceHolder=mSurfaceview.getHolder();//绑定SurfaceView,取得SurfaceHolder对象

mSurfaceHolder.addCallback(this);//SurfaceHolder加入回调接口

mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);//设置显示器类型,setType必须设置

//读取配置文件

SharedPreferencespreParas=PreferenceManager.getDefaultSharedPreferences(SocketCameraActivity.this);

pUsername=preParas.getString("Username","XZY");

serverUrl=preParas.getString("ServerUrl","192.168.0.100");

StringtempStr=preParas.getString("ServerPort","8888");

serverPort=Integer.parseInt(tempStr);

tempStr=preParas.getString("VideoPreRate","1");

VideoPreRate=Integer.parseInt(tempStr);

tempStr=preParas.getString("VideoQuality","85");

VideoQuality=Integer.parseInt(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();

}

@Override

protectedvoidonResume(){

super.onResume();

InitCamera();

}

/**初始化摄像头*/

privatevoidInitCamera(){

try{

mCamera=Camera.open();

}catch(Exceptione){

e.printStackTrace();

}

}

@Override

protectedvoidonPause(){

super.onPause();

try{

if(mCamera!

=null){

mCamera.setPreviewCallback(null);//!

这个必须在前,不然退出出错

mCamera.stopPreview();

mCamera.release();

mCamera=null;

}

}catch(Exceptione){

e.printStackTrace();

}

}

@Override

publicvoidsurfaceChanged(SurfaceHolderarg0,intarg1,intarg2,intarg3){

//TODOAuto-generatedmethodstub

if(mCamera==null){

return;

}

mCamera.stopPreview();

mCamera.setPreviewCallback(this);

mCamera.setDisplayOrientation(90);//设置横行录制

//获取摄像头参数

Camera.Parametersparameters=mCamera.getParameters();

Sizesize=parameters.getPreviewSize();

VideoWidth=size.width;

VideoHeight=size.height;

VideoFormatIndex=parameters.getPreviewFormat();

mCamera.startPreview();

}

@Override

publicvoidsurfaceCreated(SurfaceHolderholder){

//TODOAuto-generatedmethodstub

try{

if(mCamera!

=null){

mCamera.setPreviewDisplay(mSurfaceHolder);

mCamera.startPreview();

}

}catch(IOExceptione){

e.printStackTrace();

}

}

@Override

publicvoidsurfaceDestroyed(SurfaceHolderholder){

//TODOAuto-generatedmethodstub

if(null!

=mCamera){

mCamera.setPreviewCallback(null);//!

这个必须在前,不然退出出错

mCamera.stopPreview();

mCamera.release();

mCamera=null;

}

}

@Override

publicvoidonPreviewFrame(byte[]data,Cameracamera){

//TODOAuto-generatedmethodstub

//如果没有指令传输视频,就先不传

if(!

startSendVideo)

return;

if(tempPreRate

tempPreRate++;

retur

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 初中教育

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1