该视频实现是基于TCP/IP协议的Socket(客户端)和ServerSocket(服务端)类,发送视频也就是不间断的发送图片。具体如下:
PC服务端:socketService类开启服务及监听,线程类TheadServer处理socket连接,并调用另外一个线程类ThreadClient发送图片到到另外一台手机上
视频发送端:MainVideoActivity 为显示界面,子线程ClientThread处理图片并发送到服务器
视频接受端:MainActivity为显示界面,子线程RevImageThread为接受服务端发送过来的图片
PC端 socketService类:
package com.socket;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class socketService {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(3000);
System.out.println("begin");
while(true){
new Thread(new TheadServer(ss)).start();
}
}
}
TheadServer 类:
package com.socket;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import javax.imageio.ImageIO;
public class TheadServer implements Runnable {
private Socket s = null;
private BufferedImage bufferedImage;
public InputStream ins;
public TheadServer(ServerSocket ss ) throws IOException{
System.out.println("start thread");
this.s=ss.accept();
}
@Override
public void run(){
try {
ins = s.getInputStream();
bufferedImage = ImageIO.read(ins);
ins.close();
ThreadClient tc = new ThreadClient(bufferedImage);
new Thread(tc).start();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
if(!s.isClosed())
s.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
ThreadClient类:
package com.socket;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.net.InetSocketAddress;
import java.net.Socket;
import javax.imageio.ImageIO;
public class ThreadClient implements Runnable , Serializable {
private BufferedImage bufferedImage;
public ThreadClient(BufferedImage image){
this.bufferedImage = image;
}
@Override
public void run() {
// TODO Auto-generated method stub
try {
Socket s = new Socket();
//接受视频端IP和端口
s.connect(new InetSocketAddress("10.0.56.234", 40000), 2000);
if(s.isConnected() && !s.isClosed()){
System.out.println("Client:"+s.getRemoteSocketAddress().toString());
OutputStream oos = s.getOutputStream();
ImageIO.write(bufferedImage,"JPG",oos);
oos.write("\n".getBytes());
oos.flush();
oos.close();
s.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
视频发送端:
MainVideoActivity 类
package com.example.realtimevideo;
import java.io.ByteArrayOutputStream;
import com.example.threadConnect.ClientThread;
import android.graphics.ImageFormat;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.hardware.Camera;
import android.hardware.Camera.PreviewCallback;
import android.hardware.Camera.Size;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Menu;
import android.view.SurfaceHolder;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.WindowManager;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.widget.Button;
public class MainVideoActivity extends Activity{
MyHandler handler;
ClientThread clientThread;
ByteArrayOutputStream outstream;
Button start;
Button stop;
SurfaceView surfaceView;
SurfaceHolder sfh;
Camera camera;
boolean isPreview = false; //是否在浏览中
int screenWidth=300, screenHeight=300;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 设置全屏
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_main_video);
handler = new MyHandler();
clientThread = new ClientThread(handler);
new Thread(clientThread).start();
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
screenWidth = dm.widthPixels;// 获取屏幕分辨率宽度
screenHeight = dm.heightPixels;
start = (Button)findViewById(R.id.start);
stop = (Button)findViewById(R.id.stop);
surfaceView = (SurfaceView)findViewById(R.id.surfaceView);
sfh = surfaceView.getHolder();
sfh.setFixedSize(screenWidth, screenHeight/4*3);
sfh.addCallback(new Callback(){
@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2,
int arg3) {
// TODO Auto-generated method stub
}
@Override
public void surfaceCreated(SurfaceHolder arg0) {
// TODO Auto-generated method stub
initCamera();
}
@Override
public void surfaceDestroyed(SurfaceHolder arg0) {
if (camera != null) {
if (isPreview)
camera.stopPreview();
camera.release();
camera = null;
}
}
});
//开启连接服务
start.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View arg0) {
start.setEnabled(false);
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main_video, menu);
return true;
}
@SuppressWarnings("deprecation")
private void initCamera() {
if (!isPreview) {
camera = Camera.open();
ClientThread.size = camera.getParameters().getPreviewSize();
}
if (camera != null && !isPreview) {
try{
camera.setPreviewDisplay(sfh); // 通过SurfaceView显示取景画面
Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewSize(screenWidth, screenHeight/4*3);
/* 每秒从摄像头捕获5帧画面, */
parameters.setPreviewFrameRate(5);
parameters.setPictureFormat(ImageFormat.NV21); // 设置图片格式
parameters.setPictureSize(screenWidth, screenHeight/4*3); // 设置照片的大小
camera.setDisplayOrientation(90);
camera.setPreviewCallback(new PreviewCallback(){
@Override
public void onPreviewFrame(byte[] data, Camera c) {
// TODO Auto-generated method stub
Size size = camera.getParameters().getPreviewSize();
try{
//调用image.compressToJpeg()将YUV格式图像数据data转为jpg格式
YuvImage image = new YuvImage(data, ImageFormat.NV21, size.width, size.height, null);
if(image!=null){
Message msg = clientThread.revHandler.obtainMessage();
msg.what=0x111;
msg.obj=image;
clientThread.revHandler.sendMessage(msg);
/*outstream = new ByteArrayOutputStream();
image.compressToJpeg(new Rect(0, 0, size.width, size.height), 80, outstream);
outstream.flush();
new Thread(clientThread).start();*/
}
}catch(Exception ex){
Log.e("Sys","Error:"+ex.getMessage());
}
}
});
camera.startPreview(); // 开始预览
camera.autoFocus(null); // 自动对焦
} catch (Exception e) {
e.printStackTrace();
}
isPreview = true;
}
}
static class MyHandler extends Handler{
@Override
public void handleMessage(Message msg){
if(msg.what==0x222){
//返回信息显示代码
}
}
}
}
ClientThread类:
package com.example.threadConnect;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.hardware.Camera.Size;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
public class ClientThread implements Runnable {
private static Socket socket ;
private static ByteArrayOutputStream outputstream;
private static byte byteBuffer[] = new byte[1024];
public static Size size;
//向UI线程发送消息
private Handler handler;
//接受UI线程消息
public MyHandler revHandler;
BufferedReader br= null;
static OutputStream os = null;
public ClientThread(Handler handler){
this.handler=handler;
}
@Override
public void run() {
Looper.prepare();
//接受UI发来的信息
revHandler = new MyHandler();
Looper.loop();
}
public static class MyHandler extends Handler{
@Override
public void handleMessage(Message msg){
if(msg.what==0x111){
try {
socket = new Socket("10.0.56.232",3000);
os = socket.getOutputStream();
YuvImage image = (YuvImage) msg.obj;
if(socket.isOutputShutdown()){
socket.getKeepAlive();
}else{
os = socket.getOutputStream();
outputstream = new ByteArrayOutputStream();
image.compressToJpeg(new Rect(0, 0, size.width, size.height), 80, outputstream);
ByteArrayInputStream inputstream = new ByteArrayInputStream(outputstream.toByteArray());
int amount;
while ((amount = inputstream.read(byteBuffer)) != -1) {
os.write(byteBuffer, 0, amount);
}
os.write("\n".getBytes());
outputstream.flush();
outputstream.close();
os.flush();
os.close();
socket.close();
}
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
布局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context=".MainVideoActivity" >
<SurfaceView
android:id="@+id/surfaceView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="fitCenter"
/>
<Button
android:id="@+id/start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/start"/>
<Button
android:id="@+id/stop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/stop"/>
</LinearLayout>
视频接受端:
MainActivity:
package com.example.socketphone;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;
import android.view.Menu;
import android.widget.ImageView;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.net.Socket;
import java.net.ServerSocket;
import com.example.Thread.RevImageThread;
public class MainActivity extends Activity {
RevImageThread revImageThread;
public static ImageView image;
private static Bitmap bitmap;
private static final int COMPLETED = 0x111;
private MyHandler handler;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
image=(ImageView)findViewById(R.id.imageView1);
handler = new MyHandler();
revImageThread = new RevImageThread(handler);
new Thread(revImageThread).start();
}
static class MyHandler extends Handler{
@Override
public void handleMessage(Message msg){
if (msg.what == COMPLETED) {
bitmap = (Bitmap)msg.obj;
image.setImageBitmap(bitmap);
super.handleMessage(msg);
}
}
}
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
RevImageThread类:
package com.example.Thread;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
public class RevImageThread implements Runnable {
public Socket s;
public ServerSocket ss;
//向UI线程发送消息
private Handler handler;
private Bitmap bitmap;
private static final int COMPLETED = 0x111;
public RevImageThread(Handler handler){
this.handler = handler;
}
public void run()
{
byte [] buffer = new byte[1024];
int len = 0;
try {
ss = new ServerSocket(40000);
} catch (IOException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
InputStream ins = null;
while(true){
try {
s = ss.accept();
Log.e("strat","ljq");
ins = s.getInputStream();
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
while( (len=ins.read(buffer)) != -1){
outStream.write(buffer, 0, len);
}
ins.close();byte data[] = outStream.toByteArray();
bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
Message msg =handler.obtainMessage();
msg.what = COMPLETED;
msg.obj = bitmap;
handler.sendMessage(msg);
outStream.flush();
outStream.close();
if(!s.isClosed()){
s.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//Bitmap bitmap = BitmapFactory.decodeStream(ins);
}
}
}
布局:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<ImageView
android:id="@+id/imageView1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:src="@drawable/ic_launcher"/>
</RelativeLayout>