www.9778.com 3

www.9778.comandroid平台视频框架小调研笔记

在android上,视频/音频流直播是极少有人关注的一部分。每当我们讨论流媒体,RTMP(Real
Time Messaging
Protocol)是不可或缺的。RTMP是一个基本的视频/音频直播流协议,但是不幸的是Android标准的VideoView不支持RTMP的播放。因此,如果想在android上播放RTMP直播流,你必须使用支持RTMP协议的库。在本教程中我们将讨论如何通过使用安卓的
[Vitamio]( 库播放由 RTMP
协议传输的流媒体。

视频传输协议


  1. DASH
    Dynamic Adaptive Streaming over HTTP,基于HTTP的动态自适应流
    例子:优酷土豆之类的视频网站的PC在线视频基本上都是 http + mp4 或者
    http + flv/f4v… ,使用flash播放器,编码H264
    HTTP progressive streaming
    客户端需要在硬盘上缓存所有前面已经下载的媒体数据,对本地存储空间的需求较大。播放过程中用户只能在前面已经下载媒体数据的时间范围内进行进度条搜索和快进、快退等操作,而无法在整个媒体文件时间范围内执行这些操作。

  2. RTP/RTSP
    RTSP/RTP是目前业界最为流行和广为采用的实时流媒体协议。它实际上由一组在IETF中标准化的协议所组成,包括RTSP(实时流媒体会话协议),
    SDP(会话描述协议),RTP(实时传输协议),以及针对不同编解码标准的RTP净载格式等,共同协作来构成一个流媒体协议栈。
    例子:芒果TV在线

  3. HLS
    HTTP Live
    Streaming允许内容提供者通过普通Web服务器向上述客户端提供接近实时的音视频流媒体服务,包括直播和点播。HTTP
    Live
    Streaming支持将同一节目编码为不同码率的多个替换流,客户端软件可以根据网络带宽的变化在这些不同码率的替换流之间进行智能切换。此外,HTTP
    Live
    Streaming还支持通过媒体加密和用户认证等方式来达到媒体版权保护。
    例子:手机上的一些视频播放

  4. 在一篇文章里找了一张表,列举出了这几种传输协议的特点如下

传输协议对比

1.监听播放出错

class MyOnErrorListener implements MediaPlayer.OnErrorListener {

    @Override
    public boolean onError(MediaPlayer mp, int what, int extra) {
//            Toast.makeText(SystemVideoPlayer.this, "播放出错了哦", Toast.LENGTH_SHORT).show();
        //1.播放的视频格式不支持--跳转到万能播放器继续播放
        startVitamioPlayer();
        //2.播放网络视频的时候,网络中断---1.如果网络确实断了,可以提示用于网络断了;2.网络断断续续的,重新播放
        //3.播放的时候本地文件中间有空白---下载做完成
        return true;
    }
}

www.9778.com 1

视频编码##


视频流传输中最为重要的编解码标准有国际电联的H.261、H.263、H.264,运动静止图像专家组的M-JPEG和国际标准化组织运动图像专家组的MPEG系列标准,此外在互联网上被广泛应用的还有Real-Networks的RealVideo、微软公司的WMV以及Apple公司的QuickTime等。

 

Android Vitamio 库

Vitamio是一个android和ios上基于FFmpeg的开源项目。Vitamio为我们提供了一个清洁、简单、全面、真实的硬件加速解码器和渲染器API,Vitamio是一个支持多种音视频格式
如 FLV, TS/TP, WMV, DivX,
Xvid等多种标准格式的非常强大的库。所不同的是,它也支持类似.mkv和.srt嵌入和外挂字幕播放。但是它带有一个许可证,因此在使用它之前请先获得认证。在这个android
RTMP例子中,我们不仅讨论RTMP直播流,而且也会讨论m3u8流(HLS),RTSP流和
MMS (Microsoft Media Stream)。首先让在我们的项目中引用Vitamio库。

Vitamio


支持协议

MMS
RTSP (RTP, SDP), RTMP
HTTP progressive streaming
HLS – HTTP live streaming (M3U8)

音频和视频格式

DivX/Xvid
WMV (一般只有软解码)
FLV
TS/TP
RMVB (只有软解码)
MKV
MOV
M4V
AVI
MP4
3GP

其他特性

支持Android2.1+
字幕支持,支持多种格式的外挂字幕
流媒体播放缓冲支持
播放画面比例大小随手调节
细致的 CPU 与 GPU 优化

某些优缺点

体积太。可能是因为它对本地视频的播放做了很多工作(比方说字幕的支持,多音轨的支持,CPU
与 GPU
优化),所以如果想要用它来做在线视频播放的框架的话,应该把它某些针对于本地播放的优化给砍掉(个人看法)。

支持2.1及以上的android版本。比其他的一些库支持的范围广(如
ExoPlayer和ijkplayer,依赖Android的
MediaCodec接口,该接口发布于Android4.1。因此它们不能工作于之前的Android版本),但这个可能算不上突出的优点,因为还在用2.x的版本的人已经很少了而且会越来越少。

不支持视频缩略图。
不支持两个视频同时播放。

有一个Vitamio不支持特性列表在这。

Bug
1、我在写demo的时候,发现当targetSdkVersion设定为23时候,程序一定会崩溃,出现LOAD FFMPEG ERROR: dlopen failed: libffmpeg.so: has text relocations的错误。当把targetSdkVersion设定为22及以下的时候,就不会出现问题。这个bug在issue#312和issue#323出现过。在最新版本Vitamio5.0.1中仍然存在该问题。

2、当拖动的视频的时候,偶有声音与画面出现不同步的情况。我自己也出现过。在issue#269中有类似描述。

3、一些其他rtsp和hls时候出现问题。没细看。

大小
jniLibs里面的.so文件普遍比较大,最大的x86的libffmpeg.so有7.2M,最小的armeabi-v7a的libffmpeg.so也有4.91M

总大小视不同的平台而定,普遍在6M-9M之间。
x86:9M
arm64-v8a:7.9M
armeabi-v7a:6.5M

使用方法

我拿官方给的sample看了一下,其使用方法同Android本身的MediaPlayer用法很类似。
vitamio本身封装了一个VideoView,方便使用,直接设置视频路径就行了。
mVideoView.setVideoPath(path); mVideoView.setMediaController(new MediaController(this));

当然也可以直接使用MediaPlayer,这样就需要在外面套一层TextureView或者SurfaceView。
io.vov.vitamio包下的MediaPlayer的方法大致有:
public void setDataSource(String path) 这个DataSource
可以是一个文件路径或一个 http/rtsp URL
public native void prepare()
public native void prepareAsync()
public void start()
public void stop()
public void pause()
public native void seekTo(long msec)
public void release()
public void reset()
……

还有一些常用接口,例如:

`private OnHWRenderFailedListener `
`private interface OnPreparedListener` 
`private interface OnCompletionListener` 
`private interface OnBufferingUpdateListener` 
`private interface OnCachingUpdateListener `
`private interface OnSeekCompleteListener` 
`private interface OnVideoSizeChangedListener`
`private interface OnErrorListener`

可以看到,上面列举的基本上与Android本身的MediaPlayer是差不多的。
所以使用方法也差不多。比如要播放一个视频,用一下的代码段就可以简单的实现:

`mMediaPlayer = new MediaPlayer(this);  
mMediaPlayer.setDataSource(path);  
mMediaPlayer.setDisplay(holder);  
mMediaPlayer.prepareAsync(); `

我找了一些本地视频和在线视频来播放试了一下,基本上都可以播放出来。有少数放不了的应该是其他原因(比如网络不好)。

2.万能解码框架简介

1.ffmpeg 

2.VLC

3.Vitamio 万能解码框架,在Android和IOS平台上直接使用。
Vitamio
能够流畅播放720P甚至1080P高清MKV,FLV,MP4,MOV,TS,RMVB等常见格式的视频,还可以在
Android 与 iOS 上跨平台支持 MMS, RTSP, RTMP, HLS(m3u8)
等常见的多种视频流媒体协议,包括点播与直播。

里面封装了ffmpeg

 

在Android Studio中引用Vitamio库的步骤如下:

  1. 下载Vitamio bundle
  2. 解压并且在Android Studio上File->Import Module
  3. 指定到VitamioBundle路径,选择vitamio文件夹 点击完成
  4. 在build.gradle(Module: app)依赖部分添加依赖项目(‘:vitamio’)
  5. 打开build.gradle (Module: vitamio) – 改变最小sdk版本为7
  6. 不要忘记在manifest.xml中添加internet权限
  7. www.9778.com,完成!

ExoPlayer


支持协议

RTSP (RTP, SDP), RTMP
由于android自身就支持RTSP,所以ExoPlayer自然就支持HTTP progressive
streaming/DASH Smooth Streaming

HLS
支持高级的HLS特性,例如正确处理 EXT-X-DISCONTINUITY 标签

可以看到,ExoPlayer基本上也都支持市面上常规的传输协议。

音频和视频格式

在ExoPlayer主页的列表里可以查到所支持的格式,看上去没有Vitamio所支持的广泛,但是我想rmvb这种格式都是本地播放的,在线播放也不用这样的格式,所以这些格式不支持也没什么关系。

3GPP (.3gp)
MPEG-4 (.mp4)
MPEG-TS (.ts, AAC 只支持音频, Android 3.0+)
Matroska (.mkv, Android 4.0+)
WebM (.webm)
MPEG-PS (Android 3.0+)
OGG
FLV
WAV
mov(这个在列表上没有看到,但是我自己试了一下,是可以的)

其他特性

ExoPlayer的音频和视频组件依赖Android的
MediaCodec接口,该接口发布于Android4.1(API
等级16)。因此它不能工作于之前的Android版本。
便于随着App的升级而升级。因为ExoPlayer是一个包含在你的应用中的库,对于你使用哪个版本有完全的控制权,并且你可以简单的跟随应用的升级而升级

ExoPlayer可以支持DRM技术,Digital Rights Managment (DRM)数字版权管理。

ExoPlayer 支持一些 Android MediaPlayer API 无法提供的特性,包括 DASH 和
SmoothStreaming 自适应回放,持久的高速缓存和自定义渲染器。

它使用了一些额外的库,有okhttp,Hamcrest,okio,objenesis,dexmaker

大小

由于直接依赖Android的
MediaCodec接口,所以没有额外的jniLib,体积比Vitamio要小一些,具体约是
4.5M,包括1.87M(exoplayer自身大小)+2.59M(它使用的一些其他的库的和)。

Bug
1、声音与画面不同步。我这里发现过一次。发现在issue#1416中有类似描述。
2、拖动视频进度条的后,屏幕出现类似马赛克的雪花点。

使用方法

看了一下ExoPlayer项目的demo中的PlayerActivity和DemoPlayer,其中详细的示范了如何使用ExoPlayer来进行视频播放。ExoPlayer中有三个重要的部分,TrackRender,SampleSource和DataSource,这些在ExoPlayer的Developer
guide里面有详细描述。我今天看了一点,还没看完看明白,这个接下来再看一下。先把大致的脉络捋了一下。Developer
guide有一个中文翻译版本在这。

用标准的TrackRenderer 实现视频,音频播放需要的步骤大致有:

player = ExoPlayer.Factory.newInstance(RENDERER_COUNT);//1.初始化播放器
MediaCodecVideoTrackRender videoRender = ...
MediaCodecAudioTrackRender audioRender = ...//2.构建渲染器
player.prepare(videoRender,audioRender);//3.通过prepare注入渲染器
 player.sendMessage(videoRender,MediaCodecVideoTrackRenderer.MSG_SET_SURFACE,surface);//4.将surface传递到渲染器
player.setPlayWhenReady(true);//5.开始播放
....
player.release(); //当播放完成,释放

ExoPlayer库提供MediaCodecVideoTrackRenderer作为默认的实现用于渲染视频,MediaCodecAudioTrackRender渲染音频。两种实现都是利用Android的
MediaCodec去解码每个媒体样本。

3.Vitamio的集成

1.关联Vitamio库

compile project(':vitamio')

2.把功能清单文件对应的配置拷贝过去 权限

<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />

配置

<!-- Don't forgot InitActivity -->
<activity
        android:name="io.vov.vitamio.activity.InitActivity"
        android:configChanges="orientation|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation"
        android:launchMode="singleTop"
        android:theme="@android:style/Theme.NoTitleBar"
        android:windowSoftInputMode="stateAlwaysHidden" />

3.把系统SystemVideoPlayer复制一份,改名VitamioVideoPlayer
导入的包全部换成是Vitamio的包,MediaPlayer,VideoView

自定义VitamioVideoView 继承Vitamio的VideoView

4.布局文件activitysystemvideoplayer.xml复制一份改名activityvitamiovideoplayer.xml,并且把里面的VideoView替换成Vitamio的VitamioVideoView

5.初始化Vitamio库,在布局文件加载之前

Vitamio.isInitialized(this);  

6.当系统播放器播放出错的时候跳转到VitamioVideoPlayer播放
疑问:能否直接用Vitamio播放器播放呢?

注意:a,把数据传入VtaimoVideoPlayer播放器 b,关闭系统播放器

让Activity在桌面显示图标,并且点击图标的时候进入软件

<category android:name="android.intent.category.LAUNCHER" />

  

Android RTMP流

在讲述如何使用之前,让我们先了解下RTMP。Real Time Messaging Protocol
(RTMP)是一个Adobe
Systems所拥有的一个协议。该协议是Adobe公司拥有的开发音视频流的flash
player。后来该协议的部分被公开,供公众使用。更多请查看这里.这个协议大多用于IPTV和实时视频点播流,但它也用于其他领用。

在android上,标准的VideoView不支持RTMP播放。但WebView可以播放RTMP流。这解决了播放RTMP流的问题,但是我认为web
apps 不能提供一个很好的界面和体验。因此这这个android
RTMP例子中我们将运用第三方库-Vitamio
直播RTMP流的流媒体。在工程中引用Vitamio之后,请在你的layout文件添加Vitamio的VideoView:

activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical" >

        <io.vov.vitamio.widget.VideoView             android:id="@+id/vitamio_videoView"
            android:layout_width="wrap_content"
           android:layout_height="wrap_content" />

    </LinearLayout>

另外请编写你的activity如下:

MainActivity.java

    package com.truiton.rtmpplayer;

    import android.net.Uri;
    import android.os.Bundle;
    import android.support.v7.app.ActionBarActivity;

    import java.util.HashMap;

    import io.vov.vitamio.LibsChecker;
    import io.vov.vitamio.MediaPlayer;
    import io.vov.vitamio.widget.MediaController;
    import io.vov.vitamio.widget.VideoView;

    public class MainActivity extends ActionBarActivity {
        private static final String TAG = "MainActivity";
        private String path;
        //private HashMap<String, String> options;
        private VideoView mVideoView;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            if (!LibsChecker.checkVitamioLibs(this))
                return;
            setContentView(R.layout.activity_main);
            mVideoView = (VideoView) findViewById(R.id.vitamio_videoView);
            path = "rtmp://rrbalancer.broadcast.tneg.de:1935/pw/ruk/ruk";
            /*options = new HashMap<>();
            options.put("rtmp_playpath", "");
            options.put("rtmp_swfurl", "");
            options.put("rtmp_live", "1");
            options.put("rtmp_pageurl", "");*/
            mVideoView.setVideoPath(path);
            //mVideoView.setVideoURI(Uri.parse(path), options);
            mVideoView.setMediaController(new MediaController(this));
            mVideoView.requestFocus();

            mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                @Override
                public void onPrepared(MediaPlayer mediaPlayer) {
                    mediaPlayer.setPlaybackSpeed(1.0f);
                }
            });
        }
    }

