马云说过,不要学习别人的成功,要学习别人的失败。今记录我踩过的坑,望总结失败教训。
今天经理牛人让我把从录像应用采集到的摄像头数据,传到网关程序,然后编码通过p2p传递到客户端,实时编码播放,弄了一天了,差不多弄完了,但是出现了几个问题,客户端实时视频卡顿,有的模糊不清,此刻根据以往经验,应该调调视频的帧率,码流率了,直接上代码:
public NewsmyVideoEncoder(
int width,
int height,
int framerate,
int bitrate, ArrayBlockingQueue<
byte[]> YUVQueue) {
m_width = width;
m_height = height;
m_framerate = framerate;
mYUVQueue = YUVQueue;
MediaFormat mediaFormat = MediaFormat.
createVideoFormat(
"video/avc", width, height);
mediaFormat.setInteger(MediaFormat.
KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.
COLOR_FormatYUV420SemiPlanar);
//mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar);
mediaFormat.setInteger(MediaFormat.
KEY_BIT_RATE, 200*1024*8);
mediaFormat.setInteger(MediaFormat.
KEY_FRAME_RATE, 15);
mediaFormat.setInteger(MediaFormat.
KEY_I_FRAME_INTERVAL, 1);
try {
mediaCodec = MediaCodec.
createEncoderByType(
"video/avc");
}
catch (Exception e) {
e.printStackTrace();
}
mediaCodec.configure(mediaFormat,
null,
null, MediaCodec.
CONFIGURE_FLAG_ENCODE);
mediaCodec.start();
}
帧率的大小代表了视频的流畅度,帧率越大,流畅度越好,我评估以现有的网络条件,15的帧率最合适,我调节摄像头采集的数据速率,帧率就是每秒采集图像的个数,好了,定了帧率之后,我试着调节码流率,他是每一秒传输的数据,数据越大,视频越清晰,我从小到大的调节,发现问题的解决不是很理想,依然存在卡顿,不清晰。然后经理牛人过来看了一下,猜测我的问题出现在哪里。是编码的数据问题。靠。我踩了一个很大很大的坑。上代码
@Override
public void onFrame(
byte[] buffer) {
Log.
d(
"CameraEncoder",
"拿到数据啦---------- "+buffer.
length);
if (
mYUVQueue.size() >= 10) {
mYUVQueue.poll();
}
byte[] mVideoBuffer =
new byte[
BUFFER_SIZE];
System.
arraycopy(buffer,0,mVideoBuffer,0,
BUFFER_SIZE);
mYUVQueue.add(mVideoBuffer);
}
从共享内存读到的数据我回调到这里,由于之前我只建立了一个缓存区来存储数据,传到这里,我直接添加到我的队列里了,注意了,问题就出现在这里,这里add方法添加的是引用,buffer数组一直在更新,意味着传过去的编码数据随时可能改变,这就不对了,所以我必须拷贝一份,在传过去,改完,测试,发现问题比以前好多了,视频不清晰,有混乱画面的问题解决了,果然是视频编码数据的问题。但还是有不流畅的问题,经理牛人问我的分辨率是多少,我说1920*1080,经理牛人说太大了,改小点,图像清晰点,码流率改成200*1024*8,我照做了,测试,OK,完美解决了我的问题,茅塞顿开,弄了好久的音视频,果然还需得亲自去踩这些坑,才明白这些原理和技术。总之,时刻记着,java如果传递的是引用,都是对应同一块内存,改变都改变。