コンピュータを楽しもう!!

今、自分が面白くていろいろやってみたことを書き綴りたいと思います。連絡先はtarosa.yでgmail.comです。

画面表示レートはどれくらいなのか調べてみました

先日、スマートフォン勉強会SmartWatchについて発表したときに、SmartWatchのフレームレートがどれくらいなのかという質問が出ましたので調べてみました。
方法は単純にBitmap画像をSmartWatchに転送するだけです。

SmartWatchの画面表示について

SmartWatchのプログラムは、通常、Serviceとして動いています。画面表示を行う場合は表示画像(Bitmap)のintentを発行して、ホストアプリ(LiveWareマネージャ)に受け取ってもらい、ホストアプリがSmartWatchにBluetoothを使って動画を送信する手順となります。
なので、画像の転送レートのネックになりそうなところは、intentの処理とBluetoothの通信ということになります。
先ずは、テストプログラムを貼っておきます。

  • BGMは後付けです。音は鳴りません。画面に残像が残るのは撮影に使ったWebカメラのせいです。

D

転送プログラム

以下のプログラムは動画を表示させているところの抜粋です。/mnt/sdcard/images/BadApple/にimage0000.bmpファイルが入っており、これを順番に表示しているだけです。ただ、都度読み込んでいると処理が遅いので、先に500枚(50秒分)先読みしています。
aniLoadFlg配列は先読みできているかどうかを調べるフラグです。SWDrawは自作の描画classです。

private class Animation implements Runnable {
 private final String SDFolder = "/mnt/sdcard/images/BadApple/";

 private boolean aniIsStopped = false;
 private long aniTime1 = 0;
 private int aniInterval = 100;

 private int aniCnt1 = 0;
 private int aniCnt2 = 0;
 private Bitmap[] aniPicture = new Bitmap[500];
 private byte[] aniLoadFlg = new byte[500];

 Animation(){

   //画面を自動消灯しない
   setScreenState(Control.Intents.SCREEN_STATE_ON);
   //Log.d(SwService.LOG_TAG, "Control.Intents#SCREEN_STATE_ON");

   SWDraw.PutText("Now Loading...", 0, 60, 18, Color.WHITE, 0, 0);
   showBitmap(SWDraw.MainBmp);

   aniCnt1 = 0;
   aniCnt2 = 0;

   String fname = "";
   for( int i=0; i<500; i++){
     fname = SDFolder + String.format("image%1$04d.bmp", i+1);
     Log.d(SwService.LOG_TAG, fname);
     aniPicture[i] = BitmapFactory.decodeFile(fname);
     aniLoadFlg[i] = 0;
   }
   aniTime1 = System.currentTimeMillis();
 }

動画を止めるときはフラグを立てるだけです。

 public void stop() {
   aniIsStopped = true;
 }

画像転送

画像転送は下記のrunスレッドで行っています。Bitmapファイルは100ms単位に切り出していて、ファイル名の連番が100ms単位になるようにしています。なので、下記の式で表示すべき画像番号を求めています。

aniCnt1 = (int)((System.currentTimeMillis() - aniTime1) / aniInterval);

上の式を使っているので、実際のこま落ち量はわからないのですが、転送は間に合っているようです。転送が間に合っていないと、次の画像がaniPicture配列に読み込めない現象が発生するのですが、例えば、下記ソースの "if(aniLoadFlg[aniCnt1-501]==1)" の部分をコメントにして動作させても、読み込み落ちしている画像は余り有りませんでした。

10fps以上は別のプログラムで試したのですが、どうもintentがつっかえてくるようです。正確に確認したわけではないので、間違っているかもしれません。

最後の mHandler.postDelayed(this, ms時間)は必要で、これが無いとタッチやスィープイベントがうまく拾えませんでした。

 @Override
 public void run() {

   if (!aniIsStopped) {
     if( aniCnt1!=aniCnt2){
       if( aniCnt1>0 && aniCnt1<=500 ){
         showBitmap(aniPicture[aniCnt1-1]);
         aniPicture[aniCnt1-1] = BitmapFactory.decodeFile(
             SDFolder + String.format("image%1$04d.bmp", aniCnt1 + 500)
         );
         aniLoadFlg[aniCnt1-1] = 1;
       }
       else if(aniCnt1>500 && aniCnt1<=1000){
         if(aniLoadFlg[aniCnt1-501]==1){
           showBitmap(aniPicture[aniCnt1-501]);
         }
         aniPicture[aniCnt1-501] = BitmapFactory.decodeFile(
             SDFolder + String.format("image%1$04d.bmp", aniCnt1 + 500)
         );
         aniLoadFlg[aniCnt1-501] = 2;
       }
       else if(aniCnt1>1000 && aniCnt1<=1500){
         if(aniLoadFlg[aniCnt1-1001]==2){
           showBitmap(aniPicture[aniCnt1-1001]);
         }
         aniPicture[aniCnt1-1001] = BitmapFactory.decodeFile(
             SDFolder + String.format("image%1$04d.bmp", aniCnt1 + 500)
         );
         aniLoadFlg[aniCnt1-1001] = 3;
       }
       else if(aniCnt1>1500 && aniCnt1<=1690){
         if(aniLoadFlg[aniCnt1-1501]==3){
           showBitmap(aniPicture[aniCnt1-1501]);
         }
         aniPicture[aniCnt1-1501] = BitmapFactory.decodeFile(
             SDFolder + String.format("image%1$04d.bmp", aniCnt1 + 500)
         );
         aniLoadFlg[aniCnt1-1501] = 4;
       }
       else if(aniCnt1>1690 && aniCnt1<=2000){
         if(aniLoadFlg[aniCnt1-1501]==3){
           showBitmap(aniPicture[aniCnt1-1501]);
         }
       }
       else if(aniCnt1>2000 && aniCnt1<=2190){
         if(aniLoadFlg[aniCnt1-2001]==4){
           showBitmap(aniPicture[aniCnt1-2001]);
         }
       }

       aniCnt2 = aniCnt1;
     }

     aniCnt1 = (int)((System.currentTimeMillis() - aniTime1) / aniInterval);
     if(aniCnt1>2190){
       //動作を停止させるための計算
       aniCnt2 = aniCnt1;
       aniTime1 = System.currentTimeMillis() - 2191 * aniInterval;
     }

     if (mHandler != null) {
       mHandler.postDelayed(this, 1);
     }
   }
 }