虽然上面代码很清晰明了,但需要指出的是请修改你播放RTMP流的路径。在android上,有时可能使用带报头路径来播放RTMP流。幸运的是,Vitamio
RTMP播放器也支持这种方式。因此,所有类型的RTMP流可以使用Vitamio库。上面的例子会是这个样子:

www.9778.com 2

vlc-android


支持协议支持的音频和视频格式
与上面的两个框架差不多,基本上常见的都支持。没有什么特殊的。

大小
jniLibs里面的.so比vitamio的还要大。不同平台不同版本的总大小在11-14M左右。

特性
字幕支持,包括ASS 和 DVD 字幕
多声道,多字幕
支持多核解码
支持开启全硬件加速
支持手势控制,耳机控制
声音均衡器

问题
我发现在android上,用这个框架进行自己的开发的项目没有上面两种框架多,相关资料和问题都很少。
api经常变

3.当万能播放器播放失败的提示

class MyOnErrorListener implements MediaPlayer.OnErrorListener {
    @Override
    public boolean onError(MediaPlayer mp, int what, int extra) {
        //什么情况下会出错
        //1.播放的格式不支持-跳转到万能播放器继续播放
        //Toast.makeText(VitamioVideoPlayerActivity.this,"播放视频出错了="+extra,Toast.LENGTH_SHORT).show();
        showErrorDialog();
        //2.播放视频的过程中网络中断--播放重试
        //3.播放的文件中间缺省--把下载模块解决好,不要用空白
        return true;
    }
}

  

