getMap() {
return mMap;
}
/**
* Returns true iff a key of the given name exists in the format.
*/
public final boolean containsKey(String name) {
return mMap.containsKey(name);
}
/**
* Returns the value of an integer key.
*/
public final int getInteger(String name) {
return ((Integer)mMap.get(name)).intValue();
}
/**
* Returns the value of an integer key, or the default value if the
* key is missing or is for another type value.
* @hide
*/
public final int getInteger(String name, int defaultValue) {
try {
return getInteger(name);
}
catch (NullPointerException e) { /* no such field */ }
catch (ClassCastException e) { /* field of different type */ }
return defaultValue;
}
/**
* Returns the value of a long key.
*/
public final long getLong(String name) {
return ((Long)mMap.get(name)).longValue();
}
/**
* Returns the value of a float key.
*/
public final float getFloat(String name) {
return ((Float)mMap.get(name)).floatValue();
}
/**
* Returns the value of a string key.
*/
public final String getString(String name) {
return (String)mMap.get(name);
}
/**
* Returns the value of a ByteBuffer key.
*/
public final ByteBuffer getByteBuffer(String name) {
return (ByteBuffer)mMap.get(name);
}
/**
* Sets the value of an integer key.
*/
public final void setInteger(String name, int value) {
mMap.put(name, Integer.valueOf(value));
}
/**
* Sets the value of a long key.
*/
public final void setLong(String name, long value) {
mMap.put(name, Long.valueOf(value));
}
/**
* Sets the value of a float key.
*/
public final void setFloat(String name, float value) {
mMap.put(name, Float.valueOf(value));
}
/**
* Sets the value of a string key.
*/
public final void setString(String name, String value) {
mMap.put(name, value);
}
/**
* Sets the value of a ByteBuffer key.
*/
public final void setByteBuffer(String name, ByteBuffer bytes) {
mMap.put(name, bytes);
}
/**
* Creates a minimal audio format.
* @param mime The mime type of the content.
* @param sampleRate The sampling rate of the content.
* @param channelCount The number of audio channels in the content.
*/
public static final MediaFormat createAudioFormat(
String mime,
int sampleRate,
int channelCount) {
MediaFormat format = new MediaFormat();
format.setString(KEY_MIME, mime);
format.setInteger(KEY_SAMPLE_RATE, sampleRate);
format.setInteger(KEY_CHANNEL_COUNT, channelCount);
return format;
}
/**
* Creates a minimal subtitle format.
* @param title The content of the Subtitle
* @param language The language of the content, using either ISO 639-1 or 639-2/T
* codes. Specify null or "und" if language information is only included
* in the content. (This will also work if there are multiple language
* tracks in the content.)
*/
public static final MediaFormat createSubtitleFormat(
String title,
String language) {
MediaFormat format = new MediaFormat();
format.setString(KEY_TITLE, title);
format.setString(KEY_LANGUAGE, language);
return format;
}
/**
* Creates a minimal video format.
* @param mime The mime type of the content.
* @param width The width of the content (in pixels)
* @param height The height of the content (in pixels)
*/
public static final MediaFormat createVideoFormat(
String mime,
int width,
int height) {
MediaFormat format = new MediaFormat();
format.setString(KEY_MIME, mime);
format.setInteger(KEY_WIDTH, width);
format.setInteger(KEY_HEIGHT, height);
return format;
}
@Override
public String toString() {
return mMap.toString();
}
}
================================================
FILE: vitamio/src/io/vov/vitamio/MediaMetadataRetriever.java
================================================
/*
* Copyright (C) 2008 The Android Open Source Project
* Copyright (C) 2013 YIXIA.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 io.vov.vitamio;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.util.Log;
import io.vov.vitamio.utils.FileUtils;
import java.io.FileDescriptor;
import java.io.IOException;
/**
* MediaMetadataRetriever is used to get meta data from any media file
*
*
*
* MediaMetadataRetriever mmr = new MediaMetadataRetriever(this);
* mmr.setDataSource(this, mediaUri);
* String title = mmr.extractMetadata(METADATA_KEY_TITLE);
* Bitmap frame = mmr.getFrameAtTime(-1);
* mmr.release();
*
*/
public class MediaMetadataRetriever {
private AssetFileDescriptor mFD = null;
static {
String LIB_ROOT = Vitamio.getLibraryPath();
Log.i("LIB ROOT: %s", LIB_ROOT);
System.load( LIB_ROOT + "libstlport_shared.so");
System.load( LIB_ROOT +"libvscanner.so");
loadFFmpeg_native( LIB_ROOT + "libffmpeg.so");
native_init();
}
private int mNativeContext;
public MediaMetadataRetriever(Context ctx) {
native_setup();
}
private static native boolean loadFFmpeg_native(String ffmpegPath);
public void setDataSource(Context context, Uri uri) throws IOException, IllegalArgumentException,
SecurityException, IllegalStateException {
if (context == null || uri == null)
throw new IllegalArgumentException();
String scheme = uri.getScheme();
if (scheme == null || scheme.equals("file")) {
setDataSource(FileUtils.getPath(uri.toString()));
return;
}
try {
ContentResolver resolver = context.getContentResolver();
mFD = resolver.openAssetFileDescriptor(uri, "r");
if (mFD == null)
return;
setDataSource(mFD.getParcelFileDescriptor().getFileDescriptor());
return;
} catch (Exception e) {
closeFD();
}
Log.e("Couldn't open file on client side, trying server side %s", uri.toString());
setDataSource(uri.toString());
return;
}
public native void setDataSource(String path) throws IOException, IllegalArgumentException,
IllegalStateException;
public native void setDataSource(FileDescriptor fd) throws IOException, IllegalArgumentException,
IllegalStateException;
/**
* Call this method after setDataSource(). This method retrieves the meta data
* value associated with the keyCode.
*
* The keyCode currently supported is listed below as METADATA_XXX constants.
* With any other value, it returns a null pointer.
*
* @param keyCode One of the constants listed below at the end of the class.
* @return The meta data value associate with the given keyCode on success;
* null on failure.
*/
public native String extractMetadata(String keyCode) throws IllegalStateException;
public native Bitmap getFrameAtTime(long timeUs) throws IllegalStateException;
/**
* Call this method after setDataSource(). This method finds the optional
* graphic or album/cover art associated associated with the data source. If
* there are more than one pictures, (any) one of them is returned.
*
* @return null if no such graphic is found.
*/
public native byte[] getEmbeddedPicture() throws IllegalStateException;
private native void _release();
private native void native_setup();
private static native final void native_init();
private native final void native_finalize();
public void release() {
_release();
closeFD();
}
@Override
protected void finalize() throws Throwable {
try {
native_finalize();
} finally {
super.finalize();
}
}
private void closeFD() {
if (mFD != null) {
try {
mFD.close();
} catch (IOException e) {
}
mFD = null;
}
}
/*
* Do not change these metadata key values without updating their
* counterparts in c file
*/
/**
* The metadata key to retrieve the information about the album title of the
* data source.
*/
public static final String METADATA_KEY_ALBUM = "album";
/**
* The metadata key to retrieve the main creator of the set/album, if
* different from artist. e.g. "Various Artists" for compilation albums.
*/
public static final String METADATA_KEY_ALBUM_ARTIST = "album_artist";
/**
* The metadata key to retrieve the information about the artist of the data
* source.
*/
public static final String METADATA_KEY_ARTIST = "artist";
/**
* The metadata key to retrieve the any additional description of the file.
*/
public static final String METADATA_KEY_COMMENT = "comment";
/**
* The metadata key to retrieve the information about the author of the data
* source.
*/
public static final String METADATA_KEY_AUTHOR = "author";
/**
* The metadata key to retrieve the information about the composer of the data
* source.
*/
public static final String METADATA_KEY_COMPOSER = "composer";
/**
* The metadata key to retrieve the name of copyright holder.
*/
public static final String METADATA_KEY_COPYRIGHT = "copyright";
/**
* The metadata key to retrieve the date when the file was created, preferably
* in ISO 8601.
*/
public static final String METADATA_KEY_CREATION_TIME = "creation_time";
/**
* The metadata key to retrieve the date when the work was created, preferably
* in ISO 8601.
*/
public static final String METADATA_KEY_DATE = "date";
/**
* The metadata key to retrieve the number of a subset, e.g. disc in a
* multi-disc collection.
*/
public static final String METADATA_KEY_DISC = "disc";
/**
* The metadata key to retrieve the name/settings of the software/hardware
* that produced the file.
*/
public static final String METADATA_KEY_ENCODER = "encoder";
/**
* The metadata key to retrieve the person/group who created the file.
*/
public static final String METADATA_KEY_ENCODED_BY = "encoded_by";
/**
* The metadata key to retrieve the original name of the file.
*/
public static final String METADATA_KEY_FILENAME = "filename";
/**
* The metadata key to retrieve the content type or genre of the data source.
*/
public static final String METADATA_KEY_GENRE = "genre";
/**
* The metadata key to retrieve the main language in which the work is
* performed, preferably in ISO 639-2 format. Multiple languages can be
* specified by separating them with commas.
*/
public static final String METADATA_KEY_LANGUAGE = "language";
/**
* The metadata key to retrieve the artist who performed the work, if
* different from artist. E.g for "Also sprach Zarathustra", artist would be
* "Richard Strauss" and performer "London Philharmonic Orchestra".
*/
public static final String METADATA_KEY_PERFORMER = "performer";
/**
* The metadata key to retrieve the name of the label/publisher.
*/
public static final String METADATA_KEY_PUBLISHER = "publisher";
/**
* The metadata key to retrieve the name of the service in broadcasting
* (channel name).
*/
public static final String METADATA_KEY_SERVICE_NAME = "service_name";
/**
* The metadata key to retrieve the name of the service provider in
* broadcasting.
*/
public static final String METADATA_KEY_SERVICE_PROVIDER = "service_provider";
/**
* The metadata key to retrieve the data source title.
*/
public static final String METADATA_KEY_TITLE = "title";
/**
* The metadata key to retrieve the number of this work in the set, can be in
* form current/total.
*/
public static final String METADATA_KEY_TRACK = "track";
/**
* The metadata key to retrieve the total bitrate of the bitrate variant that
* the current stream is part of.
*/
public static final String METADATA_KEY_VARIANT_BITRATE = "bitrate";
/**
* The metadata key to retrieve the playback duration of the data source.
*/
public static final String METADATA_KEY_DURATION = "duration";
/**
* The metadata key to retrieve the audio codec of the work.
*/
public static final String METADATA_KEY_AUDIO_CODEC = "audio_codec";
/**
* The metadata key to retrieve the video codec of the work.
*/
public static final String METADATA_KEY_VIDEO_CODEC = "video_codec";
/**
* This key retrieves the video rotation angle in degrees, if available. The
* video rotation angle may be 0, 90, 180, or 270 degrees.
*/
public static final String METADATA_KEY_VIDEO_ROTATION = "rotate";
/**
* If the media contains video, this key retrieves its width.
*/
public static final String METADATA_KEY_VIDEO_WIDTH = "width";
/**
* If the media contains video, this key retrieves its height.
*/
public static final String METADATA_KEY_VIDEO_HEIGHT = "height";
/**
* The metadata key to retrieve the number of tracks, such as audio, video,
* text, in the data source, such as a mp4 or 3gpp file.
*/
public static final String METADATA_KEY_NUM_TRACKS = "num_tracks";
/**
* If this key exists the media contains audio content. if has audio, return
* 1.
*/
public static final String METADATA_KEY_HAS_AUDIO = "has_audio";
/**
* If this key exists the media contains video content. if has video, return
* 1.
*/
public static final String METADATA_KEY_HAS_VIDEO = "has_video";
}
================================================
FILE: vitamio/src/io/vov/vitamio/MediaPlayer.java
================================================
/*
* Copyright (C) 2006 The Android Open Source Project
* Copyright (C) 2013 YIXIA.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 io.vov.vitamio;
import android.annotation.SuppressLint;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.text.TextUtils;
import android.util.SparseArray;
import android.view.Surface;
import android.view.SurfaceHolder;
import io.vov.vitamio.utils.ContextUtils;
import io.vov.vitamio.utils.FileUtils;
import io.vov.vitamio.utils.Log;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* MediaPlayer class can be used to control playback of audio/video files and
* streams. An example on how to use the methods in this class can be found in
* {@link io.vov.vitamio.widget.VideoView}. This class will function the same as
* android.media.MediaPlayer in most cases. Please see Audio and
* Video for additional help using MediaPlayer.
*/
public class MediaPlayer {
public static final int CACHE_TYPE_NOT_AVAILABLE = 1;
public static final int CACHE_TYPE_START = 2;
public static final int CACHE_TYPE_UPDATE = 3;
public static final int CACHE_TYPE_SPEED = 4;
public static final int CACHE_TYPE_COMPLETE = 5;
public static final int CACHE_INFO_NO_SPACE = 1;
public static final int CACHE_INFO_STREAM_NOT_SUPPORT = 2;
public static final int MEDIA_ERROR_UNKNOWN = 1;
public static final int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200;
/** File or network related operation errors. */
public static final int MEDIA_ERROR_IO = -5;
/** Bitstream is not conforming to the related coding standard or file spec. */
public static final int MEDIA_ERROR_MALFORMED = -1007;
/** Bitstream is conforming to the related coding standard or file spec, but
* the media framework does not support the feature. */
public static final int MEDIA_ERROR_UNSUPPORTED = -1010;
/** Some operation takes too long to complete, usually more than 3-5 seconds. */
public static final int MEDIA_ERROR_TIMED_OUT = -110;
/**
* The video is too complex for the decoder: it can't decode frames fast
* enough. Possibly only the audio plays fine at this stage.
*
* @see io.vov.vitamio.MediaPlayer.OnInfoListener
*/
public static final int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700;
/**
* MediaPlayer is temporarily pausing playback internally in order to buffer
* more data.
*/
public static final int MEDIA_INFO_BUFFERING_START = 701;
/**
* MediaPlayer is resuming playback after filling buffers.
*/
public static final int MEDIA_INFO_BUFFERING_END = 702;
public static final int MEDIA_INFO_FILE_OPEN_OK = 704;
public static final int MEDIA_INFO_UNKNOW_TYPE = 1001;
public static final int MEDIA_INFO_GET_CODEC_INFO_ERROR = 1002;
/**
* The media cannot be seeked (e.g live stream)
*
* @see io.vov.vitamio.MediaPlayer.OnInfoListener
*/
public static final int MEDIA_INFO_NOT_SEEKABLE = 801;
/**
* The rate in KB/s of av_read_frame()
*
* @see io.vov.vitamio.MediaPlayer.OnInfoListener
*/
public static final int MEDIA_INFO_DOWNLOAD_RATE_CHANGED = 901;
public static final int VIDEOQUALITY_LOW = -16;
public static final int VIDEOQUALITY_MEDIUM = 0;
public static final int VIDEOQUALITY_HIGH = 16;
public static final int VIDEOCHROMA_RGB565 = 0;
public static final int VIDEOCHROMA_RGBA = 1;
/**
* The subtitle displayed is embeded in the movie
*/
public static final int SUBTITLE_INTERNAL = 0;
/**
* The subtitle displayed is an external file
*/
public static final int SUBTITLE_EXTERNAL = 1;
/**
* The external subtitle types which Vitamio supports.
*/
public static final String[] SUB_TYPES = {".srt", ".ssa", ".smi", ".txt", ".sub", ".ass", ".webvtt"};
private static final int MEDIA_NOP = 0;
private static final int MEDIA_PREPARED = 1;
private static final int MEDIA_PLAYBACK_COMPLETE = 2;
private static final int MEDIA_BUFFERING_UPDATE = 3;
private static final int MEDIA_SEEK_COMPLETE = 4;
private static final int MEDIA_SET_VIDEO_SIZE = 5;
private static final int MEDIA_ERROR = 100;
private static final int MEDIA_INFO = 200;
private static final int MEDIA_CACHE = 300;
private static final int MEDIA_HW_ERROR = 400;
private static final int MEDIA_TIMED_TEXT = 1000;
private static final int MEDIA_CACHING_UPDATE = 2000;
private static final String MEDIA_CACHING_SEGMENTS = "caching_segment";
private static final String MEDIA_CACHING_TYPE = "caching_type";
private static final String MEDIA_CACHING_INFO = "caching_info";
private static final String MEDIA_SUBTITLE_STRING = "sub_string";
private static final String MEDIA_SUBTITLE_BYTES = "sub_bytes";
private static final String MEDIA_SUBTITLE_TYPE = "sub_type";
private static final int SUBTITLE_TEXT = 0;
private static final int SUBTITLE_BITMAP = 1;
private static AtomicBoolean NATIVE_OMX_LOADED = new AtomicBoolean(false);
private Context mContext;
private Surface mSurface;
private SurfaceHolder mSurfaceHolder;
private EventHandler mEventHandler;
private PowerManager.WakeLock mWakeLock = null;
private boolean mScreenOnWhilePlaying;
private boolean mStayAwake;
private Metadata mMeta;
private TrackInfo[] mInbandTracks;
private TrackInfo mOutOfBandTracks;
private AssetFileDescriptor mFD = null;
private OnHWRenderFailedListener mOnHWRenderFailedListener;
private OnPreparedListener mOnPreparedListener;
private OnCompletionListener mOnCompletionListener;
private OnBufferingUpdateListener mOnBufferingUpdateListener;
private OnCachingUpdateListener mOnCachingUpdateListener;
private OnSeekCompleteListener mOnSeekCompleteListener;
private OnVideoSizeChangedListener mOnVideoSizeChangedListener;
private OnErrorListener mOnErrorListener;
/**
* Register a callback to be invoked when an info/warning is available.
*
* @param listener
* the callback that will be run
*/
private OnInfoListener mOnInfoListener;
private OnTimedTextListener mOnTimedTextListener;
private AudioTrack mAudioTrack;
private int mAudioTrackBufferSize;
private Surface mLocalSurface;
private Bitmap mBitmap;
private ByteBuffer mByteBuffer;
/**
* Default constructor. The same as Android's MediaPlayer().
*
* When done with the MediaPlayer, you should call {@link #release()}, to free
* the resources. If not released, too many MediaPlayer instances may result
* in an exception.
*
*/
public MediaPlayer(Context ctx) {
this(ctx, false);
}
private static String path;
/**
* Default constructor. The same as Android's MediaPlayer().
*
* When done with the MediaPlayer, you should call {@link #release()}, to free
* the resources. If not released, too many MediaPlayer instances may result
* in an exception.
*
*
* @param preferHWDecoder MediaPlayer will try to use hardware accelerated decoder if true
*/
public MediaPlayer(Context ctx, boolean preferHWDecoder) {
mContext = ctx;
String LIB_ROOT = Vitamio.getLibraryPath();
if (preferHWDecoder) {
if (!NATIVE_OMX_LOADED.get()) {
if (Build.VERSION.SDK_INT > 17)
loadOMX_native( LIB_ROOT + "libOMX.18.so");
else if (Build.VERSION.SDK_INT > 13)
loadOMX_native( LIB_ROOT + "libOMX.14.so");
else if (Build.VERSION.SDK_INT > 10)
loadOMX_native( LIB_ROOT + "libOMX.11.so");
else
loadOMX_native( LIB_ROOT + "libOMX.9.so");
NATIVE_OMX_LOADED.set(true);
}
} else {
try {
unloadOMX_native();
} catch (UnsatisfiedLinkError e) {
Log.e("unloadOMX failed %s", e.toString());
}
NATIVE_OMX_LOADED.set(false);
}
Looper looper;
if ((looper = Looper.myLooper()) != null)
mEventHandler = new EventHandler(this, looper);
else if ((looper = Looper.getMainLooper()) != null)
mEventHandler = new EventHandler(this, looper);
else
mEventHandler = null;
native_init();
}
static {
String LIB_ROOT = Vitamio.getLibraryPath();
try {
System.load( LIB_ROOT + "libstlport_shared.so");
System.load( LIB_ROOT + "libvplayer.so");
loadFFmpeg_native( LIB_ROOT + "libffmpeg.so");
boolean vvo_loaded = false;
if (Build.VERSION.SDK_INT > 8)
vvo_loaded = loadVVO_native( LIB_ROOT + "libvvo.9.so");
else if (Build.VERSION.SDK_INT > 7)
vvo_loaded = loadVVO_native( LIB_ROOT + "libvvo.8.so");
else
vvo_loaded = loadVVO_native( LIB_ROOT + "libvvo.7.so");
if (!vvo_loaded) {
vvo_loaded = loadVVO_native( LIB_ROOT + "libvvo.j.so");
Log.d("FALLBACK TO VVO JNI " + vvo_loaded);
}
loadVAO_native( LIB_ROOT + "libvao.0.so");
} catch (java.lang.UnsatisfiedLinkError e) {
Log.e("Error loading libs", e);
}
}
private static void postEventFromNative(Object mediaplayer_ref, int what, int arg1, int arg2, Object obj) {
MediaPlayer mp = (MediaPlayer) (mediaplayer_ref);
if (mp == null)
return;
try {
//synchronized (mp.mEventHandler) {
if (mp.mEventHandler != null) {
Message m = mp.mEventHandler.obtainMessage(what, arg1, arg2, obj);
mp.mEventHandler.sendMessage(m);
}
} catch (Exception e) {
Log.e("exception: " + e);
}
}
private static native boolean loadVAO_native(String vaoPath);
private static native boolean loadVVO_native(String vvoPath);
private static native boolean loadOMX_native(String omxPath);
private static native void unloadOMX_native();
private static native boolean loadFFmpeg_native(String ffmpegPath);
private native void _setVideoSurface(Surface surface);
/**
* Sets the SurfaceHolder to use for displaying the video portion of the
* media. This call is optional. Not calling it when playing back a video will
* result in only the audio track being played.
*
* @param sh the SurfaceHolder to use for video display
*/
public void setDisplay(SurfaceHolder sh) {
if (sh == null) {
releaseDisplay();
} else {
mSurfaceHolder = sh;
mSurface = sh.getSurface();
_setVideoSurface(mSurface);
updateSurfaceScreenOn();
}
}
/**
* Sets the Surface to use for displaying the video portion of the media. This
* is similar to {@link #setDisplay(SurfaceHolder)}.
*
* @param surface the Surface to use for video display
*/
public void setSurface(Surface surface) {
if (surface == null) {
releaseDisplay();
} else {
mSurfaceHolder = null;
mSurface = surface;
_setVideoSurface(mSurface);
updateSurfaceScreenOn();
}
}
/**
* Sets the data source (file-path or http/rtsp URL) to use.
*
* @param path the path of the file, or the http/rtsp URL of the stream you want
* to play
* @throws IllegalStateException if it is called in an invalid state
*
*
* When path refers to a local file, the file may
* actually be opened by a process other than the calling
* application. This implies that the pathname should be an absolute
* path (as any other process runs with unspecified current working
* directory), and that the pathname should reference a
* world-readable file. As an alternative, the application could
* first open the file for reading, and then use the file descriptor
* form {@link #setDataSource(FileDescriptor)}.
*/
public void setDataSource(String path) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
_setDataSource(path, null, null);
}
/**
* Sets the data source as a content Uri.
*
* @param context the Context to use when resolving the Uri
* @param uri the Content URI of the data you want to play
* @throws IllegalStateException if it is called in an invalid state
*/
public void setDataSource(Context context, Uri uri) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
setDataSource(context, uri, null);
}
public void setDataSource(Context context, Uri uri, Map headers) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
if (context == null || uri == null)
throw new IllegalArgumentException();
String scheme = uri.getScheme();
if (scheme == null || scheme.equals("file")) {
setDataSource(FileUtils.getPath(uri.toString()));
return;
}
try {
ContentResolver resolver = context.getContentResolver();
mFD = resolver.openAssetFileDescriptor(uri, "r");
if (mFD == null)
return;
setDataSource(mFD.getParcelFileDescriptor().getFileDescriptor());
return;
} catch (Exception e) {
closeFD();
}
setDataSource(uri.toString(), headers);
}
/**
* Sets the data source (file-path or http/rtsp URL) to use.
*
* @param path the path of the file, or the http/rtsp URL of the stream you want to play
* @param headers the headers associated with the http request for the stream you want to play
* @throws IllegalStateException if it is called in an invalid state
*/
public void setDataSource(String path, Map headers)
throws IOException, IllegalArgumentException, SecurityException, IllegalStateException
{
String[] keys = null;
String[] values = null;
if (headers != null) {
keys = new String[headers.size()];
values = new String[headers.size()];
int i = 0;
for (Map.Entry entry: headers.entrySet()) {
keys[i] = entry.getKey();
values[i] = entry.getValue();
++i;
}
}
setDataSource(path, keys, values);
}
/**
* Sets the data source (file-path or http/rtsp URL) to use.
*
* @param path the path of the file, or the http/rtsp URL of the stream you want to play
* @param keys AVOption key
* @param values AVOption value
* @throws IllegalStateException if it is called in an invalid state
*/
public void setDataSource(String path, String[] keys, String[] values) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
final Uri uri = Uri.parse(path);
if ("file".equals(uri.getScheme())) {
path = uri.getPath();
}
final File file = new File(path);
if (file.exists()) {
FileInputStream is = new FileInputStream(file);
FileDescriptor fd = is.getFD();
setDataSource(fd);
is.close();
} else {
_setDataSource(path, keys, values);
}
}
/**
* Set the segments source url
* @param segments the array path of the url e.g. Segmented video list
* @param cacheDir e.g. getCacheDir().toString()
*/
public void setDataSegments(String[] uris, String cacheDir) {
_setDataSegmentsSource(uris, cacheDir);
}
public void setOnHWRenderFailedListener(OnHWRenderFailedListener l) {
mOnHWRenderFailedListener = l;
}
/**
* Sets the data source (file-path or http/rtsp/mms URL) to use.
*
* @param path the path of the file, or the http/rtsp/mms URL of the stream you
* want to play
* @param keys AVOption key
* @param values AVOption value
* @throws IllegalStateException if it is called in an invalid state
*/
private native void _setDataSource(String path, String[] keys, String[] values) throws IOException, IllegalArgumentException, IllegalStateException;
/**
* Sets the data source (FileDescriptor) to use. It is the caller's
* responsibility to close the file descriptor. It is safe to do so as soon as
* this call returns.
*
* @param fd the FileDescriptor for the file you want to play
* @throws IllegalStateException if it is called in an invalid state
*/
public native void setDataSource(FileDescriptor fd) throws IOException, IllegalArgumentException, IllegalStateException;
/**
* Set the segments source url
* @param segments the array path of the url
* @param cacheDir e.g. getCacheDir().toString()
*/
private native void _setDataSegmentsSource(String[] segments, String cacheDir);
/**
* Prepares the player for playback, synchronously.
*
* After setting the datasource and the display surface, you need to either
* call prepare() or prepareAsync(). For files, it is OK to call prepare(),
* which blocks until MediaPlayer is ready for playback.
*
* @throws IllegalStateException if it is called in an invalid state
*/
public native void prepare() throws IOException, IllegalStateException;
/**
* Prepares the player for playback, asynchronously.
*
* After setting the datasource and the display surface, you need to either
* call prepare() or prepareAsync(). For streams, you should call
* prepareAsync(), which returns immediately, rather than blocking until
* enough data has been buffered.
*
* @throws IllegalStateException if it is called in an invalid state
*/
public native void prepareAsync() throws IllegalStateException;
/**
* Starts or resumes playback. If playback had previously been paused,
* playback will continue from where it was paused. If playback had been
* stopped, or never started before, playback will start at the beginning.
*
* @throws IllegalStateException if it is called in an invalid state
*/
public void start() throws IllegalStateException {
stayAwake(true);
if (mInBuffering) {
//Log.i("MiuiVideo: now is in buffering, and will start after buffering");
mNeedResume = true;
} else {
//Log.i("MiuiVideo: start player");
_start();
}
}
private native void _start() throws IllegalStateException;
/**
* The same as {@link #pause()}
*
* @throws IllegalStateException if the internal player engine has not been initialized.
*/
public void stop() throws IllegalStateException {
stayAwake(false);
_stop();
mInBuffering = false;
mNeedResume = false;
}
private native void _stop() throws IllegalStateException;
/**
* Pauses playback. Call start() to resume.
*
* @throws IllegalStateException if the internal player engine has not been initialized.
*/
public void pause() throws IllegalStateException {
stayAwake(false);
mNeedResume = false;
//Log.i("MiuiVideo: pause player");
_pause();
}
private native void _pause() throws IllegalStateException;
/**
* Set the low-level power management behavior for this MediaPlayer. This can
* be used when the MediaPlayer is not playing through a SurfaceHolder set
* with {@link #setDisplay(SurfaceHolder)} and thus can use the high-level
* {@link #setScreenOnWhilePlaying(boolean)} feature.
*
* This function has the MediaPlayer access the low-level power manager
* service to control the device's power usage while playing is occurring. The
* parameter is a combination of {@link android.os.PowerManager} wake flags.
* Use of this method requires {@link android.Manifest.permission#WAKE_LOCK}
* permission. By default, no attempt is made to keep the device awake during
* playback.
*
* @param context the Context to use
* @param mode the power/wake mode to set
* @see android.os.PowerManager
*/
@SuppressLint("Wakelock")
public void setWakeMode(Context context, int mode) {
boolean washeld = false;
if (mWakeLock != null) {
if (mWakeLock.isHeld()) {
washeld = true;
mWakeLock.release();
}
mWakeLock = null;
}
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(mode | PowerManager.ON_AFTER_RELEASE, MediaPlayer.class.getName());
mWakeLock.setReferenceCounted(false);
if (washeld) {
mWakeLock.acquire();
}
}
/**
* Control whether we should use the attached SurfaceHolder to keep the screen
* on while video playback is occurring. This is the preferred method over
* {@link #setWakeMode} where possible, since it doesn't require that the
* application have permission for low-level wake lock access.
*
* @param screenOn Supply true to keep the screen on, false to allow it to turn off.
*/
public void setScreenOnWhilePlaying(boolean screenOn) {
if (mScreenOnWhilePlaying != screenOn) {
mScreenOnWhilePlaying = screenOn;
updateSurfaceScreenOn();
}
}
@SuppressLint("Wakelock")
private void stayAwake(boolean awake) {
if (mWakeLock != null) {
if (awake && !mWakeLock.isHeld()) {
mWakeLock.acquire();
} else if (!awake && mWakeLock.isHeld()) {
mWakeLock.release();
}
}
mStayAwake = awake;
updateSurfaceScreenOn();
}
private void updateSurfaceScreenOn() {
if (mSurfaceHolder != null)
mSurfaceHolder.setKeepScreenOn(mScreenOnWhilePlaying && mStayAwake);
}
/**
* Returns the width of the video.
*
* @return the width of the video, or 0 if there is no video, or the width has
* not been determined yet. The OnVideoSizeChangedListener can be
* registered via
* {@link #setOnVideoSizeChangedListener(OnVideoSizeChangedListener)}
* to provide a notification when the width is available.
*/
public native int getVideoWidth();
private native int getVideoWidth_a();
/**
* Returns the height of the video.
*
* @return the height of the video, or 0 if there is no video, or the height
* has not been determined yet. The OnVideoSizeChangedListener can be
* registered via
* {@link #setOnVideoSizeChangedListener(OnVideoSizeChangedListener)}
* to provide a notification when the height is available.
*/
public native int getVideoHeight();
private native int getVideoHeight_a();
/**
* Checks whether the MediaPlayer is playing.
*
* @return true if currently playing, false otherwise
*/
public native boolean isPlaying();
/**
* Set whether cache the online playback file
* @param cache
*/
public native void setUseCache(boolean cache);
/**
* set cache file dir
* @param directory
*/
public native void setCacheDirectory(String directory);
/**
* Adaptive streaming support, default is false
*
* @param adaptive true if wanna adaptive steam
*
*/
public native void setAdaptiveStream(boolean adaptive);
/**
* Seeks to specified time position.
*
* @param msec the offset in milliseconds from the start to seek to
* @throws IllegalStateException if the internal player engine has not been initialized
*/
public native void seekTo(long msec) throws IllegalStateException;
/**
* Gets the current playback position.
*
* @return the current position in milliseconds
*/
public native long getCurrentPosition();
/**
* Get the current video frame
*
* @return bitmap object
*/
public native Bitmap getCurrentFrame();
/**
* Gets the duration of the file.
*
* @return the duration in milliseconds
*/
public native long getDuration();
/**
* Gets the media metadata.
*
* @return The metadata, possibly empty. null if an error occurred.
*/
public Metadata getMetadata() {
if (mMeta == null) {
mMeta = new Metadata();
Map meta = new HashMap