文档章节

MediaCodec 编解码 CTS示例

Javan
 Javan
发布于 2015/10/21 17:23
字数 710
阅读 579
收藏 3
点赞 0
评论 0

**Google CTS source **

   private void encodeDecodeVideo() {
        int width = 328, height = 248;
        int bitRate = 1000000;
        int frameRate = 15;
        String mimeType = "video/avc";
        int threshold = 50;
        int maxerror = 50;

        MediaCodec encoder, decoder = null;
        ByteBuffer[] encoderInputBuffers;
        ByteBuffer[] encoderOutputBuffers;
        ByteBuffer[] decoderInputBuffers = null;
        ByteBuffer[] decoderOutputBuffers = null;

        int numCodecs = MediaCodecList.getCodecCount();
        MediaCodecInfo codecInfo = null;
        for (int i = 0; i < numCodecs && codecInfo == null; i++) {
            MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i);
            if (!info.isEncoder()) {
                continue;
            }
            String[] types = info.getSupportedTypes();
            boolean found = false;
            for (int j = 0; j < types.length && !found; j++) {
                if (types[j].equals(mimeType))
                    found = true;
            }
            if (!found)
                continue;
            codecInfo = info;
        }
        Log.d(TAG, "Found " + codecInfo.getName() + " supporting " + mimeType);

        int colorFormat = 0;
        MediaCodecInfo.CodecCapabilities capabilities = codecInfo.getCapabilitiesForType(mimeType);
        for (int i = 0; i < capabilities.colorFormats.length && colorFormat == 0; i++) {
            int format = capabilities.colorFormats[i];
            switch (format) {
            case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar:
            case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedPlanar:
            case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar:
            case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedSemiPlanar:
            case MediaCodecInfo.CodecCapabilities.COLOR_TI_FormatYUV420PackedSemiPlanar:
                colorFormat = format;
                break;
            default:
                Log.d(TAG, "Skipping unsupported color format " + format);
                break;
            }
        }
        assertTrue("no supported color format", colorFormat != 0);
        Log.d(TAG, "Using color format " + colorFormat);

        if (codecInfo.getName().equals("OMX.TI.DUCATI1.VIDEO.H264E")) {
            // This codec doesn't support a width not a multiple of 16,
            // so round down.
            width &= ~15;
        }
        int stride = width;
        int sliceHeight = height;
        if (codecInfo.getName().startsWith("OMX.Nvidia.")) {
            stride = (stride + 15)/16*16;
            sliceHeight = (sliceHeight + 15)/16*16;
        }
        encoder = MediaCodec.createByCodecName(codecInfo.getName());
        MediaFormat inputFormat = MediaFormat.createVideoFormat(mimeType, width, height);
        inputFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
        inputFormat.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate);
        inputFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat);
        inputFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 75);
        inputFormat.setInteger("stride", stride);
        inputFormat.setInteger("slice-height", sliceHeight);
        Log.d(TAG, "Configuring encoder with input format " + inputFormat);
        encoder.configure(inputFormat, null /* surface */, null /* crypto */, MediaCodec.CONFIGURE_FLAG_ENCODE);
        encoder.start();
        encoderInputBuffers = encoder.getInputBuffers();
        encoderOutputBuffers = encoder.getOutputBuffers();

        int chromaStride = stride/2;
        int frameSize = stride*sliceHeight + 2*chromaStride*sliceHeight/2;
        byte[] inputFrame = new byte[frameSize];
        if (colorFormat == MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar ||
            colorFormat == MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedPlanar) {
            for (int y = 0; y < height; y++) {
                for (int x = 0; x < width; x++) {
                    int Y = (x + y) & 255;
                    int Cb = 255*x/width;
                    int Cr = 255*y/height;
                    inputFrame[y*stride + x] = (byte) Y;
                    inputFrame[stride*sliceHeight + (y/2)*chromaStride + (x/2)] = (byte) Cb;
                    inputFrame[stride*sliceHeight + chromaStride*(sliceHeight/2) + (y/2)*chromaStride + (x/2)] = (byte) Cr;
                }
            }
        } else {
            for (int y = 0; y < height; y++) {
                for (int x = 0; x < width; x++) {
                    int Y = (x + y) & 255;
                    int Cb = 255*x/width;
                    int Cr = 255*y/height;
                    inputFrame[y*stride + x] = (byte) Y;
                    inputFrame[stride*sliceHeight + 2*(y/2)*chromaStride + 2*(x/2)] = (byte) Cb;
                    inputFrame[stride*sliceHeight + 2*(y/2)*chromaStride + 2*(x/2) + 1] = (byte) Cr;
                }
            }
        }

        // start encoding + decoding
        final long kTimeOutUs = 5000;
        MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
        boolean sawInputEOS = false;
        boolean sawOutputEOS = false;
        MediaFormat oformat = null;
        int errors = -1;
        int numInputFrames = 0;
        while (!sawOutputEOS && errors < 0) {
            if (!sawInputEOS) {
                int inputBufIndex = encoder.dequeueInputBuffer(kTimeOutUs);

                if (inputBufIndex >= 0) {
                    ByteBuffer dstBuf = encoderInputBuffers[inputBufIndex];

                int sampleSize = frameSize;
                long presentationTimeUs = 0;

                if (numInputFrames >= 10) {
                    Log.d(TAG, "saw input EOS.");
                    sawInputEOS = true;
                    sampleSize = 0;
                } else {
                    dstBuf.clear();
                    dstBuf.put(inputFrame);
                    presentationTimeUs = numInputFrames*1000000/frameRate;
                    numInputFrames++;
                }

                encoder.queueInputBuffer(
                        inputBufIndex,
                        0 /* offset */,
                        sampleSize,
                        presentationTimeUs,
                        sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
            }
        }

        int res = encoder.dequeueOutputBuffer(info, kTimeOutUs);

        if (res >= 0) {
            int outputBufIndex = res;
            ByteBuffer buf = encoderOutputBuffers[outputBufIndex];

            buf.position(info.offset);
            buf.limit(info.offset + info.size);

            if ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {

                decoder = MediaCodec.createDecoderByType(mimeType);
                MediaFormat format = MediaFormat.createVideoFormat(mimeType, width, height);
                format.setByteBuffer("csd-0", buf);
                decoder.configure(format, null /* surface */, null /* crypto */, 0 /* flags */);
                decoder.start();
                decoderInputBuffers = decoder.getInputBuffers();
                decoderOutputBuffers = decoder.getOutputBuffers();
            } else {
                int decIndex = decoder.dequeueInputBuffer(-1);
                decoderInputBuffers[decIndex].clear();
                decoderInputBuffers[decIndex].put(buf);
                decoder.queueInputBuffer(decIndex, 0, info.size, info.presentationTimeUs, info.flags);
            }

            encoder.releaseOutputBuffer(outputBufIndex, false /* render */);
        } else if (res == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
            encoderOutputBuffers = encoder.getOutputBuffers();

            Log.d(TAG, "encoder output buffers have changed.");
        } else if (res == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
            MediaFormat encformat = encoder.getOutputFormat();

            Log.d(TAG, "encoder output format has changed to " + encformat);
        }

        if (decoder == null)
            res = MediaCodec.INFO_TRY_AGAIN_LATER;
        else
            res = decoder.dequeueOutputBuffer(info, kTimeOutUs);

        if (res >= 0) {
            int outputBufIndex = res;
            ByteBuffer buf = decoderOutputBuffers[outputBufIndex];

            buf.position(info.offset);
            buf.limit(info.offset + info.size);

            if (info.size > 0) {
                errors = checkFrame(buf, info, oformat, width, height, threshold);
            }

            decoder.releaseOutputBuffer(outputBufIndex, false /* render */);

            if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
                Log.d(TAG, "saw output EOS.");
                sawOutputEOS = true;
            }
        } else if (res == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
            decoderOutputBuffers = decoder.getOutputBuffers();

            Log.d(TAG, "decoder output buffers have changed.");
        } else if (res == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
            oformat = decoder.getOutputFormat();

            Log.d(TAG, "decoder output format has changed to " + oformat);
        }

    }

    encoder.stop();
    encoder.release();
    decoder.stop();
    decoder.release();

    assertTrue("no frame decoded", errors >= 0);
    assertTrue("decoding error too big: " + errors + "/" + maxerror, errors <= maxerror);
}