private void showErrorDialog() {
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setTitle("提示");
    builder.setMessage("播放视频出错了");
    builder.setPositiveButton("退出播放", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            finish();
        }
    });
    builder.show();
}

 

Android RTSP流媒体

实时流协议(RTSP)通过多媒体服务器传输内容,例如YouTube使用RTSP流发布内容。关于RTSP流比较容易的部分是,它可以通过android标准的VideoView来完成,想了解更多,请参考我的VideoView例子。

但是如果你使用Vitamio库,可以更好的播放RTSP流。事实上Vitamio也支持RTSP流的回播。和上面过程是一样的,包括Vitamio的VideoView在布局文件,并使用路径变量指定的RTSP
url

    mVideoView = (VideoView) findViewById(R.id.vitamio_videoView);
    path = "rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov";
    mVideoView.setVideoPath(path);
    mVideoView.setMediaController(new MediaController(this));
    mVideoView.requestFocus();

    mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
        @Override
        public void onPrepared(MediaPlayer mediaPlayer) {
            mediaPlayer.setPlaybackSpeed(1.0f);
        }
    });

几个框架的一些比较


Vitamio ExoPlayer vlc-android
支持协议 MMS、RTSP 、HTTP、HLS RTSP 、HTTP、HLS RTSP 、HTTP、HLS
支持格式 3gp、mp4、mp4、mkv
webm、FLV、WAV、AVI
3gp、mp4、mp4、mkv
webm、FLV、WAV
3gp、mp4、mp4、mkv
webm、FLV、WAV、AVI
体积 不同平台6M-9M 约4.5M 不同平台11M-14M
bug 1、targetSdkVersion设定为23时一定会崩溃
2、拖动的视频的时候,偶有声音与画面出现不同步
1、声音与画面不同步
2、拖动视频进度条现类似马赛克的雪花点
暂未发现
封装程度 有直接封装好的VideoView使用
也可以与TextureView或SurfaceView结合
需要与TextureView或SurfaceView结合 有直接封装好的VideoView使用,也可以与TextureView或SurfaceView结合
其他 使用自身的.so文件,支持android2.1+ 1、依赖 MediaCodec接口,支持android4.1+
2、依赖于okhttp,Hamcrest,okio,objenesis,dexmaker
使用自身的.so文件,支持android2.2+

