package com.media.ffmpeg;
import java.io.IOException;
import java.lang.ref.WeakReference;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.view.Surface;
import android.view.SurfaceHolder;
public class FFMpegPlayer extends MediaPlayer
{
private static final int MEDIA_NOP = 0; // interface test message
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;
public static final int MEDIA_ERROR_UNKNOWN = 1;
public static final int MEDIA_ERROR_SERVER_DIED = 100;
public static final int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200;
public static final int MEDIA_INFO_UNKNOWN = 1;
public static final int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700;
public static final int MEDIA_INFO_BAD_INTERLEAVING = 800;
public static final int MEDIA_INFO_NOT_SEEKABLE = 801;
public static final int MEDIA_INFO_METADATA_UPDATE = 802;
public static final int MEDIA_INFO_FRAMERATE_VIDEO = 900;
public static final int MEDIA_INFO_FRAMERATE_AUDIO = 901;
public static final int HARDWARE_DECODE = 1;
public static final int SOFTWARE_DECODE = 0;
private final static String TAG = "FFMpegPlayer";
private int mNativeContext;
private int mNativeData = 0;
private Surface mSurface;
private AudioTrack mTrack;
private SurfaceHolder mSurfaceHolder;
private static Rect mRect = null;
private EventHandler mEventHandler;
private PowerManager.WakeLock mWakeLock = null;
private boolean mScreenOnWhilePlaying;
private boolean mStayAwake;
private static GLRenderControler mGlRenderControler;
//sunyuanzeng
private MediaDecoder mVideoDecoder;
private Context mContext;
//end
static
{
try
{
FFMpeg loadLib = new FFMpeg();
native_init();
}
catch (Exception e)
{
e.printStackTrace();
}
}
public FFMpegPlayer()
{
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();
native_setup(new WeakReference<FFMpegPlayer>(this));
}
public FFMpegPlayer( Context context )
{
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();
native_setup(new WeakReference<FFMpegPlayer>(this));
//sunyuanzeng
mContext = context;
//end
}
private static void postEventFromNative(Object mediaplayer_ref, int what, int arg1, int arg2, Object obj)
{
FFMpegPlayer mp = (FFMpegPlayer) ((WeakReference<?>) mediaplayer_ref).get();
if (mp == null)
{
return;
}
if (mp.mEventHandler != null)
{
Message m = mp.mEventHandler.obtainMessage(what, arg1, arg2, obj);
mp.mEventHandler.sendMessage(m);
}
}
public void setDisplay(SurfaceHolder sh)
{
mSurfaceHolder = sh;
if (sh != null)
{
mSurface = sh.getSurface();
}
else
{
mSurface = null;
}
updateSurfaceScreenOn();
// _setVideoSurface(mSurface);
}
public void start() throws IllegalStateException
{
stayAwake(true);
_start();
}
public void stop() throws IllegalStateException
{
stayAwake(false);
_stop();
}
public void pause() throws IllegalStateException
{
stayAwake(false);
_pause();
}
public void prepareAsync() throws IllegalStateException
{
try
{
prepare();
}
catch (IOException e)
{
e.printStackTrace();
}
}
public void setDataSource(Context context, Uri uri)
{
try
{
setDataSource(uri.toString());
//setDataSource("http://cache.video.qiyi.com/mm/f0a6f7d6dfe445598498191fa0ac6879/484/cfe19c08d4b3592064624d6ec93d836e.m3u8?msessionid=NzdjNTcwNjJlN2M2OWI4ZjA0N2M5MTM0MTc3YWEwYzE=");
}
catch (IllegalArgumentException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IllegalStateException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private native void _setVideoSurface(Surface surface) throws IOException;
public native void setDataSource(String path) throws IOException, IllegalArgumentException, IllegalStateException;
public native void prepare() throws IOException, IllegalStateException;
private native void _start() throws IllegalStateException;
private native void _stop() throws IllegalStateException;
private native void _pause() throws IllegalStateException;
public native int getVideoWidth();
public native int getVideoHeight();
public native String getLastUrl();
public native String getVersion();
public native boolean isPlaying();
public native void seekTo(int msec) throws IllegalStateException;
public native int getCurrentPosition();
public native int getDuration();
private native void _release();
private native void _reset();
private native int native_suspend_resume(boolean isSuspend);
public native void setAudioStreamType(int streamtype);
private static native final void native_init() throws RuntimeException;
private native final void native_setup(Object mediaplayer_this);
private native final void native_finalize();
public native void native_gl_resize(int w, int h);
public native void native_gl_render();
public void release()
{
// Log.i(TAG, "release()");
stayAwake(false);
updateSurfaceScreenOn();
mOnPreparedListener = null;
mOnBufferingUpdateListener = null;
mOnCompletionListener = null;
mOnSeekCompleteListener = null;
mOnErrorListener = null;
mOnInfoListener = null;
mOnVideoSizeChangedListener = null;
_release();
/*
if (mSurfaceHolder != null){
Canvas tmpCanvas = mSurfaceHolder.lockCanvas(mRect);
if (tmpCanvas != null){
//tmpCanvas.drawColor(Color.BLACK);
Log.d(TAG,"drawColor");
mSurfaceHolder.unlockCanvasAndPost(tmpCanvas);
}
}
*/
}
public void reset()
{
stayAwake(false);
_reset();
mEventHandler.removeCallbacksAndMessages(null);
}
public boolean suspend()
{
// Log.i(TAG, "suspend()");
if (native_suspend_resume(true) < 0)
{
return false;
}
stayAwake(false);
mEventHandler.removeCallbacksAndMessages(null);
return true;
}
public boolean resume()
{
if (native_suspend_resume(false) < 0)
{
return false;
}
if (isPlaying())
{
stayAwake(true);
}
return true;
}
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();
}
}
public void setScreenOnWhilePlaying(boolean screenOn)
{
if (mScreenOnWhilePlaying != screenOn)
{
mScreenOnWhilePlaying = screenOn;
updateSurfaceScreenOn();
}
}
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);
}
}
private OnVideoSizeChangedListener mOnVideoSizeChangedListener;
public void setOnVideoSizeChangedListener(OnVideoSizeChangedListener mSizeChangedListener)
{
mOnVideoSizeChangedListener = mSizeChangedListener;
}
private OnSeekCompleteListener mOnSeekCompleteListener;
public void setOnSeekCompleteListener(OnSeekCompleteListener listener)
{
mOnSeekCompleteListener = listener;
}
private OnPreparedListener mOnPreparedListener;
public void setOnPreparedListener(OnPreparedListener listener)
{
mOnPreparedListener = listener;
}
private OnBufferingUpdateListener mOnBufferingUpdateListener;
public void setOnBufferingUpdateListener(OnBufferingUpdateListener listener)
{
mOnBufferingUpdateListener = listener;
}
private OnCompletionListener mOnCompletionListener;
public void setOnCompletionListener(OnCompletionListener listener)
{
mOnCompletionListener = listener;
}
private OnErrorListener mOnErrorListener;
public void setOnErrorListener(OnErrorListener listener)
{
mOnErrorListener = listener;
}
private OnInfoListener mOnInfoListener;
public void setOnInfoListener(OnInfoListener listener)
{
mOnInfoListener = listener;
}
private class EventHandler extends Handler
{
private FFMpegPlayer mMediaPlayer;
public EventHandler(FFMpegPlayer ffmpegPlayer, Looper looper)
{
super(looper);
mMediaPlayer = ffmpegPlayer;
}
@Override
public void handleMessage(Message msg)
{
if (mMediaPlayer.mNativeContext == 0)
{
return;
}
switch (msg.what)
{
case MEDIA_PREPARED:
if (mOnPreparedListener != null)
mOnPreparedListener.onPrepared(mMediaPlayer);
return;
case MEDIA_PLAYBACK_COMPLETE:
if (mOnCompletionListener != null)
mOnCompletionListener.onCompletion(mMediaPlayer);
stayAwake(false);
return;
case MEDIA_BUFFERING_UPDATE:
if (mOnBufferingUpdateListener != null)
{
mOnBufferingUpdateListener.onBufferingUpdate(mMediaPlayer, msg.arg1);
}
return;
case MEDIA_SEEK_COMPLETE:
if (mOnSeekCompleteListener != null)
mOnSeekCompleteListener.onSeekComplete(mMediaPlayer);
return;
case MEDIA_SET_VIDEO_SIZE:
if (mOnVideoSizeChangedListener != null)
{
//by wmw,2012-02-27
if (null == mRect)
{
mRect = new Rect();
mRect.set(0, 0, msg.arg1, msg.arg2);
}
mOnVideoSizeChangedListener.onVideoSizeChanged(mMediaPlayer, msg.arg1, msg.arg2);
}
return;
case MEDIA_ERROR:
boolean error_was_handled = false;
if (mOnErrorListener != null)
{
error_was_handled = mOnErrorListener.onError(mMediaPlayer, msg.arg1, msg.arg2);
}
if (mOnCompletionListener != null && !error_was_handled)
{
mOnCompletionListener.onCompletion(mMediaPlayer);
}
stayAwake(false);
return;
case MEDIA_INFO:
if (mOnInfoListener != null)
{
mOnInfoListener.onInfo(mMediaPlayer, msg.arg1, msg.arg2);
}
return;
case MEDIA_NOP:
break;
default:
return;
}
}
}
public static void initAudioTrack(Object mediaplayer_ref, int sampleRateInHz, int channelConfig) throws IOException
{
FFMpegPlayer mp = (FFMpegPlayer) ((WeakReference<?>) mediaplayer_ref).get();
if (mp == null)
{
return;
}
int bufferSizeInBytes = AudioTrack.getMinBufferSize(sampleRateInHz, channelConfig, AudioFormat.ENCODING_PCM_16BIT);
mp.mTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRateInHz, channelConfig, AudioFormat.ENCODING_PCM_16BIT, bufferSizeInBytes, AudioTrack.MODE_STREAM);
mp.mTrack.play();
}
public static void writeAudioTrack(Object mediaplayer_ref, byte[] audioData, int size) throws IOException
{
FFMpegPlayer mp = (FFMpegPlayer) ((WeakReference<?>) mediaplayer_ref).get();
if (mp == null)
{
return;
}
mp.mTrack.write(audioData, 0, size);
}
public static void releaseAudioTrack(Object mediaplayer_ref) throws IOException
{
FFMpegPlayer mp = (FFMpegPlayer) ((WeakReference<?>) mediaplayer_ref).get();
if (mp == null)
{
return;
}
if (mp.mTrack != null)
{
mp.mTrack.stop();
mp.mTrack.release();
mp.mTrack = null;
}
}
private native void _setAudioTrack(AudioTrack track) throws IOException;
public static void JavaDraw(Object mediaplayer_ref) throws IOException
{
FFMpegPlayer mp = (FFMpegPlayer) ((WeakReference<?>) mediaplayer_ref).get();
if (mp == null)
{
return;
}
Canvas canvas = mp.mSurfaceHolder.lockCanvas(mRect);
//added by wmw,2012-04-09
if (canvas == null)
{
return;
}
_nativeDraw(canvas);
mp.mSurfaceHolder.unlockCanvasAndPost(canvas);
}
private static native void _nativeDraw(Canvas canvas);
public interface GLRenderControler{
void setGLStartRenderMode();
void setGLStopRenderMode();
}
public void setRenderControler(GLRenderControler controler) {
mGlRenderControler = controler;
}
public static void stopRenderMode() {
if (mGlRenderControler != null)
mGlRenderControler.setGLStopRenderMode();
}
public static void startRenderMode() {
if (mGlRenderControler != null)
mGlRenderControler.setGLStartRenderMode();
}
//sunyuanzeng
public static void initVideoDecoder( Object mediaplayer_ref, int width, int height ) throws IOException
{
}
public static void stopVideoDecoder( Object mediaplayer_ref ) throws IOException
{
FFMpegPlayer mp = (FFMpegPlayer) ((WeakReference<?>) mediaplayer_ref).get();
if (mp == null )
{
return;
}
if(mp.mVideoDecoder != null)
{
// Log.d("chenyg", "stopVideoDecoder");
mp.mVideoDecoder.stopCodec();
mp.mVideoDecoder = null;
}
}
public static int fillInputBuffer( Object mediaplayer_ref, byte[] data, long pts, int flush ) throws IOException
{
FFMpegPlayer mp = (FFMpegPlayer) ((WeakReference<?>) mediaplayer_ref).get();
if (mp == null || mp.mVideoDecoder == null)
{
return -1;
}
return mp.mVideoDecoder.fillInputBuffer(data, pts, flush);
}
public static int flushCodec( Object mediaplayer_ref ) throws IOException
{
// Log.d("chenyg", "flushCodec");
FFMpegPlayer mp = (FFMpegPlayer) ((WeakReference<?>) mediaplayer_ref).get();
if (mp == null)
{
return -1;
}
if( mp.mVideoDecoder != null )
{
mp.mVideoDecoder.flushCodec();
}
return 0;
}
public void setDecoderSurface( Surface surface )
{
mSurface = surface;
}
public native int _native_sync( long pts ) throws IOException;
public native int setHardwareDecode( int hwDecode ) throws IOException;
//end
}