车载流媒体作为一个热点越来越引起大家的重视,car-eye 行车记录仪,是基于RTSP协议开发的开源android程序,支持最多四路视频录像,支持最多四路视频上传。传输视频采用RTSP协议。首先我们介绍一下,视频数据从摄像头获取到编码,到传输给流媒体服务器的过程:
1. 摄像头数据通过priewcallback获得数据为YV12的数据
设置好基本的预览的参数:
parameters.setPreviewSize(Constants.RECORD_VIDEO_WIDTH, Constants.RECORD_VIDEO_HEIGHT);
parameters.setPreviewFpsRange(20,20);
camera[index].startPreview();
在需要数据的时候打开预览callback:
camera[index].setPreviewCallback(preview[index]);
preview[0] = new PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, Camera camera1) {
// TODO Auto-generated method stub
MediaCodecManager.getInstance().onPreviewFrameUpload(data,0,camera[0]);
}
};
public void onPreviewFrameUpload(byte[] data,int index,Camera camera){
if (data == null ) {
camera.addCallbackBuffer(data);
return;
}
Camera.Size previewSize = camera.getParameters().getPreviewSize();
if (data.length != Constants.UPLOAD_VIDEO_HEIGHT * Constants.UPLOAD_VIDEO_WIDTH * 3 / 2) {
camera.addCallbackBuffer(data);
Log.d("CMD", " onPreviewFrameUpload return"+data.length);
return;
}
MainService.getInstance().SetPreviewValid(index);
if(mVC[index]!= null)
{
mVC[index].onVideo(data, previewFormat);
}else
{
camera.setPreviewCallback(null);
}
camera.addCallbackBuffer(data);
}
}
2. 讲H264的数据流,传输到编码器进行编码传输:
public int onVideo(byte[] data, int format) {
if (!mVideoStarted)return 0;
inputBuffers = mMediaCodec.getInputBuffers();
outputBuffers = mMediaCodec.getOutputBuffers();
int bufferIndex = mMediaCodec.dequeueInputBuffer(0);
// MainService.mEasyPusher.addwatermarkScale(data, Scaler, data.length,Constants.RECORD_VIDEO_WIDTH,Constants.RECORD_VIDEO_HEIGHT,Constants.UPLOAD_VIDEO_WIDTH,Constants.UPLOAD_VIDEO_HEIGHT);
if (bufferIndex >= 0) {
ByteBuffer buffer = null;
buffer = inputBuffers[bufferIndex];
buffer.clear();
buffer.put(data);
buffer.clear();
mMediaCodec.queueInputBuffer(bufferIndex, 0, data.length, System.nanoTime() / 1000, 0);
}
/*if (time > 0)
try {
Thread.sleep(time / 2);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
lastPush = System.currentTimeMillis();*/
return 0;
}
@Override
public void run(){
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
int outputBufferIndex = 0;
byte[] mPpsSps = new byte[0];
byte[]h264 = new byte[mWidth*mHeight*3/2];
do {
outputBufferIndex = mMediaCodec.dequeueOutputBuffer(bufferInfo, 30000);
if (outputBufferIndex == MediaCodec.INFO_TRY_AGAIN_LATER) {
// no output available yet
} else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
// not expected for an encoder
} else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
/* EasyMuxer muxer = mMuxer;
if (muxer != null) {
// should happen before receiving buffers, and should only happen once
MediaFormat newFormat = mMediaCodec.getOutputFormat();
muxer.addTrack(newFormat, true);
}*/
} else if (outputBufferIndex < 0) {
// let's ignore it
} else {
ByteBuffer outputBuffer;
outputBuffer = outputBuffers[outputBufferIndex];
EasyMuxer muxer = mMuxer;
if (muxer != null) {
muxer.pumpStream(outputBuffer, bufferInfo, true);
}
boolean sync = false;
if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {// sps
sync = (bufferInfo.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) != 0;
if (!sync) {
byte[] temp = new byte[bufferInfo.size];
outputBuffer.get(temp);
mPpsSps = temp;
mMediaCodec.releaseOutputBuffer(outputBufferIndex, false);
continue;
} else {
mPpsSps = new byte[0];
}
}
sync |= (bufferInfo.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) != 0;
int len = mPpsSps.length + bufferInfo.size;
if (len > h264.length){
h264 = new byte[len];
}
if (sync) {
System.arraycopy(mPpsSps, 0, h264, 0, mPpsSps.length);
outputBuffer.get(h264, mPpsSps.length, bufferInfo.size);
int Time =(int)( ( bufferInfo.presentationTimeUs / 1000) &0xffffff);
mPusher.SendBuffer(0, h264, mPpsSps.length + bufferInfo.size, 0, m_index);
}else{
int Time =(int)( ( bufferInfo.presentationTimeUs / 1000) &0xffffff);
outputBuffer.get(h264, 0, bufferInfo.size);
mPusher.SendBuffer(0, h264, bufferInfo.size, 0, m_index);
}
mMediaCodec.releaseOutputBuffer(outputBufferIndex, false);
}
}
while (mVideoStarted);
}
其中 mPusher.SendBuffer(0, h264, mPpsSps.length + bufferInfo.size, 0, m_index); 讲获得H264的流传输到多媒体平台。
相关代码下载car-eye开源平台网址:https://github.com/Car-eye-admin/ 有关技术咨询可以加群590411159。