最近做一个项目, 录制视频添加水印功能, 但是完成之后发现高速晃动手机录制的画面有断裂, 有马赛克的问题。 处理过程是从摄像头回调数据放入队列中, 上层将数据的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出来的数组中, 这样, 原始数据指针就不会被覆盖, 该问题就会解决了。