ページ

2013/11/23

[Android]機種依存でMediaRecorderで動画撮影に失敗する

来たぜ!Android の機種依存の闇に!

Android の機種依存の特徴

  • まともに組んでも何故か動かない
  • 動かない原因がわからない
  • 機種依存の実機がないと何が起きてるのかわからない
Xperia 系端末は適当に組んでも良い感じに動いてくれるけど
他の機種で動かないっていうのは、まぁあることだ。
まとも組めばいいのだけど Android API で対処できる範囲でまともに組んでも動かないやつがいて、
そういうのが本当の機種依存なわけだ。
そういうやつはたいていエラーログにもろくな情報がない。

MediaRecorder は機種依存でなくてもろくなエラーログを出力しなくて、
start failed とか stop failed とだけ言ってくるので失敗してるのはわかってるよ!と言い返したくなる。
MediaRecorder なんかは Java 層がただのラッパーだから仕方ないのかもしれないが直せなくて辛い。
Android API を眺めて設定項目を変えて色々試してみるしかなくて機種依存の実機がないと修正は困難になる。

愚痴はココらへんにして、Samsung Galaxy S2 SC-02C と HUAWEI M886 で起きたバグを確認したい。

Samsung Galaxy S2 SC-02C 動画撮影が開始できない機種依存バグ

まずはこいつを見てくれ。見事に MediaRecorder#start() で RuntimeException で落ちてるだろう?
しかもメッセージは start failed. と来た。Caused by もないとはいよいよもって死ぬがよい。
{
  "Exception": {
    "name": "java.lang.RuntimeException",
    "message": "start failed.",
    "ExceptionStacktrace": [
      "at [MediaRecorder#start:-2]",
      "at [aa#b:-1]",
      "at [VideoCameraActivity#f:-1]",
      "at [e#onClick:-1]",
      "at [View#performClick:3620]",
      "at [View$PerformClick#run:14292]",
      "at [Handler#handleCallback:605]",
      "at [Handler#dispatchMessage:92]",
      "at [Looper#loop:137]",
      "at [ActivityThread#main:4507]",
      "at [Method#invokeNative:-2]",
      "at [Method#invoke:511]",
      "at [ZygoteInit$MethodAndArgsCaller#run:980]",
      "at [ZygoteInit#main:747]",
      "at [NativeStart#main:-2]"
    ]
  }
}
この JSON は独自クラッシュレポートによって手に入れたものだ。こいつがあると色々便利だ。
[Android]独自クラッシュレポート送信機能を実装する レポート作成編 | DevAchieve
カメラパラメータをこいつで送信してわかったことがある。
DisplaySize(800x480)、PreviewSize(800x480) に対して VideoSize(720x480) で
CamcorderProfile は "videoFrameWidth: ": 1920, "videoFrameHeight: ": 1080 という設定になっていた。
こいつが怪しい。
試しに Xperia A の値を確認すると、
DispalySize(1184x720)、PreviewSize(1280x720) に対して VideoSize(1920x1080) で
CamcorderProfile は "videoFrameWidth: ": 1920, "videoFrameHeight: ": 1080 という設定になっていた。
VideoSize と CamcorderProfile の videoFrame(Width|Height) が一致していない。

とここまで書いて気がついたのだが、 VideoSize は MediaRecorder#setVideoSize で設定している。
MediaRecorder#setVideoSize(int width, int height) | Android Developers
071 プレビューが見えるように撮影ができるように修正 refs #6 #11 · c2b99d2 · gabu/gabubon2
ちょうど↑こんなかんじで PreviewSize を指定していたのだけど
VideoSize(720x480) って PreviewSize(800x480) の近似サイズなような気がする。
Galaxy S2 のサポートしているビデオサイズのリストは以下のとおり。
"video-size-values": "720x480,176x144,320x240,352x288,640x480,1280x720,1920x1080"

この線が濃厚なので調べてみると Stack Overflow にそれっぽい回答があった。
video - How to use getSupportedVideoSizes() on Android? - Stack Overflow
CamcorderProfile camcorderProfile = CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_HIGH);
mMediaRecorder.setVideoSize(camcorderProfile.videoFrameWidth, camcorderProfile.videoFrameHeight);
上記のように CamcorderProfile の videoFrame(Width|Height) を使えば確実みたい。
このへんの指定の情報が少なすぎて泣ける。
過去にきっと泣かされてきたエンジニアたち↓
ビデオアプリが難なワケ: hikariのブログ
071 動画撮影が行えない · Issue #6 · gabu/gabubon2
希望を信じた Androider を、わたしは泣かせたくない。ということで多分解決。
機種依存バグじゃなくて Android API の使い方を間違えた僕が悪い。

HUAWEI M886 動画撮影が開始できない機種依存バグ

さてもう一つ。こっちはかなり高い確率で本当に機種依存バグ。だって中華端末だもん。
以下はレポートの設定値の一部抜粋。
{
    "preview-size": "1280x720",
    "preview-size-values": "1280x720,800x480,768x432,720x480,640x480,576x432,480x320,384x288,352x288,320x240,240x160,176x144",
    "record-size": "",
    "videoFrameWidth: ": 1280,
    "videoFrameHeight: ": 720
}
DisplaySize(854x480), PreviewSize(1280x720) で VideoSize がなくて
なぜか "record-size" で、しかも空という状況。
Android の Camera.Parameters を確認すると以下の定義は見つかるが、
"record-size" という設定値のキーはない。
private static final String KEY_VIDEO_SIZE = "video-size";
レポートくれたユーザーには思わず俺が直せることを祈ってくれって返した!
さすがに設定キーが違うと設定メソッド使えないから上の修正で奇跡的に直ることを祈ってくれ!

このように動画撮影には色々ノウハウが必要だから気をつけるんだぞ!
DevCamera はそのへん頑張ってるから応援よろしくお願いします。