Android开发:实时处理摄像头预览帧视频------浅析PreviewCallback,onPreviewFrame,AsyncTask的综合应用 这里将大致框架介绍了,但很多人对onPreviewFrame()里的处理提出质疑。认为下面的转换是多余的:
final YuvImage image = new YuvImage(mData, ImageFormat.NV21, w, h, null); ByteArrayOutputStream os = new ByteArrayOutputStream(mData.length); if(!image.compressToJpeg(new Rect(0, 0, w, h), 100, os)){ return null; } byte[] tmp = os.toByteArray(); Bitmap bmp = BitmapFactory.decodeByteArray(tmp, 0,tmp.length);
因为这个mData是byte[ ]格式,转换流程是:byte[ ]---YuvImage----ByteArrayOutputStream---byte[ ]-----Bitmap。乍一看这个转换还真是多余了。看看看goolge的api:
public abstract void onPreviewFrame (byte[] data, Camera camera) Added in API level 1 Called as preview frames are displayed. This callback is invoked on the event thread open(int) was called from. If using the YV12 format, refer to the equations in setPreviewFormat(int) for the arrangement of the pixel data in the preview callback buffers. Parameters data the contents of the preview frame in the format defined by ImageFormat, which can be queried with getPreviewFormat(). If setPreviewFormat(int) is never called, the default will be the YCbCr_420_SP (NV21) format. camera the Camera service object.
大致意思是:可以用getPreviewFormat()查询
支持的预览帧格式。如果setPreviewFormat(INT)
从未被调用,默认将使用YCbCr_420_SP的格式(NV21)。
setPreviewFormat里,它又说:
public void setPreviewFormat (int pixel_format) Added in API level 1 Sets the image format for preview pictures. If this is never called, the default format will be NV21, which uses the NV21 encoding format. Use getSupportedPreviewFormats() to get a list of the available preview formats. It is strongly recommended that either NV21 or YV12 is used, since they are supported by all camera devices. For YV12, the image buffer that is received is not necessarily tightly packed, as there may be padding at the end of each row of pixel data, as described in YV12. For camera callback data, it can be assumed that the stride of the Y and UV data is the smallest possible that meets the alignment requirements. That is, if the preview size is width x height, then the following equations describe the buffer index for the beginning of row y for the Y plane and row c for the U and V planes: yStride = (int) ceil(width / 16.0) * 16; uvStride = (int) ceil( (yStride / 2) / 16.0) * 16; ySize = yStride * height; uvSize = uvStride * height / 2; yRowIndex = yStride * y; uRowIndex = ySize + uvSize + uvStride * c; vRowIndex = ySize + uvStride * c; size = ySize + uvSize * 2;
强烈建议使用NV21格式和YV21格式,而默认情况下是NV21格式,也就是YUV420SP的。因此不经过转换,直接用BitmapFactory解析是不能成功的。事实也是如此。直接解析mData将会得到如下的错误:
另外下面也提到NV21是通用的。
getSupportedPreviewFormats()
Added inAPI level 5
Gets the supported preview formats.NV21
is always supported.YV12
is always supported since API level 12.
如果嫌YuvImage进行压缩解析的慢,只能自己写转换函数了,网上常见的有三种:
一:这里只是一个编码框架
参考这里:Android 实时视频采集—Camera预览采集
// 【获取视频预览帧的接口】 mJpegPreviewCallback = new Camera.PreviewCallback() { @Override public void onPreviewFrame(byte[] data, Camera camera) { //传递进来的data,默认是YUV420SP的 // TODO Auto-generated method stub try { Log.i(TAG, "going into onPreviewFrame"); //mYUV420sp = data; // 获取原生的YUV420SP数据 YUVIMGLEN = data.length; // 拷贝原生yuv420sp数据 mYuvBufferlock.acquire(); System.arraycopy(data, 0, mYUV420SPSendBuffer, 0, data.length); //System.arraycopy(data, 0, mWrtieBuffer, 0, data.length); mYuvBufferlock.release(); // 开启编码线程,如开启PEG编码方式线程 mSendThread1.start(); } catch (Exception e) { Log.v("System.out", e.toString()); }// endtry }// endonPriview };
二、下面是将yuv420sp转成rgb参考这里:android视频采集
private void updateIM() { try { // 解析YUV成RGB格式 decodeYUV420SP(byteArray, yuv420sp, width, height); DataBuffer dataBuffer = new DataBufferByte(byteArray, numBands); WritableRaster wr = Raster.createWritableRaster(sampleModel, dataBuffer, new Point(0, 0)); im = new BufferedImage(cm, wr, false, null); } catch (Exception ex) { ex.printStackTrace(); } } private static void decodeYUV420SP(byte[] rgbBuf, byte[] yuv420sp, int width, int height) { final int frameSize = width * height; if (rgbBuf == null) throw new NullPointerException("buffer 'rgbBuf' is null"); if (rgbBuf.length < frameSize * 3) throw new IllegalArgumentException("buffer 'rgbBuf' size " + rgbBuf.length + " < minimum " + frameSize * 3); if (yuv420sp == null) throw new NullPointerException("buffer 'yuv420sp' is null"); if (yuv420sp.length < frameSize * 3 / 2) throw new IllegalArgumentException("buffer 'yuv420sp' size " + yuv420sp.length + " < minimum " + frameSize * 3 / 2); int i = 0, y = 0; int uvp = 0, u = 0, v = 0; int y1192 = 0, r = 0, g = 0, b = 0; for (int j = 0, yp = 0; j < height; j++) { uvp = frameSize + (j >> 1) * width; u = 0; v = 0; for (i = 0; i < width; i++, yp++) { y = (0xff & ((int) yuv420sp[yp])) - 16; if (y < 0) y = 0; if ((i & 1) == 0) { v = (0xff & yuv420sp[uvp++]) - 128; u = (0xff & yuv420sp[uvp++]) - 128; } y1192 = 1192 * y; r = (y1192 + 1634 * v); g = (y1192 - 833 * v - 400 * u); b = (y1192 + 2066 * u); if (r < 0) r = 0; else if (r > 262143) r = 262143; if (g < 0) g = 0; else if (g > 262143) g = 262143; if (b < 0) b = 0; else if (b > 262143) b = 262143; rgbBuf[yp * 3] = (byte) (r >> 10); rgbBuf[yp * 3 + 1] = (byte) (g >> 10); rgbBuf[yp * 3 + 2] = (byte) (b >> 10); } } } public static void main(String[] args) { Frame f = new FlushMe(); } }
三、将YUV420SP转成YUV420格式
参考这里:Android如何实现边采集边上传
private byte[] changeYUV420SP2P(byte[]data,int length){ int width = 176; int height = 144; byte[] str = new byte[length]; System.arraycopy(data, 0, str, 0,width*height); int strIndex = width*height; for(int i = width*height+1; i < length ;i+=2) { str[strIndex++] = data[i]; } for(int i = width*height;i<length;i+=2) { str[strIndex++] = data[i]; } return str; }
至于怎么从YUV420SP中直接提取出Y分量进行后续检测,这个还要研究一番。有知道的大神多赐教。
----------------------------------------------------------------------------------------本文系原创,转载请注明作者:yanzi1225627
相关推荐
支持从摄像头采集图像,并用MediaCodec API进行硬编码,编码后的数据保存到一个H264文件。这个例子也支持软编码,使用的是FFmpeg。
打开摄像头并对摄像头获取的每一帧图像进行保存,边录像和上传视频流,并保存为本地.h264文件
Step1:调用MediaRecorder对象的setVideoEncoder()、setVideoEncodingBitRate(int bitRate)、setVideoFrameRate()方法设置所录制的视频编码格式、编码位率、每秒多少帧等,这些参数可以控制所录制的视频品质、文件...
功能特点 视频编码:H.264 推流协议:RTMP 预览与推流分辨率可分别自由设置 支持前、后置摄像头动态切换 支持软编、硬编及软编兼容模式 网络自适应,可根据实际网络情况动态调整目标码率,保证流畅性 音频...
需要自己实现的代码只是打开摄像头,写一个SurfaceView进行预览,然后实现PreviewCallback将摄像头每一帧的数据交给javacv即可 javacv地址:https://github.com/bytedeco/javacv demo地址:...
10.2.2 使用摄像头预览 321 10.2.3 照相 322 10.3 Sensor Manager简介 323 10.4 使用加速计和指南针 324 10.4.1 加速计介绍 325 10.4.2 检测加速度的改变 325 10.4.3 创建一个速度计 327 10.4.4 确定方向 ...
我将带领大家一起来学习使用FFmpeg开发视频监控项目,并动手操练。 具体内容包括: 一、视频监控的架构和流程 二、FFmpeg4.3+SDL2+Qt5开发环境的搭建 三、FFmpeg的SDK编程回顾总结并操练 四、SDL2.0的编程回顾总结并...
主要介绍了关于Android 4.4相机预览、录像花屏的问题的解决方法,非常不错,具有参考借鉴价值,需要的朋友参考下吧
网络条件:局域网 实现方法:摄像头获取预览数据→转为yuv→编码为h264→分包→rtp发送→接收端接收→解码→显示 注:调下ip就可以运行了,花屏的话调KEY_FRAME_RATE
使用C++调用Android底层接口,实现了从Camera摄像头拿去数据并进行H264 OMX编码
此项目还使用Android最新的进行视频/音频编码,并使用流行的C ibrary librtmp(包括源代码)进行rtmp流传输,此外,还提供了在摄像头捕获阶段之后和编码阶段之前实现实时效果滤镜的功能。 一些功能是: 支持Android...
10.2.1 控制摄像头设置 10.2.2 使用摄像头预览 10.2.3 照相 10.3 Sensor Manager简介 10.4 使用加速计和指南针 10.4.1 加速计介绍 10.4.2 检测加速度的改变 10.4.3 创建一个速度计 10.4.4 确定方向 10.4.5 创建指南...
10.2.2 使用摄像头预览 10.2.3 照相 10.3 Sensor Manager简介 10.4 使用加速计和指南针 10.4.1 加速计介绍 10.4.2 检测加速度的改变 10.4.3 创建一个速度计 10.4.4 确定方向 10.4.5 创建指南针和地平仪 10.5 Android...
采集摄像头及音频编码成H264+AAC后转给rtsp服务器 直接用vlc就可预览手机摄像头 rtsp服务器源码参见http://download.csdn.net/detail/bxinquan/9477741
采集摄像头及音频编码成H264+AAC后转给rtsp服务器 直接用vlc就可预览手机摄像头 支持OPENGLES美颜、加动图
sh_camera是car-eye开放源码团队开发的基于android系统的一个应用程序。主要界面如下图: 其中面板的中按钮依次为拍摄,录像,实时上传,打开预览,内部可以远程和本地回放文件,设置按钮,人脸识别 设置界面的图...
如上图所示,要实现特效直播至少需要实现这五个模块:相机采集、设备运动方向检测、人脸识别功能、本地预览绘制以及编码发送。下面我们就逐个介绍下在Android端这个五个功能的大致实现原理。想正常的看到摄像头所...
联络我 Sachintha Rathnayake Sacheerc IA12 联络我 ContactME是一个简单有用的... 请注意,在开发过程中,您必须按照以下要求将手机连接到Android Studio才能运行预览。 先决条件 Android 6.0(Marshmallow) or Lat