MediaPlayerControl接口分析

来源:互联网 发布:mac os qq截图 编辑:程序博客网 时间:2024/04/27 17:10

VedioView是android API中一个已经封装完成的播放控件,该控件的源码中显示

文中代码无特殊解释都为VideoView 中源码

public class VideoView extends SurfaceView
        implements MediaPlayerControl, SubtitleController.Anchor {

... ...

        }


而这个MediaPlayerControl,则是由MediaController提供的一个interface,起源码部分

以下代码为MediaController的源码

    public interface MediaPlayerControl {        void    start();        void    pause();        int     getDuration();        int     getCurrentPosition();        void    seekTo(int pos);        boolean isPlaying();        int     getBufferPercentage();        boolean canPause();        boolean canSeekBackward();        boolean canSeekForward();        /**         * Get the audio session id for the player used by this VideoView. This can be used to         * apply audio effects to the audio track of a video.         * @return The audio session, or 0 if there was an error.         */        int     getAudioSessionId();    }
</pre><pre name="code" class="java">
//此处的start()是由MediaPlayer的start()方法实际完成
 @Override    public void start() {        if (isInPlaybackState()) {            mMediaPlayer.start();            mCurrentState = STATE_PLAYING;        }        mTargetState = STATE_PLAYING;    }
//void pause();视频暂停,同样由<span style="font-family:Arial,Helvetica,sans-serif">MediaPlayer的实例暂停   @Override    public void pause() {        if (isInPlaybackState()) {            if (mMediaPlayer.isPlaying()) {                mMediaPlayer.pause();                mCurrentState = STATE_PAUSED;            }        }        mTargetState = STATE_PAUSED;    }

//getDuration();通过MediaPlayer获取视频长度
@Override    public int getDuration() {        if (isInPlaybackState()) {            return mMediaPlayer.getDuration();        }        return -1;    }


getCurrentPosition();获得当前视频播放位置

    @Override    public int getCurrentPosition() {        if (isInPlaybackState()) {            return mMediaPlayer.getCurrentPosition();        }        return 0;    }

seekTo(int msec);进度跳转

 @Override    public void seekTo(int msec) {        if (isInPlaybackState()) {            mMediaPlayer.seekTo(msec);            mSeekWhenPrepared = 0;        } else {            mSeekWhenPrepared = msec;        }    }

isPlaying();当前是否正在播放

    @Override    public boolean isPlaying() {        return isInPlaybackState() && mMediaPlayer.isPlaying();    }

getBufferPercentage();网络视频缓冲的百分比进度

    @Override    public int getBufferPercentage() {        if (mMediaPlayer != null) {            return mCurrentBufferPercentage;        }        return 0;    }
这个mCurrentBufferPercentage是由
...mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);            mCurrentBufferPercentage = 0;...    private MediaPlayer.OnBufferingUpdateListener mBufferingUpdateListener =        new MediaPlayer.OnBufferingUpdateListener() {        public void onBufferingUpdate(MediaPlayer mp, int percent) {            mCurrentBufferPercentage = percent;        }    };...
那么可以看出mCurrentBufferPercentage是由MediaPlayer中的interface OnBufferingUpdateListener获得

这里的为MediaPlayer中的源码

/**     * Interface definition of a callback to be invoked indicating buffering     * status of a media resource being streamed over the network.     */    public interface OnBufferingUpdateListener    {        /**         * Called to update status in buffering a media stream received through         * progressive HTTP download. The received buffering percentage         * indicates how much of the content has been buffered or played.         * For example a buffering update of 80 percent when half the content         * has already been played indicates that the next 30 percent of the         * content to play has been buffered.         *         * @param mp      the MediaPlayer the update pertains to         * @param percent the percentage (0-100) of the content         *                that has been buffered or played thus far         */        void onBufferingUpdate(MediaPlayer mp, int percent);    }


