Android使用MediaCodec解码视频

kotlin 复制代码
import android.media.MediaCodec
import android.media.MediaExtractor
import android.media.MediaFormat
import android.util.Log
import java.io.IOException
import java.nio.ByteBuffer

class VideoDecoder {

    companion object {
        private const val TAG = "VideoDecoder"
    }

    fun decodeVideo(videoPath: String) {
        val mediaExtractor = MediaExtractor()

        try {
            // 设置数据源
            mediaExtractor.setDataSource(videoPath)

            // 获取视频轨道索引
            var trackIndex = -1
            val numTracks = mediaExtractor.trackCount
            for (i in 0 until numTracks) {
                val format = mediaExtractor.getTrackFormat(i)
                val mime = format.getString(MediaFormat.KEY_MIME)
                if (mime?.startsWith("video/") == true) {
                    trackIndex = i
                    break
                }
            }

            if (trackIndex == -1) {
                Log.e(TAG, "No video track found!")
                return
            }

            // 选择视频轨道
            mediaExtractor.selectTrack(trackIndex)
            val format = mediaExtractor.getTrackFormat(trackIndex)

            // 获取解码器
            val mimeType = format.getString(MediaFormat.KEY_MIME)
            val mediaCodec = MediaCodec.createDecoderByType(mimeType!!)
            mediaCodec.configure(format, null, null, 0)
            mediaCodec.start()

            // 获取解码器的输入输出缓冲区
//            val inputBuffers = mediaCodec.inputBuffers
//            val outputBuffers = mediaCodec.outputBuffers
            val bufferInfo = MediaCodec.BufferInfo()
            var isEOS = false
            while (!isEOS) {
                // 提交输入数据
                val inputBufferIndex = mediaCodec.dequeueInputBuffer(10000)
                if (inputBufferIndex >= 0) {
                    val inputBuffer = mediaCodec.getInputBuffer(inputBufferIndex)
                    if (inputBuffer == null) {
                        isEOS = true
                    }else{
                        val sampleSize = mediaExtractor.readSampleData(inputBuffer, 0)
                        if (sampleSize < 0) {
                            // 如果没有更多的数据,标记结束
                            mediaCodec.queueInputBuffer(inputBufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM)
                            isEOS = true
                        } else {
                            mediaCodec.queueInputBuffer(inputBufferIndex, 0, sampleSize, mediaExtractor.sampleTime, 0)
                            mediaExtractor.advance()
                        }
                    }
                }

                // 获取输出数据并处理
                val outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 10000)

                if (outputBufferIndex >= 0) {
                    // 处理帧数据,这里可以进行渲染或存储操作
                    Log.i(TAG, "Decoded frame of size: ${bufferInfo.size}")
                    val outputBuffer: ByteBuffer? = mediaCodec.getOutputBuffer(outputBufferIndex)
                    val byteArray = ByteArray(bufferInfo.size)
                    outputBuffer?.get(byteArray)

                    // 释放输出缓冲区
                    mediaCodec.releaseOutputBuffer(outputBufferIndex, false)
                    if (bufferInfo.flags and MediaCodec.BUFFER_FLAG_END_OF_STREAM !== 0) {
                        // 解码结束
                        break
                    }
                }
            }

            mediaExtractor.release()
            mediaCodec.stop()
            mediaCodec.release()

        } catch (e: IOException) {
            e.printStackTrace()
        }
    }
}
  • MediaExtractor:用于从 MP4 文件中提取视频轨道数据。通过 setDataSource() 设置视频路径,然后使用 getTrackCount() 获取轨道数量。接下来,我们通过 getTrackFormat() 获取轨道的格式,查找视频轨道。
  • MediaCodec:用于解码视频帧。我们使用 createDecoderByType() 创建合适的解码器,并通过 configure() 配置解码器,最后调用 start() 开始解码。
  • ByteBuffer:解码后的视频帧数据存储在 ByteBuffer 中。每次解码成功后,调用 dequeueOutputBuffer() 获取输出帧并通过 get() 方法提取数据。
  • BufferInfo:用于存储每帧的解码信息,例如帧大小、时间戳等。
相关推荐
Ulyanov2 小时前
AudioVision Pro:基于 PySide6 + sounddevice 的实时音频可视化播放器设计
python·算法·音视频
福大大架构师每日一题2 小时前
ComfyUI v0.34.0发布:视频、音频、三维、显存与合作节点全面更新
音视频
IT毕设实战小研2 小时前
基于大数据的国内主要农作物产量趋势分析与可视化
android·java·大数据·django·课程设计
企业数字化笔记3 小时前
固定资产历史数据怎么导入系统?Excel模板、字段映射和数据校验
android·java·数据库·后端
龙之叶4 小时前
Android出海系列-GMS认证介绍
android
潮族大Z4 小时前
Android性能优化:启动、内存、卡顿的一站式排查手册
android
敲代码的嘎仔5 小时前
用 Redis 合并写 + DelayQueue 延迟检测,把视频播放进度写库频率降到 1/60
java·开发语言·数据库·redis·缓存·音视频·高并发
事圆则缓5 小时前
从suspend字节码到 Retrofit 协程桥:挂起函数识别与恢复
android·retrofit
Xxtaoaooo6 小时前
AI 视频生成能不能真正跑通?MoneyPrinterTurbo 本地制作、远程访问与授权验证
人工智能·音视频·cpolar·ai视频·自动化短视频
杉氧6 小时前
RN 性能调优指南:重渲染(Re-renders)控制与长列表(FlatList)优化
android·前端·react native