VLC 4 Android 全面阐述

简介

Vlc for android是一款开源安卓播放器,具备播放多媒体文件、光盘、设备以及网络流媒体协议等功能,支持ARMv7 CPU或一个x86 CPU的设备,所有播放控制特性都已经开发完整。

下面将介绍如何获取代码、编译、vlc原理、缩小延迟、添加截图和录制视频、多路播放等。


详解
1、获取代码

官网源码下载:http://mirror.us.leaseweb.net/videolan/

git获取:clone from git://git.videolan.org/vlc-ports/android.git

补丁:https://patches.videolan.org/

2、编译

1、搭配环境
AndroidSDK:adt-bundle-linux-x86-20130522
JDK:jdk-7u25-linux-i586
NDK:android-ndk-r8e-linux-x86


2、安装工具
apt-get install gcc
apt-get install g++
apt-get build-dep vlc 
apt-get install git 
apt-get install wget 
apt-get install autoconf
apt-get install libtool
apt-get install subversion 
apt-get install cmake
apt-get install ant


3、配置信息

export ANDROID_NDK=/home/mythou/android-dev/android-ndk-r8e
export NDKR5C=/home/mythou/ndkr5c
export NDKR6B=/home/mythou/ndkr6b
PATH=$PATH:$NDKR6B:$ANDROID_NDK

export ANDROID_ABI=armeabi-v7a

export JAVA_HOME=/home/mythou/android-dev/jdk/jdk1.7.0_25
export JRE_HOME=/home/mythou/android-dev/jdk/jdk1.7.0_25/jre
export CLASSPATH=.:$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib
export ANT_HOME=/home/mythou/android-dev/apache-ant-1.8.0
export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH:$HOME/bin:$ANT_HOME

export ANDROID_SDK=/home/mythou/android-dev/adt-bundle-linux-x86-20130522/sdk
PATH=$PATH:$ANDROID_SDK/tools:$ANDROID_SDK/platform-tools


4、编译

sh compile.sh   or    sh compile.sh release


5、辅助库

由于某些原因,有些库无法获得,请手动下载放入便可。

3、vlc播放原理

