IjkVideoView.java 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148
  1. /*
  2. * Copyright (C) 2015 Bilibili
  3. * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. package com.edufound.mobile.xxt.ijkplayer.media;
  18. import android.annotation.TargetApi;
  19. import android.content.Context;
  20. import android.content.res.Resources;
  21. import android.media.AudioManager;
  22. import android.media.MediaPlayer;
  23. import android.net.Uri;
  24. import android.os.Build;
  25. import android.support.annotation.NonNull;
  26. import android.text.TextUtils;
  27. import android.util.AttributeSet;
  28. import android.util.Log;
  29. import android.view.Gravity;
  30. import android.view.KeyEvent;
  31. import android.view.MotionEvent;
  32. import android.view.View;
  33. import android.widget.FrameLayout;
  34. import android.widget.MediaController;
  35. import android.widget.TextView;
  36. import android.widget.Toast;
  37. import com.edufound.mobile.xxt.R;
  38. import com.edufound.mobile.xxt.ijkplayer.application.Settings;
  39. import com.edufound.mobile.xxt.ijkplayer.services.MediaPlayerService;
  40. import java.io.File;
  41. import java.io.IOException;
  42. import java.util.ArrayList;
  43. import java.util.List;
  44. import java.util.Locale;
  45. import java.util.Map;
  46. import tv.danmaku.ijk.media.exo.IjkExoMediaPlayer;
  47. import tv.danmaku.ijk.media.player.AndroidMediaPlayer;
  48. import tv.danmaku.ijk.media.player.IMediaPlayer;
  49. import tv.danmaku.ijk.media.player.IjkMediaPlayer;
  50. import tv.danmaku.ijk.media.player.IjkTimedText;
  51. import tv.danmaku.ijk.media.player.TextureMediaPlayer;
  52. import tv.danmaku.ijk.media.player.misc.IMediaDataSource;
  53. import tv.danmaku.ijk.media.player.misc.ITrackInfo;
  54. public class IjkVideoView extends FrameLayout implements MediaController.MediaPlayerControl {
  55. private String TAG = "IjkVideoView";
  56. // settable by the client
  57. private Uri mUri;
  58. private Map<String, String> mHeaders;
  59. // all possible internal states
  60. private static final int STATE_ERROR = -1;
  61. private static final int STATE_IDLE = 0;
  62. private static final int STATE_PREPARING = 1;
  63. private static final int STATE_PREPARED = 2;
  64. private static final int STATE_PLAYING = 3;
  65. private static final int STATE_PAUSED = 4;
  66. private static final int STATE_PLAYBACK_COMPLETED = 5;
  67. // mCurrentState is a VideoView object's current state.
  68. // mTargetState is the state that a method caller intends to reach.
  69. // For instance, regardless the VideoView object's current state,
  70. // calling pause() intends to bring the object to a target state
  71. // of STATE_PAUSED.
  72. private int mCurrentState = STATE_IDLE;
  73. private int mTargetState = STATE_IDLE;
  74. // All the stuff we need for playing and showing a video
  75. private IRenderView.ISurfaceHolder mSurfaceHolder = null;
  76. private IMediaPlayer mMediaPlayer = null;
  77. // private int mAudioSession;
  78. private int mVideoWidth;
  79. private int mVideoHeight;
  80. private int mSurfaceWidth;
  81. private int mSurfaceHeight;
  82. private int mVideoRotationDegree;
  83. private IMediaController mMediaController;
  84. private IMediaPlayer.OnCompletionListener mOnCompletionListener;
  85. private IMediaPlayer.OnPreparedListener mOnPreparedListener;
  86. private int mCurrentBufferPercentage;
  87. private IMediaPlayer.OnErrorListener mOnErrorListener;
  88. private IMediaPlayer.OnInfoListener mOnInfoListener;
  89. private int mSeekWhenPrepared; // recording the seek position while preparing
  90. private boolean mCanPause = true;
  91. private boolean mCanSeekBack = true;
  92. private boolean mCanSeekForward = true;
  93. /** Subtitle rendering widget overlaid on top of the video. */
  94. // private RenderingWidget mSubtitleWidget;
  95. /**
  96. * Listener for changes to subtitle data, used to redraw when needed.
  97. */
  98. // private RenderingWidget.OnChangedListener mSubtitlesChangedListener;
  99. private Context mAppContext;
  100. private Settings mSettings;
  101. private IRenderView mRenderView;
  102. private int mVideoSarNum;
  103. private int mVideoSarDen;
  104. // private InfoHudViewHolder mHudViewHolder;
  105. private long mPrepareStartTime = 0;
  106. private long mPrepareEndTime = 0;
  107. private long mSeekStartTime = 0;
  108. private long mSeekEndTime = 0;
  109. private TextView subtitleDisplay;
  110. public IjkVideoView(Context context) {
  111. super(context);
  112. initVideoView(context);
  113. }
  114. public IjkVideoView(Context context, AttributeSet attrs) {
  115. super(context, attrs);
  116. initVideoView(context);
  117. }
  118. public IjkVideoView(Context context, AttributeSet attrs, int defStyleAttr) {
  119. super(context, attrs, defStyleAttr);
  120. initVideoView(context);
  121. }
  122. @TargetApi(Build.VERSION_CODES.LOLLIPOP)
  123. public IjkVideoView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
  124. super(context, attrs, defStyleAttr, defStyleRes);
  125. initVideoView(context);
  126. }
  127. // REMOVED: onMeasure
  128. // REMOVED: onInitializeAccessibilityEvent
  129. // REMOVED: onInitializeAccessibilityNodeInfo
  130. // REMOVED: resolveAdjustedSize
  131. private void initVideoView(Context context) {
  132. mAppContext = context.getApplicationContext();
  133. mSettings = new Settings(mAppContext);
  134. initBackground();
  135. initRenders();
  136. mVideoWidth = 0;
  137. mVideoHeight = 0;
  138. // REMOVED: getHolder().addCallback(mSHCallback);
  139. // REMOVED: getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
  140. setFocusable(true);
  141. setFocusableInTouchMode(true);
  142. requestFocus();
  143. // REMOVED: mPendingSubtitleTracks = new Vector<Pair<InputStream, MediaFormat>>();
  144. mCurrentState = STATE_IDLE;
  145. mTargetState = STATE_IDLE;
  146. subtitleDisplay = new TextView(context);
  147. subtitleDisplay.setTextSize(24);
  148. subtitleDisplay.setGravity(Gravity.CENTER);
  149. FrameLayout.LayoutParams layoutParams_txt = new FrameLayout.LayoutParams(
  150. FrameLayout.LayoutParams.MATCH_PARENT,
  151. FrameLayout.LayoutParams.WRAP_CONTENT,
  152. Gravity.BOTTOM);
  153. addView(subtitleDisplay, layoutParams_txt);
  154. }
  155. public void setRenderView(IRenderView renderView) {
  156. if (mRenderView != null) {
  157. if (mMediaPlayer != null)
  158. mMediaPlayer.setDisplay(null);
  159. View renderUIView = mRenderView.getView();
  160. mRenderView.removeRenderCallback(mSHCallback);
  161. mRenderView = null;
  162. removeView(renderUIView);
  163. }
  164. if (renderView == null)
  165. return;
  166. mRenderView = renderView;
  167. renderView.setAspectRatio(mCurrentAspectRatio);
  168. if (mVideoWidth > 0 && mVideoHeight > 0)
  169. renderView.setVideoSize(mVideoWidth, mVideoHeight);
  170. if (mVideoSarNum > 0 && mVideoSarDen > 0)
  171. renderView.setVideoSampleAspectRatio(mVideoSarNum, mVideoSarDen);
  172. View renderUIView = mRenderView.getView();
  173. FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
  174. FrameLayout.LayoutParams.WRAP_CONTENT,
  175. FrameLayout.LayoutParams.WRAP_CONTENT,
  176. Gravity.CENTER);
  177. renderUIView.setLayoutParams(lp);
  178. addView(renderUIView);
  179. mRenderView.addRenderCallback(mSHCallback);
  180. mRenderView.setVideoRotation(mVideoRotationDegree);
  181. }
  182. public void setRender(int render) {
  183. switch (render) {
  184. case RENDER_NONE:
  185. setRenderView(null);
  186. break;
  187. case RENDER_TEXTURE_VIEW: {
  188. TextureRenderView renderView = new TextureRenderView(getContext());
  189. if (mMediaPlayer != null) {
  190. renderView.getSurfaceHolder().bindToMediaPlayer(mMediaPlayer);
  191. renderView.setVideoSize(mMediaPlayer.getVideoWidth(), mMediaPlayer.getVideoHeight());
  192. renderView.setVideoSampleAspectRatio(mMediaPlayer.getVideoSarNum(), mMediaPlayer.getVideoSarDen());
  193. renderView.setAspectRatio(mCurrentAspectRatio);
  194. }
  195. setRenderView(renderView);
  196. break;
  197. }
  198. case RENDER_SURFACE_VIEW: {
  199. SurfaceRenderView renderView = new SurfaceRenderView(getContext());
  200. setRenderView(renderView);
  201. break;
  202. }
  203. default:
  204. Log.e(TAG, String.format(Locale.getDefault(), "invalid render %d\n", render));
  205. break;
  206. }
  207. }
  208. // public void setHudView(TableLayout tableLayout) {
  209. // mHudViewHolder = new InfoHudViewHolder(getContext(), tableLayout);
  210. // }
  211. /**
  212. * Sets video path.
  213. *
  214. * @param path the path of the video.
  215. */
  216. public void setVideoPath(String path) {
  217. setVideoURI(Uri.parse(path));
  218. }
  219. /**
  220. * Sets video URI.
  221. *
  222. * @param uri the URI of the video.
  223. */
  224. public void setVideoURI(Uri uri) {
  225. setVideoURI(uri, null);
  226. }
  227. /**
  228. * Sets video URI using specific headers.
  229. *
  230. * @param uri the URI of the video.
  231. * @param headers the headers for the URI request.
  232. * Note that the cross domain redirection is allowed by default, but that can be
  233. * changed with key/value pairs through the headers parameter with
  234. * "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value
  235. * to disallow or allow cross domain redirection.
  236. */
  237. private void setVideoURI(Uri uri, Map<String, String> headers) {
  238. mUri = uri;
  239. mHeaders = headers;
  240. mSeekWhenPrepared = 0;
  241. openVideo();
  242. requestLayout();
  243. invalidate();
  244. }
  245. public Uri getUrl() {
  246. return mUri;
  247. }
  248. // REMOVED: addSubtitleSource
  249. // REMOVED: mPendingSubtitleTracks
  250. public void stopPlayback() {
  251. if (mMediaPlayer != null) {
  252. mMediaPlayer.stop();
  253. mMediaPlayer.release();
  254. mMediaPlayer = null;
  255. // if (mHudViewHolder != null)
  256. // mHudViewHolder.setMediaPlayer(null);
  257. mCurrentState = STATE_IDLE;
  258. mTargetState = STATE_IDLE;
  259. AudioManager am = (AudioManager) mAppContext.getSystemService(Context.AUDIO_SERVICE);
  260. am.abandonAudioFocus(null);
  261. }
  262. }
  263. @TargetApi(Build.VERSION_CODES.M)
  264. private void openVideo() {
  265. if (mUri == null || mSurfaceHolder == null) {
  266. // not ready for playback just yet, will try again later
  267. return;
  268. }
  269. // we shouldn't clear the target state, because somebody might have
  270. // called start() previously
  271. release(false);
  272. AudioManager am = (AudioManager) mAppContext.getSystemService(Context.AUDIO_SERVICE);
  273. am.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
  274. try {
  275. mMediaPlayer = createPlayer(mSettings.getPlayer());
  276. // TODO: create SubtitleController in MediaPlayer, but we need
  277. // a context for the subtitle renderers
  278. final Context context = getContext();
  279. // REMOVED: SubtitleController
  280. // REMOVED: mAudioSession
  281. mMediaPlayer.setOnPreparedListener(mPreparedListener);
  282. mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
  283. mMediaPlayer.setOnCompletionListener(mCompletionListener);
  284. mMediaPlayer.setOnErrorListener(mErrorListener);
  285. mMediaPlayer.setOnInfoListener(mInfoListener);
  286. mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
  287. mMediaPlayer.setOnSeekCompleteListener(mSeekCompleteListener);
  288. mMediaPlayer.setOnTimedTextListener(mOnTimedTextListener);
  289. mCurrentBufferPercentage = 0;
  290. String scheme = mUri.getScheme();
  291. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
  292. mSettings.getUsingMediaDataSource() &&
  293. (TextUtils.isEmpty(scheme) || scheme.equalsIgnoreCase("file"))) {
  294. IMediaDataSource dataSource = new FileMediaDataSource(new File(mUri.toString()));
  295. mMediaPlayer.setDataSource(dataSource);
  296. } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
  297. mMediaPlayer.setDataSource(mAppContext, mUri, mHeaders);
  298. } else {
  299. mMediaPlayer.setDataSource(mUri.toString());
  300. }
  301. bindSurfaceHolder(mMediaPlayer, mSurfaceHolder);
  302. mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
  303. mMediaPlayer.setScreenOnWhilePlaying(true);
  304. mPrepareStartTime = System.currentTimeMillis();
  305. mMediaPlayer.prepareAsync();
  306. // if (mHudViewHolder != null)
  307. // mHudViewHolder.setMediaPlayer(mMediaPlayer);
  308. // REMOVED: mPendingSubtitleTracks
  309. // we don't set the target state here either, but preserve the
  310. // target state that was there before.
  311. mCurrentState = STATE_PREPARING;
  312. attachMediaController();
  313. } catch (IOException ex) {
  314. Log.w(TAG, "Unable to open content: " + mUri, ex);
  315. mCurrentState = STATE_ERROR;
  316. mTargetState = STATE_ERROR;
  317. mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
  318. } catch (IllegalArgumentException ex) {
  319. Log.w(TAG, "Unable to open content: " + mUri, ex);
  320. mCurrentState = STATE_ERROR;
  321. mTargetState = STATE_ERROR;
  322. mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
  323. } finally {
  324. // REMOVED: mPendingSubtitleTracks.clear();
  325. }
  326. }
  327. public void setMediaController(IMediaController controller) {
  328. if (mMediaController != null) {
  329. mMediaController.hide();
  330. }
  331. mMediaController = controller;
  332. attachMediaController();
  333. }
  334. private void attachMediaController() {
  335. if (mMediaPlayer != null && mMediaController != null) {
  336. mMediaController.setMediaPlayer(this);
  337. View anchorView = this.getParent() instanceof View ?
  338. (View) this.getParent() : this;
  339. mMediaController.setAnchorView(anchorView);
  340. mMediaController.setEnabled(isInPlaybackState());
  341. }
  342. }
  343. IMediaPlayer.OnVideoSizeChangedListener mSizeChangedListener =
  344. new IMediaPlayer.OnVideoSizeChangedListener() {
  345. public void onVideoSizeChanged(IMediaPlayer mp, int width, int height, int sarNum, int sarDen) {
  346. mVideoWidth = mp.getVideoWidth();
  347. mVideoHeight = mp.getVideoHeight();
  348. mVideoSarNum = mp.getVideoSarNum();
  349. mVideoSarDen = mp.getVideoSarDen();
  350. if (mVideoWidth != 0 && mVideoHeight != 0) {
  351. if (mRenderView != null) {
  352. mRenderView.setVideoSize(mVideoWidth, mVideoHeight);
  353. mRenderView.setVideoSampleAspectRatio(mVideoSarNum, mVideoSarDen);
  354. }
  355. // REMOVED: getHolder().setFixedSize(mVideoWidth, mVideoHeight);
  356. requestLayout();
  357. }
  358. }
  359. };
  360. IMediaPlayer.OnPreparedListener mPreparedListener = new IMediaPlayer.OnPreparedListener() {
  361. public void onPrepared(IMediaPlayer mp) {
  362. mPrepareEndTime = System.currentTimeMillis();
  363. // mHudViewHolder.updateLoadCost(mPrepareEndTime - mPrepareStartTime);
  364. mCurrentState = STATE_PREPARED;
  365. // Get the capabilities of the player for this stream
  366. // REMOVED: Metadata
  367. if (mOnPreparedListener != null) {
  368. mOnPreparedListener.onPrepared(mMediaPlayer);
  369. }
  370. if (mMediaController != null) {
  371. mMediaController.setEnabled(true);
  372. }
  373. mVideoWidth = mp.getVideoWidth();
  374. mVideoHeight = mp.getVideoHeight();
  375. int seekToPosition = mSeekWhenPrepared; // mSeekWhenPrepared may be changed after seekTo() call
  376. if (seekToPosition != 0) {
  377. seekTo(seekToPosition);
  378. }
  379. if (mVideoWidth != 0 && mVideoHeight != 0) {
  380. //Log.i("@@@@", "video size: " + mVideoWidth +"/"+ mVideoHeight);
  381. // REMOVED: getHolder().setFixedSize(mVideoWidth, mVideoHeight);
  382. if (mRenderView != null) {
  383. mRenderView.setVideoSize(mVideoWidth, mVideoHeight);
  384. mRenderView.setVideoSampleAspectRatio(mVideoSarNum, mVideoSarDen);
  385. if (!mRenderView.shouldWaitForResize() || mSurfaceWidth == mVideoWidth && mSurfaceHeight == mVideoHeight) {
  386. // We didn't actually change the size (it was already at the size
  387. // we need), so we won't get a "surface changed" callback, so
  388. // start the video here instead of in the callback.
  389. if (mTargetState == STATE_PLAYING) {
  390. start();
  391. if (mMediaController != null) {
  392. mMediaController.show();
  393. }
  394. } else if (!isPlaying() &&
  395. (seekToPosition != 0 || getCurrentPosition() > 0)) {
  396. if (mMediaController != null) {
  397. // Show the media controls when we're paused into a video and make 'em stick.
  398. mMediaController.show(0);
  399. }
  400. }
  401. }
  402. }
  403. } else {
  404. // We don't know the video size yet, but should start anyway.
  405. // The video size might be reported to us later.
  406. if (mTargetState == STATE_PLAYING) {
  407. start();
  408. }
  409. }
  410. }
  411. };
  412. private IMediaPlayer.OnCompletionListener mCompletionListener =
  413. new IMediaPlayer.OnCompletionListener() {
  414. public void onCompletion(IMediaPlayer mp) {
  415. mCurrentState = STATE_PLAYBACK_COMPLETED;
  416. mTargetState = STATE_PLAYBACK_COMPLETED;
  417. if (mMediaController != null) {
  418. mMediaController.hide();
  419. }
  420. if (mOnCompletionListener != null) {
  421. mOnCompletionListener.onCompletion(mMediaPlayer);
  422. }
  423. }
  424. };
  425. private IMediaPlayer.OnInfoListener mInfoListener =
  426. new IMediaPlayer.OnInfoListener() {
  427. public boolean onInfo(IMediaPlayer mp, int arg1, int arg2) {
  428. if (mOnInfoListener != null) {
  429. mOnInfoListener.onInfo(mp, arg1, arg2);
  430. }
  431. switch (arg1) {
  432. case IMediaPlayer.MEDIA_INFO_VIDEO_TRACK_LAGGING:
  433. Log.d(TAG, "MEDIA_INFO_VIDEO_TRACK_LAGGING:");
  434. break;
  435. case IMediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START:
  436. Log.d(TAG, "MEDIA_INFO_VIDEO_RENDERING_START:");
  437. break;
  438. case IMediaPlayer.MEDIA_INFO_BUFFERING_START:
  439. Log.d(TAG, "MEDIA_INFO_BUFFERING_START:");
  440. break;
  441. case IMediaPlayer.MEDIA_INFO_BUFFERING_END:
  442. Log.d(TAG, "MEDIA_INFO_BUFFERING_END:");
  443. break;
  444. case IMediaPlayer.MEDIA_INFO_NETWORK_BANDWIDTH:
  445. Log.d(TAG, "MEDIA_INFO_NETWORK_BANDWIDTH: " + arg2);
  446. break;
  447. case IMediaPlayer.MEDIA_INFO_BAD_INTERLEAVING:
  448. Log.d(TAG, "MEDIA_INFO_BAD_INTERLEAVING:");
  449. break;
  450. case IMediaPlayer.MEDIA_INFO_NOT_SEEKABLE:
  451. Log.d(TAG, "MEDIA_INFO_NOT_SEEKABLE:");
  452. break;
  453. case IMediaPlayer.MEDIA_INFO_METADATA_UPDATE:
  454. Log.d(TAG, "MEDIA_INFO_METADATA_UPDATE:");
  455. break;
  456. case IMediaPlayer.MEDIA_INFO_UNSUPPORTED_SUBTITLE:
  457. Log.d(TAG, "MEDIA_INFO_UNSUPPORTED_SUBTITLE:");
  458. break;
  459. case IMediaPlayer.MEDIA_INFO_SUBTITLE_TIMED_OUT:
  460. Log.d(TAG, "MEDIA_INFO_SUBTITLE_TIMED_OUT:");
  461. break;
  462. case IMediaPlayer.MEDIA_INFO_VIDEO_ROTATION_CHANGED:
  463. mVideoRotationDegree = arg2;
  464. Log.d(TAG, "MEDIA_INFO_VIDEO_ROTATION_CHANGED: " + arg2);
  465. if (mRenderView != null)
  466. mRenderView.setVideoRotation(arg2);
  467. break;
  468. case IMediaPlayer.MEDIA_INFO_AUDIO_RENDERING_START:
  469. Log.d(TAG, "MEDIA_INFO_AUDIO_RENDERING_START:");
  470. break;
  471. }
  472. return true;
  473. }
  474. };
  475. private IMediaPlayer.OnErrorListener mErrorListener =
  476. new IMediaPlayer.OnErrorListener() {
  477. public boolean onError(IMediaPlayer mp, int framework_err, int impl_err) {
  478. Log.d(TAG, "Error: " + framework_err + "," + impl_err);
  479. mCurrentState = STATE_ERROR;
  480. mTargetState = STATE_ERROR;
  481. if (mMediaController != null) {
  482. mMediaController.hide();
  483. }
  484. /* If an error handler has been supplied, use it and finish. */
  485. if (mOnErrorListener != null) {
  486. if (mOnErrorListener.onError(mMediaPlayer, framework_err, impl_err)) {
  487. return true;
  488. }
  489. }
  490. /* Otherwise, pop up an error dialog so the user knows that
  491. * something bad has happened. Only try and pop up the dialog
  492. * if we're attached to a window. When we're going away and no
  493. * longer have a window, don't bother showing the user an error.
  494. */
  495. if (getWindowToken() != null) {
  496. Resources r = mAppContext.getResources();
  497. int messageId;
  498. if (framework_err == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) {
  499. messageId = R.string.VideoView_error_text_invalid_progressive_playback;
  500. } else {
  501. messageId = R.string.VideoView_error_text_unknown;
  502. }
  503. // new AlertDialog.Builder(getContext())
  504. // .setMessage(messageId)
  505. // .setPositiveButton(R.string.VideoView_error_button,
  506. // new DialogInterface.OnClickListener() {
  507. // public void onClick(DialogInterface dialog, int whichButton) {
  508. // /* If we get here, there is no onError listener, so
  509. // * at least inform them that the video is over.
  510. // */
  511. // if (mOnCompletionListener != null) {
  512. // mOnCompletionListener.onCompletion(mMediaPlayer);
  513. // }
  514. // }
  515. // })
  516. // .setCancelable(false)
  517. // .show();
  518. Toast.makeText(mAppContext, "出现异常,请按返回退出", Toast.LENGTH_SHORT).show();
  519. }
  520. return true;
  521. }
  522. };
  523. private IMediaPlayer.OnBufferingUpdateListener mBufferingUpdateListener =
  524. new IMediaPlayer.OnBufferingUpdateListener() {
  525. public void onBufferingUpdate(IMediaPlayer mp, int percent) {
  526. mCurrentBufferPercentage = percent;
  527. }
  528. };
  529. private IMediaPlayer.OnSeekCompleteListener mSeekCompleteListener = new IMediaPlayer.OnSeekCompleteListener() {
  530. @Override
  531. public void onSeekComplete(IMediaPlayer mp) {
  532. mSeekEndTime = System.currentTimeMillis();
  533. // mHudViewHolder.updateSeekCost(mSeekEndTime - mSeekStartTime);
  534. }
  535. };
  536. private IMediaPlayer.OnTimedTextListener mOnTimedTextListener = new IMediaPlayer.OnTimedTextListener() {
  537. @Override
  538. public void onTimedText(IMediaPlayer mp, IjkTimedText text) {
  539. if (text != null) {
  540. subtitleDisplay.setText(text.getText());
  541. }
  542. }
  543. };
  544. /**
  545. * Register a callback to be invoked when the media file
  546. * is loaded and ready to go.
  547. *
  548. * @param l The callback that will be run
  549. */
  550. public void setOnPreparedListener(IMediaPlayer.OnPreparedListener l) {
  551. mOnPreparedListener = l;
  552. }
  553. /**
  554. * Register a callback to be invoked when the end of a media file
  555. * has been reached during playback.
  556. *
  557. * @param l The callback that will be run
  558. */
  559. public void setOnCompletionListener(IMediaPlayer.OnCompletionListener l) {
  560. mOnCompletionListener = l;
  561. }
  562. public void setOnSeekCompleteListener(IMediaPlayer.OnSeekCompleteListener l) {
  563. mSeekCompleteListener = l;
  564. }
  565. /**
  566. * Register a callback to be invoked when an error occurs
  567. * during playback or setup. If no listener is specified,
  568. * or if the listener returned false, VideoView will inform
  569. * the user of any errors.
  570. *
  571. * @param l The callback that will be run
  572. */
  573. public void setOnErrorListener(IMediaPlayer.OnErrorListener l) {
  574. mOnErrorListener = l;
  575. }
  576. /**
  577. * Register a callback to be invoked when an informational event
  578. * occurs during playback or setup.
  579. *
  580. * @param l The callback that will be run
  581. */
  582. public void setOnInfoListener(IMediaPlayer.OnInfoListener l) {
  583. mOnInfoListener = l;
  584. }
  585. // REMOVED: mSHCallback
  586. private void bindSurfaceHolder(IMediaPlayer mp, IRenderView.ISurfaceHolder holder) {
  587. if (mp == null)
  588. return;
  589. if (holder == null) {
  590. mp.setDisplay(null);
  591. return;
  592. }
  593. holder.bindToMediaPlayer(mp);
  594. }
  595. IRenderView.IRenderCallback mSHCallback = new IRenderView.IRenderCallback() {
  596. @Override
  597. public void onSurfaceChanged(@NonNull IRenderView.ISurfaceHolder holder, int format, int w, int h) {
  598. if (holder.getRenderView() != mRenderView) {
  599. Log.e(TAG, "onSurfaceChanged: unmatched render callback\n");
  600. return;
  601. }
  602. mSurfaceWidth = w;
  603. mSurfaceHeight = h;
  604. boolean isValidState = (mTargetState == STATE_PLAYING);
  605. boolean hasValidSize = !mRenderView.shouldWaitForResize() || (mVideoWidth == w && mVideoHeight == h);
  606. if (mMediaPlayer != null && isValidState && hasValidSize) {
  607. if (mSeekWhenPrepared != 0) {
  608. seekTo(mSeekWhenPrepared);
  609. }
  610. start();
  611. }
  612. }
  613. @Override
  614. public void onSurfaceCreated(@NonNull IRenderView.ISurfaceHolder holder, int width, int height) {
  615. if (holder.getRenderView() != mRenderView) {
  616. Log.e(TAG, "onSurfaceCreated: unmatched render callback\n");
  617. return;
  618. }
  619. mSurfaceHolder = holder;
  620. if (mMediaPlayer != null)
  621. bindSurfaceHolder(mMediaPlayer, holder);
  622. else
  623. openVideo();
  624. }
  625. @Override
  626. public void onSurfaceDestroyed(@NonNull IRenderView.ISurfaceHolder holder) {
  627. if (holder.getRenderView() != mRenderView) {
  628. Log.e(TAG, "onSurfaceDestroyed: unmatched render callback\n");
  629. return;
  630. }
  631. // after we return from this we can't use the surface any more
  632. mSurfaceHolder = null;
  633. // REMOVED: if (mMediaController != null) mMediaController.hide();
  634. // REMOVED: release(true);
  635. releaseWithoutStop();
  636. }
  637. };
  638. public void releaseWithoutStop() {
  639. if (mMediaPlayer != null)
  640. mMediaPlayer.setDisplay(null);
  641. }
  642. /*
  643. * release the media player in any state
  644. */
  645. public void release(boolean cleartargetstate) {
  646. if (mMediaPlayer != null) {
  647. mMediaPlayer.reset();
  648. mMediaPlayer.release();
  649. mMediaPlayer = null;
  650. // REMOVED: mPendingSubtitleTracks.clear();
  651. mCurrentState = STATE_IDLE;
  652. if (cleartargetstate) {
  653. mTargetState = STATE_IDLE;
  654. }
  655. AudioManager am = (AudioManager) mAppContext.getSystemService(Context.AUDIO_SERVICE);
  656. am.abandonAudioFocus(null);
  657. }
  658. }
  659. @Override
  660. public boolean onTouchEvent(MotionEvent ev) {
  661. if (isInPlaybackState() && mMediaController != null) {
  662. toggleMediaControlsVisiblity();
  663. }
  664. return false;
  665. }
  666. @Override
  667. public boolean onTrackballEvent(MotionEvent ev) {
  668. if (isInPlaybackState() && mMediaController != null) {
  669. toggleMediaControlsVisiblity();
  670. }
  671. return false;
  672. }
  673. @Override
  674. public boolean onKeyDown(int keyCode, KeyEvent event) {
  675. boolean isKeyCodeSupported = keyCode != KeyEvent.KEYCODE_BACK &&
  676. keyCode != KeyEvent.KEYCODE_VOLUME_UP &&
  677. keyCode != KeyEvent.KEYCODE_VOLUME_DOWN &&
  678. keyCode != KeyEvent.KEYCODE_VOLUME_MUTE &&
  679. keyCode != KeyEvent.KEYCODE_MENU &&
  680. keyCode != KeyEvent.KEYCODE_CALL &&
  681. keyCode != KeyEvent.KEYCODE_ENDCALL;
  682. if (isInPlaybackState() && isKeyCodeSupported && mMediaController != null) {
  683. if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK ||
  684. keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) {
  685. if (mMediaPlayer.isPlaying()) {
  686. pause();
  687. mMediaController.show();
  688. } else {
  689. start();
  690. mMediaController.hide();
  691. }
  692. return true;
  693. } else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) {
  694. if (!mMediaPlayer.isPlaying()) {
  695. start();
  696. mMediaController.hide();
  697. }
  698. return true;
  699. } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP
  700. || keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) {
  701. if (mMediaPlayer.isPlaying()) {
  702. pause();
  703. mMediaController.show();
  704. }
  705. return true;
  706. } else {
  707. toggleMediaControlsVisiblity();
  708. }
  709. }
  710. return super.onKeyDown(keyCode, event);
  711. }
  712. private void toggleMediaControlsVisiblity() {
  713. if (mMediaController.isShowing()) {
  714. mMediaController.hide();
  715. } else {
  716. mMediaController.show();
  717. }
  718. }
  719. @Override
  720. public void start() {
  721. if (isInPlaybackState()) {
  722. mMediaPlayer.start();
  723. mCurrentState = STATE_PLAYING;
  724. }
  725. mTargetState = STATE_PLAYING;
  726. }
  727. @Override
  728. public void pause() {
  729. if (isInPlaybackState()) {
  730. if (mMediaPlayer.isPlaying()) {
  731. mMediaPlayer.pause();
  732. mCurrentState = STATE_PAUSED;
  733. }
  734. }
  735. mTargetState = STATE_PAUSED;
  736. }
  737. public void suspend() {
  738. release(false);
  739. }
  740. public void resume() {
  741. openVideo();
  742. }
  743. @Override
  744. public int getDuration() {
  745. // if (isInPlaybackState()) {
  746. if (mMediaPlayer != null) {
  747. return (int) mMediaPlayer.getDuration();
  748. }
  749. // }
  750. return 0;
  751. }
  752. @Override
  753. public int getCurrentPosition() {
  754. if (isInPlaybackState()) {
  755. return (int) mMediaPlayer.getCurrentPosition();
  756. }
  757. return 0;
  758. }
  759. @Override
  760. public void seekTo(int msec) {
  761. if (isInPlaybackState()) {
  762. mSeekStartTime = System.currentTimeMillis();
  763. mMediaPlayer.seekTo(msec);
  764. mSeekWhenPrepared = 0;
  765. } else {
  766. mSeekWhenPrepared = msec;
  767. }
  768. }
  769. @Override
  770. public boolean isPlaying() {
  771. return isInPlaybackState() && mMediaPlayer.isPlaying();
  772. }
  773. @Override
  774. public int getBufferPercentage() {
  775. if (mMediaPlayer != null) {
  776. return mCurrentBufferPercentage;
  777. }
  778. return 0;
  779. }
  780. private boolean isInPlaybackState() {
  781. return (mMediaPlayer != null &&
  782. mCurrentState != STATE_ERROR &&
  783. mCurrentState != STATE_IDLE &&
  784. mCurrentState != STATE_PREPARING);
  785. }
  786. @Override
  787. public boolean canPause() {
  788. return mCanPause;
  789. }
  790. @Override
  791. public boolean canSeekBackward() {
  792. return mCanSeekBack;
  793. }
  794. @Override
  795. public boolean canSeekForward() {
  796. return mCanSeekForward;
  797. }
  798. @Override
  799. public int getAudioSessionId() {
  800. return 0;
  801. }
  802. // REMOVED: getAudioSessionId();
  803. // REMOVED: onAttachedToWindow();
  804. // REMOVED: onDetachedFromWindow();
  805. // REMOVED: onLayout();
  806. // REMOVED: draw();
  807. // REMOVED: measureAndLayoutSubtitleWidget();
  808. // REMOVED: setSubtitleWidget();
  809. // REMOVED: getSubtitleLooper();
  810. //-------------------------
  811. // Extend: Aspect Ratio
  812. //-------------------------
  813. private static final int[] s_allAspectRatio = {
  814. IRenderView.AR_ASPECT_FIT_PARENT,
  815. IRenderView.AR_ASPECT_FILL_PARENT,
  816. IRenderView.AR_ASPECT_WRAP_CONTENT,
  817. // IRenderView.AR_MATCH_PARENT,
  818. IRenderView.AR_16_9_FIT_PARENT,
  819. IRenderView.AR_4_3_FIT_PARENT};
  820. private int mCurrentAspectRatioIndex = 0;
  821. private int mCurrentAspectRatio = s_allAspectRatio[0];
  822. public int toggleAspectRatio() {
  823. mCurrentAspectRatioIndex++;
  824. mCurrentAspectRatioIndex %= s_allAspectRatio.length;
  825. mCurrentAspectRatio = s_allAspectRatio[mCurrentAspectRatioIndex];
  826. if (mRenderView != null)
  827. mRenderView.setAspectRatio(mCurrentAspectRatio);
  828. return mCurrentAspectRatio;
  829. }
  830. //-------------------------
  831. // Extend: Render
  832. //-------------------------
  833. public static final int RENDER_NONE = 0;
  834. public static final int RENDER_SURFACE_VIEW = 1;
  835. public static final int RENDER_TEXTURE_VIEW = 2;
  836. private List<Integer> mAllRenders = new ArrayList<Integer>();
  837. private int mCurrentRenderIndex = 0;
  838. private int mCurrentRender = RENDER_NONE;
  839. private void initRenders() {
  840. mAllRenders.clear();
  841. if (mSettings.getEnableSurfaceView())
  842. mAllRenders.add(RENDER_SURFACE_VIEW);
  843. if (mSettings.getEnableTextureView() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
  844. mAllRenders.add(RENDER_TEXTURE_VIEW);
  845. if (mSettings.getEnableNoView())
  846. mAllRenders.add(RENDER_NONE);
  847. if (mAllRenders.isEmpty())
  848. mAllRenders.add(RENDER_SURFACE_VIEW);
  849. mCurrentRender = mAllRenders.get(mCurrentRenderIndex);
  850. setRender(mCurrentRender);
  851. }
  852. public int toggleRender() {
  853. mCurrentRenderIndex++;
  854. mCurrentRenderIndex %= mAllRenders.size();
  855. mCurrentRender = mAllRenders.get(mCurrentRenderIndex);
  856. setRender(mCurrentRender);
  857. return mCurrentRender;
  858. }
  859. //-------------------------
  860. // Extend: Player
  861. //-------------------------
  862. public int togglePlayer() {
  863. if (mMediaPlayer != null)
  864. mMediaPlayer.release();
  865. if (mRenderView != null)
  866. mRenderView.getView().invalidate();
  867. openVideo();
  868. return mSettings.getPlayer();
  869. }
  870. public IMediaPlayer createPlayer(int playerType) {
  871. IMediaPlayer mediaPlayer = null;
  872. switch (playerType) {
  873. case Settings.PV_PLAYER__IjkExoMediaPlayer: {
  874. IjkExoMediaPlayer IjkExoMediaPlayer = new IjkExoMediaPlayer(mAppContext);
  875. mediaPlayer = IjkExoMediaPlayer;
  876. }
  877. break;
  878. case Settings.PV_PLAYER__AndroidMediaPlayer: {
  879. AndroidMediaPlayer androidMediaPlayer = new AndroidMediaPlayer();
  880. mediaPlayer = androidMediaPlayer;
  881. }
  882. break;
  883. case Settings.PV_PLAYER__IjkMediaPlayer:
  884. default: {
  885. IjkMediaPlayer ijkMediaPlayer = null;
  886. if (mUri != null) {
  887. ijkMediaPlayer = new IjkMediaPlayer();
  888. ijkMediaPlayer.native_setLogLevel(IjkMediaPlayer.IJK_LOG_DEBUG);
  889. ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "dns_cache_clear", 1);
  890. if (mSettings.getUsingMediaCodec()) {
  891. ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1);
  892. if (mSettings.getUsingMediaCodecAutoRotate()) {
  893. ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", 1);
  894. } else {
  895. ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", 0);
  896. }
  897. if (mSettings.getMediaCodecHandleResolutionChange()) {
  898. ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-handle-resolution-change", 1);
  899. } else {
  900. ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-handle-resolution-change", 0);
  901. }
  902. } else {
  903. ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 0);
  904. }
  905. if (mSettings.getUsingOpenSLES()) {
  906. ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "opensles", 1);
  907. } else {
  908. ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "opensles", 0);
  909. }
  910. String pixelFormat = mSettings.getPixelFormat();
  911. if (TextUtils.isEmpty(pixelFormat)) {
  912. ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", IjkMediaPlayer.SDL_FCC_RV32);
  913. } else {
  914. ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", pixelFormat);
  915. }
  916. ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "framedrop", 1);
  917. ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "start-on-prepared", 0);
  918. ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "http-detect-range-support", 0);
  919. ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_CODEC, "skip_loop_filter", 48);
  920. }
  921. mediaPlayer = ijkMediaPlayer;
  922. }
  923. break;
  924. }
  925. if (mSettings.getEnableDetachedSurfaceTextureView()) {
  926. mediaPlayer = new TextureMediaPlayer(mediaPlayer);
  927. }
  928. return mediaPlayer;
  929. }
  930. //-------------------------
  931. // Extend: Background
  932. //-------------------------
  933. private boolean mEnableBackgroundPlay = false;
  934. private void initBackground() {
  935. mEnableBackgroundPlay = mSettings.getEnableBackgroundPlay();
  936. if (mEnableBackgroundPlay) {
  937. MediaPlayerService.intentToStart(getContext());
  938. mMediaPlayer = MediaPlayerService.getMediaPlayer();
  939. // if (mHudViewHolder != null)
  940. // mHudViewHolder.setMediaPlayer(mMediaPlayer);
  941. }
  942. }
  943. public boolean isBackgroundPlayEnabled() {
  944. return mEnableBackgroundPlay;
  945. }
  946. public void enterBackground() {
  947. MediaPlayerService.setMediaPlayer(mMediaPlayer);
  948. }
  949. public void stopBackgroundPlay() {
  950. MediaPlayerService.setMediaPlayer(null);
  951. }
  952. private String buildResolution(int width, int height, int sarNum, int sarDen) {
  953. StringBuilder sb = new StringBuilder();
  954. sb.append(width);
  955. sb.append(" x ");
  956. sb.append(height);
  957. if (sarNum > 1 || sarDen > 1) {
  958. sb.append("[");
  959. sb.append(sarNum);
  960. sb.append(":");
  961. sb.append(sarDen);
  962. sb.append("]");
  963. }
  964. return sb.toString();
  965. }
  966. private String buildTimeMilli(long duration) {
  967. long total_seconds = duration / 1000;
  968. long hours = total_seconds / 3600;
  969. long minutes = (total_seconds % 3600) / 60;
  970. long seconds = total_seconds % 60;
  971. if (duration <= 0) {
  972. return "--:--";
  973. }
  974. if (hours >= 100) {
  975. return String.format(Locale.US, "%d:%02d:%02d", hours, minutes, seconds);
  976. } else if (hours > 0) {
  977. return String.format(Locale.US, "%02d:%02d:%02d", hours, minutes, seconds);
  978. } else {
  979. return String.format(Locale.US, "%02d:%02d", minutes, seconds);
  980. }
  981. }
  982. private String buildTrackType(int type) {
  983. Context context = getContext();
  984. switch (type) {
  985. case ITrackInfo.MEDIA_TRACK_TYPE_VIDEO:
  986. return context.getString(R.string.TrackType_video);
  987. case ITrackInfo.MEDIA_TRACK_TYPE_AUDIO:
  988. return context.getString(R.string.TrackType_audio);
  989. case ITrackInfo.MEDIA_TRACK_TYPE_SUBTITLE:
  990. return context.getString(R.string.TrackType_subtitle);
  991. case ITrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT:
  992. return context.getString(R.string.TrackType_timedtext);
  993. case ITrackInfo.MEDIA_TRACK_TYPE_METADATA:
  994. return context.getString(R.string.TrackType_metadata);
  995. case ITrackInfo.MEDIA_TRACK_TYPE_UNKNOWN:
  996. default:
  997. return context.getString(R.string.TrackType_unknown);
  998. }
  999. }
  1000. private String buildLanguage(String language) {
  1001. if (TextUtils.isEmpty(language))
  1002. return "und";
  1003. return language;
  1004. }
  1005. public ITrackInfo[] getTrackInfo() {
  1006. if (mMediaPlayer == null)
  1007. return null;
  1008. return mMediaPlayer.getTrackInfo();
  1009. }
  1010. }