解决Android平台移植ffmpeg的一揽子问题


IT行业是一个踩在巨人肩膀上前进的行业,否则做的事情不一定有意义,所以我也是基于havlenapetr移植的ffmpeg基础上做了些改进,他做的主要贡献有:

1. 移植了ffmpeg并将与媒体相关的结构体在java层重新进行了封装,方便应用程序在java层直接操作ffmpeg API,如各种媒体格式转码及播放,如图1所示

2. 模仿Android的MediaPlayer类实现了ffmpeg的播放接口,如setDataSource(),setDisplay(),start(), stop(),pause()等,缺点是没有实现seek功能。

3. 实现了一个简单播放器功能,抛弃掉ffmpeg自带的ffplay播放器,他重新实现了音视频的分离播放和同步处理等播放器应有的功能。

图1 ffmpeg的java层封装

基于Android移植ffmpeg的意义在于:

1.解决了Android媒体框架OpenCore的多媒体支持不足,虽然说Android平台的软解功耗大,但是从PC机的发展历史看,Android的视频处理以后也会走以硬解为主,软解为辅的路线。

2. 解决Android平台直播的问题,虽然Android支持RTSP/RTP的直播方案,但是这种方案主要是普遍用在电信设备上,基于互联网的海量视频服务提供者还是以http live streaming方案为主,测试时可以用ffmpeg将直播流打包成分段的ts流(如10秒钟),然后组织成m3u8文件实现完整的直播方案,而且互联网的直播内容还有很多是基于mms协议的,视频格式是wmv,要聚集这些内容都是离不开ffmpeg软解的。

 

移植步骤:

1. 下载havlenaptr移植的ffmpeg(https://github.com/havlenapetr/FFMpeg/zipball/debug).

2.  基于ndk编译下载的ffmpeg,出现的编译问题主要是文件的存放路径不对,修改jni目录下的Android.mk文件,增加头文件目录$(LOCAL_PATH)/../include/android,修改Vector.h文件为:

#include <cutils/log.h>
#include <utils/VectorImpl.h>
#include <utils/TypeHelpers.h>

3.utils目录下缺少TypeHelpers.h,添加该文件:

  1. /*  
  2.  *  TypeHelpers.h  
  3.  *    
  4.  *  Copyright 2005 The Android Open Source Project  
  5.  *  
  6.  */  
  7.   
  8. #ifndef ANDROID_TYPE_HELPERS_H   
  9. #define ANDROID_TYPE_HELPERS_H   
  10.   
  11. #include <new>   
  12. #include <stdint.h>   
  13. #include <string.h>   
  14. #include <sys/types.h>   
  15.   
  16. // ---------------------------------------------------------------------------   
  17.   
  18. namespace android {   
  19.   
  20. /*  
  21.  * Types traits  
  22.  */  
  23.        
  24. template <typename T> struct trait_trivial_ctor  { enum { value = false }; };   
  25. template <typename T> struct trait_trivial_dtor  { enum { value = false }; };   
  26. template <typename T> struct trait_trivial_copy  { enum { value = false }; };   
  27. template <typename T> struct trait_trivial_assign{ enum { value = false }; };   
  28.   
  29. template <typename T> struct trait_pointer     { enum { value = false }; };       
  30. template <typename T> struct trait_pointer<T*> { enum { value = true }; };   
  31.   
  32. #define ANDROID_BASIC_TYPES_TRAITS( T )                                       \   
  33.     template<> struct trait_trivial_ctor< T >  { enum { value = true }; };    \   
  34.     template<> struct trait_trivial_dtor< T >  { enum { value = true }; };    \   
  35.     template<> struct trait_trivial_copy< T >  { enum { value = true }; };    \   
  36.     template<> struct trait_trivial_assign< T >{ enum { value = true }; };    
  37.   
  38. #define ANDROID_TYPE_TRAITS( T, ctor, dtor, copy, assign )                    \   
  39.     template<> struct trait_trivial_ctor< T >  { enum { value = ctor }; };    \   
  40.     template<> struct trait_trivial_dtor< T >  { enum { value = dtor }; };    \   
  41.     template<> struct trait_trivial_copy< T >  { enum { value = copy }; };    \   
  42.     template<> struct trait_trivial_assign< T >{ enum { value = assign }; };    
  43.   
  44. template <typename TYPE>   
  45. struct traits {   
  46.     enum {   
  47.         is_pointer          = trait_pointer<TYPE>::value,   
  48.         has_trivial_ctor    = is_pointer || trait_trivial_ctor<TYPE>::value,   
  49.         has_trivial_dtor    = is_pointer || trait_trivial_dtor<TYPE>::value,   
  50.         has_trivial_copy    = is_pointer || trait_trivial_copy<TYPE>::value,   
  51.         has_trivial_assign  = is_pointer || trait_trivial_assign<TYPE>::value      
  52.     };   
  53. };   
  54.   
  55. template <typename T, typename U>   
  56. struct aggregate_traits {   
  57.     enum {   
  58.         is_pointer          = false,   
  59.         has_trivial_ctor    = traits<T>::has_trivial_ctor && traits<U>::has_trivial_ctor,   
  60.         has_trivial_dtor    = traits<T>::has_trivial_dtor && traits<U>::has_trivial_dtor,   
  61.         has_trivial_copy    = traits<T>::has_trivial_copy && traits<U>::has_trivial_copy,   
  62.         has_trivial_assign  = traits<T>::has_trivial_assign && traits<U>::has_trivial_assign   
  63.     };   
  64. };   
  65.   
  66. // ---------------------------------------------------------------------------   
  67.   
  68. /*  
  69.  * basic types traits  
  70.  */  
  71.     
  72. ANDROID_BASIC_TYPES_TRAITS( void );   
  73. ANDROID_BASIC_TYPES_TRAITS( bool );   
  74. ANDROID_BASIC_TYPES_TRAITS( char );   
  75. ANDROID_BASIC_TYPES_TRAITS( unsigned char );   
  76. ANDROID_BASIC_TYPES_TRAITS( short );   
  77. ANDROID_BASIC_TYPES_TRAITS( unsigned short );   
  78. ANDROID_BASIC_TYPES_TRAITS( int );   
  79. ANDROID_BASIC_TYPES_TRAITS( unsigned int );   
  80. ANDROID_BASIC_TYPES_TRAITS( long );   
  81. ANDROID_BASIC_TYPES_TRAITS( unsigned long );   
  82. ANDROID_BASIC_TYPES_TRAITS( long long );   
  83. ANDROID_BASIC_TYPES_TRAITS( unsigned long long );   
  84. ANDROID_BASIC_TYPES_TRAITS( float );   
  85. ANDROID_BASIC_TYPES_TRAITS( double );   
  86.   
  87. // ---------------------------------------------------------------------------   
  88.   
  89.        
  90. /*  
  91.  * compare and order types  
  92.  */  
  93.   
  94. template<typename TYPE> inline  
  95. int strictly_order_type(const TYPE& lhs, const TYPE& rhs) {   
  96.     return (lhs < rhs) ? 1 : 0;   
  97. }   
  98.   
  99. template<typename TYPE> inline  
  100. int compare_type(const TYPE& lhs, const TYPE& rhs) {   
  101.     return strictly_order_type(rhs, lhs) - strictly_order_type(lhs, rhs);   
  102. }   
  103.   
  104. /*  
  105.  * create, destroy, copy and assign types...  
  106.  */  
  107.     
  108. template<typename TYPE> inline  
  109. void construct_type(TYPE* p, size_t n) {   
  110.     if (!traits<TYPE>::has_trivial_ctor) {   
  111.         while (n--) {   
  112.             new(p++) TYPE;   
  113.         }   
  114.     }   
  115. }   
  116.   
  117. template<typename TYPE> inline  
  118. void destroy_type(TYPE* p, size_t n) {   
  119.     if (!traits<TYPE>::has_trivial_dtor) {   
  120.         while (n--) {   
  121.             p->~TYPE();   
  122.             p++;   
  123.         }   
  124.     }   
  125. }   
  126.   
  127. template<typename TYPE> inline  
  128. void copy_type(TYPE* d, const TYPE* s, size_t n) {   
  129.     if (!traits<TYPE>::has_trivial_copy) {   
  130.         while (n--) {   
  131.             new(d) TYPE(*s);   
  132.             d++, s++;   
  133.         }   
  134.     } else {   
  135.         memcpy(d,s,n*sizeof(TYPE));   
  136.     }   
  137. }   
  138.   
  139. template<typename TYPE> inline  
  140. void assign_type(TYPE* d, const TYPE* s, size_t n) {   
  141.     if (!traits<TYPE>::has_trivial_assign) {   
  142.         while (n--) {   
  143.             *d++ = *s++;   
  144.         }   
  145.     } else {   
  146.         memcpy(d,s,n*sizeof(TYPE));   
  147.     }   
  148. }   
  149.   
  150. template<typename TYPE> inline  
  151. void splat_type(TYPE* where, const TYPE* what, size_t n) {   
  152.     if (!traits<TYPE>::has_trivial_copy) {   
  153.         while (n--) {   
  154.             new(where) TYPE(*what);   
  155.             where++;   
  156.         }   
  157.     } else {   
  158.          while (n--) {   
  159.              *where++ = *what;   
  160.         }   
  161.     }   
  162. }   
  163.   
  164. template<typename TYPE> inline  
  165. void move_forward_type(TYPE* d, const TYPE* s, size_t n = 1) {   
  166.     if (!traits<TYPE>::has_trivial_copy || !traits<TYPE>::has_trivial_dtor) {   
  167.         d += n;   
  168.         s += n;   
  169.         while (n--) {   
  170.             --d, --s;   
  171.             if (!traits<TYPE>::has_trivial_copy) {   
  172.                 new(d) TYPE(*s);   
  173.             } else {   
  174.                 *d = *s;   
  175.             }   
  176.             if (!traits<TYPE>::has_trivial_dtor) {   
  177.                 s->~TYPE();   
  178.             }   
  179.         }   
  180.     } else {   
  181.         memmove(d,s,n*sizeof(TYPE));   
  182.     }   
  183. }   
  184.   
  185. template<typename TYPE> inline  
  186. void move_backward_type(TYPE* d, const TYPE* s, size_t n = 1) {   
  187.     if (!traits<TYPE>::has_trivial_copy || !traits<TYPE>::has_trivial_dtor) {   
  188.         while (n--) {   
  189.             if (!traits<TYPE>::has_trivial_copy) {   
  190.                 new(d) TYPE(*s);   
  191.             } else {   
  192.                 *d = *s;   
  193.             }   
  194.             if (!traits<TYPE>::has_trivial_dtor) {   
  195.                 s->~TYPE();   
  196.             }   
  197.             d++, s++;   
  198.         }   
  199.     } else {   
  200.         memmove(d,s,n*sizeof(TYPE));   
  201.     }   
  202. }   
  203. // ---------------------------------------------------------------------------   
  204.   
  205. /*  
  206.  * a key/value pair  
  207.  */  
  208.   
  209. template <typename KEY, typename VALUE>   
  210. struct key_value_pair_t {   
  211.     KEY     key;   
  212.     VALUE   value;   
  213.     key_value_pair_t() { }   
  214.     key_value_pair_t(const key_value_pair_t& o) : key(o.key), value(o.value) { }   
  215.     key_value_pair_t(const KEY& k, const VALUE& v) : key(k), value(v)  { }   
  216.     key_value_pair_t(const KEY& k) : key(k) { }   
  217.     inline bool operator < (const key_value_pair_t& o) const {   
  218.         return strictly_order_type(key, o.key);   
  219.     }   
  220. };   
  221.   
  222. template<>   
  223. template <typename K, typename V>   
  224. struct trait_trivial_ctor< key_value_pair_t<K, V> >   
  225. enum { value = aggregate_traits<K,V>::has_trivial_ctor }; };   
  226. template<>    
  227. template <typename K, typename V>   
  228. struct trait_trivial_dtor< key_value_pair_t<K, V> >   
  229. enum { value = aggregate_traits<K,V>::has_trivial_dtor }; };   
  230. template<>    
  231. template <typename K, typename V>   
  232. struct trait_trivial_copy< key_value_pair_t<K, V> >   
  233. enum { value = aggregate_traits<K,V>::has_trivial_copy }; };   
  234. template<>    
  235. template <typename K, typename V>   
  236. struct trait_trivial_assign< key_value_pair_t<K, V> >   
  237. enum { value = aggregate_traits<K,V>::has_trivial_assign};};   
  238.   
  239. // ---------------------------------------------------------------------------   
  240.   
  241. }; // namespace android   
  242.   
  243. // ---------------------------------------------------------------------------   
  244.   
  245. #endif // ANDROID_TYPE_HELPERS_H  

4.编译中出现 make: *** No rule to make target `/cygdrive/e/workspace/myffmpeg/obj/local/armeabi/libjniaudio.so', needed by `/cygdrive/e/workspace/myffmpeg/obj/local/armeabi/libmediaplayer.a'.  Stop. 需要把下载的ffmpeg中的libjniaudio.so和libjnivideo.so放到错误中指定的目录下。

5. 编译成功后运行的结果如下:

    

当点击媒体文件播放时,发现画面显示不正常,如下所示:

调试后发现MediaPlayer.cpp中没有像Android自带播放器一样实现OnVideoSizeChangedListener的回调函数,当播放视图(SurfaceView)创建后没有根据实际播放的视频大小做调整,而且画面没有居中显示,所以我在此基础上做了如下改进

1. 实现OnVideoSizeChangedListener接口,通知播放界面调整大小

2. 播放界面剧中显示,等比率缩放视频大小。

3. 实现Seek功能(还在调试中)

下面是调整后播放flv(h264+aac)格式(分辨率为320*240,25帧/S)的结果,软解播放达到平均22帧/s

 

其它wmv,ts流,avi等格式均可播放,但是音质效果需要改进。

相关内容