bug列表有待增加,上面列出的bug均在我的手机上复现过。有些bug的具体的描述见上文每个框架条目下的BUG项及其给出的issue链接。

To Be Continue…

4.系统播放器和万能播放器手动切换  

case R.id.btn_switch:
   new AlertDialog.Builder(VideoPlayerActivity.this)
         .setMessage("当前是系统播放器,是否要切换万能播放器播放")
         .setNegativeButton("下次再说", null)
         .setPositiveButton("立刻切换",
                 new DialogInterface.OnClickListener() {
                     public void onClick(DialogInterface dialog, int whichButton) {
                      //退出播放器
                      startVitamioPlyer();
                     }
                 })

         .setCancelable(false)
         .show();
  break;

  

  

 

 

Android m3u8 流媒体

“如何在android上播放m3u8视频”是android开发者最常见的问题之一。通过Http
协议进行视频流直播最简单的办法就是使用标准的 VideoView.
但只能在androiD3.0以上的设备上播放m3u8流。因为在Android
3.0引入HTTP/ HTTPS直播和HTTP/
HTTPS渐进式流媒体协议,在android3.1完全支持HTTPS。

如果你希望在早期的版本上实现支持android m3u8流的HTTP实时流媒体
(HLS)。应该考虑使用Vitamio库,这个库支持在android
API7以上播放m3u8。使用方式,同样的在布局文件中使用Vitamio的VideoView,并指定的HTTP实时流媒体URL。

    mVideoView = (VideoView) findViewById(R.id.vitamio_videoView);
    path = "http://93.184.221.133/00573D/236/236-0.m3u8";
    mVideoView.setVideoPath(path);
    mVideoView.setMediaController(new MediaController(this));
    mVideoView.requestFocus();

    mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
        @Override
        public void onPrepared(MediaPlayer mediaPlayer) {
            mediaPlayer.setPlaybackSpeed(1.0f);
        }
    });

