2012年5月28日 星期一

Android Video Playback



  • Create a layout for video playback
    setContentView(R.layout.video_playback);


  • Create a video view and video controller for video playback

    mVideoView = (VideoView)findViewById(
                                R.id.video_playback_view);
    mMediaController = new MediaController(this);
    mVideoView.setMediaController(mMediaController);
    mVideoView.setOnPreparedListener(
                   new OnPreparedListener() {
        @Override
        public void onPrepared(MediaPlayer mediaPlayer) {
            AudioManager audioManager = (AudioManager)
                getApplicationContext().getSystemService(
                    Context.AUDIO_SERVICE);
            mOriginalVideoVolume = audioManager.
                getStreamVolume(AudioManager.STREAM_MUSIC);
            if (mOriginalVideoVolume != mVideoVolume) {
                audioManager.setStreamVolume(
                    AudioManager.STREAM_MUSIC, mVideoVolume,
                    AudioManager.FLAG_PLAY_SOUND);
            }
            int duration = mVideoView.getDuration();
            mMediaController.show(duration);
            mVideoView.start();
        }
    });
    mVideoView.setOnCompletionListener(
                   new MediaPlayer.OnCompletionListener() {
        @Override
        public void onCompletion(MediaPlayer mp) {
            AudioManager audioManager = (AudioManager)
                getApplicationContext().
                    getSystemService(Context.AUDIO_SERVICE);
            if (mOriginalVideoVolume != mVideoVolume) {
                audioManager.setStreamVolume(
                    AudioManager.STREAM_MUSIC,
                    mOriginalVideoVolume,
                    AudioManager.FLAG_PLAY_SOUND);
            }
            finish();
        }
    });

  • Set video path on resume

    protected void onResume() {
        ...
        if (mVideoPath.equalsIgnoreCase("default_video")) {
            finish();
        } else
            mVideoView.setVideoPath(mVideoPath);
    }

  • Sample code for android video playback

import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnPreparedListener;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Window;
import android.view.WindowManager;
import android.widget.MediaController;
import android.widget.VideoView;

public class VideoPlaybackActivity extends Activity {
    private final String mTAG = "VideoPlaybackActivity";
    private VideoView mVideoView;
    private MediaController mMediaController;
    private String mVideoPath;
    private int mOriginalVideoVolume;
    private int mVideoVolume;
   
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.video_playback);
        getWindow().addFlags(
            WindowManager.LayoutParams.FLAG_FULLSCREEN);
        getWindow().addFlags(
            WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        SharedPreferences preferences = getApplicationContext().
           getSharedPreferences("VideoRecording", MODE_PRIVATE);
        mVideoPath = preferences.getString("video_path",
                        "default_video");
        AudioManager audioManager = (AudioManager)
                        getApplicationContext().getSystemService(
                            Context.AUDIO_SERVICE);
        mVideoVolume = preferences.getInt("video_volume",
                          audioManager.getStreamMaxVolume(
                              AudioManager.STREAM_MUSIC));
        mVideoView = (VideoView)findViewById(
                                    R.id.video_playback_view);
        mMediaController = new MediaController(this);
        mVideoView.setMediaController(mMediaController);
        mVideoView.setOnPreparedListener(
                       new OnPreparedListener() {
            @Override
            public void onPrepared(MediaPlayer mediaPlayer) {
                AudioManager audioManager = (AudioManager)
                    getApplicationContext().getSystemService(
                        Context.AUDIO_SERVICE);
                mOriginalVideoVolume = audioManager.
                    getStreamVolume(AudioManager.STREAM_MUSIC);
                if (mOriginalVideoVolume != mVideoVolume) {
                    audioManager.setStreamVolume(
                        AudioManager.STREAM_MUSIC, mVideoVolume,
                        AudioManager.FLAG_PLAY_SOUND);
                }
                int duration = mVideoView.getDuration();
                mMediaController.show(duration);
                mVideoView.start();
            }
        });
        mVideoView.setOnCompletionListener(
                       new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
                AudioManager audioManager = (AudioManager)
                    getApplicationContext().
                        getSystemService(Context.AUDIO_SERVICE);
                if (mOriginalVideoVolume != mVideoVolume) {
                    audioManager.setStreamVolume(
                        AudioManager.STREAM_MUSIC,
                        mOriginalVideoVolume,
                        AudioManager.FLAG_PLAY_SOUND);
                }
                finish();
            }
        });
    }
   
    @Override
    protected void onResume() {
        super.onResume();
        if (mVideoPath.equalsIgnoreCase("default_video")) {
            finish();
        } else
            mVideoView.setVideoPath(mVideoPath);
    }
}