备注

学习理解该代码,有问题可以留言

© 著作权归作者所有

共有 人打赏支持
Javan
粉丝 0
博文 9
码字总数 5102
作品 0
厦门
高级程序员
Android音频编解码和混音实现

相关源码:https://github.com/YeDaxia/MusicPlus 认识数字音频: 在实现之前,我们先来了解一下数字音频的有关属性。 采样频率(Sample Rate):每秒采集声音的数量,它用赫兹(Hz)来表示。(采样...

叶大侠 ⋅ 2016/03/11 ⋅ 14

MediaCodec进行AAC编解码(文件格式转换)

AAC,全称Advanced Audio Coding,是一种专为声音数据设计的文件压缩格式。与MP3不同,它采用了全新的算法进行编码,更加高效,具有更高的“性价比”。利用AAC格式,可使人感觉声音质量没有明...

eric__ ⋅ 01/04 ⋅ 0

MediaCodec 可以解码 High Profile H.264吗

请教大家, 传过来的是High Profile H.264 字节流,用MediaCodec 可以解码吗? 低级别的媒体编解码器 不懂什么意思。 MediaCodec class can be used to access low-level media codec, i.e....

cylvzj ⋅ 2014/02/14 ⋅ 0

微信团队分享:微信Android版小视频编码填过的那些坑

