opencv讀取視頻實時傳輸到Android端

在傳輸視頻音頻的時候一般選用UDP協議,因爲TCP會檢查傳輸的數據包是否正確,當錯誤時要求重傳,這樣在觀看實時視頻時會造成卡頓。UDP並不會去要求重傳,它會把錯誤的直接丟掉,而丟掉少許的數據包對我們觀看視頻來說並不會造成太大的影響,所以選用UDP協議。
傳輸的Python代碼如下:

import cv2
import socket
sever = socket.socket()
server=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #創建socket對象
ser=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #創建socket對象
server.bind(("",8888))
filePath = r"F:\Python\picture\vtest.avi"
camera = cv2.VideoCapture(filePath)
re = server.recvfrom(2048)
while True:
    ret,frame = camera.read()
    if not ret:
        break
    frame = cv2.resize(frame,(1000,700))
    data = cv2.imencode(".jpg", frame, [int(cv2.IMWRITE_JPEG_QUALITY), 15])[1]
    ser.sendto(data,(re[1][0],9999))
server.close()
ser.close()

imencode將傳輸的每一幀編碼爲JPG格式,後面的15是壓縮率,取值在1到100之間,並且數值越大傳輸效果越好。
Android端代碼如下:

package com.example.bishe;

import androidx.appcompat.app.AppCompatActivity;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class MainActivity extends AppCompatActivity {

    private final static String SEND_IP = "192.168.2.110";  //發送IP
    private final static int SEND_PORT = 8888;               //發送端口號
    private final static int RECEIVE_PORT = 9999;            //接收端口號

    private boolean listenStatus = true;  //接收線程的循環標識
    private byte[] buf;
    Bitmap bp;

    private DatagramSocket receiveSocket;
    private DatagramSocket sendSocket;
    private DatagramSocket reveSocket;
    private InetAddress serverAddr;
    private SendHandler sendHandler = new SendHandler();
    private ReceiveHandler receiveHandler = new ReceiveHandler();

    private ImageView imgShow;
    private Button btn;


    class ReceiveHandler extends Handler{
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
           imgShow.setImageBitmap(bp);


        }
    }





    class SendHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
        }
    }


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        imgShow = findViewById(R.id.img_show);
        btn = findViewById(R.id.btn_send);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new UdpSendThread().start();
            }
        });
        new UdpReceiveThread().start();

    }
    /*
     *   UDP數據接受線程
     * */
    public class UdpReceiveThread extends Thread
    {
        @Override
        public void run()
        {
            try
            {

                reveSocket = new DatagramSocket(RECEIVE_PORT);
                serverAddr = InetAddress.getByName(SEND_IP);
                //ByteArrayOutputStream out = new ByteArrayOutputStream();
                while(listenStatus)
                {
                    byte[] inBuf= new byte[1024*1024];
                    DatagramPacket inPacket=new DatagramPacket(inBuf,inBuf.length);
                    //out.write(inPacket.getData());
                    reveSocket.receive(inPacket);
                    if(!inPacket.getAddress().equals(serverAddr)){
                        throw new IOException("未知名的報文");
                    }

                    ByteArrayInputStream in = new ByteArrayInputStream(inPacket.getData());
                    receiveHandler.sendEmptyMessage(1);
                    bp = BitmapFactory.decodeStream(in);


                }


            } catch (Exception e)
            {
                e.printStackTrace();
            }finally {
                reveSocket.close();
            }
        }
    }

    /*
     *   UDP數據發送線程
     * */
    public class UdpSendThread extends Thread {
        @Override
        public void run() {
            try {
                buf = "i am an android developer, hello android! ".getBytes();

                // 創建DatagramSocket對象,使用端口8888
                sendSocket = new DatagramSocket(8888);

                serverAddr = InetAddress.getByName(SEND_IP);

                DatagramPacket outPacket = new DatagramPacket(buf, buf.length, serverAddr, SEND_PORT);
                sendSocket.send(outPacket);

                sendSocket.close();
                sendHandler.sendEmptyMessage(1);

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

佈局文件如下:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_margin="5dp"
        android:gravity="center_horizontal"
        android:orientation="vertical"
        android:layout_height="match_parent">
        <ImageView
            android:layout_width="match_parent"
            android:id="@+id/img_show"
            android:layout_marginTop="30dp"
            android:background="#000000"
            android:layout_height="300dp">
        </ImageView>
        <Button
            android:layout_width="wrap_content"

            android:layout_marginTop="10dp"
            android:id="@+id/btn_send"
            android:text="鏈接到服務器"
            android:textSize="30sp"
            android:layout_height="wrap_content">
        </Button>
    </LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

效果圖:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章