Android Activity Lifecycle


了解Activity的生命週期各階段,是撰寫Android程式很重要的基本概念,Android Activity的生命週期,如下圖所示:

 – Android Activity的生命週期
談到 Android Activity的生命週期,我們可以區分三個迴圈來探討:
l   整個生命週期
Android Activity整個生命週期,由呼叫onCreate(Bundle)開始,於最後呼叫onDestroy()結束。在onCreate()函式中,必須對所有全域變數進行進行初始化設定,在執行onDestroy()時,必須釋放所有使用資源。
l   可見生命週期
Android Activity的可見生命週期,介於呼叫onStart()函式,及呼叫對應的onStop()函式之間,在這段時間,Activity顯示在螢幕上,但不一定是使用者可以直接互動的狀態,在這兩個函式之間,程式必須建立與顯示相關的資源,並於onStop執行時,釋放這些資源。Android Activity整個生命週期中,隨著Activity的顯示和隱藏,onStart()onStop()可以被呼叫很多次。
l   前景生命週期
Android Activity前景生命週期,介於呼叫onResume()函式,及呼叫對應的onPause()函式之間,在這段時間,Activity在所有Activity的最上層,是處在與使用者直接互動的狀態,Activity可能在onResumeonPause之間頻繁切換狀態,因此這兩個函式的處理動作必須盡量精簡。