视频播放的基本步骤:
    1、access 访问(获取视频数据)
    2、demux 解复用(音频、视频分离)  
    3、decode 解码(音频和视频的解码)
    4、output 输出(音频和视频的输出(aout和vout)


如图:

VLC 4 Android 全面阐述_第1张图片

4、缩小延迟

修改延迟的方法有两种:1、直接用Java代码实现;2、在vlc库中修改。

涉及延迟的参数有:file-caching(文件缓存)、live-caching(直播缓存)、network-caching(网络缓存)、sout-mux-caching(输出缓存)。


Java代码实现如下:

[java]  view plain copy
  1. options.add(":file-caching=1500");//文件缓存  
  2. options.add(":network-caching=1500");//网络缓存  
  3.   
  4. options.add(":live-caching=1500");//直播缓存  
  5. options.add(":sout-mux-caching=1500");//输出缓存  
  6.   
  7. options.add(":codec=mediacodec,iomx,all");  

vlc库实现如下:

查找目标文件vlc/src/libvlc-module.c  修改对应的参数

[java]  view plain copy
  1. add_integer( "file-caching", DEFAULT_PTS_DELAY / 3000,  
  2.              CACHING_TEXT, CACHING_LONGTEXT, true )  
  3. add_integer( "live-caching", DEFAULT_PTS_DELAY / 3000,  
  4.              CAPTURE_CACHING_TEXT, CAPTURE_CACHING_LONGTEXT, true )  
  5. add_integer( "network-caching", CLOCK_FREQ / 3000,  
  6.              NETWORK_CACHING_TEXT, NETWORK_CACHING_LONGTEXT, true )  
  7. add_integer( "sout-mux-caching"1000, SOUT_MUX_CACHING_TEXT,  
  8.                             SOUT_MUX_CACHING_LONGTEXT, true )  

把分母数据增大,缓存的数据就越小,延迟就减少,流畅性就减少,相反,分母数据减少,缓存的数据就越大,延迟就增加,流畅性就增加。

测试结果,延迟明显减少。

5、添加截图和录制视频

官方已给出补丁实现截图和录制视频

1、截图

修改文件: android/configure.sh  搜索内容 -disable-sout   并删除

修改文件:android/vlc/contrib/src/ffmpeg/rules.mak  增加-enable-encoder=png的编码器 实现png格式截图

[java]  view plain copy
  1. FFMPEGCONF += --disable-encoders --disable-muxers  
  2.  改成FFMPEGCONF += --disable-encoders --enable-encoder=png --disable-muxers  

源码重新编译便可

编译过程中可能会出现如下问题:

[java]  view plain copy
  1. ./vlc/android/modules/.libs/libvorbis_plugin.a(libvorbis_plugin_la-vorbis.o): in function OpenEncoder:../../modules/codec/vorbis.c:758: error: undefined reference to 'vorbis_encode_setup_vbr‘  
解决方法:
修改文件  vlc-android/jni/Android.mk

[java]  view plain copy
  1.  LOCAL_LDLIBS := -L$(VLC_CONTRIB)/lib \    
  2.     $(VLC_MODULES) \    
  3.     $(VLC_BUILD_DIR)/lib/.libs/libvlc.a \    
  4.     $(VLC_BUILD_DIR)/src/.libs/libvlccore.a \    
  5.     $(VLC_BUILD_DIR)/compat/.libs/libcompat.a \    
  6.     -ldl -lz -lm -llog \    
  7.     -ldvbpsi -lebml -lmatroska -ltag \    
  8.     -logg -lFLAC -ltheora -lvorbis -lvorbisfile -lvorbisenc \    
  9.     -lmpeg2 -la52 \    
  10.     -lavformat -lavcodec -lswscale -lavutil -lpostproc -lgsm -lopenjpeg \    
  11.     -lliveMedia -lUsageEnvironment -lBasicUsageEnvironment -lgroupsock \    
  12.     -lspeex -lspeexdsp \    
  13.     -lxml2 -lpng -lgnutls -lgcrypt -lgpg-error \    
  14.     -lnettle -lhogweed -lgmp \    
  15.     -lfreetype -liconv -lass -lfribidi -lopus \    
  16.     -lEGL -lGLESv2 -ljpeg \    
  17.     $(CPP_STATIC)    
  18.   
  19. 在  
  20. -logg -lFLAC -ltheora -lvorbis   
  21. 后添加  
  22. -lvorbisfile -lvorbisenc   

[java]  view plain copy
  1. error: undefined reference to 'vlc_entry__access_output_udp'  
解决方法:
修改文件: /vlc/modules/access_output/ Modules.am

[java]  view plain copy
  1. SOURCES_access_output_dummy = dummy.c    
  2.     SOURCES_access_output_file = file.c    
  3.     SOURCES_access_output_udp = udp.c    
  4.     SOURCES_access_output_http = http.c bonjour.c bonjour.h    
  5.     SOURCES_access_output_shout = shout.c    
  6.         
  7.         
  8.     access_output_LTLIBRARIES += \    
  9.         libaccess_output_dummy_plugin.la \    
  10.         libaccess_output_file_plugin.la \    
  11.         libaccess_output_udp_plugin.la \    
  12.         libaccess_output_http_plugin.la    
  13.         
  14.         
  15.     #libaccess_output_udp_plugin_la_SOURCES = udp.c    
  16.     #libaccess_output_udp_plugin_la_LIBADD = $(SOCKET_LIBS) $(LIBPTHREAD)    
  17.     #access_output_LTLIBRARIES += libaccess_output_udp_plugin.la    
  18.         
  19.         
  20.     libaccess_output_livehttp_plugin_la_SOURCES = livehttp.c    
  21.     libaccess_output_livehttp_plugin_la_CFLAGS = $(AM_CFLAGS) $(GCRYPT_CFLAGS)    
  22.     libaccess_output_livehttp_plugin_la_LIBADD = $(GCRYPT_LIBS) -lgpg-error    
  23.     if HAVE_GCRYPT    
  24.     access_output_LTLIBRARIES += libaccess_output_livehttp_plugin.la    
  25.     endif    
  26.   
  27. 内容覆盖便可  


相关源码添加:

在libvlcjni.c中增加函数:

[java]  view plain copy
  1. boolean Java_org_videolan_libvlc_LibVLC_takeSnapShot(JNIEnv *env, jobject thiz,jint number, jstring path, jint width,jint height)    
  2. {    
  3.     jboolean isCopy;    
  4.    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);    
  5.      /* Get C string */    
  6.    const char* psz_path = (*env)->GetStringUTFChars(env, path, &isCopy);    
  7.     
  8.    if (mp)    
  9.         if(libvlc_video_take_snapshot(mp, (int)number,psz_path , (int)width,(int)height)==0)    
  10.             return JNI_TRUE;    
  11.    return JNI_FALSE;    
  12.     
  13. }    

LibVlc.java中增加native函数的接口和调用方法:

[java]  view plain copy
  1. private native boolean takeSnapShot( int num, String file, int width, int height);    
[java]  view plain copy
  1. public boolean takeSnapShot(String file, int width, int height) {    
  2.     return takeSnapShot(0, file, width, height);    
  3. }   

2、录制视频

录制补丁  https://patches.videolan.org/patch/606/

补丁内容如下:

[java]  view plain copy
  1. diff --git a/include/vlc/libvlc_events.h b/include/vlc/libvlc_events.h  
  2. index 2cfedbf..25a16ea 100644  
  3. --- a/include/vlc/libvlc_events.h  
  4. +++ b/include/vlc/libvlc_events.h  
  5. @@ -72,6 +72,8 @@ enum libvlc_event_e {  
  6.      libvlc_MediaPlayerSnapshotTaken,  
  7.      libvlc_MediaPlayerLengthChanged,  
  8.      libvlc_MediaPlayerVout,  
  9. +    libvlc_MediaPlayerRecordableChanged,  
  10. +    libvlc_MediaPlayerRecordingFinished,  
  11.    
  12.      libvlc_MediaListItemAdded=0x200,  
  13.      libvlc_MediaListWillAddItem,  
  14. @@ -165,6 +167,14 @@ typedef struct libvlc_event_t  
  15.          } media_player_pausable_changed;  
  16.          struct  
  17.          {  
  18. +            int new_recordable;  
  19. +        } media_player_recordable_changed;  
  20. +        struct  
  21. +        {  
  22. +            char *psz_filename;  
  23. +        } media_player_recording_finished;  
  24. +        struct  
  25. +        {  
  26.              int new_count;  
  27.          } media_player_vout;  
  28.    
  29. diff --git a/include/vlc/libvlc_media_player.h b/include/vlc/libvlc_media_player.h  
  30. index aefef02..8ddef37 100644  
  31. --- a/include/vlc/libvlc_media_player.h  
  32. +++ b/include/vlc/libvlc_media_player.h  
  33. @@ -1628,6 +1628,121 @@ LIBVLC_API int libvlc_audio_set_delay( libvlc_media_player_t *p_mi, int64_t i_de  
  34.    
  35.  /** @} audio */  
  36.    
  37. +/** 
  38. + * Can the media player record the current media? 
  39. + * 
  40. + * Media must be buffering or playing before it can be recorded. 
  41. + * 
  42. + * The media player event manager will emit a libvlc_MediaPlayerRecordableChanged event 
  43. + * when the recordable state changes after starting media playback. The event data will 
  44. + * describe the new recordable state, so invocation of this API method is not strictly 
  45. + * necessary to determine when recording can be started. 
  46. + * 
  47. + * A libvlc_MediaPlayerRecordableChanged event will not be emitted if the media is 
  48. + * stopped (notified by a libvlc_MediaPlayerStoppedEvent) or finishes normally (notified 
  49. + * by a libvlc_MediaPlayerFinished event). 
  50. + * 
  51. + * A calling application should therefore register an event callback for those events 
  52. + * so that it may query the new recordable state and manage recording at the appropriate 
  53. + * time. 
  54. + * 
  55. + * \param p_mi media player 
  56. + * \return true if the media player can record, false if it can not 
  57. + * \version LibVLC 2.1.0 or later 
  58. + */  
  59. +LIBVLC_API bool libvlc_media_player_is_recordable( libvlc_media_player_t *p_mi );  
  60. +  
  61. +/** 
  62. + * Is the current media being recorded? 
  63. + * 
  64. + * \param p_mi media player 
  65. + * \return true if recording, false if not 
  66. + * \version LibVLC 2.1.0 or later 
  67. + */  
  68. +LIBVLC_API bool libvlc_media_player_is_recording( libvlc_media_player_t *p_mi );  
  69. +  
  70. +/** 
  71. + * Start recording the current media. 
  72. + * 
  73. + * Media must be buffering or playing before it can be recorded. A calling application 
  74. + * can begin recording immediately on receipt of a libvlc_MediaPlayerRecordableChanged 
  75. + * event sent via the media player event manager (if recording is possible for the 
  76. + * currently playing media), and any time thereafter until the media stops. 
  77. + * 
  78. + * Media will be saved to the file path denoted by the psz_filename parameter if it is 
  79. + * supplied. Any such supplied filename should not include a file extension as the 
  80. + * correct file extension will automatically be appended when the file is created. This 
  81. + * filename may denote a full path name, but each directory in the path must already 
  82. + * exist or recording will silently fail. If the calling application chooses to specify 
  83. + * the filename then it is the responsibility of that application to take account of 
  84. + * this and itself make sure any needed directories are created. 
  85. + * 
  86. + * Alternatively, a calling application need not supply a filename and so instead let 
  87. + * vlc automatically generate a unique filename. This will cause vlc to create a new 
  88. + * file in the appropriate media directory for the user - for example "~/Videos". The 
  89. + * actual filename used will be sent in an event when the recording is complete. 
  90. + * 
  91. + * When recording has finished and the new file has been completely saved, a 
  92. + * libvlc_MediaPlayerRecordingFinished event will be sent via the media player event 
  93. + * manager. The event data will contain the filename of the newly recorded file - this 
  94. + * will either be the filename as specified by the calling application or a filename 
  95. + * generated by vlc if the application did not supply a filename. In either case, this 
  96. + * filename will include the automatically appended file extension. 
  97. + * 
  98. + * The saved media file will not be immediately available or visible until recording 
  99. + * has completely finished and the libvlc_MediaPlayerRecordingFinished event has been 
  100. + * received, or the media has stopped or finished normally. 
  101. + * 
  102. + * Recording can be stopped and started on-the-fly once the recordable state is set; 
  103. + * each time recording is stopped and restarted a new file will be created so a calling 
  104. + * application should take care to provide unique filenames, or defer to vlc to create 
  105. + * unique filenames. 
  106. + * 
  107. + * Recording will be stopped when the media stops playing, and must be explicitly 
  108. + * started again to restart recording, i.e. the recording state is not automatically 
  109. + * preserved when playing media subsequently. 
  110. + * 
  111. + * Media player functionailty such as next/previous chapter, set time or position and 
  112. + * so on are ineffective when recording is enabled. However, pausing the media is 
  113. + * possible and will pause the recording; unpausing the media will resume playback and 
  114. + * recording. 
  115. + * 
  116. + * Recording of the primary media or sub-items is possible. 
  117. + * 
  118. + * \param p_mi media player 
  119. + * \param psz_filename name of the file to save the media to, not including any file extension, 
  120. + *                     or NULL if vlc should generate the filename automatically 
  121. + * \return 0 if recording was started, -1 on error 
  122. + * \version LibVLC 2.1.0 or later 
  123. + */  
  124. +LIBVLC_API int libvlc_media_player_record_start( libvlc_media_player_t *p_mi, const char *psz_filename );  
  125. +  
  126. +/** 
  127. + * Stop recording the current media. 
  128. + * 
  129. + * This method requests that the recording stop, and will return immediately. Recording 
  130. + * will not stop immediately. 
  131. + * 
  132. + * When the recording actually stops some short time later and the new file has 
  133. + * finished being written, a libvlc_MediaPlayerRecordingFinished event will be sent via 
  134. + * the media player event manager. The newly recorded file will not be visible or 
  135. + * available until after this event has been sent. 
  136. + * 
  137. + * The event data will contain the full name of the file that was created. The filename 
  138. + * will either be that as was specified by the calling application on invoking 
  139. + * libvlc_media_player_record_start(), or the filename that vlc automatically generated 
  140. + * if the calling application did not supply its own filename. In either case the 
  141. + * filename will contain the automatically appended file extension. 
  142. + * 
  143. + * There is no need to invoke this method to stop the recording if the media is stopped 
  144. + * or finishes playing normally. 
  145. + * 
  146. + * \param p_mi media player 
  147. + * \return 0 if recording was stopped, -1 on error 
  148. + * \version LibVLC 2.1.0 or later 
  149. + */  
  150. +LIBVLC_API int libvlc_media_player_record_stop( libvlc_media_player_t *p_mi );  
  151. +  
  152.  /** @} media_player */  
  153.    
  154.  # ifdef __cplusplus  
  155. diff --git a/lib/event.c b/lib/event.c  
  156. index c71a48a..7ef4abd 100644  
  157. --- a/lib/event.c  
  158. +++ b/lib/event.c  
  159. @@ -279,6 +279,8 @@ static const event_name_t event_list[] = {  
  160.      DEF(MediaPlayerSnapshotTaken)  
  161.      DEF(MediaPlayerLengthChanged)  
  162.      DEF(MediaPlayerVout)  
  163. +    DEF(MediaPlayerRecordableChanged)  
  164. +    DEF(MediaPlayerRecordingFinished)  
  165.    
  166.      DEF(MediaListItemAdded)  
  167.      DEF(MediaListWillAddItem)  
  168. diff --git a/lib/libvlc.sym b/lib/libvlc.sym  
  169. index 42dad5c..3ff67ef 100644  
  170. --- a/lib/libvlc.sym  
  171. +++ b/lib/libvlc.sym  
  172. @@ -137,6 +137,8 @@ libvlc_media_player_get_title  
  173.  libvlc_media_player_get_title_count  
  174.  libvlc_media_player_get_xwindow  
  175.  libvlc_media_player_has_vout  
  176. +libvlc_media_player_is_recordable  
  177. +libvlc_media_player_is_recording  
  178.  libvlc_media_player_is_seekable  
  179.  libvlc_media_player_is_playing  
  180.  libvlc_media_player_new  
  181. @@ -146,6 +148,8 @@ libvlc_media_player_set_pause  
  182.  libvlc_media_player_pause  
  183.  libvlc_media_player_play  
  184.  libvlc_media_player_previous_chapter  
  185. +libvlc_media_player_record_start  
  186. +libvlc_media_player_record_stop  
  187.  libvlc_media_player_release  
  188.  libvlc_media_player_retain  
  189.  libvlc_media_player_set_agl  
  190. diff --git a/lib/media_player.c b/lib/media_player.c  
  191. index a41b8c7..6573197 100644  
  192. --- a/lib/media_player.c  
  193. +++ b/lib/media_player.c  
  194. @@ -64,6 +64,10 @@ input_pausable_changed( vlc_object_t * p_this, char const * psz_cmd,  
  195.                          vlc_value_t oldval, vlc_value_t newval,  
  196.                          void * p_userdata );  
  197.  static int  
  198. +input_recordable_changed( vlc_object_t *p_this, char const *psz_cmd,  
  199. +                          vlc_value_t oldval, vlc_value_t newval,  
  200. +                          void *p_userdata );  
  201. +static int  
  202.  input_event_changed( vlc_object_t * p_this, char const * psz_cmd,  
  203.                       vlc_value_t oldval, vlc_value_t newval,  
  204.                       void * p_userdata );  
  205. @@ -72,6 +76,10 @@ static int  
  206.  snapshot_was_taken( vlc_object_t *p_this, char const *psz_cmd,  
  207.                      vlc_value_t oldval, vlc_value_t newval, void *p_data );  
  208.    
  209. +static int  
  210. +file_recording_finished( vlc_object_t *p_this, char const *psz_cmd,  
  211. +                         vlc_value_t oldval, vlc_value_t newval, void *p_data );  
  212. +  
  213.  static void libvlc_media_player_destroy( libvlc_media_player_t *p_mi );  
  214.    
  215.  /* 
  216. @@ -132,6 +140,8 @@ static void release_input_thread( libvlc_media_player_t *p_mi, bool b_input_abor 
  217.                       input_seekable_changed, p_mi ); 
  218.      var_DelCallback( p_input_thread, "can-pause", 
  219.                      input_pausable_changed, p_mi ); 
  220. +    var_DelCallback( p_input_thread, "can-record", 
  221. +                     input_recordable_changed, p_mi ); 
  222.      var_DelCallback( p_input_thread, "intf-event", 
  223.                       input_event_changed, p_mi ); 
  224.   
  225. @@ -227,6 +237,25 @@ input_pausable_changed( vlc_object_t * p_this, char const * psz_cmd, 
  226.  } 
  227.   
  228.  static int 
  229. +input_recordable_changed( vlc_object_t *p_this, char const *psz_cmd, 
  230. +                          vlc_value_t oldval, vlc_value_t newval, 
  231. +                          void *p_userdata ) 
  232. +{ 
  233. +    VLC_UNUSED(p_this); 
  234. +    VLC_UNUSED(psz_cmd); 
  235. +    VLC_UNUSED(oldval); 
  236. + 
  237. +    libvlc_media_player_t *p_mi = p_userdata; 
  238. +    libvlc_event_t event; 
  239. + 
  240. +    event.type = libvlc_MediaPlayerRecordableChanged; 
  241. +    event.u.media_player_recordable_changed.new_recordable = newval.b_bool; 
  242. + 
  243. +    libvlc_event_send( p_mi->p_event_manager, &event ); 
  244. +    return VLC_SUCCESS; 
  245. +} 
  246. + 
  247. +static int 
  248.  input_event_changed( vlc_object_t * p_this, char const * psz_cmd, 
  249.                       vlc_value_t oldval, vlc_value_t newval, 
  250.                       void * p_userdata ) 
  251. @@ -357,6 +386,23 @@ static int snapshot_was_taken(vlc_object_t *p_this, char const *psz_cmd, 
  252.      return VLC_SUCCESS; 
  253.  } 
  254.   
  255. +static int file_recording_finished(vlc_object_t *p_this, char const *psz_cmd, 
  256. +                                   vlc_value_t oldval, vlc_value_t newval, void *p_data ) 
  257. +{ 
  258. +    VLC_UNUSED(p_this); 
  259. +    VLC_UNUSED(psz_cmd); 
  260. +    VLC_UNUSED(oldval); 
  261. + 
  262. +    libvlc_media_player_t *p_mi = p_data; 
  263. +    libvlc_event_t event; 
  264. + 
  265. +    event.type = libvlc_MediaPlayerRecordingFinished; 
  266. +    event.u.media_player_recording_finished.psz_filename = newval.psz_string; 
  267. + 
  268. +    libvlc_event_send(p_mi->p_event_manager, &event); 
  269. +    return VLC_SUCCESS; 
  270. +} 
  271. + 
  272.  static input_thread_t *find_input (vlc_object_t *obj) 
  273.  { 
  274.      libvlc_media_player_t *mp = (libvlc_media_player_t *)obj; 
  275. @@ -480,6 +526,10 @@ libvlc_media_player_new( libvlc_instance_t *instance ) 
  276.      var_Create (mp, "amem-set-volume", VLC_VAR_ADDRESS); 
  277.      var_Create (mp, "amem-format", VLC_VAR_STRING | VLC_VAR_DOINHERIT); 
  278.      var_Create (mp, "amem-rate", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT); 
  279. + 
  280. +    var_Create (mp, "recording-finished", VLC_VAR_STRING); 
  281. +    var_AddCallback (mp, "recording-finished", file_recording_finished, mp); 
  282. + 
  283.      var_Create (mp, "amem-channels", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT); 
  284.   
  285.      mp->p_md = NULL; 
  286. @@ -515,6 +565,9 @@ libvlc_media_player_new( libvlc_instance_t *instance ) 
  287.      register_event(mp, TitleChanged); 
  288.      register_event(mp, PausableChanged); 
  289.   
  290. +    register_event(mp, RecordableChanged); 
  291. +    register_event(mp, RecordingFinished); 
  292. + 
  293.      register_event(mp, Vout); 
  294.   
  295.      /* Snapshot initialization */  
  296. @@ -566,6 +619,8 @@ static void libvlc_media_player_destroy( libvlc_media_player_t *p_mi )  
  297.      var_DelCallback( p_mi->p_libvlc,  
  298.                       "snapshot-file", snapshot_was_taken, p_mi );  
  299.    
  300. +    var_DelCallback( p_mi, "recording-finished", file_recording_finished, p_mi );  
  301. +  
  302.      /* No need for lock_input() because no other threads knows us anymore */  
  303.      if( p_mi->input.p_thread )  
  304.          release_input_thread(p_mi, true);  
  305. @@ -732,12 +787,14 @@ int libvlc_media_player_play( libvlc_media_player_t *p_mi )  
  306.    
  307.      var_AddCallback( p_input_thread, "can-seek", input_seekable_changed, p_mi );  
  308.      var_AddCallback( p_input_thread, "can-pause", input_pausable_changed, p_mi );  
  309. +    var_AddCallback( p_input_thread, "can-record", input_recordable_changed, p_mi );  
  310.      var_AddCallback( p_input_thread, "intf-event", input_event_changed, p_mi );  
  311.    
  312.      if( input_Start( p_input_thread ) )  
  313.      {  
  314.          unlock_input(p_mi);  
  315.          var_DelCallback( p_input_thread, "intf-event", input_event_changed, p_mi );  
  316. +        var_DelCallback( p_input_thread, "can-record", input_recordable_changed, p_mi );  
  317.          var_DelCallback( p_input_thread, "can-pause", input_pausable_changed, p_mi );  
  318.          var_DelCallback( p_input_thread, "can-seek", input_seekable_changed, p_mi );  
  319.          vlc_object_release( p_input_thread );  
  320. @@ -1409,3 +1466,62 @@ void libvlc_media_player_next_frame( libvlc_media_player_t *p_mi )  
  321.          vlc_object_release( p_input_thread );  
  322.      }  
  323.  }  
  324. +  
  325. +bool libvlc_media_player_is_recordable( libvlc_media_player_t *p_mi )  
  326. +{  
  327. +    input_thread_t *p_input_thread;  
  328. +    bool b_can_record;  
  329. +  
  330. +    p_input_thread = libvlc_get_input_thread( p_mi );  
  331. +    if( !p_input_thread )  
  332. +        return false;  
  333. +  
  334. +    b_can_record = var_GetBool( p_input_thread, "can-record" );  
  335. +  
  336. +    vlc_object_release( p_input_thread );  
  337. +    return b_can_record;  
  338. +}  
  339. +  
  340. +bool libvlc_media_player_is_recording( libvlc_media_player_t *p_mi )  
  341. +{  
  342. +    input_thread_t *p_input_thread;  
  343. +    bool b_record;  
  344. +  
  345. +    p_input_thread = libvlc_get_input_thread( p_mi );  
  346. +    if( !p_input_thread )  
  347. +        return false;  
  348. +  
  349. +    b_record = var_GetBool( p_input_thread, "record" );  
  350. +  
  351. +    vlc_object_release( p_input_thread );  
  352. +    return b_record;  
  353. +}  
  354. +  
  355. +int libvlc_media_player_record_start( libvlc_media_player_t *p_mi, const char* psz_filename )  
  356. +{  
  357. +    input_thread_t *p_input_thread;  
  358. +  
  359. +    p_input_thread = libvlc_get_input_thread( p_mi );  
  360. +    if( !p_input_thread )  
  361. +        return -1;  
  362. +  
  363. +    var_SetString( p_input_thread, "input-record-path", psz_filename );  
  364. +    var_SetBool( p_input_thread, "record"true );  
  365. +  
  366. +    vlc_object_release( p_input_thread );  
  367. +    return 0;  
  368. +}  
  369. +  
  370. +int libvlc_media_player_record_stop( libvlc_media_player_t *p_mi )  
  371. +{  
  372. +    input_thread_t *p_input_thread;  
  373. +  
  374. +    p_input_thread = libvlc_get_input_thread( p_mi );  
  375. +    if( !p_input_thread )  
  376. +        return -1;  
  377. +  
  378. +    var_SetBool( p_input_thread, "record"false );  
  379. +  
  380. +    vlc_object_release( p_input_thread );  
  381. +    return 0;  
  382. +}  
  383. diff --git a/modules/stream_out/record.c b/modules/stream_out/record.c  
  384. index de6d32e..40ddfea 100644  
  385. --- a/modules/stream_out/record.c  
  386. +++ b/modules/stream_out/record.c  
  387. @@ -110,6 +110,8 @@ struct sout_stream_sys_t  
  388.      int              i_id;  
  389.      sout_stream_id_t **id;  
  390.      mtime_t     i_dts_start;  
  391. +  
  392. +    char *psz_record_file;  
  393.  };  
  394.    
  395.  static void OutputStart( sout_stream_t *p_stream );  
  396. @@ -158,6 +160,8 @@ static int Open( vlc_object_t *p_this )  
  397.      p_sys->i_dts_start = 0;  
  398.      TAB_INIT( p_sys->i_id, p_sys->id );  
  399.    
  400. +    p_sys->psz_record_file = NULL;  
  401. +  
  402.      return VLC_SUCCESS;  
  403.  }  
  404.    
  405. @@ -172,6 +176,19 @@ static void Close( vlc_object_t * p_this )  
  406.      if( p_sys->p_out )  
  407.          sout_StreamChainDelete( p_sys->p_out, p_sys->p_out );  
  408.    
  409. +    if( p_sys->psz_record_file ) {  
  410. +        for( vlc_object_t *p_mp = p_stream->p_parent; p_mp; p_mp = p_mp->p_parent )  
  411. +        {  
  412. +            if( var_Type( p_mp, "recording-finished" ) )  
  413. +            {  
  414. +                var_SetString( p_mp, "recording-finished", p_sys->psz_record_file );  
  415. +                break;  
  416. +            }  
  417. +        }  
  418. +  
  419. +        free( p_sys->psz_record_file );  
  420. +    }  
  421. +  
  422.      TAB_CLEAN( p_sys->i_id, p_sys->id );  
  423.      free( p_sys->psz_prefix );  
  424.      free( p_sys );  
  425. @@ -352,7 +369,10 @@ static int OutputNew( sout_stream_t *p_stream,  
  426.      }  
  427.    
  428.      if( psz_file && psz_extension )  
  429. +    {  
  430. +        p_sys->psz_record_file = strdup( psz_file );  
  431.          var_SetString( p_stream->p_libvlc, "record-file", psz_file );  
  432. +    }  
  433.    
  434.      free( psz_file );  
  435.      free( psz_output );  
  436. diff --git a/src/input/var.c b/src/input/var.c  
  437. index 9613fe2..04f33b9 100644  
  438. --- a/src/input/var.c  
  439. +++ b/src/input/var.c  
  440. @@ -210,6 +210,9 @@ void input_ControlVarInit ( input_thread_t *p_input )  
  441.      text.psz_string = _("Subtitles Track");  
  442.      var_Change( p_input, "spu-es", VLC_VAR_SETTEXT, &text, NULL );  
  443.    
  444. +    /* ES Out */  
  445. +    var_Create( p_input, "input-record-path", VLC_VAR_STRING | VLC_VAR_DOINHERIT );  
  446. +  
  447.      /* Special read only objects variables for intf */  
  448.      var_Create( p_input, "bookmarks", VLC_VAR_STRING | VLC_VAR_DOINHERIT );  
  449.    

