23

I try to organize background video recording in Android 4.0. But I can't do it because of these problems:

  1. Dummy Surface does not work in MediaRecorder (error: invalid surface)

  2. If you use Surface 1 x 1 px on Activity, Surface is destroyed on Activity pause (recording is stopped)

  3. If you use Surface 1 x 1 px on WindowsManager, Surface is destroyed on Application pause (recording is stopped)

  4. SurfaceTexture does not work in MediaRecorder.setPreviewDisplay(new Surface(SurfaceTexture))

  5. Widget does not allow to handle Surface 1 x 1 px

  6. Status Bar does not allow to handle Surface 1 x 1 px

Please, help me to find right way.

shamanpenza
  • 263
  • 1
  • 3
  • 7

3 Answers3

44

Sample and simple code (tested on Jelly Bean, SGS2):

public class BackgroundVideoRecorder extends Service implements SurfaceHolder.Callback {

    private WindowManager windowManager;
    private SurfaceView surfaceView;
    private Camera camera = null;
    private MediaRecorder mediaRecorder = null;

    @Override
    public void onCreate() {

        // Start foreground service to avoid unexpected kill
        Notification notification = new Notification.Builder(this)
            .setContentTitle("Background Video Recorder")
            .setContentText("")
            .setSmallIcon(R.drawable.ic_launcher)
            .build();
        startForeground(1234, notification);

        // Create new SurfaceView, set its size to 1x1, move it to the top left corner and set this service as a callback
        windowManager = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
        surfaceView = new SurfaceView(this);
        LayoutParams layoutParams = new WindowManager.LayoutParams(
            1, 1,
            WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
            WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
            PixelFormat.TRANSLUCENT
        );
        layoutParams.gravity = Gravity.LEFT | Gravity.TOP;
        windowManager.addView(surfaceView, layoutParams);
        surfaceView.getHolder().addCallback(this);

    }

    // Method called right after Surface created (initializing and starting MediaRecorder)
    @Override
    public void surfaceCreated(SurfaceHolder surfaceHolder) {

        camera = Camera.open();
        mediaRecorder = new MediaRecorder();
        camera.unlock();

        mediaRecorder.setPreviewDisplay(surfaceHolder.getSurface());
        mediaRecorder.setCamera(camera);
        mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
        mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
        mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));

        mediaRecorder.setOutputFile(
                Environment.getExternalStorageDirectory()+"/"+
                DateFormat.format("yyyy-MM-dd_kk-mm-ss", new Date().getTime())+
                ".mp4"
        );

        try { mediaRecorder.prepare(); } catch (Exception e) {}
        mediaRecorder.start();

    }

    // Stop recording and remove SurfaceView
    @Override
    public void onDestroy() {

        mediaRecorder.stop();
        mediaRecorder.reset();
        mediaRecorder.release();

        camera.lock();
        camera.release();

        windowManager.removeView(surfaceView);

    }

    @Override
    public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {}

    @Override
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {}

    @Override
    public IBinder onBind(Intent intent) { return null; }

}

Don't forget about permissions:

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
cman
  • 441
  • 4
  • 4
  • Was about to post this. The trick is setting the MediaRecorder on the OnSurfaceCreated, after that it gets pretty straightforward. – Felipe Leusin Jun 03 '13 at 16:32
  • Thank you for great piece of code, but I have a small problem with that. I tested it on Nexus 5X and I got camera upsidedown. I tried camera.setDisplayOrientation(90) and camera.getParameters().setRotation(90), but nothing is changing camera orientation. Do you have any idea how to change it? – Michal Dec 21 '16 at 21:15
  • 1
    I'm really sorry for answering so late. I hope this helps: https://plus.google.com/+AndroidDevelopers/posts/jXNFNKWxsc3 - if not, you can try this: mediaRecorder.setOrientationHint(180); - it doesn't change the orientation of camera, but tells video player to change the orientation when playing. That's all i know. – cman Apr 02 '17 at 18:01
  • This solution works but screen gets freeze when start recording. Tested in nought – Trupti Nasit Sep 11 '20 at 08:55
2
try { 
        mediaRecorder.prepare(); 
    } catch (Exception e) {}
    mediaRecorder.start();
    Timer t = new Timer();
    t.schedule(new TimerTask() {
        @Override
        public void run() {
            stopSelf();
        }
    }, 5000);
}catch(Exception e){}

Just a small modification to the above code...it will save the 5sec file to the root folder in ur sdcard...modify the timer according to ur need. and it worked on Nexus 4 and Micromax as well..

-4

I found the answer: it is necessary to use WindowManager and call it from Service.

shamanpenza
  • 263
  • 1
  • 3
  • 7