1、前言 Android端的视频相关的开发,大概一直是整个Android生态,以及Android API中,最为分裂以及兼容性问题最为突出的一部分。摄像头,以及视频编码相关的API,Google一直对这方面的控制力...

JackJiang2011 ⋅ 2017/10/31 ⋅ 0

Android播放器的录制实践

播放录制是在观众端录制视频内容存至本地。观众对观看内容非常感兴趣想要将该视频内容留存至本地时便可使用该功能。 一. 可行的方案 在Android端实现播放录制的方法大约有下面三种: 1. 录屏...

敏哥侃视界 ⋅ 2017/12/26 ⋅ 0

Android Mediacodec如何获取当前解码帧的bitmap??

下面是解码及显示视频的核心代码,但是由于绘制图片部分由mediacodec自己完成了,我不知如何获得解码后的bitmap。想实现的就是通过该bitmap保存视频截图功能。 inputBuffers = mediaCodec.ge...

沧海宇尘 ⋅ 2015/07/07 ⋅ 2

android硬编码h264数据,并使用rtp推送数据流,实现一个简单的直播-MediaCodec(二)

上篇博客是使用MediaCodec编码摄像头预览数据成h264数据,并用rtp发送实时数据流。这篇博客是接收h264数据流MediaCodec解码并显示。 先上代码的结构图: eclipse的工程,接收端比较简单只有两...

xmc281141947 ⋅ 2017/08/02 ⋅ 0

iOS音视频相关资料

0!hardman的专栏 音视频直播编码等全! 1、iOS系统中H264硬解及显示说明 2、Android Mediacodec硬解H264并显示 3、使用SDL2.0进行YUV显示 4、FFmpeg基础一 5、http://depthlove.github.io/...

十八郎 ⋅ 2016/12/21 ⋅ 0

Android 音视频开发入门指南

最近收到很多网友通过邮件或者留言说想学习音视频开发,该如何入门,我今天专门写篇文章统一回复下吧。 音视频这块,目前的确没有比较系统的教程或者书籍,网上的博客文章也都是比较零散的,...

