MediaCodec 使用(二)-- YUV打包成MP4

图像数据格式简介
  • YUV格式:
    • planar:先连续存储所有像素点的Y,紧接着存储所有像素点的U,再存储所有像素点的V,
      将Y、U、V的三个分量分别存放在不同的矩阵中
    • packed:将Y、U、V值存储成Macro Pixels数组,和RGB的存放方式类似
  • YUV存储:
    • 主流的采样方式主要有:YUV444,YUV422,YUV420,只有正确的还原每个像素点的YUV值,才能通过YUV与RGB的转换公式提取出每个像素点的RGB值,然后显示出来
      • YUV 4:4:4表示完全取样,每一个Y对应一组UV分量,一个YUV占8+8+8 = 24bits 3个字节
      • YUV 4:2:2表示2:1的水平取样,垂直完全采样,每两个Y共用一组UV分量,一个YUV占8+4+4 = 16bits 2个字节
      • YUV 4:2:0表示2:1的水平取样,垂直2:1采样,每四个Y共用一组UV分量,一个YUV占8+2+2 = 12bits 1.5个字节
      • YUV4:1:1表示4:1的水平取样,垂直完全采样
获取图像数据帧并进行编码
  • 使用MediaCodec对onPreviewFrame获取返回的图像帧(格式默认为NV21)进行编码,并使用MediaMuxer进行保存
创建编码器并打包
class VideoEncoder(size: Camera.Size) : AppCompatActivity() {
    private var mSize: Camera.Size

    private var mTrackIndex: Int = 0

    init {
        mSize = size
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 初始化编码器
        val mediaFormat =
            MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, mSize.width, mSize.height)
        mediaFormat.setInteger(
            MediaFormat.KEY_COLOR_FORMAT,
            MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible
        )
        mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 1048576)
        mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 30)
        mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1)
        val mediaCodec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_AVC)
        val mp4Path = Environment.getExternalStorageDirectory().toString() + "wjx" + ".mp4"
        // 创建混合生成器MediaMuxer
        val mediaMuxer = MediaMuxer(mp4Path, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4)
        // 配置状态
        mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)
        mediaCodec.start()
        encodeVideo(mediaCodec, mediaMuxer)
    }


    /**
     * 通过getInputBuffers获取输入队列,然后调用dequeueInputBuffer获取输入队列空闲数组下标,
     * 注意dequeueOutputBuffer会有几个特殊的返回值表示当前编解码状态的变化,
     * 然后再通过queueInputBuffer把原始YUV数据送入编码器,
     * 而在输出队列端同样通过getOutputBuffers和dequeueOutputBuffer获取输出的h264流,
     * 处理完输出数据之后,需要通过releaseOutputBuffer把输出buffer还给系统,重新放到输出队列中。
     */
    private fun encodeVideo(mediaCodec: MediaCodec, mediaMuxer: MediaMuxer) {
        Thread(object : Runnable {
            override fun run() {
                while (true) {
                    try {
                        val bufferInfo = MediaCodec.BufferInfo()
                        val outputBufferId = mediaCodec.dequeueOutputBuffer(bufferInfo, 0)
                        if (outputBufferId >= 0) {
                            val outPutBuffer = mediaCodec.getOutputBuffer(outputBufferId)
                            val h264: ByteArray = ByteArray(bufferInfo.size)
                            val outputBuffer = mediaCodec.getOutputBuffer(0)
                            outPutBuffer?.get(h264)
                            outPutBuffer?.position(bufferInfo.offset)
                            outPutBuffer?.limit(bufferInfo.offset + bufferInfo.size)
                            mediaMuxer.writeSampleData(mTrackIndex, outputBuffer!!, bufferInfo)
                            mediaCodec.releaseOutputBuffer(outputBufferId, false)
                        } else if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
                            val mediaFormat = mediaCodec.outputFormat
                            mTrackIndex = mediaMuxer.addTrack(mediaFormat)
                            mediaMuxer.start()
                        }
                    } catch (e: InterruptedException) {
                        e.printStackTrace()
                    }
                }
                mediaCodec.stop()
                mediaCodec.release()
                mediaMuxer.stop()
                mediaMuxer.release()
            }
        }).start();
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wjxbless

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值