在前几篇已经顺利的使用serversocket线程把远程推送的流媒体视频和音频数据保存到两个集合对象里了。
接下来就是需要继续开启线程来对解析的数据进行播放了。
先看音频,开启一个线程
long start = System.currentTimeMillis();
getG726();//解码播放
long end = System.currentTimeMillis();
long end_start = end - start;
// Log.e("@@", "@@g726:" + end_start);
if (end_start >= time) {
g726Handler.postDelayed(myg726Runnable, 0);
} else {
g726Handler.postDelayed(myg726Runnable, time - end_start);
}
解码播放,耗时大于定时器的时间,那么播放下一帧音频以耗时为准。否则,用规定的20ms时间减去耗时作为剩下的时间作为等待的时间。确保每一帧的时间(解码播放时间+等待时间)在20ms
具体的解码过程
if (10 >= server.getClientInputThread().allg726.size()) {
} else {
if (isstartvideo) {//开始播放后开始 合并两帧解码 音质相对好点,音频RTP头26,另含4字节海思头
g726data = server.getClientInputThread().allg726.get(8);
g726data1 = server.getClientInputThread().allg726.get(9);
if (isPlayAudio) {
if (g726data != null && g726data1 != null) {//4字节的海思头已在开始去掉
g726temp = new byte[g726data.length + g726data1.length - 0];
System.arraycopy(g726data, 0, g726temp, 0, g726data.length - 0);
System.arraycopy(g726data1, 0, g726temp, g726data.length - 0, g726data1.length - 0);
int audiotype=server.getClientInputThread().audioType;
if (audiotype==8) {
pcm = HstAVNativeJNI.OneG726Topcm(g726temp);
}else if (audiotype==6) {
G711Decode.decode(g726temp, 0, g726temp.length, pcm);
}
else
{
System.arraycopy(g726temp,0,pcm,0,g726temp.length);
}
/**
* 模拟环境下 音频数据不够长(暂时用填补海思头的方法)
*/
// byte[] pcm2=new byte[pcm.length+64];
// System.arraycopy(pcm,0,pcm2,0,pcm.length);
// for (int i = 1; i <=64 ; i++) {
// pcm2[pcm2.length-i]=(byte)0xf0;
// }
// Log.e("@@","@@"+g726data.length+" "+pcm.length);
mat.playAudioTrack(pcm, 0, pcm.length);
}
} else {
}
server.getClientInputThread().allg726.remove(9);
// if (g726data!=null){
// g726temp=new byte[g726data.length-30];
// System.arraycopy(g726data,30,g726temp,0,80);
// pcm = HstAVNativeJNI.OneG726Topcm(g726temp);
// mat.playAudioTrack(pcm, 0, pcm.length);
// }
server.getClientInputThread().allg726.remove(8);
}
}
音频把两帧音频合并为一帧然后在播,音质好。
视频帧
在播放视频时,把解码视频和播放视频放到了两个线程,这是和音频的差异。
/**
* 播放图片线程
*/
private void showH264() {
h264Handler = new Handler();
myh264Runnable = new Runnable() {
public void run() {
if (server != null) {
if (server.getClientInputThread() != null) {
geth264();
}
}
h264Handler.postDelayed(myh264Runnable, 0);
}
};
h264Handler.postDelayed(myh264Runnable, 0);
}
/**
* 显示一帧图片
*/
private void geth264() {
if (server==null||server.getClientInputThread()==null){
return;
}
if (0 == server.getClientInputThread().allmp4.size()) {
} else {
data = server.getClientInputThread().allmp4.get(0);
if (data != null) {
temp = new byte[data.length];
System.arraycopy(data, 0, temp, 0, data.length );
if (temp.length > 5) {
if (temp[0] == 0x00 && temp[1] == 0x00 && temp[2] == 0x00 && temp[3] == 0x01 && temp[4] == 0x67) {
if (isstart) {
temponedata = new byte[frontlength];
System.arraycopy(onedata, 0, temponedata, 0, frontlength);
h264list.add(temponedata);
frontlength = 0;
System.arraycopy(temp, 0, onedata, frontlength, temp.length);
frontlength += temp.length;
} else {
isstart = true;
frontlength = 0;
System.arraycopy(temp, 0, onedata, frontlength, temp.length);
frontlength += temp.length;
}
} else if (temp[0] == 0x00 && temp[1] == 0x00 && temp[2] == 0x00 && temp[3] == 0x01 && temp[4] == 0x61) {
if (isstart) {
temponedata = new byte[frontlength];
System.arraycopy(onedata, 0, temponedata, 0, frontlength);
h264list.add(temponedata);
frontlength = 0;
System.arraycopy(temp, 0, onedata, frontlength, temp.length);
frontlength += temp.length;
}
} else {
if (isstart) {
System.arraycopy(temp, 0, onedata, frontlength, temp.length);
frontlength += temp.length;
}
}
} else {
if (isstart) {
System.arraycopy(temp, 0, onedata, frontlength, temp.length);
frontlength += temp.length;
}
}
}
server.getClientInputThread().allmp4.remove(0);
}
}
/**
* 播放
*/
private void show() {
showHandler = new Handler();
myshowRunnable = new Runnable() {
public void run() {
Log.e("@@:a:"+a, "@@@result:show"+h264list.size()+"isstarrvideo:"+isstartvideo );
if (h264list.size() > 2) {
if (isstartvideo==false) {
playRealAVUI.setWaitForMsgIndex(0);
}
isstartvideo = true;
if (onvideoChange != null) {
onvideoChange.setOnVideoChangeListener(isstartvideo);
}
}
long start = System.currentTimeMillis();
if (isstartvideo) {
if (h264list.size() > 0) {
listdata = h264list.get(0);
h264list.remove(0);
if (listdata != null) {
if (listdata[0] == 0x00 && listdata[1] == 0x00 && listdata[2] == 0x00 && listdata[3] == 0x01 && listdata[4] == 0x67) {
if (a == 0) {
HstAVNativeJNI.play2(listdata, surfaceViewHolder.getSurface());
} else if (a == 1) {
HstAVNativeJNI.play22(listdata, surfaceViewHolder.getSurface());
} else if (a == 2) {
HstAVNativeJNI.play23(listdata, surfaceViewHolder.getSurface());
} else if (a == 3) {
HstAVNativeJNI.play24(listdata, surfaceViewHolder.getSurface());
}
} else {
if (a == 0) {
HstAVNativeJNI.play2(listdata, surfaceViewHolder.getSurface());
} else if (a == 1) {
HstAVNativeJNI.play22(listdata, surfaceViewHolder.getSurface());
} else if (a == 2) {
HstAVNativeJNI.play23(listdata, surfaceViewHolder.getSurface());
} else if (a == 3) {
HstAVNativeJNI.play24(listdata, surfaceViewHolder.getSurface());
}
}
}
hwhandler.sendEmptyMessage(0x123);
}
}
long end = System.currentTimeMillis();
long end_start = end - start;
// Log.e("@@", "@@show:" + end_start);
if (end_start > 40) {
showHandler.postDelayed(myshowRunnable, 0);
} else {
showHandler.postDelayed(myshowRunnable, 40 - end_start);
}
}
};
showHandler.postDelayed(myshowRunnable, 0);
}
视频宽高适配
Handler hwhandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (!isClicked) {
return;
}
int h = surfaceView.getLayoutParams().height;
int w = surfaceView.getLayoutParams().width;
if (a == 0) {
if (w > 0) {
h = (int) (w * chufa(HstAVNativeJNI.getHeight(), HstAVNativeJNI.getWidth()));
} else {
w = (int) (h * chufa(HstAVNativeJNI.getWidth(), HstAVNativeJNI.getHeight()));
}
} else if (a == 1) {
if (w > 0) {
h = (int) (w * chufa(HstAVNativeJNI.getHeight2(), HstAVNativeJNI.getWidth2()));
} else {
w = (int) (h * chufa(HstAVNativeJNI.getWidth2(), HstAVNativeJNI.getHeight2()));
}
} else if (a == 2) {
if (w > 0) {
h = (int) (w * chufa(HstAVNativeJNI.getHeight3(), HstAVNativeJNI.getWidth3()));
} else {
w = (int) (h * chufa(HstAVNativeJNI.getWidth3(), HstAVNativeJNI.getHeight3()));
}
} else if (a == 3) {
if (w > 0) {
h = (int) (w * chufa(HstAVNativeJNI.getHeight4(), HstAVNativeJNI.getWidth4()));
} else {
w = (int) (h * chufa(HstAVNativeJNI.getWidth4(), HstAVNativeJNI.getHeight4()));
}
}
// Log.e("@@","@@w="+w+" h="+h);
surfaceViewHolder.setFixedSize(w, h);//设置视频大小
ll_progress.setVisibility(View.GONE);
tv_zhegai.setVisibility(View.GONE);
}
};