Androidで撮影したビデオがWebサイトで見られない

Android
Android ビデオ録画機能を作る

Androidで撮影したビデオがWebサイトで見られない

かなりマニアックなシチュエーションだと思いますが、今、次のようなことにトライしています。なお、ここまでの歩みはAndroid ビデオ録画機能を作るにもまとめてあります。

今回は、スマホで動画を撮影に加えて、

  1. Androidアプリで動画を撮影
  2. Webサーバーにアップロードして、Webでもその動画が楽しめる!

というものなんですが、Androidアプリでちょこっとパラメーターをいじるとブラウザで見られないという事象が発生していました。
なので、調べたことを書いておきます。

検証したスマホはXperia SO-04Dです。PCはWin7と、下記で紹介するブラウザたちです。

①まず、最初は下記のようにやっていました。
MediaRecorderを作るときに、getCamcoderProfileというメソッドのほうで、なるべく低い画質のビデオを作るべく、CamcorderProfile.QUALITY_LOWを指定しています。

 if(mrec == null){
      mrec = new MediaRecorder(); 
      mrec.setOnInfoListener(this);
      mrec.setOnErrorListener(this);       
 }
         
 mrec.setCamera(mCamera);
 
 mrec.setAudioSource(MediaRecorder.AudioSource.MIC);
        
 mrec.setVideoSource(MediaRecorder.VideoSource.CAMERA);
 
 int displayRotation = getOrientation(context, mrec);
 mrec.setOrientationHint(displayRotation);
 
 //ビデオの画質
 CamcorderProfile camcorderProfile = getCamcoderProfile(context, mrec);
 mrec.setProfile(camcorderProfile);
       
 mrec.setVideoSize(camcorderProfile.videoFrameWidth, camcorderProfile.videoFrameHeight);        
 
 mrec.setOutputFile(file_path);
        
 mrec.setPreviewDisplay(surfaceHolder.getSurface());
 private static CamcorderProfile getCamcoderProfile(Context context, MediaRecorder mrec){
       // 録画される画面の縦横を決める
       int degrees = getSurfaceDegrees(context);
 
       Camera.CameraInfo camInfo = new Camera.CameraInfo();
       int camera_id = findFrontFacingCameraID();
       Camera.getCameraInfo(camera_id, camInfo);
 
       //ビデオの画質
       CamcorderProfile camcorderProfile = CamcorderProfile.get(camera_id, CamcorderProfile.QUALITY_LOW);
       
       return camcorderProfile;
   }
   

しかし、上記でアップロードされたビデオファイルを見ると、

Firefox 38.0.5 「サポートされたファイル形式およびMIME形式のファイルが見つかりませんでした」
IE11 「無効なソース」
Chrome 再生のコントロールパネルが表示されるけれども、再生されない状態

となります。下記は悲しいIE11の画面です。
ie11.png

ちなみに、ブラウザ側のHTML5のビデオプレーヤーは下記のように指定しています。

 <video controls>
   <source src="hogehoge.mp4" type="video/webm">
   <source src="hogehoge.mp4" type="video/mp4">
    I'm sorry; your browser doesn't support HTML5 video in WebM with VP8 or MP4 with H.264.
 </video>

下記のサイトなどを調べて、MP4だったら再生されるはず? と思っていたため、最初かなり時間がかかりました。
https://developer.mozilla.org/ja/docs/Web/HTML/Supported_media_formats

たとえば、撮影した動画ではなくって、別のMP4なら再生されるため、もしかしてビデオコーデックのせいかな?と考えました。
で、動画ファイルのコーデックを調べられるMediaInfoというフリーソフトをインスコして調べてみます。

MediaInfo
http://www.gigafree.net/media/mediainfo.html

mediaInfo.png

えっ H263のビデオコーデックになっています。

コーデックについて、本腰で調べるときがきたようです…。
下記のWikipediaで調べてみます。
https://ja.wikipedia.org/wiki/%E3%82%B3%E3%83%BC%E3%83%87%E3%83%83%E3%82%AF

ふうむ。


ビデオコーデックを指定しないといけないのか!と思い、前にも散々、Androidでビデオ録画機能を作る時に気をつけたいことで公式ドキュメント読みなさーいっ って言ってたんですが、またまた公式ドキュメントを読んでいたにもかかわらず、英語力があまりなくって誤解していたみたいです[sad]

下記のページにある
http://developer.android.com/guide/topics/media/camera.html

次の記述ですね。

