该视频实现是基于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>