Android利用mediacodec进行视频H264编码解码播放
来源:互联网 发布:淘宝修图兼职 编辑:程序博客网 时间:2024/04/30 02:12
H264是目前最常用的视频压缩格式之一,可以将视频、图片、音频等转换为字符串流形式,以此可以进行再次编辑、传输等。详情参考http://blog.csdn.NET/lcalqf/article/details/42556219。
在Android里,最常用的视频编码解码用的API就是mediacodec了,可以进行多种格式的硬解码,也能和mediamuxer一起使用实现音视频文件的编辑(结合MediaExtractor),用OpenGL绘制Surface并生成mp4文件,屏幕录像以及类似Camera app里的录像功能(虽然这个用MediaRecorder更合适)等,注意它们和其它一些多媒体相关类的关系和区别:MediaExtractor用于音视频分路,和MediaMuxer正好是反过程。MediaFormat用于描述多媒体数据的格式。MediaRecorder用于录像+压缩编码,生成编码好的文件如mp4, 3gpp,视频主要是用于录制Camera preview。MediaPlayer用于播放压缩编码后的音视频文件。AudioRecord用于录制PCM数据。AudioTrack用于播放PCM数据。PCM即原始音频采样数据,可以用如vlc播放器播放。参考博客:http://www.thinksaas.cn/topics/0/348/348569.html
好了,然后开始我们的编解码之旅吧。
首先,在确定了输入源以后(我的是mSurface,里面是保存着我的截屏Surface),设置编码器:
MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, mWidth, mHeight);//MIME_TYPE = "video/avc",H264的MIME类型,宽,高format.setInteger(MediaFormat.KEY_COLOR_FORMAT,MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);//设置颜色格式format.setInteger(MediaFormat.KEY_BIT_RATE, mBitRate);//设置比特率format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE);//设置帧率format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL);//设置关键帧mEncoder = MediaCodec.createEncoderByType(MIME_TYPE);//创建编码器mEncoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);//四个参数,第一个是media格式,第二个是解码器播放的surfaceview,第三个是MediaCrypto,第四个是编码解码的标识mSurface = mEncoder.createInputSurface();//我的输入源Log.d(TAG, "created input surface: " + mSurface);mEncoder.start();
附上我输入源的代码吧,
mMediaProjectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
Intent captureIntent = mMediaProjectionManager.createScreenCaptureIntent();startActivityForResult(captureIntent, REQUEST_CODE);
MediaProjection mediaProjection = mMediaProjectionManager.getMediaProjection(resultCode, data);
mVirtualDisplay = mMediaProjection.createVirtualDisplay(TAG + "-display", mWidth, mHeight, mDpi, DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC, mSurface, null, null);
从我代码中一行行拷过来的,有点散,不过基本意思就是用mediaprojectionmanager截屏,获取数据。
然后是进行数据编码:
inputObject=new InputObject();int index = mEncoder.dequeueOutputBuffer(mBufferInfo, TIMEOUT_US);//获取输出区的缓冲的索引Log.i(TAG, "dequeue output buffer index=" + index);if (index == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { resetOutputFormat();//重新设置media格式} else if (index == MediaCodec.INFO_TRY_AGAIN_LATER) { Log.d(TAG, "retrieving buffers time out!"); try { // wait 10ms Thread.sleep(10); } catch (InterruptedException e) { }} else if (index >= 0) { encodeToVideoTrack(index); mEncoder.releaseOutputBuffer(index, false);//释放缓存的资源
对于重新设置media格式这里,我并没进行更多操作:
private void resetOutputFormat() { // should happen before receiving buffers, and should only happen once MediaFormat newFormat = mEncoder.getOutputFormat();}
接下来根据索引就是获取编码的数据(我这里将它取到了byte数组中):
private void encodeToVideoTrack(int index) { ByteBuffer encodedData = mEncoder.getOutputBuffer(index); if (encodedData != null) { encodedData.position(mBufferInfo.offset); encodedData.limit(mBufferInfo.offset + mBufferInfo.size); try { int jj=encodedData.remaining(); byte[] b=new byte[encodedData.remaining()]; encodedData.get(b, 0, b.length); } catch(Exception e){ e.printStackTrace(); } }}
然后就是进行解码和播放:
首先是初始化解码器:
MediaFormat mediaFormat = MediaFormat.createVideoFormat( MIME_TYPE, mWidth, mHeigh);mediaCodec = MediaCodec.createDecoderByType(MIME_TYPE);//这里是建立的解码器mediaCodec.configure(mediaFormat, surface, null, 0);//注意上面编码器的注释,看看区别mediaCodec.start();
然后是解码:
int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);//获取输入缓冲区的索引if (inputBufferIndex >= 0) { ByteBuffer inputBuffer = inputBuffers[inputBufferIndex]; inputBuffer.clear(); inputBuffer.put(byteBuffer);//先获取缓冲区,再放入值 mediaCodec.queueInputBuffer(inputBufferIndex, 0, size, i * 1000000 / 30, 0);//四个参数,第一个是输入缓冲区的索引,第二个是放入的数据大小,第三个是时间戳,保证递增就是 i++;}MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);while (outputBufferIndex >= 0) { mediaCodec.releaseOutputBuffer(outputBufferIndex, true);//释放缓冲区解码的数据到surfaceview,一般到了这一步,surfaceview上就有画面了 outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);}
步骤就是这么简单,但是实际运行会有很多BUG,并且感觉和不同的设备型号也有关系。
附上我做这个时候的几个参考地址(都是大神啊)
http://www.cnblogs.com/Xiegg/p/3428529.html(mediacodec的详细文档翻译)
http://blog.csdn.Net/angcyo/article/details/51043367(mediacodec混合制作MP4)
http://blog.csdn.net/guojin08/article/details/27555473(mediacodec实现硬编码)
- Android利用mediacodec进行视频H264编码解码播放
- Android利用mediacodec进行视频H264编码解码播放
- Android利用mediacodec进行视频H264编码解码播放
- Android 解码MediaCodec 播放H264 265
- Android 解码MediaCodec 播放H264 265
- Android使用MediaCodec解码H264视频解码器
- Android 利用MediaCodec 实现硬编码 h264
- Android平台使用MediaCodec进行H264格式的视频编解码
- Android使用MediaCodec硬解码播放H264格式视频文件
- 【多媒体】Android使用MediaCodec硬解码播放H264格式视频文件
- Android使用MediaCodec硬解码播放H264格式视频文件
- 如何通过MediaCodec来进行视频解码后再编码
- android硬编码h264-MediaCodec
- android硬编码h264-MediaCodec
- android硬编码h264-MediaCodec
- android硬编码h264-MediaCodec
- Android MediaCodec h264硬件编码
- android硬编码h264-MediaCodec
- 本地测试环境搭建(二)
- hdu 1258 Sum It Up dfs暴搜
- React无状态组件更新props时会失去焦点
- Fontawesome的使用(续)
- python3与python2中字符串的区别
- Android利用mediacodec进行视频H264编码解码播放
- 微信小程序 this和that用法
- 类中const函数及非const函数的调用规则
- 修改Centos7的网卡名称ens160、eno16777984改为eth0
- 将一个double型数值保留两位小数
- 计算机基础知识
- Trackball rotate的OSG实现(二)(不是manipulator那种~是动物体那种!)
- 官方指定版本《梅迪辛哈特学院毕业》MHC证书工艺一模一样
- 分布式文件系统 FastDFS 5.09 配置