>Set the video output format and encoding. For Android 2.2 (API Level 8) and higher, use the MediaRecorder.setProfile method, and get a profile instance using CamcorderProfile.get(). For versions of Android prior to 2.2, you must set the video output format and encoding parameters:
>
> setOutputFormat() – Set the output format, specify the default setting or MediaRecorder.OutputFormat.MPEG_4.
> setAudioEncoder() – Set the sound encoding type, specify the default setting or MediaRecorder.AudioEncoder.AMR_NB.
> setVideoEncoder() – Set the video encoding type, specify the default setting or MediaRecorder.VideoEncoder.MPEG_4_SP.

Set the video encoding type, specify the default setting or MediaRecorder.VideoEncoder.MPEG_4_SP. というのは、指定しなければMPEG_4_SPが指定されるのかと思っていました。

そうではなく、指定しないとそのスマホのデフォルトが使われる、ということなんですね。そして、今回のようなトラブルになるわけですorz

で、MediaRecorderにsetVideoEncoderを設定するぞ!と下記のように変更してみると

 //中略
 int displayRotation = getOrientation(context, mrec);
 mrec.setOrientationHint(displayRotation);
 
 //下記を追加
 mrec.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
 mrec.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
 mrec.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);
        
 //ビデオの画質
 CamcorderProfile camcorderProfile = getCamcoderProfile(context, mrec);
 mrec.setProfile(camcorderProfile);
 
 //後は略

で、上記を実行すると

 setOutputFormat called in an invalid state: 4

というエラーが出て、録画を開始できません。

あわわー 

 mrec.setProfile(camcorderProfile);

とやっているので、CamcorderProfileの中で設定しないといけなかったんですね。

上記で追加したところを削除し、CamcoderProfileのフィールドのvideoCodecを
MediaRecorder.VideoEncoder.H264で指定します。

   private static CamcorderProfile getCamcoderProfile(Context context, MediaRecorder mrec){
       // 録画される画面の縦横を決める
       int degrees = getSurfaceDegrees(context);
 
       Camera.CameraInfo camInfo = new Camera.CameraInfo();
       int camera_id = findFrontFacingCameraID();
       Camera.getCameraInfo(camera_id, camInfo);
 
       //ビデオの画質
       CamcorderProfile camcorderProfile = CamcorderProfile.get(camera_id, CamcorderProfile.QUALITY_LOW);
       
       //次を追加
       camcorderProfile.videoCodec = MediaRecorder.VideoEncoder.H264;
       
       return camcorderProfile;
   }
   

上記を試してみると、下記のような感じになりました。

  • Firefox 38.0.5 「サポートされたファイル形式およびMIME形式のファイルが見つかりませんでした」
  • IE11 「無効なソース」
  • Chrome 再生できた!

おおーっ Chromeだけではとりあえず、再生できたようです!!!
しかし、これはゴールではありません。。。IE11で再生できるのが、最終ゴールなのです・・・。


これからは、あまり明確な解決方法がないんですが、下記のサイトで、Win7+IE11では、1920×1088 pixels の動画しかサポートしない、という情報がありました・・・。マジ?

http://stackoverflow.com/questions/21124885/html5-video-not-working-in-ie-11

しかし・・・動画の大きさはもしかしたら関係あるのかもしれない・・・
80Kぐらいの、とても小さい動画なので・・・。
で、次のようにビデオのサイズを上げてみました。

 //ビデオの画質
 CamcorderProfile camcorderProfile = CamcorderProfile.get(camera_id, CamcorderProfile.QUALITY_720P);
 camcorderProfile.videoCodec = MediaRecorder.VideoEncoder.H264;

すると、
Firefox 38.0.5 再生できた!
IE11 再生できた!
Chrome 再生できた!!!

ついに!再生したい全部のブラウザで再生ができました。

ちなみに、上記のようにしておくと、CamcorderProfile.QUALITY_720Pがないカメラでは、ビデオが開始できません。
なので、下記のようにカムコーダーのプロファイルがあるかどうか調べて使ったほうがいいでしょう。

 CamcorderProfile camcorderProfile = null;
 if(CamcorderProfile.hasProfile(camera_id, CamcorderProfile.QUALITY_480P)){
           
           camcorderProfile = CamcorderProfile.get(camera_id, CamcorderProfile.QUALITY_480P);
       
       }else if(CamcorderProfile.hasProfile(camera_id, CamcorderProfile.QUALITY_720P)){
       
           camcorderProfile = CamcorderProfile.get(camera_id, CamcorderProfile.QUALITY_720P);
       
       }else{
       
           camcorderProfile = CamcorderProfile.get(camera_id, CamcorderProfile.QUALITY_HIGH);
       
       }
       
  camcorderProfile.videoCodec = MediaRecorder.VideoEncoder.H264;
  • エクスペリアの英語表記はXperiaですよ。 — ゆき {2015-06-17 (水) 09:55:52}
  • ゆきさん、ご指摘有難うございました!直しました。 — 書いた人 {2015-06-22 (月) 11:33:54}

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です