Playing m3u8 stream on Android with Vitamio would look something like
this:
在androi上使用Vitamio播放m3u8流效果如下:

www.9778.com 3

Android MMS 流

Vitamio库是一个强大的库,还支持Microsoft媒体服务器(MMS)流中的播放。
MMS是网络流媒体协议,主要用于网络广播和电台直播。使用Vitamio用于在anroid的MMS流和其他协议没有什么不同。所有你需要做的只是更换路径变量指向一个MMS
url:

    mVideoView = (VideoView) findViewById(R.id.vitamio_videoView);
    path = "mms://beotelmedia.beotel.net/studiob";
    mVideoView.setVideoPath(path);
    mVideoView.setMediaController(new MediaController(this));
    mVideoView.requestFocus();

    mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
        @Override
        public void onPrepared(MediaPlayer mediaPlayer) {
            mediaPlayer.setPlaybackSpeed(1.0f);
        }
    });

结论

通过上面的讨论,可以确定地说,Vitamio是一个强大的多平台库(ios and
android)。通过使用Vitamio库 能播放多种类型的视频格式和协议如RTMP, RTSP,
HTTP Live, and
HTTP渐进式流协议。另外一个很好的功能是,vitamio支持字幕和多音轨的播放。Vitamio的唯一的缺点是,它不是完全的开源。您可能需要购买许可证来使用它。希望这会有所帮助。通过Facebook,
Google+ and Twitter来联系我们获取更多更新。