簡體   English   中英

MediaRecorder IOException 准備失敗

[英]MediaRecorder IOException prepare failed

在升級到 AndroidX 並將目標 SDK 增加到版本 28 后,此 IOException 開始在我的 Android 應用程序中發生。

在此之前,相同的代碼運行良好。

這是一個電容器應用程序,並使用電容器錄像機插件。 在后台,這個插件使用了與android.media.MediaRecorder交互的fancycamera java 庫。

這是調用 VideoRecorder.startRecording 時拋出的堆棧跟蹤,最終導致調用VideoRecorder.startRecording

I/IMediaRecorder: prepare (BpMediaRecorder client) in file frameworks/av/media/libmedia/IMediaRecorder.cpp, function prepare, line 253
E/MediaRecorder: prepare failed: -2147483648
W/System.err: java.io.IOException: prepare failed.
W/System.err:     at android.media.MediaRecorder._prepare(Native Method)
W/System.err:     at android.media.MediaRecorder.prepare(MediaRecorder.java:1038)
W/System.err:     at co.fitcom.fancycamera.Camera2.setUpMediaRecorder(Camera2.java:607)
W/System.err:     at co.fitcom.fancycamera.Camera2.startRecording(Camera2.java:837)
W/System.err:     at co.fitcom.fancycamera.FancyCamera.startRecording(FancyCamera.java:323)
W/System.err:     at com.github.sbannigan.capacitor.VideoRecorder.startRecording(VideoRecorder.java:267)
W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
W/System.err:     at com.getcapacitor.PluginHandle.invoke(PluginHandle.java:99)
W/System.err:     at com.getcapacitor.Bridge$1.run(Bridge.java:515)
W/System.err:     at android.os.Handler.handleCallback(Handler.java:907)
W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:105)
W/System.err:     at android.os.Looper.loop(Looper.java:216)
W/System.err:     at android.os.HandlerThread.run(HandlerThread.java:65)

Android 應用程序正在請求 CAMERA 和 RECORD_AUDIO 權限,我可以確認首先提示用戶輸入這些權限。

AndroidManifest.xml

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>

我還可以看到在應用程序的數據目錄中創建了一個 output 文件。 但是該文件仍然是空的。 我也手動嘗試寫入同一個文件,這是可能的,所以文件 IO 似乎不是問題。

崩潰來自本機方法,因此調試器不是很有幫助。 但是,我至少可以確認 MediaRecorder 的mPath變量在調用_prepare之前似乎設置正確。

我創建了一個具有相同堆棧的示例應用程序,可以在其中重新創建錯誤: https://github.com/disbelief/video-recorder-test

我也有興趣了解MediaRecorder.prepare拋出此異常的其他可能原因。

2022 年 6 月

我的錯誤非常簡單。 某些手機默認將相機分辨率作為屏幕尺寸,但其他手機則沒有。 這就是為什么在許多設備上它拋出prepare failed: -2147483648 MediaRecorder 的深度就是那個相機本身。 因此,您需要通過允許的大小。 顯然充其量是最大值(到mMediaRecorder.setVideoSize()

CameraPropeties props_ = new CameraPropeties(this);
int width_= = props_.getWidth();
int height_ = props_.getHeight();
...
mMediaRecorder.setVideoSize(width_,height_)
...

和相機屬性 class:

package <my.package>;
import android.content.Context;
import android.content.res.Configuration;
import android.media.CamcorderProfile;
import android.os.Build;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.WindowManager;
import androidx.annotation.RequiresApi;
import static android.content.Context.WINDOW_SERVICE;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;

public class CameraPropeties {
  private int _width;
  private int _hight;
  @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
  private void _getSupportedSizes() {
    CameraInfo recordingInfo = _getRecordingInfo();
    _width = recordingInfo.width;
    _hight = recordingInfo.height;
    Log.e("MaxSupportedSizes --", "WIDTH = " + recordingInfo.width + " HEIGHT = " + recordingInfo.height);
}

private CameraInfo _getRecordingInfo() {
    DisplayMetrics displayMetrics = new DisplayMetrics();
    WindowManager wm = (WindowManager) _context.getSystemService(WINDOW_SERVICE);
    wm.getDefaultDisplay().getRealMetrics(displayMetrics);
    int displayWidth = displayMetrics.widthPixels;
    int displayHeight = displayMetrics.heightPixels;
    int displayDensity = displayMetrics.densityDpi;

    Configuration configuration = _context.getResources().getConfiguration();
    boolean isLandscape = configuration.orientation == ORIENTATION_LANDSCAPE;

    CamcorderProfile camcorderProfile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
    int cameraWidth = camcorderProfile != null ? camcorderProfile.videoFrameWidth : -1;
    int cameraHeight = camcorderProfile != null ? camcorderProfile.videoFrameHeight : -1;
    int cameraFrameRate = camcorderProfile != null ? camcorderProfile.videoFrameRate : 30;
    return calculateCameraInfo(displayWidth, displayHeight, displayDensity, isLandscape,
            cameraWidth, cameraHeight, cameraFrameRate, 100);
}
private Context _context;
public CameraPropeties(Context c) {
    _context = c;
    _getSupportedSizes();
}
public int getWidth() {
    return _width;
}
public int getHeight() {
    return _hight;
}
static final class CameraInfo {
    final int width;
    final int height;
    final int frameRate;
    final int density;
    CameraInfo(int width$, int height$, int frameRate$, int density$) {
        this.width = width$;
        this.height = height$;
        this.frameRate = frameRate$;
        this.density = density$;
    }
}

static CameraInfo calculateCameraInfo(int displayWidth$, int displayHeight$, int displayDensity$, 
    boolean isLandscapeDevice$, int cameraWidth$, int cameraHeight$, int cameraFrameRate$,
                                      int sizePercentage$) {
    // Scale the display size before any maximum size calculations.
    displayWidth$ = displayWidth$ * sizePercentage$ / 100;
    displayHeight$ = displayHeight$ * sizePercentage$ / 100;

    if (cameraWidth$ == -1 && cameraHeight$ == -1) {
        // No cameras. Fall back to the display size.
        return new CameraInfo(displayWidth$, displayHeight$, cameraFrameRate$, displayDensity$);
    }

    int frameWidth_ = isLandscapeDevice$ ? cameraWidth$ : cameraHeight$;
    int frameHeight_ = isLandscapeDevice$ ? cameraHeight$ : cameraWidth$;
    if (frameWidth_ >= displayWidth$ && frameHeight_ >= displayHeight$) {
        // Frame can hold the entire display. Use exact values.
        return new CameraInfo(displayWidth$, displayHeight$, cameraFrameRate$, displayDensity$);
    }

    // Calculate new width or height to preserve aspect ratio.
    if (isLandscapeDevice$) {
        frameWidth_ = displayWidth$ * frameHeight_ / displayHeight$;
    } else {
        frameHeight_ = displayHeight$ * frameWidth_ / displayWidth$;
    }
    return new CameraInfo(frameWidth_, frameHeight_, cameraFrameRate$, displayDensity$);
}

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM