本篇项目地址,名字是媒体解码MediaCodec,MediaExtractor,求star
https://github.com/979451341/Audio-and-video-learning-materials

这次要用到新的东西SurfaceView、MediaCodec、MediaExtractor、MediaFormat

1.文字说明

SurfaceView:一个View,用来显示视频的,使用的时候代码都比较简单就不多说了

MediaCodec:访问底层媒体编码,能够完成媒体编码和解码
编码是将源对象内容按照一种标准转换为一种标准格式内容。
解码是和编码对应的,它使用和编码相同的标准将编码内容还原为最初的对象内容。

MediaExtractor:负责将指定类型的媒体文件从文件中找到轨道,并填充到MediaCodec的缓冲区中

MediaFormat:封装描述媒体数据格式的信息,无论是音频还是视频。媒体数据的格式被指定为字符串/值对。所有格式通用的键,所有未标记为可选的键都是必需的:
名称     值类型     描述
KEY_MIME     串     格式的类型。
KEY_MAX_INPUT_SIZE     整数     可选,输入数据缓冲区的最大大小
KEY_BIT_RATE     整数     仅编码器,所需比特率(以比特/秒为单位)

2.视频播放顺序

(1)开启两个线程分别处理MP4的音频和视频

我先说一下视频的处理

使用MediaExtractor提取资源,选择频道

  1. MediaExtractor videoExtractor = new MediaExtractor();
  2. MediaCodec videoCodec = null;
  3. try {
  4. videoExtractor.setDataSource(filePath);
  5. } catch (IOException e) {
  6. e.printStackTrace();
  7. }
  8. int videoTrackIndex;
  9. //获取视频所在轨道
  10. videoTrackIndex = getMediaTrackIndex(videoExtractor, "video/");
  11. videoExtractor.selectTrack(videoTrackIndex);

设置解码配置,并给MediaCodec配置,而且将SurfaceView于MediaCodec相关联,设置为在这个SurfaceView上显示

  1. MediaFormat mediaFormat = videoExtractor.getTrackFormat(videoTrackIndex);
  2. int width = mediaFormat.getInteger(MediaFormat.KEY_WIDTH);
  3. int height = mediaFormat.getInteger(MediaFormat.KEY_HEIGHT);
  4. float time = mediaFormat.getLong(MediaFormat.KEY_DURATION) / 1000000;
  5. callBack.videoAspect(width, height, time);
  6. videoExtractor.selectTrack(videoTrackIndex);
  7. try {
  8. videoCodec = MediaCodec.createDecoderByType(mediaFormat.getString(MediaFormat.KEY_MIME));
  9. videoCodec.configure(mediaFormat, surface, null, 0);
  10. } catch (IOException e) {
  11. e.printStackTrace();
  12. }

循环从MediaExtractor取数据放入MediaCodec,同时MediaCodec返回数据,表示视频播放状态,然后对应转台做不同的处理,

  1. while (!Thread.interrupted()) {
  2. if (!isPlaying) {
  3. continue;
  4. }
  5. //将资源传递到解码器
  6. if (!isVideoEOS) {
  7. isVideoEOS = putBufferToCoder(videoExtractor, videoCodec, inputBuffers);
  8. }
  9. int outputBufferIndex = videoCodec.dequeueOutputBuffer(videoBufferInfo, TIMEOUT_US);
  10. switch (outputBufferIndex) {
  11. case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
  12. Log.v(TAG, "format changed");
  13. break;
  14. case MediaCodec.INFO_TRY_AGAIN_LATER:
  15. Log.v(TAG, "超时");
  16. break;
  17. case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
  18. //outputBuffers = videoCodec.getOutputBuffers();
  19. Log.v(TAG, "output buffers changed");
  20. break;
  21. default:
  22. //直接渲染到Surface时使用不到outputBuffer
  23. //ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
  24. //延时操作
  25. //如果缓冲区里的可展示时间>当前视频播放的进度,就休眠一下
  26. sleepRender(videoBufferInfo, startMs);
  27. //渲染
  28. videoCodec.releaseOutputBuffer(outputBufferIndex, true);
  29. break;
  30. }
  31.  
  32. if ((videoBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
  33. Log.v(TAG, "buffer stream end");
  34. break;
  35. }
  36. }//end while

然后是音频,很相似
MediaExtractor获取资源,选择频道,得到MediaFormat,获取一些参数来配置AudioTrack,然后就不说了,上一篇博客说了如何播放音频,

  1. MediaExtractor audioExtractor = new MediaExtractor();
  2. try {
  3. audioExtractor.setDataSource(filePath);
  4. } catch (IOException e) {
  5. e.printStackTrace();
  6. }
  7.  
  8. MediaFormat mediaFormat = audioExtractor.getTrackFormat(i);
  9. String mime = mediaFormat.getString(MediaFormat.KEY_MIME);
  10. if (mime.startsWith("audio/")) {
  11. audioExtractor.selectTrack(i);
  12.  
  13. int audioChannels = mediaFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
  14. int audioSampleRate = mediaFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE);
  15. int minBufferSize = AudioTrack.getMinBufferSize(audioSampleRate,
  16. (audioChannels == 1 ? AudioFormat.CHANNEL_OUT_MONO : AudioFormat.CHANNEL_OUT_STEREO),
  17. AudioFormat.ENCODING_PCM_16BIT);
  18. int maxInputSize = mediaFormat.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE);
  19.  
  20. audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
  21. audioSampleRate,
  22. (audioChannels == 1 ? AudioFormat.CHANNEL_OUT_MONO : AudioFormat.CHANNEL_OUT_STEREO),
  23. AudioFormat.ENCODING_PCM_16BIT,
  24. audioInputBufferSize,
  25. AudioTrack.MODE_STREAM);

