《android多媒体api》之MediaPlayer自定义视频播放器
《android多媒体api》系列是整合梳理android开发中经常用到的媒体相关api;多媒体开发主要内容有音频、视频录制播放、摄像头操作、录制操作、流媒体、直播、推流、拉流等方面;最近几年移动直播和视频应用发展犹如雨后春笋一般直插云霄,呃。。好吧这段比喻可以不用看了!!,反正行业兴起肯定催生了很多多媒体相关应用开发程序员。那么怎样才能成为多媒体开发程序员,首先必须要熟练使用和了解android自带的多媒体api,并且还要掌握pcm、yuv、rgb、h264、aac、flv、mpegts、mp4、udp、rtp、rtmp等等众多文件格式和流媒体协议等等。所以这里整理android相关多媒体api,提供给想从事流媒体同学作为参照,同样还是要鸣谢网络上那些具有分享精神大神们!!
####基本概念:
- 视频播放:demuxer(解复用)->分离出音频流和视频流->decoder(解码)->播放原始数据(例如:pcm yuv)
- 视频录制:采集原始数据(例如:pcm yuv)->encoder(编码)->muxer(封装格式 例如:mp4 3gp)
- 流媒体协议:udp、rtp、rtmp、rtcp、rtsp等
- 音视频封装格式:mp4 、3gp、flv等
- 音视频编码格式:aac、amr、h264、h265等
- 原始音视频数据格式:pcm 、yuv、rgb等
流程图:
####文章目录:
- VideoView 视频播放控件
- camera配合surface预览相机画面和拍照
- MediaPlayer自定义视频播放器
- MediaRecorder音视频录制api
- AudioTrack原始音频pcm播放api
- 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自定义视频播放器相关推荐
- 《android多媒体api》之VideoView 视频播放控件
<android多媒体api>系列是整合梳理android开发中经常用到的媒体相关api:多媒体开发主要内容有音频.视频录制播放.摄像头操作.录制操作.流媒体.直播.推流.拉流等方面:最近 ...
- 一步步自定义视频播放器——TextureView+MediaPlayer自定义视频播放器
本篇参考封装一个视频播放器,原文已经写的非常棒了,本篇加入了个人对其内容的理解.秉承不重复造轮子的良好理念,接下来开始拆解轮子.内容非常多,我都差点放弃写,有耐心的请往下看 github上非常棒的视频 ...
- Android播放器自定义,android surfaceView+mediaPlayer 自定义视频播放器
你可以参考我的写法,注意点就是你自定义的MyCallBack()里面要回调,也就是我写的SurfaceCallBack()里面的SurfaceCreated()函数要实现你写的setOnPrepare ...
- 《android多媒体api》之MediaRecorder音视频录制api
<android多媒体api>系列是整合梳理android开发中经常用到的媒体相关api:多媒体开发主要内容有音频.视频录制播放.摄像头操作.录制操作.流媒体.直播.推流.拉流等方面:最近 ...
- 《android多媒体api》之AudioTrack原始音频pcm播放api
<android多媒体api>系列是整合梳理android开发中经常用到的媒体相关api:多媒体开发主要内容有音频.视频录制播放.摄像头操作.录制操作.流媒体.直播.推流.拉流等方面:最近 ...
- 《android多媒体api》之AudioRecord原始音频pcm录制api
<android多媒体api>系列是整合梳理android开发中经常用到的媒体相关api:多媒体开发主要内容有音频.视频录制播放.摄像头操作.录制操作.流媒体.直播.推流.拉流等方面:最近 ...
- Android 自定义视频播放器
由于录像之后,原先选用的腾讯VOD点播播放器显示出来竖屏都变横屏了,虽然选中了现在的腾讯VOD点播,还是把Android视频播放器了解了一番. Android自定义视频播放器有以下三种: 一.Medi ...
- Android进阶:自定义视频播放器开发(上)
随着快手,抖音,西瓜视频等视频APP的崛起,视频播放已经成为主流,此时作为Android研发的你,想要提高自己的能力还不知道怎么开发视频播放器怎么行?所以今天就带着大家一起开发一个简易播放器:Smal ...
- Android进阶:自定义视频播放器开发(下)
上一篇文章我们主要讲了视频播放器开发之前需要准备的一个知识,TextureView,用于对图像流的处理.这篇文章开始构建一个基础的视频播放器. 一.准备工作 在之前的文章已经说过了,播放器也是一个vi ...
最新文章
- VS中dll以及lib生成路径设置
- Java线程---休眠问题来看并发执行
- Python 基础篇-正斜杠(/)和反斜杠(\)的用法
- toch_geometric 笔记:message passing GCNConv
- 源达投顾软件怎么样_源达投顾:让人工智能炒股终端变得更简单
- STM32开发 -- 系统软复位
- 删除空值_Excel表格批量删除空值,你会么?
- 卡通驱动项目ThreeDPoseTracker——模型驱动解析
- c++ 低位在前 高位在后_A股市场:如果股票涨停后第二天“高开低走”,你知道怎么操作才能利益最大化吗?...
- html5的canvas动画,Canvas HTML5简介 · Canvas动画教程
- 我开着超市,不好好做自己的生意,每天却为社区团购平台打工
- 2_用keras训练一个神经网络及不同优化和初始化对性能的影响分析
- nx显示服务器错误,ug6.0软件打开出现nx许可证错误的解决办法
- 运放技术——压摆率和上升时间
- Rails PayPal 支付对接
- Dreamweaver CS6 破解安装
- [Big Data - Codis, Mycat(cobar)] 企业互联网+转型实战:如何进行PB级别数据的架构变迁...
- linux已经读写次数ssd剩余,固态硬盘ssd写入量剩余读写次数怎样查
- Html 实现角标效果
- Vue 路由懒加载根据根路由合并chunk块
热门文章
- windows11电脑右下角没有输入法解决方法
- RPG地图绘制 Android studio
- html 什么标签不换行,css不换行代码是什么?
- skyline TerraBuilder 制作MPT方法与技巧(1) - cannel(转载)
- myeclise CI 2018 9破解方法
- C++ 工程实践(7):iostream 的用途与局限
- 图解:Elasticsearch 8.X 如何求解环比上升比例?
- 13章、Java泛型——泛型的定义与作用
- 每日一面 - JVM 何时会 Stop the world
- python学习之xpath使用案例总结_xPath 用法总结整理