Android利用mediacodec进行视频H264编码解码播放

原创 2016年08月03日 17:30:22

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 previewMediaPlayer用于播放压缩编码后的音视频文件。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实现硬编码)


版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/bit_kaki/article/details/52105733

Android-->MediaMuxer,MediaCodec,AudioRecord及Camera实现音频视频混合MP4文件

本文相当长,读者请注意… 阅读之前,我喜欢你已经了解了以下内容: 1:https://github.com/saki4510t/AudioVideoRecordingSample 这个开源...
  • angcyo
  • angcyo
  • 2016-04-02 13:29:50
  • 29469

使用MediaCodec播放视频

public class MediaCodecPlayer { private static final String PATH = "/sdcard/a.mp4"; private...
  • leilu000
  • leilu000
  • 2017-12-22 15:05:28
  • 11049

Android在MediaMuxer和MediaCodec录制视频示例 - audio+video

在Android多媒体类,MediaMuxer和MediaCodec这是一个相对年轻,他们是JB 4.1和JB 4.3据介绍。 前者被用来产生一个混合的音频和视频的多媒体文件。的缺点是,现在可以...
  • luoyouren
  • luoyouren
  • 2016-08-06 12:01:52
  • 7280

MediaCodec 解码视频文件

首先初始化解码器: 其中包括视频解码器 和 音频解码器 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { ...
  • qichuangguo
  • qichuangguo
  • 2017-08-02 14:36:45
  • 460

Android 使用MediaCodec实现视频的无缝切换

Android 使用MediaCodec实现视频的无缝切换一、功能说明:在不同控件之间实现视频的无缝切换。不会黑屏,也不需要重新创建解码器。百度上面很多视频播放都是利用MediaPlayer+显示视图...
  • chezi008
  • chezi008
  • 2018-01-04 13:47:44
  • 6419

Android使用MediaCodec硬解码播放H264格式视频文件

前些时间,通过各种搜索加请教了好几个同行的朋友,在他们的指点下实现: RTSP+H264实时视频播放播放及把实时视频流保存到手机SD卡中,再对保存的H264格式文件进行播放等基本功能。 非常感...
  • true100
  • true100
  • 2017-01-03 11:36:29
  • 14228

Android MediaCodec API实现的音视频编解码

音视频编解码思路主要借自己开发音视频编解码的经验谈谈思路,希望可以帮助刚接触音视频编解码的猿们: 音视频的原始数据格式 YUV数据之间的转换 MediaCodec 将原始音视频数据编码 音视频两者之间...
  • qq_26986211
  • qq_26986211
  • 2016-09-06 17:58:36
  • 3404

Android 用MediaCodec实现视频硬解码

本 文向你讲述如何用android标准的API (MediaCodec)实现视频的硬件编解码。例程将从摄像头采集视频开始,然后进行H264编码,再解码,然后显示。 1、从摄像头采集视频  ...
  • u010164190
  • u010164190
  • 2016-11-19 20:34:58
  • 624

Android 用Mediacodec硬解码视频包AVpacket

*****我的视频课程:FFmpeg打造Android万能音频播放器*****         FFmpeg是一个很不错的开源的音视频编解码库,其编解码器几乎涵盖所有格式的音视频。但是它...
  • ywl5320
  • ywl5320
  • 2018-01-03 21:13:47
  • 594

MediaCodec解码H264视频数据

  • 2016年11月21日 14:02
  • 9.53MB
  • 下载
收藏助手
不良信息举报
您举报文章:Android利用mediacodec进行视频H264编码解码播放
举报原因:
原因补充:

(最多只允许输入30个字)