范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

MediaCodecAPI,完成音频AAC硬编,5。0异步处理,AudioRecord录音

  本文代码示例采用的Kotlin语法,但是没什么高级特性
  MediaExtractor:视频文件的提取器,能将视频和音频分离
  MediaMuxer:音视频文件合成器,能将提取到的视频和音频合成新的视频
  MediaFormat :提取器获取到的媒体格式类,保存了获取到的媒体的信息(媒体类型, 帧率等)1.设置需要权限
  一.如果是本地文件,会涉及到读取和写入,需要在Manifest配置
  6.0以上要在代码中动态申请,这里就省略了2.获取需要的视频文件
  本文是直接通过contentResolver查询多媒体文件val cursor = contentResolver.query(
  MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
  null, null, null, null
  )
  // 查询到的数据存储到了自建的Song类中,存了文件名(name)和路径(path),然后用ListView展示,
  为了省事,直接使用的就是点击的文件和相邻下一个文件做为提取视频和音频的原材料 如果不想麻烦去找文件,也可以直接把视频文件放到res/raw文件夹下,raw要自己创建 然后获取文件,MediaExtractor.setDataSource支持很多方式填充
  【更多音视频学习资料,点击下方链接免费领取↓↓ ,先码住不迷路~】
  点击领取→音视频开发基础知识和资料包3.提取音视频/**
  * 配置音视频提取器
  * @param position 点击的文件下标
  */
  fun configureVideoAndAudioExtractor(position: Int) {
  try {
  //1.设置要提取视频的文件
  /**
  *
  * MediaExtractor反复提示初始化失败
  * 1.检查文件访问权限
  * 2.检查视频文件大小是否大于0!!!!!!!!!!!!!!!
  * 3.最好不要用拼接路径,比如
  * mVideoMediaExtractor.setDataSource(context.getFilesDir()+"xxx.mp4")
  * 最好添加路径变量或完整路径地址,比如下面的变量或
  * "mnt/sdcard/.../.../xxx.mp4"这种的
  */
  //初始化解析器和合成器对象,合成输入的格式是mp4,
  //outputVideoPath是合成后输出的路径,自己构建就好
  //我的是fileDir+"video.mp4"
  mMediaMuxer = MediaMuxer(outputVideoPath,
  MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4)
  mVideoMediaExtractor = MediaExtractor()
  mAudioMediaExtractor = MediaExtractor()
  //songList是一个集合,存着Song类,
  //设置要提取出视频的原材料文件
  mVideoMediaExtractor.setDataSource(songList[position].path)
  //设置要提取出音频的文件
  mAudioMediaExtractor.setDataSource(songList[position].path)
  //获取轨道,找到视频轨道
  for (i in 0 until mVideoMediaExtractor.trackCount) {
  val mediaFormat = mVideoMediaExtractor.getTrackFormat(i)
  if (mediaFormat.getString(MediaFormat.KEY_MIME).startsWith("video/")) {
  //获取到视频轨道
  mVideoMediaExtractor.selectTrack(i)
  //获取添加到Muxer后生成的新的视频轨道下标
  videoMuxerTrackIndex = mMediaMuxer.addTrack(mediaFormat)
  //获取视频帧最大值,为了后面合成新视频,读取文件时候设定缓冲区大小
  maxFrameSize = mediaFormat.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE)
  //获取视频帧率,为了后面计算获取到的文件处于的播放时间
  frameRate = mediaFormat.getInteger(MediaFormat.KEY_FRAME_RATE)
  }
  }
  //找到视频文件中的音频轨道,方法和获取视频差不多
  for (j in 0 until mAudioMediaExtractor.trackCount) {
  val mediaFormat = mAudioMediaExtractor.getTrackFormat(j)
  if (mediaFormat.getString(MediaFormat.KEY_MIME).startsWith("audio/")) {
  //获取音轨
  mAudioMediaExtractor.selectTrack(j)
  //添加音轨到Muxer
  audioMuxerTrackIndex = mMediaMuxer.addTrack(mediaFormat)
  //获取音频最大输入,为了计算缓冲区大小
  maxAudioSize = mediaFormat.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE)
  }
  }
  //这个方法内执行MediaMuxer的合成操作,下面会贴出来
  compoundVideoAndAudioWithPermissionCheck()
  } catch (e: IOException) {
  Log.i("exception", e.message)
  } finally {
  //释放资源,切记最后要是放资源,重新添加合成文件时候要新建MediaExtractor和MediaMuxer
  if (mMediaMuxer != null) {
  mMediaMuxer.release()
  }
  if (mVideoMediaExtractor != null) {
  mVideoMediaExtractor.release()
  }
  if (mAudioMediaExtractor != null) {
  mAudioMediaExtractor.release()
  }
  }
  }
  总结一下步骤就是
  1.创建MediaExtractor和MediaMuxer对象
  2.为MediaExtractor对象添加需要的文件setDataSource()
  3.for循环获取视频轨道和音频轨道MediaExtractor#selectTrack(),并添加到MediaMuxer中 MediaMuxer#addTrack()
  4.开始准备合并4.合成音视频/**
  * 合成视频和音频
  */
  fun compoundVideoAndAudio() {
  //1.开始合成
  mMediaMuxer.start()
  //2.输入提取到的视频,videoMuxerTrackIndex是之前addTrack生成的下标,
  //如果为-1就是添加失败
  if (-1 != videoMuxerTrackIndex) {
  //描述缓冲区数据信息类,最后Muxer合成要求有的东西
  val videoBufferInfo = MediaCodec.BufferInfo()
  //创建缓冲区,最后Muxer合成要求有的东西
  val videoByteBuffer = ByteBuffer.allocate(maxFrameSize)
  while (true) {
  /3./获取样本大小
  val videoSampleSize = mVideoMediaExtractor.readSampleData(videoByteBuffer, 0)
  if (videoSampleSize < 0) {
  break
  }
  //4.设置样本信息
  videoBufferInfo.offset = 0 //堆buffer缓冲区写入时的字节偏移
  videoBufferInfo.size = videoSampleSize
  videoBufferInfo.flags = mVideoMediaExtractor.sampleFlags
  //读取到的文件的时间戳,单位是微秒
  videoBufferInfo.presentationTimeUs += 1000 * 1000 / frameRate //每次加每帧的微秒数
  //MediaMuxer写入样本数据
  //videoMuxerTrackIndex 之前加入Muxer的视频轨下标
  //videoByteBuffer 上面创建的Buffer对象
  //videoBufferInfo 上面创建的BufferInfo对象
  mMediaMuxer.writeSampleData(videoMuxerTrackIndex, videoByteBuffer, videoBufferInfo)
  //5.推进到下个样本 类似快进
  mVideoMediaExtractor.advance()
  }
  }
  /**
  * 合成音频,和视频类似
  */
  if (-1 != audioMuxerTrackIndex) {
  val audioBufferInfo = MediaCodec.BufferInfo()
  val audioByteBuffer = ByteBuffer.allocate(maxAudioSize)
  while (true) {
  val audioSampleSize = mAudioMediaExtractor.readSampleData(audioByteBuffer, 0)
  if (audioSampleSize < 0) {
  break
  }
  audioBufferInfo.offset = 0
  audioBufferInfo.size = audioSampleSize
  audioBufferInfo.flags = mAudioMediaExtractor.sampleFlags
  audioBufferInfo.presentationTimeUs += 1000 * 1000 / frameRate
  mMediaMuxer.writeSampleData(audioMuxerTrackIndex, audioByteBuffer, audioBufferInfo)
  mAudioMediaExtractor.advance()
  }
  }
  }
  }
  }
  这个方法是在之前的方法内调用,所以try..catch写在上面的方法中,这些步骤都可以在子线程中去做,最后可以通过系统的VideoView控件来播放outputVideoPath路径的视频,查看是否合成成功
  【更多音视频学习资料,点击下方链接免费领取↓↓ ,先码住不迷路~】
  点击领取→音视频开发基础知识和资料包总结流程创建Buffer对象和MediaCodec#BufferInfo对象读取样本数据,验证数据大小填写bufferInfo的信息将缓冲区内容写入Muxer调用MediaExtractor#advance(),推进到下个样本数据,循环步骤2-5释放资源
  需要注意的地方!!!!!!!!!!!!!!!
  1.权限获取
  2.验证要提取的文件是否合法,比如大小,本人遇到MediaExtractor.setDataSource()一直无法初始化MediaExtractor,结果发现添加的视频大小为0KB
  3.时间戳会影响合成后效果,需要注意计算
  如果你对音视频开发感兴趣,觉得文章对您有帮助,别忘了点赞、收藏哦!或者对本文的一些阐述有自己的看法,有任何问题,欢迎在下方评论区讨论!

