Android音视频播放:音视频同步

本文详细介绍了Android音视频播放的实现,包括音视频数据流分离提取器、视频播放、音频播放、调用播放流程及音视频同步。通过封装MediaExtractor实现音频和视频的提取,使用Surface和AudioTrack进行渲染和播放。最后,文章讨论了音视频同步的重要性,提出了以系统时间为同步信号源的策略,确保音视频同步播放。
摘要由CSDN通过智能技术生成

https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3472732648,1327081532&fm=26&gp=0.jpg

 

目录


一、Android音视频硬解码篇:

二、使用OpenGL渲染视频画面篇

三、Android FFmpeg音视频解码篇

  • 1,FFmpeg so库编译
  • 2,Android 引入FFmpeg
  • 3,Android FFmpeg视频解码播放
  • 4,Android FFmpeg+OpenSL ES音频解码播放
  • 5,Android FFmpeg+OpenGL ES播放视频
  • 6,Android FFmpeg简单合成MP4:视屏解封与重新封装
  • 7,Android FFmpeg视频编码

本文你可以了解到

上一篇文章,主要讲了Android MediaCodec实现音视频硬解码的流程,搭建了基础解码框架。本文将讲解具体的音视频渲染,包括MediaCodec初始化、Surface初始化,AudioTrack初始化、音视频数据流分离提取等,以及非常重要的音视频同步。

在上一篇文章定义的解码流程框架基类中,预留了几个虚函数,留给子类初始化自己的东西,本篇,就来看看如何实现。

一、音视频数据流分离提取器

上篇文章,多次提到音视频数据分离提取器,在实现音视频解码器子类之前,先把这个实现了。

封装Android原生提取器

之前提过,Android原生自带有一个MediaExtractor,用于音视频数据分离和提取,接来下基于这个,做一个支持音视频提取的工具类MMExtractor:

  class MMExtractor(path: String?) {

      /**音视频分离器*/
      private var mExtractor: MediaExtractor? = null
    
      /**音频通道索引*/
      private var mAudioTrack = -1
    
      /**视频通道索引*/
      private var mVideoTrack = -1
    
      /**当前帧时间戳*/
      private var mCurSampleTime: Long = 0
    
      /**开始解码时间点*/
      private var mStartPos: Long = 0

      init {
          //【1,初始化】
          mExtractor = MediaExtractor()
          mExtractor?.setDataSource(path)
      }

      /**
       * 获取视频格式参数
       */
      fun getVideoFormat(): MediaFormat? {
          //【2.1,获取视频多媒体格式】
          for (i in 0 until mExtractor!!.trackCount) {
              val mediaFormat = mExtractor!!.getTrackFormat(i)
              val mime = mediaFormat.getString(MediaFormat.KEY_MIME)
              if (mime.startsWith("video/")) {
                  mVideoTrack = i
                  break
              }
          }
          return if (mVideoTrack >= 0)
              mExtractor!!.getTrackFormat(mVideoTrack)
          else null
      }

      /**
       * 获取音频格式参数
       */
      fun getAudioFormat(): MediaFormat? {
          //【2.2,获取音频频多媒体格式】
          for (i in 0 until mExtractor!!.trackCount) {
              val mediaFormat = mExtractor!!.getTrackFormat(i)
              val mime = mediaFormat.getString(MediaFormat.KEY_MIME)
              if (mime.startsWith("audio/")) {
                  mAudioTrack = i
                  break
              }
          }
          return if (mAudioTrack >= 0) {
              mExtractor!!.getTrackFormat(mAudioTrack)
          } else null
      }

      /**
       * 读取视频数据
       */
      fun readBuffer(byteBuffer: ByteBuffer): Int {
          //【3,提取数据】
          byteBuffer.clear()
          selectSourceTrack()
          var readSampleCount = mExtractor!!.readSampleData(byteBuffer, 0)
          if (readSampleCount < 0) {
              return -1
          }
          mCurSampleTime = mExtractor!!.sampleTime
          mExtractor!!.advance()
          return readSampleCount
      }

      /**
       * 选择通道
       */
      private fun selectSourceTrack() {
          if (mVideoTrack >= 0) {
              mExtractor!!.selectTrack(mVideoTrack)
          } else if (mAudioTrack >= 0) {
              mExtractor!!.selectTrack(mAudioTrack)
          }
      }

       /**
       * Seek到指定位置,并返回实际帧的时间戳
       */
      fun seek(pos: Long): Long {
          mExtractor!!.seekTo(pos, MediaExtractor.SEEK_TO_PREVIOUS_SYNC)
          return mExtractor!!.sampleTime
      }

      /**
      
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值