Android實時監控項目第四篇:后臺線程發送預覽幀視頻數據

出處:http://blog.csdn.net/ns_code/article/details/13005125

還記得上篇提到的setPreviewCallback(Camera.PreviewCallback cb)函數嗎?我們在開始預覽幀視頻之前,調用的它,這里要注意其內部的Camera.PreviewCallback類型的參數,我們需要寫一個類繼承Camera.PreviewCallback的類,在該類中覆寫public void onPreviewFrame(byte[] data, Camera camera)方法,這里的data參數保存的即是預覽幀是視頻數據,一旦程序調用Camera.PreviewCallback接口,便會自動調用發方法,因此當我們在開始預覽幀視頻之前調用setPreviewCallback(Camera.PreviewCallback cb)函數時,便會回調該方法,理論上來說我們在這個方法中寫發送幀視頻的代碼就行了,但實際上我們并不能這么做,因為發送視頻數據是一個很耗時的操作,為了防止UI線程阻塞,我們需要另外開啟一個線程,在該線程中實現視頻的發送操作。

這里我們采用AsyncTask<Void, Void, Void>后臺線程,因此我們需要再寫一個類,繼承AsyncTask<Void, Void, Void>抽象類,并覆寫其中的protected Void doInBackground(Void... params)方法,在該方法中編寫發送視頻數據的程序即可,這里要注意形參的含義,因為的項目中不需要用到這三個參數,因此全部傳入Void.

//該方法運行在后臺線程中,主要負責執行耗時的后臺計算傳輸等工作,
//實際的后臺操作被UI Thread調用時,該方法被回調
@Override
protected Void doInBackground(Void... params) {
//cam = (CameraActivity)context;
Size size = cam.getCamera().getParameters().getPreviewSize();
int wide = size.width;
int high = size.height;
YuvImage image = new YuvImage(data, ImageFormat.NV21, wide, high, null);
//因為要實時處理視頻流,因此用內存操作流比較合適
ByteArrayOutputStream os = new ByteArrayOutputStream(data.length);
if(!image.compressToJpeg(new Rect(0, 0, wide, high), 100, os)){
    return null;
}
send(os);
return null;
}

這里倒數第三行的send(os)記為發送視頻的操作,當然,如果你是做其他的操作,而不是傳輸視頻數據,你也可以將其改為其他的函數,比如做街景檢測、人臉車牌識別等,而其他代碼基本不用修改,發送視頻的send方法基本就是按照TCP協議編寫,在JAVA中是用Socket類編寫客戶端的代碼:

//發送視頻流到PC端,這里傳遞過來的參數os中保存的是視頻輸出流數據
private void send(ByteArrayOutputStream os) {
//定義用來保存從輸入流中讀取的視頻流數據的byte數組
byte[] buffer = new byte[1024];
try {
    Socket client = new Socket(ipName,30000);
    OutputStream outSocket = client.getOutputStream();
    //實例化內存輸入流,將視頻流數據寫入到內存中
    ByteArrayInputStream inputFromOs = new ByteArrayInputStream(os.toByteArray());
    //不斷從內存中讀取數據到buffer中,不斷再從buffer中將視頻數據發送到outSocket流中
    int amount;
    while((amount =inputFromOs.read(buffer) ) != -1)
        outSocket.write(buffer, 0, amount);
    //這里需要刷新用到緩沖區的輸出流
    os.flush();
    inputFromOs.close();
    os.close();
    outSocket.close();
} catch (UnknownHostException e) {
    e.printStackTrace();
    System.out.println("無法找到要連接的服務器");
} catch (IOException e) {
    e.printStackTrace();
    System.out.println("IO錯誤");
}

}

最后,什么時候調用protected Void doInBackground(Void... params)方法呢?看了上面那兩篇博客,應該也會明白了,當調用execute(Params... params)方法時,便會自動回調該方法,從而執行其內部代碼。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,833評論 25 708
  • public classCamera.Parametersextends Objectjava.lang.Obje...
    冉冉升起的小太陽閱讀 10,958評論 0 7
  • 從三月份找實習到現在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂視家的研發崗...
    時芥藍閱讀 42,341評論 11 349
  • 看到這篇文章,我想起了我小時候發新書的興奮勁。回到家,父母便拿出早幾天已經積攢準備好的干凈的牛皮紙,給我制作書皮了...
    小灰灰蟲蟲閱讀 337評論 0 0
  • 習慣晚睡的我,睡前習慣看點劇。無獨有偶,零點30分,我開始看《轉山》,《轉山》這部電影是“暴風”推薦的,看了一下...
    織了芽閱讀 326評論 0 0