Android Video Recording


  • Create a layout for video capture
    setContentView(R.layout.video_capture);
  • Create a button for video recording start and stop
    mVideoRecording = (Button)findViewById(R.id.video_recording);
    mVideoRecording.setOnClickListener(
        new Button.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mIsRecordingVideo == false) {
                    mVideoRecording.setText(
                        R.string.video_recording_stop);
                    videoRecordingStart();
                } else {
                    videoRecordingStop();                    
                }
            }
        });

  • Create a preview surface view and surface holder
    mPreview = (SurfaceView) findViewById(
                                 R.id.video_capture_view);
    SurfaceHolder holder = mPreview.getHolder();
    holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

  • Stop video recording on activity pause

    public void onPause() {
                    ...
        if (mIsRecordingVideo == true) {
            videoRecordingStop();
        ...
                    
  • Search for front facing camera and set orientation
    CameraInfo camerainfo = new Camera.CameraInfo();
    for (int index = 0;
         index < Camera.getNumberOfCameras();
         index++) {
        Camera.getCameraInfo(index, camerainfo);
        if (camerainfo.facing ==
            Camera.CameraInfo.CAMERA_FACING_FRONT) {
            try {
                mCamera = Camera.open(index);
                mCameraOrientation =
                    (camerainfo.orientation + 0) % 360;
                mCameraOrientation = (360 - mCameraOrientation);
                mCamera.setDisplayOrientation(
                            mCameraOrientation);
                Camera.Parameters cameraparameters =
                                      mCamera.getParameters();
                cameraparameters.setRotation(
                                     camerainfo.orientation);
                mCamera.setParameters(cameraparameters);
            } catch (RuntimeException e) {
                Log.i(mTAG, e.getMessage(), e);  
            }
        }
    }

  • Search for back facing camera and set orientation
    for (int index = 0;
         index < Camera.getNumberOfCameras();
         index++) {
        Camera.getCameraInfo(index, camerainfo);
        if (camerainfo.facing ==
            Camera.CameraInfo.CAMERA_FACING_BACK) {
            try {
                mCamera = Camera.open(index);
                mCameraOrientation =
                    (camerainfo.orientation + 0) % 360;
                mCamera.setDisplayOrientation(
                            mCameraOrientation);
                Camera.Parameters cameraparameters =
                                      mCamera.getParameters();
                cameraparameters.setRotation(
                                     camerainfo.orientation);
                mCamera.setParameters(cameraparameters);
            } catch (RuntimeException e) {
                Log.i(mTAG, e.getMessage(), e);  
            }
        }
    }
  • Start camera preview and unlock
    mCamera.startPreview();
    mCamera.unlock();
  • Generate mp4 file name for video recording
    String path = null;
    File dir = null;
    String name = null;
    try {
        path = String.format(getExternalFilesDir(null).
                                 getPath().toString());
        dir = new File(path);
        if (!dir.exists())
            dir.mkdirs();
        MP4FileFilter filter = new MP4FileFilter();
        File[] files = dir.listFiles(filter);
        if (files != null) {
            for (File file : files) {
                file.delete();
            }
        }
        name = String.format("/%d.mp4",
                                 System.currentTimeMillis());
    } catch(Exception e) {
        Log.i(mTAG, e.getMessage(), e);  
    }

  • Create media recorder and setting up
    mMediaRecorder = new MediaRecorder();
    mMediaRecorder.setCamera(mCamera);
    mMediaRecorder.setVideoSource(
                       MediaRecorder.VideoSource.CAMERA);
    mMediaRecorder.setAudioSource(
                       MediaRecorder.AudioSource.MIC);
    mMediaRecorder.setOutputFormat(
                       MediaRecorder.OutputFormat.MPEG_4);
    mMediaRecorder.setVideoEncoder(
                       MediaRecorder.VideoEncoder.H264);
    mMediaRecorder.setAudioEncoder(
                       MediaRecorder.AudioEncoder.AAC);
    if ((path != null) && (name != null)) {
        mVideoRecordingPath = path + name;
        mMediaRecorder.setOutputFile(new File(path,
                           name).getAbsolutePath());
        mMediaRecorder.setVideoSize(640, 480);
        mMediaRecorder.setVideoFrameRate(15);
    }

  • Stop camera preview and release
    mCamera.stopPreview();
    mCamera.release();

  • Stop media recorder and release
    mMediaRecorder.stop();
    ...
    mMediaRecorder.release();

  • Save video file path and video volume for later use
    SharedPreferences preferences = getApplicationContext().
                          getSharedPreferences("VideoRecording",
                              MODE_PRIVATE);
    Editor editor = preferences.edit();
    editor.putString("video_path", mVideoRecordingPath);
    AudioManager audioManager = (AudioManager)
                     getApplicationContext().
                         getSystemService(Context.AUDIO_SERVICE);
    mVideoVolume = audioManager.getStreamVolume(
                                    AudioManager.STREAM_MUSIC);
    editor.putInt("video_volume", mVideoVolume);
    editor.commit();


  • Remove title bar

    requestWindowFeature(Window.FEATURE_NO_TITLE);

  • Set full screen display and keep screen on          getWindow().addFlags(
        WindowManager.LayoutParams.FLAG_FULLSCREEN);
    getWindow().addFlags(
        WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);




  • Sample code for android video recording:
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;

import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.media.AudioManager;
import android.media.MediaRecorder;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;

public class VideoRecordingActivity extends Activity {
 private final String mTAG = "VideoRecordingActivity";
    private Button mVideoRecording;
    private boolean mIsRecordingVideo = false;
    private SurfaceView mPreview;
    private MediaRecorder mMediaRecorder;
    private Camera mCamera;
    private int mCameraOrientation = 0;
    private String mVideoRecordingPath;
    private int mVideoVolume;
   
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.video_capture);
        getWindow().addFlags(
            WindowManager.LayoutParams.FLAG_FULLSCREEN);
        getWindow().addFlags(
            WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        mVideoRecording = (Button)findViewById(
                                      R.id.video_recording);
        mVideoRecording.setOnClickListener(new Button.
                            OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mIsRecordingVideo == false) {
                    mVideoRecording.setText(
                        R.string.video_recording_stop);
                    videoRecordingStart();
                } else {
                    videoRecordingStop();                    
                }
            }
        });
        mPreview = (SurfaceView) findViewById(
                                     R.id.video_capture_view);
        SurfaceHolder holder = mPreview.getHolder();
        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }
   
    @Override
    public void onPause() {
        super.onPause();
        if (mIsRecordingVideo == true) {
            videoRecordingStop();                    
        }
    }

    private void videoRecordingStart() {
        CameraInfo camerainfo = new Camera.CameraInfo();
        for (int index = 0;
             index < Camera.getNumberOfCameras();
             index++) {
            Camera.getCameraInfo(index, camerainfo);
            if (camerainfo.facing ==
                    Camera.CameraInfo.CAMERA_FACING_FRONT) {
                try {
                    mCamera = Camera.open(index);
                    mCameraOrientation =
                        (camerainfo.orientation + 0) % 360;
                    mCameraOrientation =
                        (360 - mCameraOrientation);
                    mCamera.setDisplayOrientation(
                                mCameraOrientation);
                    Camera.Parameters cameraparameters =
                               mCamera.getParameters();
                    cameraparameters.setRotation(
                                         camerainfo.orientation);
                    mCamera.setParameters(cameraparameters);
                } catch (RuntimeException e) {
                    Log.i(mTAG, e.getMessage(), e);  
                }
            }
        }
        if (mCamera == null) {
            for (int index = 0;
                 index < Camera.getNumberOfCameras();
                 index++) {
                Camera.getCameraInfo(index, camerainfo);
                if (camerainfo.facing ==
                    Camera.CameraInfo.CAMERA_FACING_BACK) {
                    try {
                        mCamera = Camera.open(index);
                        mCameraOrientation =
                            (camerainfo.orientation + 0) % 360;
                        mCamera.setDisplayOrientation(
                                    mCameraOrientation);
                        Camera.Parameters cameraparameters =
                                   mCamera.getParameters();
                        cameraparameters.setRotation(
                                   camerainfo.orientation);
                        mCamera.setParameters(cameraparameters);
                    } catch (RuntimeException e) {
                        Log.i(mTAG, e.getMessage(), e);  
                    }
                }
            }
        }
       
        if (null != mCamera) {
            mCamera.startPreview();
            mCamera.unlock();
            mMediaRecorder = new MediaRecorder();
            mMediaRecorder.setCamera(mCamera);
            mMediaRecorder.setVideoSource(
                             MediaRecorder.VideoSource.CAMERA);
            mMediaRecorder.setAudioSource(
                             MediaRecorder.AudioSource.MIC);
            mMediaRecorder.setOutputFormat(
                             MediaRecorder.OutputFormat.MPEG_4);
            mMediaRecorder.setVideoEncoder(
                             MediaRecorder.VideoEncoder.H264);
            mMediaRecorder.setAudioEncoder(
                             MediaRecorder.AudioEncoder.AAC);
            String path = null;
            File dir = null;
            String name = null;
            try {
                path = String.format(getExternalFilesDir(null).
                           getPath().toString());
                dir = new File(path);
                if (!dir.exists())
                    dir.mkdirs();
                MP4FileFilter filter = new MP4FileFilter();
                File[] files = dir.listFiles(filter);
                if (files != null) {
                    for (File file : files) {
                        file.delete();
                    }
                }
                name = String.format("/%d.mp4",
                           System.currentTimeMillis());
            } catch(Exception e) {
                Log.i(mTAG, e.getMessage(), e);  
            }
            if ((path != null) && (name != null)) {
                mVideoRecordingPath = path + name;
                mMediaRecorder.setOutputFile(new File(path,
                                   name).getAbsolutePath());
                mMediaRecorder.setVideoSize(640, 480);
                mMediaRecorder.setVideoFrameRate(15);
                mMediaRecorder.setPreviewDisplay(
                    mPreview.getHolder().getSurface());
                mMediaRecorder.setOrientationHint(
                    mCameraOrientation);
          mMediaRecorder.setMaxDuration(60000);
             try {
                    mMediaRecorder.prepare();
                    mMediaRecorder.start();
                } catch (IllegalStateException e) {
                    Log.i(mTAG, e.getMessage(), e);  
                } catch (IOException e) {
                    Log.i(mTAG, e.getMessage(), e);  
                }
                mIsRecordingVideo = true;
            }
        }        
    }
   
    private class MP4FileFilter implements FileFilter {
        @Override
        public boolean accept(File pathname) {
            if (pathname.getName().toLowerCase().
                    endsWith(".mp4")) {
                return true;
            }
            return false;
        }
        
    }

    private void videoRecordingStop() {
        if (mIsRecordingVideo) {
            mMediaRecorder.stop();
            mCamera.stopPreview();
            mCamera.release();
            mMediaRecorder.release();
            SharedPreferences preferences =
                getApplicationContext().getSharedPreferences(
                    "VideoRecording", MODE_PRIVATE);
            Editor editor = preferences.edit();
            editor.putString("video_path", mVideoRecordingPath);
            AudioManager audioManager = (AudioManager)
                getApplicationContext().getSystemService(
                    Context.AUDIO_SERVICE);
            mVideoVolume = audioManager.getStreamVolume(
                               AudioManager.STREAM_MUSIC);
            editor.putInt("video_volume", mVideoVolume);
            editor.commit();
            mIsRecordingVideo = false;
            finish();
        }
    }
}