下载补丁,并把文件放到vlc目录中,执行命令patch -p1 < xxxx.patch,由于版本不一样有些地方会失败,请打开补丁自己检查手动修改。

补丁中主要相关函数:

[java]  view plain copy
  1. +bool libvlc_media_player_is_recordable( libvlc_media_player_t *p_mi )  
  2. +{  
  3. +    input_thread_t *p_input_thread;  
  4. +    bool b_can_record;  
  5. +  
  6. +    p_input_thread = libvlc_get_input_thread( p_mi );  
  7. +    if( !p_input_thread )  
  8. +        return false;  
  9. +  
  10. +    b_can_record = var_GetBool( p_input_thread, "can-record" );  
  11. +  
  12. +    vlc_object_release( p_input_thread );  
  13. +    return b_can_record;  
  14. +}  
  15. +  
  16. +bool libvlc_media_player_is_recording( libvlc_media_player_t *p_mi )  
  17. +{  
  18. +    input_thread_t *p_input_thread;  
  19. +    bool b_record;  
  20. +  
  21. +    p_input_thread = libvlc_get_input_thread( p_mi );  
  22. +    if( !p_input_thread )  
  23. +        return false;  
  24. +  
  25. +    b_record = var_GetBool( p_input_thread, "record" );  
  26. +  
  27. +    vlc_object_release( p_input_thread );  
  28. +    return b_record;  
  29. +}  
  30. +  
  31. +int libvlc_media_player_record_start( libvlc_media_player_t *p_mi, const char* psz_filename )  
  32. +{  
  33. +    input_thread_t *p_input_thread;  
  34. +  
  35. +    p_input_thread = libvlc_get_input_thread( p_mi );  
  36. +    if( !p_input_thread )  
  37. +        return -1;  
  38. +  
  39. +    var_SetString( p_input_thread, "input-record-path", psz_filename );  
  40. +    var_SetBool( p_input_thread, "record"true );  
  41. +  
  42. +    vlc_object_release( p_input_thread );  
  43. +    return 0;  
  44. +}  
  45. +  
  46. +int libvlc_media_player_record_stop( libvlc_media_player_t *p_mi )  
  47. +{  
  48. +    input_thread_t *p_input_thread;  
  49. +  
  50. +    p_input_thread = libvlc_get_input_thread( p_mi );  
  51. +    if( !p_input_thread )  
  52. +        return -1;  
  53. +  
  54. +    var_SetBool( p_input_thread, "record"false );  
  55. +  
  56. +    vlc_object_release( p_input_thread );  
  57. +    return 0;  
  58. +}  