而这3个状态,可暂停?进度条可拖动?都是怎么决定的?
        boolean canPause();
        boolean canSeekBackward();
        boolean canSeekForward();

 MediaPlayer.OnPreparedListener mPreparedListener = new MediaPlayer.OnPreparedListener() {        public void onPrepared(MediaPlayer mp) {            mCurrentState = STATE_PREPARED;            // Get the capabilities of the player for this stream            Metadata data = mp.getMetadata(MediaPlayer.METADATA_ALL,                                      MediaPlayer.BYPASS_METADATA_FILTER);            if (data != null) {                mCanPause = !data.has(Metadata.PAUSE_AVAILABLE)                        || data.getBoolean(Metadata.PAUSE_AVAILABLE);                mCanSeekBack = !data.has(Metadata.SEEK_BACKWARD_AVAILABLE)                        || data.getBoolean(Metadata.SEEK_BACKWARD_AVAILABLE);                mCanSeekForward = !data.has(Metadata.SEEK_FORWARD_AVAILABLE)                        || data.getBoolean(Metadata.SEEK_FORWARD_AVAILABLE);            } else {                mCanPause = mCanSeekBack = mCanSeekForward = true;            }

由代码中看出,这些值是由Metadata中直接带有的属性Metadata的实列化是在MediaPlayer中的public Metadata getMetadata(final boolean update_only,
                                final boolean apply_filter)方法获得:一下代码为MediaPlayer中源码

 
    /*     * @param update_only If true fetch only the set of metadata that have     *                    changed since the last invocation of getMetadata.     *                    The set is built using the unfiltered     *                    notifications the native player sent to the     *                    MediaPlayerService during that period of     *                    time. If false, all the metadatas are considered.     * @param apply_filter  If true, once the metadata set has been built based on     *                     the value update_only, the current filter is applied.     * @param reply[out] On return contains the serialized     *                   metadata. Valid only if the call was successful.     * @return The status code.     */    private native final boolean native_getMetadata(boolean update_only,                                                    boolean apply_filter,                                                    Parcel reply);
/**     * Gets the media metadata.     *     * @param update_only controls whether the full set of available     * metadata is returned or just the set that changed since the     * last call. See {@see #METADATA_UPDATE_ONLY} and {@see     * #METADATA_ALL}.     *     * @param apply_filter if true only metadata that matches the     * filter is returned. See {@see #APPLY_METADATA_FILTER} and {@see     * #BYPASS_METADATA_FILTER}.     *     * @return The metadata, possibly empty. null if an error occured.     // FIXME: unhide.     * {@hide}     */    public Metadata getMetadata(final boolean update_only,                                final boolean apply_filter) {        Parcel reply = Parcel.obtain();        Metadata data = new Metadata();        if (!native_getMetadata(update_only, apply_filter, reply)) {            reply.recycle();            return null;        }        // Metadata takes over the parcel, don't recycle it unless        // there is an error.        if (!data.parse(reply)) {            reply.recycle();            return null;        }        return data;    }

那么可以看到这里就引申到了JNI里面的方法了,可是实际上我们看到代码中import android.media.Metadata;这导入的实实在在的是一个JAVA类啊;所以应该是隐藏API

最后找到了android/media/Metadata.java

在Metadata.java中可以找到

/**   Class to hold the media's metadata.  Metadata are used   for human consumption and can be embedded in the media (e.g   shoutcast) or available from an external source. The source can be   local (e.g thumbnail stored in the DB) or remote.   Metadata is like a Bundle. It is sparse and each key can occur at   most once. The key is an integer and the value is the actual metadata.   The caller is expected to know the type of the metadata and call   the right get* method to fetch its value.      @hide   @deprecated Use {@link MediaMetadata}. */@Deprecated public class Metadata{    // The metadata are keyed using integers rather than more heavy    // weight strings. We considered using Bundle to ship the metadata    // between the native layer and the java layer but dropped that    // option since keeping in sync a native implementation of Bundle    // and the java one would be too burdensome. Besides Bundle uses    // String for its keys.    // The key range [0 8192) is reserved for the system.    //    // We manually serialize the data in Parcels. For large memory    // blob (bitmaps, raw pictures) we use MemoryFile which allow the    // client to make the data purge-able once it is done with it.    //    /**     * {@hide}     */    public static final int ANY = 0;  // Never used for metadata returned, only for filtering.                                      // Keep in sync with kAny in MediaPlayerService.cpp    // Playback capabilities.    /**     * Indicate whether the media can be paused     */    public static final int PAUSE_AVAILABLE         = 1; // Boolean    /**     * Indicate whether the media can be backward seeked     */    public static final int SEEK_BACKWARD_AVAILABLE = 2; // Boolean    /**     * Indicate whether the media can be forward seeked     */    public static final int SEEK_FORWARD_AVAILABLE  = 3; // Boolean    /**     * Indicate whether the media can be seeked     */    public static final int SEEK_AVAILABLE          = 4; // Boolean    // TODO: Should we use numbers compatible with the metadata retriever?    /**     * {@hide}     */...

OK,现在确定了视频资源的是否可以暂停,拖动的值是哪里来的了.此处JNI的分析会在下一篇文章中详细解释。

最后一个方法getAudioSessionId();这里的mAudioSession每一次获取都是MediaPlayer.getAudioSessionId()获得

    @Override    public int getAudioSessionId() {        if (mAudioSession == 0) {            MediaPlayer foo = new MediaPlayer();            mAudioSession = foo.getAudioSessionId();            foo.release();        }        return mAudioSession;    }
返回当前视频对话的ID,如果在MediaPlayer构造时发生错误,则返回0.

分析结束。




0 0