出處:http://blog.csdn.net/ns_code/article/details/13005125
還記得上篇提到的setPreviewCallback(Camera.PreviewCallback cb)函數(shù)嗎策严?我們在開始預(yù)覽幀視頻之前,調(diào)用的它烦感,這里要注意其內(nèi)部的Camera.PreviewCallback類型的參數(shù)逝变,我們需要寫一個類繼承Camera.PreviewCallback的類基茵,在該類中覆寫public void onPreviewFrame(byte[] data, Camera camera)方法,這里的data參數(shù)保存的即是預(yù)覽幀是視頻數(shù)據(jù)壳影,一旦程序調(diào)用Camera.PreviewCallback接口拱层,便會自動調(diào)用發(fā)方法,因此當(dāng)我們在開始預(yù)覽幀視頻之前調(diào)用setPreviewCallback(Camera.PreviewCallback cb)函數(shù)時态贤,便會回調(diào)該方法舱呻,理論上來說我們在這個方法中寫發(fā)送幀視頻的代碼就行了醋火,但實際上我們并不能這么做悠汽,因為發(fā)送視頻數(shù)據(jù)是一個很耗時的操作箱吕,為了防止UI線程阻塞,我們需要另外開啟一個線程柿冲,在該線程中實現(xiàn)視頻的發(fā)送操作茬高。
這里我們采用AsyncTask<Void, Void, Void>后臺線程,因此我們需要再寫一個類假抄,繼承AsyncTask<Void, Void, Void>抽象類怎栽,并覆寫其中的protected Void doInBackground(Void... params)方法,在該方法中編寫發(fā)送視頻數(shù)據(jù)的程序即可宿饱,這里要注意形參的含義熏瞄,因為的項目中不需要用到這三個參數(shù),因此全部傳入Void.
//該方法運(yùn)行在后臺線程中谬以,主要負(fù)責(zé)執(zhí)行耗時的后臺計算傳輸?shù)裙ぷ鳎?//實際的后臺操作被UI Thread調(diào)用時强饮,該方法被回調(diào)
@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);
//因為要實時處理視頻流,因此用內(nèi)存操作流比較合適
ByteArrayOutputStream os = new ByteArrayOutputStream(data.length);
if(!image.compressToJpeg(new Rect(0, 0, wide, high), 100, os)){
return null;
}
send(os);
return null;
}
這里倒數(shù)第三行的send(os)記為發(fā)送視頻的操作为黎,當(dāng)然邮丰,如果你是做其他的操作,而不是傳輸視頻數(shù)據(jù)铭乾,你也可以將其改為其他的函數(shù)剪廉,比如做街景檢測、人臉車牌識別等炕檩,而其他代碼基本不用修改斗蒋,發(fā)送視頻的send方法基本就是按照TCP協(xié)議編寫,在JAVA中是用Socket類編寫客戶端的代碼:
//發(fā)送視頻流到PC端,這里傳遞過來的參數(shù)os中保存的是視頻輸出流數(shù)據(jù)
private void send(ByteArrayOutputStream os) {
//定義用來保存從輸入流中讀取的視頻流數(shù)據(jù)的byte數(shù)組
byte[] buffer = new byte[1024];
try {
Socket client = new Socket(ipName,30000);
OutputStream outSocket = client.getOutputStream();
//實例化內(nèi)存輸入流笛质,將視頻流數(shù)據(jù)寫入到內(nèi)存中
ByteArrayInputStream inputFromOs = new ByteArrayInputStream(os.toByteArray());
//不斷從內(nèi)存中讀取數(shù)據(jù)到buffer中吹泡,不斷再從buffer中將視頻數(shù)據(jù)發(fā)送到outSocket流中
int amount;
while((amount =inputFromOs.read(buffer) ) != -1)
outSocket.write(buffer, 0, amount);
//這里需要刷新用到緩沖區(qū)的輸出流
os.flush();
inputFromOs.close();
os.close();
outSocket.close();
} catch (UnknownHostException e) {
e.printStackTrace();
System.out.println("無法找到要連接的服務(wù)器");
} catch (IOException e) {
e.printStackTrace();
System.out.println("IO錯誤");
}
}
最后,什么時候調(diào)用protected Void doInBackground(Void... params)方法呢经瓷?看了上面那兩篇博客爆哑,應(yīng)該也會明白了,當(dāng)調(diào)用execute(Params... params)方法時舆吮,便會自動回調(diào)該方法揭朝,從而執(zhí)行其內(nèi)部代碼。