Home » Android » android – setOutputFormat called in an invalid state: 4 (where and why)

android – setOutputFormat called in an invalid state: 4 (where and why)

Posted by: admin June 15, 2020 Leave a comment

Questions:

I have the following code:

Log.i("xx","A");
                 media_recorder = new MediaRecorder();
Log.i("xx","B");
                 media_recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
Log.i("xx","C");
                 media_recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); 
Log.i("xx","D");
                 media_recorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);
Log.i("xx","E");
                 media_recorder.setVideoSize(320, 240);
Log.i("xx","F");
                 media_recorder.setVideoFrameRate(15);
Log.i("xx","G");
                 CamcorderProfile profile = CamcorderProfile.get(CameraInfo.CAMERA_FACING_FRONT,CamcorderProfile.QUALITY_LOW);
Log.i("xx","H");
                 media_recorder.setProfile(profile);
Log.i("xx","I");
                 media_recorder.setOutputFile(fname);

When the code is executed, I see the following in my logs;

02-07 16:12:47.628: I/xx(15436): A
02-07 16:12:47.628: I/xx(15436): B
02-07 16:12:47.638: I/xx(15436): C
02-07 16:12:47.638: I/xx(15436): D
02-07 16:12:47.638: I/xx(15436): E
02-07 16:12:47.638: I/xx(15436): F
02-07 16:12:47.638: I/xx(15436): G
02-07 16:12:47.638: I/xx(15436): H
02-07 16:12:47.638: E/MediaRecorder(15436): setOutputFormat called in an invalid state: 4

This has confused me because the call to setOutputFormat was made between “C” and “D”, but the report of the error appears to be immediately after H (never reaching “I”). So now I don’t know what is causing the error, and I’m confused about where the error is occurring.

EDIT: I just stepped through the code in the debugger – and sure enough the error occurs during the call to setProfile(profile)… so it would appear that the call made to setOutputFormat (between “C” & “D”) must have worked ok, but then setProfile must itself make a second call to setOutputFormat which then fails… is that what’s going on?

EDIT: And what does invalid state 4 actually mean? Is there some list somewhere which tells you the meaning of each possible invalid state number 1,2,3,4…etc?

How to&Answers:

Here is source code of setProfile method:

public void setProfile(CamcorderProfile profile) {
  setOutputFormat(profile.fileFormat);
  setVideoFrameRate(profile.videoFrameRate);
  setVideoSize(profile.videoFrameWidth, profile.videoFrameHeight);
  setVideoEncodingBitRate(profile.videoBitRate);
  setVideoEncoder(profile.videoCodec);
  if (profile.quality >= CamcorderProfile.QUALITY_TIME_LAPSE_LOW &&
      profile.quality <= CamcorderProfile.QUALITY_TIME_LAPSE_QVGA) {
   // Nothing needs to be done. Call to setCaptureRate() enables
   // time lapse video recording.
  } else {
    setAudioEncodingBitRate(profile.audioBitRate);
    setAudioChannels(profile.audioChannels);
    setAudioSamplingRate(profile.audioSampleRate);
    setAudioEncoder(profile.audioCodec);
  }
}

E.g. it sets outputFormat, videoSize, encoder and frameRate to values from profile. So your code:

Log.i("xx","C");
media_recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); 
Log.i("xx","D");
media_recorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);
Log.i("xx","E");
media_recorder.setVideoSize(320, 240);
Log.i("xx","F");
media_recorder.setVideoFrameRate(15);

is at least useless, and maybe during these calls it changes state. Try without it.

Answer:

In your above code media_recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4) is called twice. 1st occurrence called by you in your code between Log.i("xx","C"); & Log.i("xx","D"); and the 2nd occurence called internally in MediaRecorder by your media_recorder.setProfile(profile); method i.e., between Log.i("xx","H"); & Log.i("xx","I");.

Because MediaRecorder object should follow the life cycle like below:
enter image description here

Refer setProfile() method in MediaRecoder class click here & compare your code again.

Answer:

It happens because you can’t change values in a MediaRecorder without calling reset(), so you have to set everything on the MediaRecorder itself (in fact you have to do this before API level 8, Android 2.2).

Alternatively, you can create a custom CamcorderProfile based on e.g. what you wanted, make the changes there and set that profile on the MediaRecorder, like this:

    // establish the media recorder
    MediaRecorder media_recorder = new MediaRecorder();
    media_recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
    media_recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);

    // Customise your profile based on a pre-existing profile
    CamcorderProfile profile = CamcorderProfile.get(CameraInfo.CAMERA_FACING_FRONT,CamcorderProfile.QUALITY_LOW);
    profile.fileFormat = MediaRecorder.OutputFormat.MPEG_4;
    profile.videoCodec = MediaRecorder.VideoEncoder.MPEG_4_SP;
    profile.videoFrameHeight = 240;
    profile.videoFrameWidth = 320;
    profile.videoBitRate = 15;

    // Apply to MediaRecorder
    media_recorder.setProfile(profile);