最近做一个项目, 录制视频添加水印功能, 但是完成之后发现高速晃动手机录制的画面有断裂, 有马赛克的问题。
处理过程是从摄像头回调数据放入队列中, 上层将数据的yuv转换角度, 添加水印后放入编码器中进行编码,但出来的效果却是这样
再跟踪数据流的过程中发现是转换角度之后才出现的问题。网上查询转换角度的算法之后,更换了几个, 都没有解决问题。
后查询代码,原来是安卓的运行机制导致的该问题, 并非转换角度的问题。
mCameraProxy.startPreview();
int size = mPreviewSize.getWidth() * mPreviewSize.getHeight() * ImageFormat.getBitsPerPixel(mPreviewFormat) / 8;
mCameraProxy.addCallbackBuffer(new byte[size]);
mCameraProxy.setPreviewCallbackWithBuffer(mFrameworkPreviewCallback);
获取的数据是通过该方式获取的。
private Camera.PreviewCallback mFrameworkPreviewCallback = new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] bytes, Camera camera) {
if (mPreviewCallback != null) {
mModeDeviceCallback.onPreviewStart();
Log.i(“fengq”, “mFrameworkPreviewCallback v1”);
mPreviewCallback.onPreviewCallback(bytes, mPreviewFormat, mCameraId);
}
if(mCameraProxy != null){
mCameraProxy.addCallbackBuffer(bytes);
}
MediaMuxerUtils.getMuxerRunnableInstance().setCameraId(mCameraId);
MediaMuxerUtils.getMuxerRunnableInstance().addVideoFrameData(bytes);
}
};
通过该方式获取的数据,如果上层处理速度跟不上,其中的bytes是后面的帧将前面的覆盖。导致出现的问题
public void addData(byte[] yuvData) {
if(frameBytes != null && yuvData != null && isEncoderStart){
Log.i(“fengq”, “yuvData.length=” + yuvData.length + “frameBytes.size=” + frameBytes.size());
int length = yuvData.length;
if(frameLength == length){
boolean isOffer = frameBytes.offer(yuvData);
if(!isOffer){
frameBytes.poll();
frameBytes.offer(yuvData);
}
}
}
}
改成
public void addData(byte[] yuvData) {
if(frameBytes != null && yuvData != null && isEncoderStart){
Log.i(“fengq”, “yuvData.length=” + yuvData.length + “frameBytes.size=” + frameBytes.size());
int length = yuvData.length;
if(frameLength == length){
byte[] newYuvData = new byte[length];
System.arraycopy(yuvData, 0, newYuvData, 0, length);
boolean isOffer = frameBytes.offer(newYuvData);
if(!isOffer){
frameBytes.poll();
frameBytes.offer(yuvData);
}
}
}
}
在上层处理的时候,将原始数据复制到new出来的数组中, 这样, 原始数据指针就不会被覆盖, 该问题就会解决了。