画面表示レートはどれくらいなのか調べてみました
先日、スマートフォン勉強会でSmartWatchについて発表したときに、SmartWatchのフレームレートがどれくらいなのかという質問が出ましたので調べてみました。
方法は単純にBitmap画像をSmartWatchに転送するだけです。
SmartWatchの画面表示について
SmartWatchのプログラムは、通常、Serviceとして動いています。画面表示を行う場合は表示画像(Bitmap)のintentを発行して、ホストアプリ(LiveWareマネージャ)に受け取ってもらい、ホストアプリがSmartWatchにBluetoothを使って動画を送信する手順となります。
なので、画像の転送レートのネックになりそうなところは、intentの処理とBluetoothの通信ということになります。
先ずは、テストプログラムを貼っておきます。
- BGMは後付けです。音は鳴りません。画面に残像が残るのは撮影に使ったWebカメラのせいです。
転送プログラム
以下のプログラムは動画を表示させているところの抜粋です。/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); } } }