12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148 |
- /*
- * Copyright (C) 2015 Bilibili
- * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package com.edufound.mobile.xxt.ijkplayer.media;
- import android.annotation.TargetApi;
- import android.content.Context;
- import android.content.res.Resources;
- import android.media.AudioManager;
- import android.media.MediaPlayer;
- import android.net.Uri;
- import android.os.Build;
- import android.support.annotation.NonNull;
- import android.text.TextUtils;
- import android.util.AttributeSet;
- import android.util.Log;
- import android.view.Gravity;
- import android.view.KeyEvent;
- import android.view.MotionEvent;
- import android.view.View;
- import android.widget.FrameLayout;
- import android.widget.MediaController;
- import android.widget.TextView;
- import android.widget.Toast;
- import com.edufound.mobile.xxt.R;
- import com.edufound.mobile.xxt.ijkplayer.application.Settings;
- import com.edufound.mobile.xxt.ijkplayer.services.MediaPlayerService;
- import java.io.File;
- import java.io.IOException;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Locale;
- import java.util.Map;
- import tv.danmaku.ijk.media.exo.IjkExoMediaPlayer;
- import tv.danmaku.ijk.media.player.AndroidMediaPlayer;
- import tv.danmaku.ijk.media.player.IMediaPlayer;
- import tv.danmaku.ijk.media.player.IjkMediaPlayer;
- import tv.danmaku.ijk.media.player.IjkTimedText;
- import tv.danmaku.ijk.media.player.TextureMediaPlayer;
- import tv.danmaku.ijk.media.player.misc.IMediaDataSource;
- import tv.danmaku.ijk.media.player.misc.ITrackInfo;
- public class IjkVideoView extends FrameLayout implements MediaController.MediaPlayerControl {
- private String TAG = "IjkVideoView";
- // settable by the client
- private Uri mUri;
- private Map<String, String> mHeaders;
- // all possible internal states
- private static final int STATE_ERROR = -1;
- private static final int STATE_IDLE = 0;
- private static final int STATE_PREPARING = 1;
- private static final int STATE_PREPARED = 2;
- private static final int STATE_PLAYING = 3;
- private static final int STATE_PAUSED = 4;
- private static final int STATE_PLAYBACK_COMPLETED = 5;
- // mCurrentState is a VideoView object's current state.
- // mTargetState is the state that a method caller intends to reach.
- // For instance, regardless the VideoView object's current state,
- // calling pause() intends to bring the object to a target state
- // of STATE_PAUSED.
- private int mCurrentState = STATE_IDLE;
- private int mTargetState = STATE_IDLE;
- // All the stuff we need for playing and showing a video
- private IRenderView.ISurfaceHolder mSurfaceHolder = null;
- private IMediaPlayer mMediaPlayer = null;
- // private int mAudioSession;
- private int mVideoWidth;
- private int mVideoHeight;
- private int mSurfaceWidth;
- private int mSurfaceHeight;
- private int mVideoRotationDegree;
- private IMediaController mMediaController;
- private IMediaPlayer.OnCompletionListener mOnCompletionListener;
- private IMediaPlayer.OnPreparedListener mOnPreparedListener;
- private int mCurrentBufferPercentage;
- private IMediaPlayer.OnErrorListener mOnErrorListener;
- private IMediaPlayer.OnInfoListener mOnInfoListener;
- private int mSeekWhenPrepared; // recording the seek position while preparing
- private boolean mCanPause = true;
- private boolean mCanSeekBack = true;
- private boolean mCanSeekForward = true;
- /** Subtitle rendering widget overlaid on top of the video. */
- // private RenderingWidget mSubtitleWidget;
- /**
- * Listener for changes to subtitle data, used to redraw when needed.
- */
- // private RenderingWidget.OnChangedListener mSubtitlesChangedListener;
- private Context mAppContext;
- private Settings mSettings;
- private IRenderView mRenderView;
- private int mVideoSarNum;
- private int mVideoSarDen;
- // private InfoHudViewHolder mHudViewHolder;
- private long mPrepareStartTime = 0;
- private long mPrepareEndTime = 0;
- private long mSeekStartTime = 0;
- private long mSeekEndTime = 0;
- private TextView subtitleDisplay;
- public IjkVideoView(Context context) {
- super(context);
- initVideoView(context);
- }
- public IjkVideoView(Context context, AttributeSet attrs) {
- super(context, attrs);
- initVideoView(context);
- }
- public IjkVideoView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- initVideoView(context);
- }
- @TargetApi(Build.VERSION_CODES.LOLLIPOP)
- public IjkVideoView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- initVideoView(context);
- }
- // REMOVED: onMeasure
- // REMOVED: onInitializeAccessibilityEvent
- // REMOVED: onInitializeAccessibilityNodeInfo
- // REMOVED: resolveAdjustedSize
- private void initVideoView(Context context) {
- mAppContext = context.getApplicationContext();
- mSettings = new Settings(mAppContext);
- initBackground();
- initRenders();
- mVideoWidth = 0;
- mVideoHeight = 0;
- // REMOVED: getHolder().addCallback(mSHCallback);
- // REMOVED: getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
- setFocusable(true);
- setFocusableInTouchMode(true);
- requestFocus();
- // REMOVED: mPendingSubtitleTracks = new Vector<Pair<InputStream, MediaFormat>>();
- mCurrentState = STATE_IDLE;
- mTargetState = STATE_IDLE;
- subtitleDisplay = new TextView(context);
- subtitleDisplay.setTextSize(24);
- subtitleDisplay.setGravity(Gravity.CENTER);
- FrameLayout.LayoutParams layoutParams_txt = new FrameLayout.LayoutParams(
- FrameLayout.LayoutParams.MATCH_PARENT,
- FrameLayout.LayoutParams.WRAP_CONTENT,
- Gravity.BOTTOM);
- addView(subtitleDisplay, layoutParams_txt);
- }
- public void setRenderView(IRenderView renderView) {
- if (mRenderView != null) {
- if (mMediaPlayer != null)
- mMediaPlayer.setDisplay(null);
- View renderUIView = mRenderView.getView();
- mRenderView.removeRenderCallback(mSHCallback);
- mRenderView = null;
- removeView(renderUIView);
- }
- if (renderView == null)
- return;
- mRenderView = renderView;
- renderView.setAspectRatio(mCurrentAspectRatio);
- if (mVideoWidth > 0 && mVideoHeight > 0)
- renderView.setVideoSize(mVideoWidth, mVideoHeight);
- if (mVideoSarNum > 0 && mVideoSarDen > 0)
- renderView.setVideoSampleAspectRatio(mVideoSarNum, mVideoSarDen);
- View renderUIView = mRenderView.getView();
- FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
- FrameLayout.LayoutParams.WRAP_CONTENT,
- FrameLayout.LayoutParams.WRAP_CONTENT,
- Gravity.CENTER);
- renderUIView.setLayoutParams(lp);
- addView(renderUIView);
- mRenderView.addRenderCallback(mSHCallback);
- mRenderView.setVideoRotation(mVideoRotationDegree);
- }
- public void setRender(int render) {
- switch (render) {
- case RENDER_NONE:
- setRenderView(null);
- break;
- case RENDER_TEXTURE_VIEW: {
- TextureRenderView renderView = new TextureRenderView(getContext());
- if (mMediaPlayer != null) {
- renderView.getSurfaceHolder().bindToMediaPlayer(mMediaPlayer);
- renderView.setVideoSize(mMediaPlayer.getVideoWidth(), mMediaPlayer.getVideoHeight());
- renderView.setVideoSampleAspectRatio(mMediaPlayer.getVideoSarNum(), mMediaPlayer.getVideoSarDen());
- renderView.setAspectRatio(mCurrentAspectRatio);
- }
- setRenderView(renderView);
- break;
- }
- case RENDER_SURFACE_VIEW: {
- SurfaceRenderView renderView = new SurfaceRenderView(getContext());
- setRenderView(renderView);
- break;
- }
- default:
- Log.e(TAG, String.format(Locale.getDefault(), "invalid render %d\n", render));
- break;
- }
- }
- // public void setHudView(TableLayout tableLayout) {
- // mHudViewHolder = new InfoHudViewHolder(getContext(), tableLayout);
- // }
- /**
- * Sets video path.
- *
- * @param path the path of the video.
- */
- public void setVideoPath(String path) {
- setVideoURI(Uri.parse(path));
- }
- /**
- * Sets video URI.
- *
- * @param uri the URI of the video.
- */
- public void setVideoURI(Uri uri) {
- setVideoURI(uri, null);
- }
- /**
- * Sets video URI using specific headers.
- *
- * @param uri the URI of the video.
- * @param headers the headers for the URI request.
- * Note that the cross domain redirection is allowed by default, but that can be
- * changed with key/value pairs through the headers parameter with
- * "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value
- * to disallow or allow cross domain redirection.
- */
- private void setVideoURI(Uri uri, Map<String, String> headers) {
- mUri = uri;
- mHeaders = headers;
- mSeekWhenPrepared = 0;
- openVideo();
- requestLayout();
- invalidate();
- }
- public Uri getUrl() {
- return mUri;
- }
- // REMOVED: addSubtitleSource
- // REMOVED: mPendingSubtitleTracks
- public void stopPlayback() {
- if (mMediaPlayer != null) {
- mMediaPlayer.stop();
- mMediaPlayer.release();
- mMediaPlayer = null;
- // if (mHudViewHolder != null)
- // mHudViewHolder.setMediaPlayer(null);
- mCurrentState = STATE_IDLE;
- mTargetState = STATE_IDLE;
- AudioManager am = (AudioManager) mAppContext.getSystemService(Context.AUDIO_SERVICE);
- am.abandonAudioFocus(null);
- }
- }
- @TargetApi(Build.VERSION_CODES.M)
- private void openVideo() {
- if (mUri == null || mSurfaceHolder == null) {
- // not ready for playback just yet, will try again later
- return;
- }
- // we shouldn't clear the target state, because somebody might have
- // called start() previously
- release(false);
- AudioManager am = (AudioManager) mAppContext.getSystemService(Context.AUDIO_SERVICE);
- am.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
- try {
- mMediaPlayer = createPlayer(mSettings.getPlayer());
- // TODO: create SubtitleController in MediaPlayer, but we need
- // a context for the subtitle renderers
- final Context context = getContext();
- // REMOVED: SubtitleController
- // REMOVED: mAudioSession
- mMediaPlayer.setOnPreparedListener(mPreparedListener);
- mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
- mMediaPlayer.setOnCompletionListener(mCompletionListener);
- mMediaPlayer.setOnErrorListener(mErrorListener);
- mMediaPlayer.setOnInfoListener(mInfoListener);
- mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
- mMediaPlayer.setOnSeekCompleteListener(mSeekCompleteListener);
- mMediaPlayer.setOnTimedTextListener(mOnTimedTextListener);
- mCurrentBufferPercentage = 0;
- String scheme = mUri.getScheme();
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
- mSettings.getUsingMediaDataSource() &&
- (TextUtils.isEmpty(scheme) || scheme.equalsIgnoreCase("file"))) {
- IMediaDataSource dataSource = new FileMediaDataSource(new File(mUri.toString()));
- mMediaPlayer.setDataSource(dataSource);
- } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
- mMediaPlayer.setDataSource(mAppContext, mUri, mHeaders);
- } else {
- mMediaPlayer.setDataSource(mUri.toString());
- }
- bindSurfaceHolder(mMediaPlayer, mSurfaceHolder);
- mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
- mMediaPlayer.setScreenOnWhilePlaying(true);
- mPrepareStartTime = System.currentTimeMillis();
- mMediaPlayer.prepareAsync();
- // if (mHudViewHolder != null)
- // mHudViewHolder.setMediaPlayer(mMediaPlayer);
- // REMOVED: mPendingSubtitleTracks
- // we don't set the target state here either, but preserve the
- // target state that was there before.
- mCurrentState = STATE_PREPARING;
- attachMediaController();
- } catch (IOException ex) {
- Log.w(TAG, "Unable to open content: " + mUri, ex);
- mCurrentState = STATE_ERROR;
- mTargetState = STATE_ERROR;
- mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
- } catch (IllegalArgumentException ex) {
- Log.w(TAG, "Unable to open content: " + mUri, ex);
- mCurrentState = STATE_ERROR;
- mTargetState = STATE_ERROR;
- mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
- } finally {
- // REMOVED: mPendingSubtitleTracks.clear();
- }
- }
- public void setMediaController(IMediaController controller) {
- if (mMediaController != null) {
- mMediaController.hide();
- }
- mMediaController = controller;
- attachMediaController();
- }
- private void attachMediaController() {
- if (mMediaPlayer != null && mMediaController != null) {
- mMediaController.setMediaPlayer(this);
- View anchorView = this.getParent() instanceof View ?
- (View) this.getParent() : this;
- mMediaController.setAnchorView(anchorView);
- mMediaController.setEnabled(isInPlaybackState());
- }
- }
- IMediaPlayer.OnVideoSizeChangedListener mSizeChangedListener =
- new IMediaPlayer.OnVideoSizeChangedListener() {
- public void onVideoSizeChanged(IMediaPlayer mp, int width, int height, int sarNum, int sarDen) {
- mVideoWidth = mp.getVideoWidth();
- mVideoHeight = mp.getVideoHeight();
- mVideoSarNum = mp.getVideoSarNum();
- mVideoSarDen = mp.getVideoSarDen();
- if (mVideoWidth != 0 && mVideoHeight != 0) {
- if (mRenderView != null) {
- mRenderView.setVideoSize(mVideoWidth, mVideoHeight);
- mRenderView.setVideoSampleAspectRatio(mVideoSarNum, mVideoSarDen);
- }
- // REMOVED: getHolder().setFixedSize(mVideoWidth, mVideoHeight);
- requestLayout();
- }
- }
- };
- IMediaPlayer.OnPreparedListener mPreparedListener = new IMediaPlayer.OnPreparedListener() {
- public void onPrepared(IMediaPlayer mp) {
- mPrepareEndTime = System.currentTimeMillis();
- // mHudViewHolder.updateLoadCost(mPrepareEndTime - mPrepareStartTime);
- mCurrentState = STATE_PREPARED;
- // Get the capabilities of the player for this stream
- // REMOVED: Metadata
- if (mOnPreparedListener != null) {
- mOnPreparedListener.onPrepared(mMediaPlayer);
- }
- if (mMediaController != null) {
- mMediaController.setEnabled(true);
- }
- mVideoWidth = mp.getVideoWidth();
- mVideoHeight = mp.getVideoHeight();
- int seekToPosition = mSeekWhenPrepared; // mSeekWhenPrepared may be changed after seekTo() call
- if (seekToPosition != 0) {
- seekTo(seekToPosition);
- }
- if (mVideoWidth != 0 && mVideoHeight != 0) {
- //Log.i("@@@@", "video size: " + mVideoWidth +"/"+ mVideoHeight);
- // REMOVED: getHolder().setFixedSize(mVideoWidth, mVideoHeight);
- if (mRenderView != null) {
- mRenderView.setVideoSize(mVideoWidth, mVideoHeight);
- mRenderView.setVideoSampleAspectRatio(mVideoSarNum, mVideoSarDen);
- if (!mRenderView.shouldWaitForResize() || mSurfaceWidth == mVideoWidth && mSurfaceHeight == mVideoHeight) {
- // We didn't actually change the size (it was already at the size
- // we need), so we won't get a "surface changed" callback, so
- // start the video here instead of in the callback.
- if (mTargetState == STATE_PLAYING) {
- start();
- if (mMediaController != null) {
- mMediaController.show();
- }
- } else if (!isPlaying() &&
- (seekToPosition != 0 || getCurrentPosition() > 0)) {
- if (mMediaController != null) {
- // Show the media controls when we're paused into a video and make 'em stick.
- mMediaController.show(0);
- }
- }
- }
- }
- } else {
- // We don't know the video size yet, but should start anyway.
- // The video size might be reported to us later.
- if (mTargetState == STATE_PLAYING) {
- start();
- }
- }
- }
- };
- private IMediaPlayer.OnCompletionListener mCompletionListener =
- new IMediaPlayer.OnCompletionListener() {
- public void onCompletion(IMediaPlayer mp) {
- mCurrentState = STATE_PLAYBACK_COMPLETED;
- mTargetState = STATE_PLAYBACK_COMPLETED;
- if (mMediaController != null) {
- mMediaController.hide();
- }
- if (mOnCompletionListener != null) {
- mOnCompletionListener.onCompletion(mMediaPlayer);
- }
- }
- };
- private IMediaPlayer.OnInfoListener mInfoListener =
- new IMediaPlayer.OnInfoListener() {
- public boolean onInfo(IMediaPlayer mp, int arg1, int arg2) {
- if (mOnInfoListener != null) {
- mOnInfoListener.onInfo(mp, arg1, arg2);
- }
- switch (arg1) {
- case IMediaPlayer.MEDIA_INFO_VIDEO_TRACK_LAGGING:
- Log.d(TAG, "MEDIA_INFO_VIDEO_TRACK_LAGGING:");
- break;
- case IMediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START:
- Log.d(TAG, "MEDIA_INFO_VIDEO_RENDERING_START:");
- break;
- case IMediaPlayer.MEDIA_INFO_BUFFERING_START:
- Log.d(TAG, "MEDIA_INFO_BUFFERING_START:");
- break;
- case IMediaPlayer.MEDIA_INFO_BUFFERING_END:
- Log.d(TAG, "MEDIA_INFO_BUFFERING_END:");
- break;
- case IMediaPlayer.MEDIA_INFO_NETWORK_BANDWIDTH:
- Log.d(TAG, "MEDIA_INFO_NETWORK_BANDWIDTH: " + arg2);
- break;
- case IMediaPlayer.MEDIA_INFO_BAD_INTERLEAVING:
- Log.d(TAG, "MEDIA_INFO_BAD_INTERLEAVING:");
- break;
- case IMediaPlayer.MEDIA_INFO_NOT_SEEKABLE:
- Log.d(TAG, "MEDIA_INFO_NOT_SEEKABLE:");
- break;
- case IMediaPlayer.MEDIA_INFO_METADATA_UPDATE:
- Log.d(TAG, "MEDIA_INFO_METADATA_UPDATE:");
- break;
- case IMediaPlayer.MEDIA_INFO_UNSUPPORTED_SUBTITLE:
- Log.d(TAG, "MEDIA_INFO_UNSUPPORTED_SUBTITLE:");
- break;
- case IMediaPlayer.MEDIA_INFO_SUBTITLE_TIMED_OUT:
- Log.d(TAG, "MEDIA_INFO_SUBTITLE_TIMED_OUT:");
- break;
- case IMediaPlayer.MEDIA_INFO_VIDEO_ROTATION_CHANGED:
- mVideoRotationDegree = arg2;
- Log.d(TAG, "MEDIA_INFO_VIDEO_ROTATION_CHANGED: " + arg2);
- if (mRenderView != null)
- mRenderView.setVideoRotation(arg2);
- break;
- case IMediaPlayer.MEDIA_INFO_AUDIO_RENDERING_START:
- Log.d(TAG, "MEDIA_INFO_AUDIO_RENDERING_START:");
- break;
- }
- return true;
- }
- };
- private IMediaPlayer.OnErrorListener mErrorListener =
- new IMediaPlayer.OnErrorListener() {
- public boolean onError(IMediaPlayer mp, int framework_err, int impl_err) {
- Log.d(TAG, "Error: " + framework_err + "," + impl_err);
- mCurrentState = STATE_ERROR;
- mTargetState = STATE_ERROR;
- if (mMediaController != null) {
- mMediaController.hide();
- }
- /* If an error handler has been supplied, use it and finish. */
- if (mOnErrorListener != null) {
- if (mOnErrorListener.onError(mMediaPlayer, framework_err, impl_err)) {
- return true;
- }
- }
- /* Otherwise, pop up an error dialog so the user knows that
- * something bad has happened. Only try and pop up the dialog
- * if we're attached to a window. When we're going away and no
- * longer have a window, don't bother showing the user an error.
- */
- if (getWindowToken() != null) {
- Resources r = mAppContext.getResources();
- int messageId;
- if (framework_err == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) {
- messageId = R.string.VideoView_error_text_invalid_progressive_playback;
- } else {
- messageId = R.string.VideoView_error_text_unknown;
- }
- // new AlertDialog.Builder(getContext())
- // .setMessage(messageId)
- // .setPositiveButton(R.string.VideoView_error_button,
- // new DialogInterface.OnClickListener() {
- // public void onClick(DialogInterface dialog, int whichButton) {
- // /* If we get here, there is no onError listener, so
- // * at least inform them that the video is over.
- // */
- // if (mOnCompletionListener != null) {
- // mOnCompletionListener.onCompletion(mMediaPlayer);
- // }
- // }
- // })
- // .setCancelable(false)
- // .show();
- Toast.makeText(mAppContext, "出现异常,请按返回退出", Toast.LENGTH_SHORT).show();
- }
- return true;
- }
- };
- private IMediaPlayer.OnBufferingUpdateListener mBufferingUpdateListener =
- new IMediaPlayer.OnBufferingUpdateListener() {
- public void onBufferingUpdate(IMediaPlayer mp, int percent) {
- mCurrentBufferPercentage = percent;
- }
- };
- private IMediaPlayer.OnSeekCompleteListener mSeekCompleteListener = new IMediaPlayer.OnSeekCompleteListener() {
- @Override
- public void onSeekComplete(IMediaPlayer mp) {
- mSeekEndTime = System.currentTimeMillis();
- // mHudViewHolder.updateSeekCost(mSeekEndTime - mSeekStartTime);
- }
- };
- private IMediaPlayer.OnTimedTextListener mOnTimedTextListener = new IMediaPlayer.OnTimedTextListener() {
- @Override
- public void onTimedText(IMediaPlayer mp, IjkTimedText text) {
- if (text != null) {
- subtitleDisplay.setText(text.getText());
- }
- }
- };
- /**
- * Register a callback to be invoked when the media file
- * is loaded and ready to go.
- *
- * @param l The callback that will be run
- */
- public void setOnPreparedListener(IMediaPlayer.OnPreparedListener l) {
- mOnPreparedListener = l;
- }
- /**
- * Register a callback to be invoked when the end of a media file
- * has been reached during playback.
- *
- * @param l The callback that will be run
- */
- public void setOnCompletionListener(IMediaPlayer.OnCompletionListener l) {
- mOnCompletionListener = l;
- }
- public void setOnSeekCompleteListener(IMediaPlayer.OnSeekCompleteListener l) {
- mSeekCompleteListener = l;
- }
- /**
- * Register a callback to be invoked when an error occurs
- * during playback or setup. If no listener is specified,
- * or if the listener returned false, VideoView will inform
- * the user of any errors.
- *
- * @param l The callback that will be run
- */
- public void setOnErrorListener(IMediaPlayer.OnErrorListener l) {
- mOnErrorListener = l;
- }
- /**
- * Register a callback to be invoked when an informational event
- * occurs during playback or setup.
- *
- * @param l The callback that will be run
- */
- public void setOnInfoListener(IMediaPlayer.OnInfoListener l) {
- mOnInfoListener = l;
- }
- // REMOVED: mSHCallback
- private void bindSurfaceHolder(IMediaPlayer mp, IRenderView.ISurfaceHolder holder) {
- if (mp == null)
- return;
- if (holder == null) {
- mp.setDisplay(null);
- return;
- }
- holder.bindToMediaPlayer(mp);
- }
- IRenderView.IRenderCallback mSHCallback = new IRenderView.IRenderCallback() {
- @Override
- public void onSurfaceChanged(@NonNull IRenderView.ISurfaceHolder holder, int format, int w, int h) {
- if (holder.getRenderView() != mRenderView) {
- Log.e(TAG, "onSurfaceChanged: unmatched render callback\n");
- return;
- }
- mSurfaceWidth = w;
- mSurfaceHeight = h;
- boolean isValidState = (mTargetState == STATE_PLAYING);
- boolean hasValidSize = !mRenderView.shouldWaitForResize() || (mVideoWidth == w && mVideoHeight == h);
- if (mMediaPlayer != null && isValidState && hasValidSize) {
- if (mSeekWhenPrepared != 0) {
- seekTo(mSeekWhenPrepared);
- }
- start();
- }
- }
- @Override
- public void onSurfaceCreated(@NonNull IRenderView.ISurfaceHolder holder, int width, int height) {
- if (holder.getRenderView() != mRenderView) {
- Log.e(TAG, "onSurfaceCreated: unmatched render callback\n");
- return;
- }
- mSurfaceHolder = holder;
- if (mMediaPlayer != null)
- bindSurfaceHolder(mMediaPlayer, holder);
- else
- openVideo();
- }
- @Override
- public void onSurfaceDestroyed(@NonNull IRenderView.ISurfaceHolder holder) {
- if (holder.getRenderView() != mRenderView) {
- Log.e(TAG, "onSurfaceDestroyed: unmatched render callback\n");
- return;
- }
- // after we return from this we can't use the surface any more
- mSurfaceHolder = null;
- // REMOVED: if (mMediaController != null) mMediaController.hide();
- // REMOVED: release(true);
- releaseWithoutStop();
- }
- };
- public void releaseWithoutStop() {
- if (mMediaPlayer != null)
- mMediaPlayer.setDisplay(null);
- }
- /*
- * release the media player in any state
- */
- public void release(boolean cleartargetstate) {
- if (mMediaPlayer != null) {
- mMediaPlayer.reset();
- mMediaPlayer.release();
- mMediaPlayer = null;
- // REMOVED: mPendingSubtitleTracks.clear();
- mCurrentState = STATE_IDLE;
- if (cleartargetstate) {
- mTargetState = STATE_IDLE;
- }
- AudioManager am = (AudioManager) mAppContext.getSystemService(Context.AUDIO_SERVICE);
- am.abandonAudioFocus(null);
- }
- }
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- if (isInPlaybackState() && mMediaController != null) {
- toggleMediaControlsVisiblity();
- }
- return false;
- }
- @Override
- public boolean onTrackballEvent(MotionEvent ev) {
- if (isInPlaybackState() && mMediaController != null) {
- toggleMediaControlsVisiblity();
- }
- return false;
- }
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- boolean isKeyCodeSupported = keyCode != KeyEvent.KEYCODE_BACK &&
- keyCode != KeyEvent.KEYCODE_VOLUME_UP &&
- keyCode != KeyEvent.KEYCODE_VOLUME_DOWN &&
- keyCode != KeyEvent.KEYCODE_VOLUME_MUTE &&
- keyCode != KeyEvent.KEYCODE_MENU &&
- keyCode != KeyEvent.KEYCODE_CALL &&
- keyCode != KeyEvent.KEYCODE_ENDCALL;
- if (isInPlaybackState() && isKeyCodeSupported && mMediaController != null) {
- if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK ||
- keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) {
- if (mMediaPlayer.isPlaying()) {
- pause();
- mMediaController.show();
- } else {
- start();
- mMediaController.hide();
- }
- return true;
- } else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) {
- if (!mMediaPlayer.isPlaying()) {
- start();
- mMediaController.hide();
- }
- return true;
- } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP
- || keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) {
- if (mMediaPlayer.isPlaying()) {
- pause();
- mMediaController.show();
- }
- return true;
- } else {
- toggleMediaControlsVisiblity();
- }
- }
- return super.onKeyDown(keyCode, event);
- }
- private void toggleMediaControlsVisiblity() {
- if (mMediaController.isShowing()) {
- mMediaController.hide();
- } else {
- mMediaController.show();
- }
- }
- @Override
- public void start() {
- if (isInPlaybackState()) {
- mMediaPlayer.start();
- mCurrentState = STATE_PLAYING;
- }
- mTargetState = STATE_PLAYING;
- }
- @Override
- public void pause() {
- if (isInPlaybackState()) {
- if (mMediaPlayer.isPlaying()) {
- mMediaPlayer.pause();
- mCurrentState = STATE_PAUSED;
- }
- }
- mTargetState = STATE_PAUSED;
- }
- public void suspend() {
- release(false);
- }
- public void resume() {
- openVideo();
- }
- @Override
- public int getDuration() {
- // if (isInPlaybackState()) {
- if (mMediaPlayer != null) {
- return (int) mMediaPlayer.getDuration();
- }
- // }
- return 0;
- }
- @Override
- public int getCurrentPosition() {
- if (isInPlaybackState()) {
- return (int) mMediaPlayer.getCurrentPosition();
- }
- return 0;
- }
- @Override
- public void seekTo(int msec) {
- if (isInPlaybackState()) {
- mSeekStartTime = System.currentTimeMillis();
- mMediaPlayer.seekTo(msec);
- mSeekWhenPrepared = 0;
- } else {
- mSeekWhenPrepared = msec;
- }
- }
- @Override
- public boolean isPlaying() {
- return isInPlaybackState() && mMediaPlayer.isPlaying();
- }
- @Override
- public int getBufferPercentage() {
- if (mMediaPlayer != null) {
- return mCurrentBufferPercentage;
- }
- return 0;
- }
- private boolean isInPlaybackState() {
- return (mMediaPlayer != null &&
- mCurrentState != STATE_ERROR &&
- mCurrentState != STATE_IDLE &&
- mCurrentState != STATE_PREPARING);
- }
- @Override
- public boolean canPause() {
- return mCanPause;
- }
- @Override
- public boolean canSeekBackward() {
- return mCanSeekBack;
- }
- @Override
- public boolean canSeekForward() {
- return mCanSeekForward;
- }
- @Override
- public int getAudioSessionId() {
- return 0;
- }
- // REMOVED: getAudioSessionId();
- // REMOVED: onAttachedToWindow();
- // REMOVED: onDetachedFromWindow();
- // REMOVED: onLayout();
- // REMOVED: draw();
- // REMOVED: measureAndLayoutSubtitleWidget();
- // REMOVED: setSubtitleWidget();
- // REMOVED: getSubtitleLooper();
- //-------------------------
- // Extend: Aspect Ratio
- //-------------------------
- private static final int[] s_allAspectRatio = {
- IRenderView.AR_ASPECT_FIT_PARENT,
- IRenderView.AR_ASPECT_FILL_PARENT,
- IRenderView.AR_ASPECT_WRAP_CONTENT,
- // IRenderView.AR_MATCH_PARENT,
- IRenderView.AR_16_9_FIT_PARENT,
- IRenderView.AR_4_3_FIT_PARENT};
- private int mCurrentAspectRatioIndex = 0;
- private int mCurrentAspectRatio = s_allAspectRatio[0];
- public int toggleAspectRatio() {
- mCurrentAspectRatioIndex++;
- mCurrentAspectRatioIndex %= s_allAspectRatio.length;
- mCurrentAspectRatio = s_allAspectRatio[mCurrentAspectRatioIndex];
- if (mRenderView != null)
- mRenderView.setAspectRatio(mCurrentAspectRatio);
- return mCurrentAspectRatio;
- }
- //-------------------------
- // Extend: Render
- //-------------------------
- public static final int RENDER_NONE = 0;
- public static final int RENDER_SURFACE_VIEW = 1;
- public static final int RENDER_TEXTURE_VIEW = 2;
- private List<Integer> mAllRenders = new ArrayList<Integer>();
- private int mCurrentRenderIndex = 0;
- private int mCurrentRender = RENDER_NONE;
- private void initRenders() {
- mAllRenders.clear();
- if (mSettings.getEnableSurfaceView())
- mAllRenders.add(RENDER_SURFACE_VIEW);
- if (mSettings.getEnableTextureView() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
- mAllRenders.add(RENDER_TEXTURE_VIEW);
- if (mSettings.getEnableNoView())
- mAllRenders.add(RENDER_NONE);
- if (mAllRenders.isEmpty())
- mAllRenders.add(RENDER_SURFACE_VIEW);
- mCurrentRender = mAllRenders.get(mCurrentRenderIndex);
- setRender(mCurrentRender);
- }
- public int toggleRender() {
- mCurrentRenderIndex++;
- mCurrentRenderIndex %= mAllRenders.size();
- mCurrentRender = mAllRenders.get(mCurrentRenderIndex);
- setRender(mCurrentRender);
- return mCurrentRender;
- }
- //-------------------------
- // Extend: Player
- //-------------------------
- public int togglePlayer() {
- if (mMediaPlayer != null)
- mMediaPlayer.release();
- if (mRenderView != null)
- mRenderView.getView().invalidate();
- openVideo();
- return mSettings.getPlayer();
- }
- public IMediaPlayer createPlayer(int playerType) {
- IMediaPlayer mediaPlayer = null;
- switch (playerType) {
- case Settings.PV_PLAYER__IjkExoMediaPlayer: {
- IjkExoMediaPlayer IjkExoMediaPlayer = new IjkExoMediaPlayer(mAppContext);
- mediaPlayer = IjkExoMediaPlayer;
- }
- break;
- case Settings.PV_PLAYER__AndroidMediaPlayer: {
- AndroidMediaPlayer androidMediaPlayer = new AndroidMediaPlayer();
- mediaPlayer = androidMediaPlayer;
- }
- break;
- case Settings.PV_PLAYER__IjkMediaPlayer:
- default: {
- IjkMediaPlayer ijkMediaPlayer = null;
- if (mUri != null) {
- ijkMediaPlayer = new IjkMediaPlayer();
- ijkMediaPlayer.native_setLogLevel(IjkMediaPlayer.IJK_LOG_DEBUG);
- ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "dns_cache_clear", 1);
- if (mSettings.getUsingMediaCodec()) {
- ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1);
- if (mSettings.getUsingMediaCodecAutoRotate()) {
- ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", 1);
- } else {
- ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", 0);
- }
- if (mSettings.getMediaCodecHandleResolutionChange()) {
- ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-handle-resolution-change", 1);
- } else {
- ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-handle-resolution-change", 0);
- }
- } else {
- ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 0);
- }
- if (mSettings.getUsingOpenSLES()) {
- ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "opensles", 1);
- } else {
- ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "opensles", 0);
- }
- String pixelFormat = mSettings.getPixelFormat();
- if (TextUtils.isEmpty(pixelFormat)) {
- ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", IjkMediaPlayer.SDL_FCC_RV32);
- } else {
- ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", pixelFormat);
- }
- ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "framedrop", 1);
- ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "start-on-prepared", 0);
- ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "http-detect-range-support", 0);
- ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_CODEC, "skip_loop_filter", 48);
- }
- mediaPlayer = ijkMediaPlayer;
- }
- break;
- }
- if (mSettings.getEnableDetachedSurfaceTextureView()) {
- mediaPlayer = new TextureMediaPlayer(mediaPlayer);
- }
- return mediaPlayer;
- }
- //-------------------------
- // Extend: Background
- //-------------------------
- private boolean mEnableBackgroundPlay = false;
- private void initBackground() {
- mEnableBackgroundPlay = mSettings.getEnableBackgroundPlay();
- if (mEnableBackgroundPlay) {
- MediaPlayerService.intentToStart(getContext());
- mMediaPlayer = MediaPlayerService.getMediaPlayer();
- // if (mHudViewHolder != null)
- // mHudViewHolder.setMediaPlayer(mMediaPlayer);
- }
- }
- public boolean isBackgroundPlayEnabled() {
- return mEnableBackgroundPlay;
- }
- public void enterBackground() {
- MediaPlayerService.setMediaPlayer(mMediaPlayer);
- }
- public void stopBackgroundPlay() {
- MediaPlayerService.setMediaPlayer(null);
- }
- private String buildResolution(int width, int height, int sarNum, int sarDen) {
- StringBuilder sb = new StringBuilder();
- sb.append(width);
- sb.append(" x ");
- sb.append(height);
- if (sarNum > 1 || sarDen > 1) {
- sb.append("[");
- sb.append(sarNum);
- sb.append(":");
- sb.append(sarDen);
- sb.append("]");
- }
- return sb.toString();
- }
- private String buildTimeMilli(long duration) {
- long total_seconds = duration / 1000;
- long hours = total_seconds / 3600;
- long minutes = (total_seconds % 3600) / 60;
- long seconds = total_seconds % 60;
- if (duration <= 0) {
- return "--:--";
- }
- if (hours >= 100) {
- return String.format(Locale.US, "%d:%02d:%02d", hours, minutes, seconds);
- } else if (hours > 0) {
- return String.format(Locale.US, "%02d:%02d:%02d", hours, minutes, seconds);
- } else {
- return String.format(Locale.US, "%02d:%02d", minutes, seconds);
- }
- }
- private String buildTrackType(int type) {
- Context context = getContext();
- switch (type) {
- case ITrackInfo.MEDIA_TRACK_TYPE_VIDEO:
- return context.getString(R.string.TrackType_video);
- case ITrackInfo.MEDIA_TRACK_TYPE_AUDIO:
- return context.getString(R.string.TrackType_audio);
- case ITrackInfo.MEDIA_TRACK_TYPE_SUBTITLE:
- return context.getString(R.string.TrackType_subtitle);
- case ITrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT:
- return context.getString(R.string.TrackType_timedtext);
- case ITrackInfo.MEDIA_TRACK_TYPE_METADATA:
- return context.getString(R.string.TrackType_metadata);
- case ITrackInfo.MEDIA_TRACK_TYPE_UNKNOWN:
- default:
- return context.getString(R.string.TrackType_unknown);
- }
- }
- private String buildLanguage(String language) {
- if (TextUtils.isEmpty(language))
- return "und";
- return language;
- }
- public ITrackInfo[] getTrackInfo() {
- if (mMediaPlayer == null)
- return null;
- return mMediaPlayer.getTrackInfo();
- }
- }
|