Android使用MediaCodec解码视频

打印 上一主题 下一主题

主题 1589|帖子 1589|积分 4767

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
  1. import android.media.MediaCodec
  2. import android.media.MediaExtractor
  3. import android.media.MediaFormat
  4. import android.util.Log
  5. import java.io.IOException
  6. import java.nio.ByteBuffer
  7. class VideoDecoder {
  8.     companion object {
  9.         private const val TAG = "VideoDecoder"
  10.     }
  11.     fun decodeVideo(videoPath: String) {
  12.         val mediaExtractor = MediaExtractor()
  13.         try {
  14.             // 设置数据源
  15.             mediaExtractor.setDataSource(videoPath)
  16.             // 获取视频轨道索引
  17.             var trackIndex = -1
  18.             val numTracks = mediaExtractor.trackCount
  19.             for (i in 0 until numTracks) {
  20.                 val format = mediaExtractor.getTrackFormat(i)
  21.                 val mime = format.getString(MediaFormat.KEY_MIME)
  22.                 if (mime?.startsWith("video/") == true) {
  23.                     trackIndex = i
  24.                     break
  25.                 }
  26.             }
  27.             if (trackIndex == -1) {
  28.                 Log.e(TAG, "No video track found!")
  29.                 return
  30.             }
  31.             // 选择视频轨道
  32.             mediaExtractor.selectTrack(trackIndex)
  33.             val format = mediaExtractor.getTrackFormat(trackIndex)
  34.             // 获取解码器
  35.             val mimeType = format.getString(MediaFormat.KEY_MIME)
  36.             val mediaCodec = MediaCodec.createDecoderByType(mimeType!!)
  37.             mediaCodec.configure(format, null, null, 0)
  38.             mediaCodec.start()
  39.             // 获取解码器的输入输出缓冲区
  40. //            val inputBuffers = mediaCodec.inputBuffers
  41. //            val outputBuffers = mediaCodec.outputBuffers
  42.             val bufferInfo = MediaCodec.BufferInfo()
  43.             var isEOS = false
  44.             while (!isEOS) {
  45.                 // 提交输入数据
  46.                 val inputBufferIndex = mediaCodec.dequeueInputBuffer(10000)
  47.                 if (inputBufferIndex >= 0) {
  48.                     val inputBuffer = mediaCodec.getInputBuffer(inputBufferIndex)
  49.                     if (inputBuffer == null) {
  50.                         isEOS = true
  51.                     }else{
  52.                         val sampleSize = mediaExtractor.readSampleData(inputBuffer, 0)
  53.                         if (sampleSize < 0) {
  54.                             // 如果没有更多的数据,标记结束
  55.                             mediaCodec.queueInputBuffer(inputBufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM)
  56.                             isEOS = true
  57.                         } else {
  58.                             mediaCodec.queueInputBuffer(inputBufferIndex, 0, sampleSize, mediaExtractor.sampleTime, 0)
  59.                             mediaExtractor.advance()
  60.                         }
  61.                     }
  62.                 }
  63.                 // 获取输出数据并处理
  64.                 val outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 10000)
  65.                 if (outputBufferIndex >= 0) {
  66.                     // 处理帧数据,这里可以进行渲染或存储操作
  67.                     Log.i(TAG, "Decoded frame of size: ${bufferInfo.size}")
  68.                     val outputBuffer: ByteBuffer? = mediaCodec.getOutputBuffer(outputBufferIndex)
  69.                     val byteArray = ByteArray(bufferInfo.size)
  70.                     outputBuffer?.get(byteArray)
  71.                     // 释放输出缓冲区
  72.                     mediaCodec.releaseOutputBuffer(outputBufferIndex, false)
  73.                     if (bufferInfo.flags and MediaCodec.BUFFER_FLAG_END_OF_STREAM !== 0) {
  74.                         // 解码结束
  75.                         break
  76.                     }
  77.                 }
  78.             }
  79.             mediaExtractor.release()
  80.             mediaCodec.stop()
  81.             mediaCodec.release()
  82.         } catch (e: IOException) {
  83.             e.printStackTrace()
  84.         }
  85.     }
  86. }
复制代码


  • MediaExtractor:用于从 MP4 文件中提取视频轨道数据。通过 setDataSource() 设置视频路径,然后使用 getTrackCount() 获取轨道数量。接下来,我们通过 getTrackFormat() 获取轨道的格式,查找视频轨道。
  • MediaCodec:用于解码视频帧。我们使用 createDecoderByType() 创建合适的解码器,并通过 configure() 设置解码器,最后调用 start() 开始解码。
  • ByteBuffer:解码后的视频帧数据存储在 ByteBuffer 中。每次解码成功后,调用 dequeueOutputBuffer() 获取输出帧并通过 get() 方法提取数据。
  • BufferInfo:用于存储每帧的解码信息,例如帧大小、时间戳等。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

tsx81429

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表