《android多媒体api》系列是整合梳理android开发中经常用到的媒体相关api;多媒体开发主要内容有音频、视频录制播放、摄像头操作、录制操作、流媒体、直播、推流、拉流等方面;最近几年移动直播和视频应用发展犹如雨后春笋一般直插云霄,呃。。好吧这段比喻可以不用看了!!,反正行业兴起肯定催生了很多多媒体相关应用开发程序员。那么怎样才能成为多媒体开发程序员,首先必须要熟练使用和了解android自带的多媒体api,并且还要掌握pcm、yuv、rgb、h264、aac、flv、mpegts、mp4、udp、rtp、rtmp等等众多文件格式和流媒体协议等等。所以这里整理android相关多媒体api,提供给想从事流媒体同学作为参照,同样还是要鸣谢网络上那些具有分享精神大神们!!

####基本概念:

  1. 视频播放:demuxer(解复用)->分离出音频流和视频流->decoder(解码)->播放原始数据(例如:pcm yuv)
  2. 视频录制:采集原始数据(例如:pcm yuv)->encoder(编码)->muxer(封装格式 例如:mp4 3gp)
  3. 流媒体协议:udp、rtp、rtmp、rtcp、rtsp等
  4. 音视频封装格式:mp4 、3gp、flv等
  5. 音视频编码格式:aac、amr、h264、h265等
  6. 原始音视频数据格式:pcm 、yuv、rgb等

流程图:

####文章目录:

  1. VideoView 视频播放控件
  2. camera配合surface预览相机画面和拍照
  3. MediaPlayer自定义视频播放器
  4. MediaRecorder音视频录制api
  5. AudioTrack原始音频pcm播放api
  6. AudioRecord原始音频pcm采集api

MediaPlayer是什么?
MediaPlayer类可用于控制音频/视频文件或流的播放。前面介绍了VideoView 跟MediaPlayer用法基本相同,不过MediaPlayer使用时候注意他有个缓存机制,如果没有缓存视频是不能够播放的;这里实现了一个基于MediaPlayer实现自定义视频播放器,具有功能播放、暂停、停止、进度条调整视频播放进度等。案例是通过surfaceview来显示画面,用seekbar来进度显示和控制,然后创建一个timer来一秒中更新一次进度条,同样进度条也可以通过手指抬起时来更新视频进度。

#####效果图:

#####MediaPlayer api方法:
方法:create(Context context, Uri uri)
解释:静态方法,通过Uri创建一个多媒体播放器。

方法:create(Context context, int resid)
解释:静态方法,通过资源ID创建一个多媒体播放器

方法:create(Context context, Uri uri, SurfaceHolder holder)
解释:静态方法,通过Uri和指定 SurfaceHolder 【抽象类】 创建一个多媒体播放器

方法: getCurrentPosition()
解释:返回 Int, 得到当前播放位置

方法: getDuration()
解释:返回 Int,得到文件的时间

方法:getVideoHeight()
解释:返回 Int ,得到视频的高度

方法:getVideoWidth()
解释:返回 Int,得到视频的宽度

方法:isLooping()
解释:返回 boolean ,是否循环播放

方法:isPlaying()
解释:返回 boolean,是否正在播放

方法:pause()
解释:无返回值 ,暂停

方法:prepare()
解释:无返回值,准备同步

方法:prepareAsync()
解释:无返回值,准备异步

方法:release()
解释:无返回值,释放 MediaPlayer 对象

方法:reset()
解释:无返回值,重置 MediaPlayer 对象

方法:seekTo(int msec)
解释:无返回值,指定播放的位置(以毫秒为单位的时间)

方法:setAudioStreamType(int streamtype)
解释:无返回值,指定流媒体的类型

方法:setDataSource(String path)
解释:无返回值,设置多媒体数据来源【根据 路径】