Jhuster ⋅ 2017/08/14 ⋅ 0

如何用 Keras 为序列预测问题开发复杂的编解码循环神经网络?

摘要: 编解码模型提供了一种使用循环神经网络来解决诸如机器翻译这样的序列预测问题的模式。编解码模型可以用Keras Python深度学习库来进行开发,使用该模型开发的神经网络机器翻译系统的示...

全球人工智能 ⋅ 2017/11/14 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

常见数据结构(二)-树(二叉树,红黑树,B树)

本文介绍数据结构中几种常见的树:二分查找树,2-3树,红黑树,B树 写在前面 本文所有图片均截图自coursera上普林斯顿的课程《Algorithms, Part I》中的Slides 相关命题的证明可参考《算法(第...

浮躁的码农 ⋅ 16分钟前 ⋅ 0

android -------- 混淆打包报错 (warning - InnerClass ...)

最近做Android混淆打包遇到一些问题,Android Sdutio 3.1 版本打包的 错误如下: Android studio warning - InnerClass annotations are missing corresponding EnclosingMember annotation......

切切歆语 ⋅ 32分钟前 ⋅ 0

eclipse酷炫大法之设置主题、皮肤

eclipse酷炫大法 目前两款不错的eclipse 1.系统设置 Window->Preferences->General->Appearance 2.Eclipse Marketplace下载【推荐】 Help->Eclipse Marketplace->搜索‘theme’进行安装 比如......

anlve ⋅ 40分钟前 ⋅ 0

vim编辑模式、vim命令模式、vim实践

vim编辑模式 编辑模式用来输入或修改文本内容,编辑模式除了Esc外其他键几乎都是输入 如何进入编辑模式 一般模式输入以下按键,均可进入编辑模式,左下角提示 insert(中文为插入) 字样 i ...

蛋黄Yolks ⋅ 44分钟前 ⋅ 0

大数据入门基础:SSH介绍

什么是ssh 简单说,SSH是一种网络协议,用于计算机之间的加密登录。 如果一个用户从本地计算机,使用SSH协议登录另一台远程计算机,我们就可以认为,这种登录是安全的,即使被中途截获,密码...

董黎明 ⋅ 今天 ⋅ 0

web3j教程

web3j是一个轻量级、高度模块化、响应式、类型安全的Java和Android类库提供丰富API,用于处理以太坊智能合约及与以太坊网络上的客户端(节点)进行集成。 汇智网最新发布的web3j教程,详细讲解...

汇智网教程 ⋅ 今天 ⋅ 0

谷歌:安全问题机制并不如你想象中安全

腾讯科技讯 5月25日,如今的你或许已经对许多网站所使用的“安全问题机制”习以为常了,但你真的认为包括“你第一个宠物的名字是什么?”这些问题能够保障你的帐户安全吗? 根据谷歌(微博)安...

问题终结者 ⋅ 今天 ⋅ 0

聊聊spring cloud gateway的RedisRateLimiter

序 本文主要研究下spring cloud gateway的RedisRateLimiter GatewayRedisAutoConfiguration spring-cloud-gateway-core-2.0.0.RELEASE-sources.jar!/org/springframework/cloud/gateway/con......

go4it ⋅ 今天 ⋅ 0

169. Majority Element - LeetCode

Question 169. Majority Element Solution 思路:构造一个map存储每个数字出现的次数,然后遍历map返回出现次数大于数组一半的数字. 还有一种思路是:对这个数组排序,次数超过n/2的元素必然在中...

yysue ⋅ 今天 ⋅ 0

NFS

14.1 NFS介绍 NFS是Network File System的缩写 NFS最早由Sun公司开发,分2,3,4三个版本,2和3由Sun起草开发,4.0开始Netapp公司参与并主导开发,最新为4.1版本 NFS数据传输基于RPC协议,RPC...

派派菠菜 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部