库调用方法函数如下:

[java]  view plain copy
  1. jboolean Java_org_videolan_libvlc_LibVLC_takeSnapShot(JNIEnv *env, jobject thiz,jint number, jstring path, jint width,jint height)    
  2. {    
  3.     jboolean isCopy;    
  4.    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);    
  5.      /* Get C string */    
  6.    const char* psz_path = (*env)->GetStringUTFChars(env, path, &isCopy);    
  7.     
  8.    if (mp)    
  9.         if(libvlc_video_take_snapshot(mp, (int)number,psz_path , (int)width,(int)height)==0)    
  10.             return JNI_TRUE;    
  11.    return JNI_FALSE;    
  12.     
  13. }    
  14.     
  15. jboolean Java_org_videolan_libvlc_LibVLC_videoRecordStart(JNIEnv *env, jobject thiz,jstring path)    
  16. {    
  17.     jboolean isCopy;    
  18.    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);    
  19.      /* Get C string */    
  20.    const char* psz_path = (*env)->GetStringUTFChars(env, path, &isCopy);    
  21.    //const char* psz_filename=(*env)->GetStringUTFChars(env, filename, &isCopy);    
  22.    if (mp)    
  23.         if(libvlc_media_player_record_start(mp,psz_path)==0)    
  24.             return JNI_TRUE;    
  25.    return JNI_FALSE;    
  26. }    
  27.     
  28. jboolean Java_org_videolan_libvlc_LibVLC_videoRecordStop(JNIEnv *env, jobject thiz)    
  29. {    
  30.     jboolean isCopy;    
  31.    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);    
  32.      /* Get C string */    
  33.    if (mp)    
  34.         if(libvlc_media_player_record_stop(mp)==0)    
  35.             return JNI_TRUE;    
  36.    return JNI_FALSE;    
  37. }    
  38.     
  39. jboolean Java_org_videolan_libvlc_LibVLC_videoIsRecording(JNIEnv *env, jobject thiz)    
  40. {    
  41.     jboolean isCopy;    
  42.    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);    
  43.    if (mp)    
  44.         if(libvlc_media_player_is_recording(mp))    
  45.             return JNI_TRUE;    
  46.    return JNI_FALSE;    
  47. }    
  48. jboolean Java_org_videolan_libvlc_LibVLC_videoIsRecordable(JNIEnv *env, jobject thiz)    
  49. {    
  50.     jboolean isCopy;    
  51.    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);    
  52.    if (mp)    
  53.         if(libvlc_media_player_is_recordable(mp))    
  54.             return JNI_TRUE;    
  55.    return JNI_FALSE;    
  56. }    
  57.     
  58. jint Java_org_videolan_libvlc_LibVLC_getState(JNIEnv *env, jobject thiz)    
  59. {    
  60.     libvlc_media_player_t *mp = getMediaPlayer(env, thiz);    
  61.     if (mp){    
  62.         libvlc_state_t state=libvlc_media_player_get_state(mp);    
  63.         return (jint)state;    
  64.     }    
  65.     else    
  66.         return -1;    
  67. }  

6、实现多路播放

使用process属性实现



总结

接触vlc for android 是帮助朋友完成一个外单,即实现认证播放器的封装(即添加播放网络视频的认证),传地址便可播放。

经测试vlc无法播放swf文件,为了弥补这已缺陷,准备添加swfdec到android平台以支持swf文件。


推荐博客网站:http://flavienlaurent.com/


你可能感兴趣的:(VLC 4 Android 全面阐述)