其实这做的不太好,因为音频和视频没有做协调,之前可能不同步

完整代码下载地址在文章头部

参考文章:
http://blog.csdn.net/qq_36467463/article/details/77990089
https://www.cnblogs.com/jiy-for-you/p/7282033.html
https://www.jianshu.com/p/6df2ab17651a

Android 音视频深入 三 MP4解码播放视频 (附源码下载)的更多相关文章

  1. leaflet-webpack 入门开发系列三地图分屏对比(附源码下载)

    前言 leaflet-webpack 入门开发系列环境知识点了解: node 安装包下载webpack 打包管理工具需要依赖 node 环境,所以 node 安装包必须安装,上面链接是官网下载地址 w ...

  2. Android中Canvas绘图基础详解(附源码下载) (转)

    Android中Canvas绘图基础详解(附源码下载) 原文链接  http://blog.csdn.net/iispring/article/details/49770651   AndroidCa ...

  3. Android 高仿 频道管理----网易、今日头条、腾讯视频 (可以拖动的GridView)附源码DEMO

    距离上次发布(android高仿系列)今日头条 --新闻阅读器 (二) 相关的内容已经半个月了,最近利用空闲时间,把今日头条客户端完善了下.完善的功能一个一个全部实现后,就放整个源码.开发的进度就是按 ...

  4. Android 音视频深入 四 录视频MP4(附源码下载)

    本篇项目地址,名字是<录音视频(有的播放器不能放,而且没有时长显示)>,求star https://github.com/979451341/Audio-and-video-learnin ...

  5. Android 音视频深入 十八 FFmpeg播放视频,有声音(附源码下载)

    项目地址https://github.com/979451341/AudioVideoStudyCodeTwo/tree/master/FFmpegv%E6%92%AD%E6%94%BE%E8%A7% ...

  6. Android 音视频深入 十五 FFmpeg 推流mp4文件(附源码下载)

    源码地址https://github.com/979451341/Rtmp 1.配置RTMP服务器 这个我不多说贴两个博客分别是在mac和windows环境上的,大家跟着弄 MAC搭建RTMP服务器h ...

  7. Android 音视频深入 九 FFmpeg解码视频生成yuv文件(附源码下载)

    项目地址,求star https://github.com/979451341/Audio-and-video-learning-materials/tree/master/FFmpeg(MP4%E8 ...

  8. Android 音视频深入 二十 FFmpeg视频压缩(附源码下载)

    项目源码https://github.com/979451341/FFmpegCompress 这个视频压缩是通过类似在mac终端上输入FFmpeg命令来完成,意思是我们需要在Android上达到能够 ...

  9. Android 音视频深入 十九 使用ijkplayer做个视频播放器(附源码下载)

    项目地址https://github.com/979451341/Myijkplayer 前段时候我觉得FFmpeg做个视频播放器好难,虽然播放上没问题,但暂停还有通过拖动进度条来设置播放进度,这些都 ...

随机推荐

  1. SpringBoot整合Servlet的两种方式

    SpringBoot整合Servlet有两种方式: 1.通过注解扫描完成Servlet组件的注册: 2.通过方法完成Servlet组件的注册: 现在简单记录一下两种方式的实现 1.通过注解扫描完成Se ...

  2. leecode第一百四十二题(环形链表II)

    /** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode ...

  3. 《剑指offer》第五十二题(两个链表的第一个公共结点)

    // 面试题52:两个链表的第一个公共结点 // 题目:输入两个链表,找出它们的第一个公共结点. #include <iostream> #include "List.h&quo ...

  4. pdf can't copy text 无法复制文字

    有些 pdf 是通过图片弄出来的,或者被 protect 了. 我们会无法 copy 里面的字. 这个时候可以用 OCR (Optical character recognition) 就是从图片中识 ...

  5. (转)stm32硬件IIC

    cube与I2C:https://www.cnblogs.com/121792730applllo/p/5044920.html I2C官网:https://www.i2c-bus.org/stand ...

  6. spring cloud: Hystrix(二):简单使用@HystrixCommand的commandProperties配置@HistrixProperty隔离策略

    spring cloud: Hystrix(二):简单使用@HystrixCommand的commandProperties配置@HistrixProperty隔离策略 某电子商务网站在一个黑色星期五 ...

  7. webService上传图片

    webService /// <summary> /// 上传图片webServer 的摘要说明 /// </summary> [WebService(Namespace = ...

  8. vmware 10.0 安装centos6.5 客户系统 几个问题

    1. vmware 10.0 安装centos6.5 客户系统 无法修改分辨率 要安装 desktop, KDE, legacy,x  组件 2. NAT 方式网卡无法自行启动 vim /etc/sy ...

  9. Mysql更改表名大小写不敏感

    编辑配置文件 vi /etc/my.cnf 在[mysqld]后添加添加 lower_case_table_names=1 重启服务 service mysqld stop service mysql ...

  10. 小程序授权demo

    <button wx:if="{{canIUse}}"   open-type="getUserInfo"  bindgetuserinfo=" ...