方法:setDataSource(FileDescriptor fd, long offset, long length)
解释:无返回值,设置多媒体数据来源【根据 FileDescriptor】

方法:setDataSource(FileDescriptor fd)
解释:无返回值,设置多媒体数据来源【根据 FileDescriptor】

方法:setDataSource(Context context, Uri uri)
解释:无返回值,设置多媒体数据来源【根据 Uri】

方法:setDisplay(SurfaceHolder sh)
解释:无返回值,设置用 SurfaceHolder 来显示多媒体

方法:setLooping(boolean looping)
解释:无返回值,设置是否循环播放

事件:setOnBufferingUpdateListener(MediaPlayer.OnBufferingUpdateListener listener)
解释:监听事件,网络流媒体的缓冲监听

事件:setOnCompletionListener(MediaPlayer.OnCompletionListener listener)
解释:监听事件,网络流媒体播放结束监听

事件:setOnErrorListener(MediaPlayer.OnErrorListener listener)
解释:监听事件,设置错误信息监听

事件:setOnVideoSizeChangedListener(MediaPlayer.OnVideoSizeChangedListener listener)
解释:监听事件,视频尺寸监听

方法:setScreenOnWhilePlaying(boolean screenOn)
解释:无返回值,设置是否使用 SurfaceHolder 显示

方法:setVolume(float leftVolume, float rightVolume)
解释:无返回值,设置音量

方法:start()
解释:无返回值,开始播放

方法:stop()
解释:无返回值,停止播放

####基于MediaPlayer实现自定义播放器:

xml布局文件:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="fill_parent"><SurfaceViewandroid:id="@+id/surfaceView1"android:layout_width="fill_parent"android:layout_height="fill_parent"/><LinearLayoutandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:layout_gravity="bottom"android:orientation="vertical"><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:orientation="horizontal"><Buttonandroid:id="@+id/btnPlayUrl"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="播放网络视频"/><Buttonandroid:id="@+id/btnPause"android:layout_width="80dip"android:layout_height="wrap_content"android:text="暂停"/><Buttonandroid:id="@+id/btnStop"android:layout_width="80dip"android:layout_height="wrap_content"android:text="停止"/></LinearLayout><LinearLayoutandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:orientation="horizontal"><SeekBarandroid:id="@+id/skbProgress"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_vertical"android:layout_weight="1.0"android:max="100"android:progress="1"android:paddingLeft="10dip"android:paddingRight="10dip"/></LinearLayout></LinearLayout>
</FrameLayout>

java代码:

package com.jared.helloffmpeg;import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.SeekBar;import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;public class RecordMP4Push extends Activity implements SurfaceHolder.Callback, MediaPlayer.OnBufferingUpdateListener {private SurfaceView surfaceView;private Button btnPause, btnPlayUrl, btnStop;private SeekBar skbProgress;private MediaPlayer player;private boolean isLoad=false;private boolean isStop=false;private Timer mTimer = new Timer();/*** Called when the activity is first created.*/@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.record_aac_and_pcm);setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);surfaceView = (SurfaceView) this.findViewById(R.id.surfaceView1);btnPlayUrl = (Button) this.findViewById(R.id.btnPlayUrl);btnPause = (Button) this.findViewById(R.id.btnPause);btnStop = (Button) this.findViewById(R.id.btnStop);skbProgress = (SeekBar) this.findViewById(R.id.skbProgress);btnPlayUrl.setOnClickListener(new ClickEvent());btnPause.setOnClickListener(new ClickEvent());btnStop.setOnClickListener(new ClickEvent());skbProgress.setOnSeekBarChangeListener(new SeekBarChangeEvent());surfaceView.getHolder().addCallback(this);}TimerTask mTimerTask = new TimerTask() {@Overridepublic void run() {if (player == null)return;if (player.isPlaying() && !skbProgress.isPressed()) {runOnUiThread(new Runnable() {@Overridepublic void run() {int position = player.getCurrentPosition();int duration = player.getDuration();if (duration > 0) {long pos = skbProgress.getMax() * position / duration;skbProgress.setProgress((int) pos);}}});}}};private void initPlayer(SurfaceHolder holder){if (player!=null)return;player=new MediaPlayer();player.setDisplay(holder);player.setOnBufferingUpdateListener(this);player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {@Overridepublic void onPrepared(MediaPlayer mediaPlayer) {if (mediaPlayer.getVideoWidth()!=0)isLoad=true;}});try {player.setDataSource("/storage/emulated/0/other/input.mp4");player.prepare();} catch (Exception e) {e.printStackTrace();}}private void freePlayer(){if (player==null)return;if (player.isPlaying()) {player.stop();}//player.reset();//清空所有设置player.release();player=null;}@Overridepublic void surfaceCreated(SurfaceHolder surfaceHolder) {}@Overridepublic void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {initPlayer(surfaceHolder);mTimer.schedule(mTimerTask, 1000, 1000);}@Overridepublic void surfaceDestroyed(SurfaceHolder surfaceHolder) {freePlayer();mTimer.cancel();}@Overridepublic void onBufferingUpdate(MediaPlayer mediaPlayer, int i) {Log.i(getClass().getSimpleName(), "buffer size=="+i);skbProgress.setSecondaryProgress(i);int currentProgress = skbProgress.getMax() * mediaPlayer.getCurrentPosition() / mediaPlayer.getDuration();Log.e(currentProgress + "% play", i + "% buffer");}class ClickEvent implements OnClickListener {@Overridepublic void onClick(View arg0) {if (!isLoad)return;if (arg0 == btnPause) {if (player.isPlaying())player.pause();} else if (arg0 == btnPlayUrl) {if (!player.isPlaying()){if (isStop){player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {@Overridepublic void onPrepared(MediaPlayer mediaPlayer) {if (mediaPlayer.getVideoWidth()==0)return;mediaPlayer.start();isStop=false;}});try {player.prepare();} catch (IOException e) {e.printStackTrace();}}else {player.start();}}} else if (arg0 == btnStop) {if (player.isPlaying()) {player.stop();skbProgress.setProgress(0);isStop=true;}}}}class SeekBarChangeEvent implements SeekBar.OnSeekBarChangeListener {int progress;@Overridepublic void onProgressChanged(SeekBar seekBar, int progress,boolean fromUser) {// 原本是(progress/seekBar.getMax())*player.mediaPlayer.getDuration()this.progress = progress * player.getDuration() / seekBar.getMax();}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {}@Overridepublic void onStopTrackingTouch(SeekBar seekBar) {// seekTo()的参数是相对与影片时间的数字,而不是与seekBar.getMax()相对的数字player.seekTo(progress);}}}

《android多媒体api》之MediaPlayer自定义视频播放器相关推荐

  1. 《android多媒体api》之VideoView 视频播放控件

    <android多媒体api>系列是整合梳理android开发中经常用到的媒体相关api:多媒体开发主要内容有音频.视频录制播放.摄像头操作.录制操作.流媒体.直播.推流.拉流等方面:最近 ...

  2. 一步步自定义视频播放器——TextureView+MediaPlayer自定义视频播放器

    本篇参考封装一个视频播放器,原文已经写的非常棒了,本篇加入了个人对其内容的理解.秉承不重复造轮子的良好理念,接下来开始拆解轮子.内容非常多,我都差点放弃写,有耐心的请往下看 github上非常棒的视频 ...

  3. Android播放器自定义,android surfaceView+mediaPlayer 自定义视频播放器

    你可以参考我的写法,注意点就是你自定义的MyCallBack()里面要回调,也就是我写的SurfaceCallBack()里面的SurfaceCreated()函数要实现你写的setOnPrepare ...

  4. 《android多媒体api》之MediaRecorder音视频录制api

    <android多媒体api>系列是整合梳理android开发中经常用到的媒体相关api:多媒体开发主要内容有音频.视频录制播放.摄像头操作.录制操作.流媒体.直播.推流.拉流等方面:最近 ...

  5. 《android多媒体api》之AudioTrack原始音频pcm播放api

    <android多媒体api>系列是整合梳理android开发中经常用到的媒体相关api:多媒体开发主要内容有音频.视频录制播放.摄像头操作.录制操作.流媒体.直播.推流.拉流等方面:最近 ...

  6. 《android多媒体api》之AudioRecord原始音频pcm录制api

    <android多媒体api>系列是整合梳理android开发中经常用到的媒体相关api:多媒体开发主要内容有音频.视频录制播放.摄像头操作.录制操作.流媒体.直播.推流.拉流等方面:最近 ...

  7. Android 自定义视频播放器

    由于录像之后,原先选用的腾讯VOD点播播放器显示出来竖屏都变横屏了,虽然选中了现在的腾讯VOD点播,还是把Android视频播放器了解了一番. Android自定义视频播放器有以下三种: 一.Medi ...

  8. Android进阶:自定义视频播放器开发(上)

    随着快手,抖音,西瓜视频等视频APP的崛起,视频播放已经成为主流,此时作为Android研发的你,想要提高自己的能力还不知道怎么开发视频播放器怎么行?所以今天就带着大家一起开发一个简易播放器:Smal ...

  9. Android进阶:自定义视频播放器开发(下)

    上一篇文章我们主要讲了视频播放器开发之前需要准备的一个知识,TextureView,用于对图像流的处理.这篇文章开始构建一个基础的视频播放器. 一.准备工作 在之前的文章已经说过了,播放器也是一个vi ...

最新文章

  1. VS中dll以及lib生成路径设置
  2. Java线程---休眠问题来看并发执行
  3. Python 基础篇-正斜杠(/)和反斜杠(\)的用法
  4. toch_geometric 笔记:message passing GCNConv
  5. 源达投顾软件怎么样_源达投顾:让人工智能炒股终端变得更简单
  6. STM32开发 -- 系统软复位
  7. 删除空值_Excel表格批量删除空值,你会么?
  8. 卡通驱动项目ThreeDPoseTracker——模型驱动解析
  9. c++ 低位在前 高位在后_A股市场:如果股票涨停后第二天“高开低走”,你知道怎么操作才能利益最大化吗?...
  10. html5的canvas动画,Canvas HTML5简介 · Canvas动画教程
  11. 我开着超市,不好好做自己的生意,每天却为社区团购平台打工
  12. 2_用keras训练一个神经网络及不同优化和初始化对性能的影响分析
  13. nx显示服务器错误,ug6.0软件打开出现nx许可证错误的解决办法
  14. 运放技术——压摆率和上升时间
  15. Rails PayPal 支付对接
  16. Dreamweaver CS6 破解安装
  17. [Big Data - Codis, Mycat(cobar)] 企业互联网+转型实战:如何进行PB级别数据的架构变迁...
  18. linux已经读写次数ssd剩余,固态硬盘ssd写入量剩余读写次数怎样查
  19. Html 实现角标效果
  20. Vue 路由懒加载根据根路由合并chunk块

热门文章

  1. windows11电脑右下角没有输入法解决方法
  2. RPG地图绘制 Android studio
  3. html 什么标签不换行,css不换行代码是什么?
  4. skyline TerraBuilder 制作MPT方法与技巧(1) - cannel(转载)
  5. myeclise CI 2018 9破解方法
  6. C++ 工程实践(7):iostream 的用途与局限
  7. 图解:Elasticsearch 8.X 如何求解环比上升比例?
  8. 13章、Java泛型——泛型的定义与作用
  9. 每日一面 - JVM 何时会 Stop the world
  10. python学习之xpath使用案例总结_xPath 用法总结整理