待就业!盘点自由市场的全明星球员,三名湖人旧将上榜NBA季前赛已经开始两天了,不少球队也已经打了季前赛的比赛,这也就意味着距离新赛季开启的时间越来越近,早些时候凯尔特人被曝出与格里芬达成一年合同。只不过目前球队方面还没有官宣签约达若为自由故我死了。当我的灵魂漂浮在空中大约五分钟后,我才意识清醒过来。熟悉的家,和跪在地上痛哭的爸妈。哦我想起来了,我是被他们逼死的。1hr我有个很爱,一直相处得很融洽的男朋友。高高瘦瘦,长爱妳,就会成全妳的自由生生世世的祈盼一点一点地感动了万能的上苍使自己成了披上诱惑衣裳的苹果等候到思念中人经过的那一刻满溢着成熟的香甜却依然打动不了近在咫尺的心不甘心的痴痴挣扎仅仅只是让自己从枝头脱落圆满贝小七蕾丝深V挺贝嫂大秀!后台同框超模软萌画面流出贝克汉姆家么女贝小七(HarperSeven),在时装周身穿深V剪裁洋装,与超模姊妹花吉吉哈蒂德(GigiHadid)贝拉哈蒂德(BellaHadid)同框的画面造成网友洗版直呼小卡西欧为GShock粉丝们,专门制作的一款腕表卡西欧今年新推出的GShockDW5600GU7,这是一款专门为了GShock粉丝们制作的一款特别的手表,而卡西欧为了庆祝MasterofG腕表世界中经常隐藏的功能。卡西欧创造了一张小斐齐肩锁骨发要火!深秋街拍美照上热搜,网友天生的电影人果然,红气养人!凭借你好李焕英,被更多观众熟知和喜欢的张小斐,在国庆节期间,晒出一组剧照。白色圆领线衣,搭配黑色直筒长裤,手拎mini包,一头齐肩锁骨发,优雅又俏皮。回眸看镜头时,秋凉了,写给最牵挂的你作者昕月蓝殇捡起一片落叶,写下一段心语,就算时间,也不能抹去对你的思念。秋凉了,写给最牵挂的你,想关心你,却找不到联系你的理由。有些情,是时光里最深的遗憾。无论走到哪里,总是为你情酒桌上不主动敬酒的人,情商都很低吗?其实他们才是高智慧的人酒桌上不主动敬酒的人,情商都很低吗?其实他们才是高智慧的人我们生活在这个社会里,总是需要了解一些为人处世的一些手段和技巧的。因为这些在你的生活上一样是很重要的。很多人觉得自己可以依跨越畏难情绪,把工作当成一场学习在决定和江武墨老师学习之前,我已经在家待业两个月,并刚好经历了一场失败的面试。那段时间我的状态很糟糕,不知道自己到底想要做什么,陷入了一种迷茫和自我否定,觉得自己什么都做不好,甚至文案众口难调,开心就好1。你要快乐,不必正常。2。一切都是最好的安排。3。如果事与愿违那一定另有安排。4。世界大雨滂沱,愿你随心而活。5。不好的事情,酌情处理,适当过滤。6。花点小心思让每天的生活过的有我爱我的国,也爱我的家我的小家和大家我的小家其实很简单,平平常常的一个小家庭。虽然说女儿己经结婚,但是她在我家附近工作,也会经常来家里吃饭。我的小家并不富裕,没有一件像样的家具。立柜还是父辈们用过的3一
南航和西工大差距有多大?哪个有发展前景?南京航空航天大学和西北工业大学比较哪个好?很多人会认为,西工大是985高校南航是211大学,可能西工大就好一些。你以为西工大985,南航211,西工大就一定好吗?未必!你以为西工大什么样的人一辈子不得癌?癌症,看似简单,其实它后面的过程非常复杂。在这个疾病中,可以说任何人都无法避免,因为我们的身体里本来就存在致癌因子。大多数人可能一辈子不会被激活,一部分人因为各种各样的原因,这个致焦虑症可以痊愈吗?如果专科医生对你下了一个焦虑障碍的诊断,焦虑障碍的治疗就是必须的,通常我们在临床上焦虑障碍是一种治疗效果较好,而且愈后不错的精神障碍。临床上通过药物治疗,或者心理治疗,或者二者联合帮亲戚炒股赚了十几万,亲戚为表示感谢要给我两千块,该不该要?溯源认为这钱一定不能要。为什么?1你帮亲戚赚了十几万,假设你整体盈利率为10,那么也是100多万,而给你的报酬仅2000元,你这亲戚也够抠门了。22000元,如果你接受了,这是对你为什么有人说瑞士银行是全世界最安全的银行?瑞士银行,在第二次世界大战爆发时,就连纳粹德国都不敢侵犯和掠夺!它之所以安全,最主要的原因就是永久安全国的身份和严格的保密制度!瑞士,是一个非常独特的国家!这个国家,打造了全球最受公务员想辞职,想法很强烈!有没有辞职后悔的?看自身原因建议你在做出决定之前,慎重!!!因为发生在我身边就有后悔的真事某执法监督局的小张近年来对自己的工作越来越不满意,每天都有干不完的事。通常是群众举报到上一级局,上级接到举报做保险销售有什么方法寻找客户资源?保险业务员的获客渠道其实有很多的,主要是看你自己适合哪个渠道。简单的说一些获客渠道吧。第一缘故市场这个是很多保险销售起步的地方,因为现在买保险的人很多,卖保险的人也很多,而中国人又都在说特斯拉底盘质感差内饰毛坯,操纵不好怎么销量还这么高?销量高是真的,底盘质感差内饰毛坯操纵不好都是没有根据人云亦云的。从销售统计数据来看,特斯拉销量遥遥领先。先说底盘,特斯拉是最早使用纯电平台,电池电机都是居中布置在底板上重心低,前后保研该不该直博?直博有什么优势和不足?在不少学校推免研究生的时候,有的导师都会问学生是否愿意直博,如果愿意的话,被保送的概率就能大大的增加。那么,本科毕业以后,是推免研究生好,还是选择直博好呢?个人以为,如果在推免研究4天时间成都走川西小环线行程怎么安排,沿途的景点都有哪些呢?你好,很高兴能回答你的问题。川西小环线是一个非常经典的线路,沿途景观非常的多而经典,4天时间略短,因此,建议把离成都较近的一些景点(比如海螺沟)放弃掉,留待以后周末的时候再去。将4内燃机车也是柴油机,那么是否像汽车一样也需要变速箱呢?如果有,是手动还是自动?内燃机车有两种类型内燃机电传动机车液力传动内燃机车,普及率最高的是电传动类型极少数为液力传动。所电传动内燃机车是增程式混动汽车的放大版,或者说是反之的缩小版。柴油机在这类火车上的作