Android Camera预览时输出的帧率控制
来源:互联网 发布:外贸网络推广 编辑:程序博客网 时间:2024/04/29 17:55
如果使用MediaCodec硬编码H264,可以使用下面的方法控制编码输出的帧率:
MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", width, height); mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar); mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, width*height*5); mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 30); mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1); try { mediaCodec = MediaCodec.createEncoderByType("video/avc"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); mediaCodec.start();
但如果是采用预览模式下得到预览的BITMAP,然后通过x264编码的来实现的方式,则需要应用层控制预览帧的帧帧率,Camera本来提供了两个接口来控制预览帧率,但从多个平台的适配发现,基本上都不能有效的控制Camera预览输出的帧率:
setPreviewFrameRate是在api level1就开始使用了,然后不是简单地设置这个方法就可以让摄像头每秒捕获多少帧数的。 比如我设置2,它一秒不会只捕获2帧数据的,从日志记录来看,相当糟糕,不会是预期的2帧,于是我查找文档,发现这个方法已经废除了。 在api level9时加入了一个方法setPreviewFpsRange (int min, int max) 预览帧数从min到max,这个值再*1000. 这个方法已经在高版本的sdk中取代了旧的setPreviewFrameRate。
上面是文章: Android camera 预览帧数和视频通话图片缓存 中提到为什么预览帧设置失效的问题,并且也给出了一个控制预览帧的方式,这里提供另外一种类似的实现:无锁队列的实现。
下面 RingBuffer的定义:
final byte STATU_INIT = 0; final byte STATU_WAIT_DEQEUE = 1; class UserDefinedBuffer{ByteBuffer mVideoFrame;byte status;}//the ring queueclass RingBuffer{int r_index;int w_index;int size;UserDefinedBuffer[] mUserDefinedBuffer; long last_time;public RingBuffer(int max_size, int capacity){mUserDefinedBuffer = new UserDefinedBuffer[max_size]; r_index = w_index = 0;size = max_size;for(int i=0 ;i<max_size; i++){mUserDefinedBuffer[i] = new UserDefinedBuffer();mUserDefinedBuffer[i].mVideoFrame = ByteBuffer.allocateDirect(capacity); }}public UserDefinedBuffer getUserDefinedBuffer(int index){return mUserDefinedBuffer[index];}int getRingW(){return w_index;}int getRingR(){return r_index;}int getRingSize(){return size;} void setUserDefinedBufferStatus(int index, byte status){synchronized(mUserDefinedBuffer[index]){mUserDefinedBuffer[index].status = status;}}byte getUserDefinedBufferStatus(int index){synchronized(mUserDefinedBuffer[index]){return mUserDefinedBuffer[index].status;} }void enqueue(byte[] _data){ int index = w_index & (size -1);Log.i(TAG, "#enqueue, index:"+index);if (index >= size){index = 0;}if (getUserDefinedBufferStatus(index) != STATU_INIT){Log.i(TAG, "i enqueue, index:"+index+", not dequeue" + ", STATUS:"+getUserDefinedBufferStatus(index));return;}setUserDefinedBufferStatus(index, STATU_WAIT_DEQEUE);mUserDefinedBuffer[index].mVideoFrame.rewind();mUserDefinedBuffer[index].mVideoFrame.put(_data);w_index += 1; }void enqueue(ByteBuffer data){ int index = w_index & (size -1);Log.i(TAG, "enqueue, index:"+index);if (index >= size){index = 0;}if (getUserDefinedBufferStatus(index) != STATU_INIT){Log.i(TAG, "ii enqueue, index:"+index+", not dequeue" + ", STATUS:"+getUserDefinedBufferStatus(index));return;}setUserDefinedBufferStatus(index, STATU_WAIT_DEQEUE);mUserDefinedBuffer[index].mVideoFrame.rewind();mUserDefinedBuffer[index].mVideoFrame.put(data); w_index += 1; //last_time = System.currentTimeMillis();} long getLastTime(){return last_time;}int dequeue(){ int index = r_index & (size -1); if (index == (w_index & (size -1))){Log.i(TAG, "dequeue, w_index:"+w_index + ", r_index:"+r_index);return -1;}Log.i(TAG, "dequeue, index:"+index);r_index += 1; //ByteBuffer data = mUserDefinedBuffer[index].mVideoFrame;//mUserDefinedBuffer[index].mVideoFrame.rewind();return index; } };
出队线程:
class PushVideoThread extends Thread{ boolean mExitFlag = false; public void setExitFlg(boolean bFlag){mExitFlag = bFlag;} @Override public void run() {android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO); Log.i(TAG, "PushVideoThread() run start.");final int delay = (100/mFps);// while(!mExitFlag){ long start=System.currentTimeMillis(); if (mRingBuffer == null){try {Thread.sleep(delay);} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();} continue; }int index = mRingBuffer.dequeue(); if (index == -1){try {Thread.sleep(delay);} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();} continue;}if (STATU_WAIT_DEQEUE != mRingBuffer.getUserDefinedBufferStatus(index)){ Log.i(TAG, "Ana dequeue mRingBuffer.getUserDefinedBufferStatus(index):"+mRingBuffer.getUserDefinedBufferStatus(index));try {Thread.sleep(delay);} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();} continue;}UserDefinedBuffer userDefindedBuffer = mRingBuffer.getUserDefinedBuffer(index); ByteBuffer byteBuffer = userDefindedBuffer.mVideoFrame; if (byteBuffer != null){framesRendered++;if ((framesRendered % 100) == 0) {logStatistics();framesRendered = 0;startTimeNs= System.nanoTime();}// Log.i(TAG, "Ana dequeue getRingW:"+ write +",getRingR:"+ read); mProducer.push(byteBuffer, mVideoFrame.capacity()); mRingBuffer.setUserDefinedBufferStatus(index, STATU_INIT); } long end=System.currentTimeMillis(); if ((end - start) < delay && (end - start) > 0){ try { long value = delay - (end -start); if (value > 0){ Thread.sleep(value); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } Log.i(TAG, "PushVideoThread() run End."); }}
RingBuffer的初始化:
static final int MAX_SIZE = 64;//must 2 mulRingBuffer mRingBuffer; void initRingBuffer(){ mRingBuffer = new RingBuffer(MAX_SIZE, mVideoFrame.capacity()); }入队:
public void onPreviewFrame(byte[] _data, Camera _camera) {mRingBuffer.enqueue(_data);}
1 0
- Android Camera预览时输出的帧率控制
- Android Camera HAL3中预览preview模式下的控制流
- Android Camera HAL3中预览preview模式下的控制流
- Android Camera HAL3中预览preview模式下的控制流
- Android Camera HAL3中预览preview模式下的控制流
- Android Camera HAL3中预览preview模式下的控制流
- Android Camera HAL3中预览preview模式下的控制流
- Android之Camera预览
- Android之Camera预览
- Android之Camera预览
- Android 5.0 Camera系统源码分析(3):Camera预览流程控制流
- Android 5.0 Camera系统源码分析(3):Camera预览流程控制流
- 解决Camera预览时倒立的问题
- android TextureView destroyDrawingCache(关闭Camera时,清除预览画面上的卡的最后一帧画面)
- android调camera api预览
- android里camera支持的预览尺寸的获取
- android里camera支持的预览尺寸的获取
- Android解决当调用Camera时预览画面有旋转的问题
- Flume环境部署和配置详解及案例大全
- 图结构练习——BFSDFS——判断可达性
- ramdisk.img system.img userdata.img 分析
- Java研发方向如何准备BAT技术面试答案(中)
- 基于jmeter和shell的接口性能自动化
- Android Camera预览时输出的帧率控制
- GPDB的spread方式测试
- 【golang】go-channel-goroutine实践1
- PHP下载图片到本机
- java归并排序
- iOS8的iPad环境下打不开相册或者拍照
- Android--Gridview使用SimpleAdapter加载bitmap图片
- SpringBoot-快速搭建WEB工程
- Android 打开闪光灯