Ubuntu 18.04でAndroid emulatorのためにkvmを有効にする
新しいマシンにAndroid studioをinstallしてAVDを作ろとしたときに以下のメッセージが表示されていることに気づいて少しハマったのでメモ。
/dev/kvm is not found
基本的にこのページに書いてあると通りに進めれば良いのですが
このコマンドを実行する前に sudo addgroup libvirtd
を実行しないと libvirtd
グループが存在しないで失敗します。
$ sudo adduser `id -un` libvirtd
あと自分のパソコンがHPのワークステーションだったので以下のリンクの手順でBIOSでVTxを有効にする必要がありました。
git のレポジトリのサブディレクトリをforkするには
元ネタはここから
www.slideshare.net
こういう一つのレポジトリに複数のアプリのコードが入っているとき特定のアプリのサブディレクトリのみを自分のレポジトリにコピーしたくなったのでやってみた。
git clone git@github.com:googlesamples/android-architecture-components.git cd android-architecture-components/ git filter-branch --force --subdirectory-filter PersistenceMigrationsSample HEAD git remote add myrepo git@github.com:hoge/PersistenceMigrationsSample.git git push myrepo
メソッド内に定義されたロカールクラスで Gson().fromJson できない原因を調査してみた
こんな感じのコードでLoader1
クラスを使ってJSONの文字列を読むことができるが Loader2
クラスを使っては読むことができない。
class Test { data class Loader1 (val type: String) fun test() { val jsonString = """{"type": "abc"}""" val ret1 = Gson().fromJson(jsonString, Loader1::class.java) assert(ret1.type == "abc") data class Loader2 (val type: String) val ret2 = Gson().fromJson(jsonString, Loader2::class.java) assert(ret2.type == "abc") // ret2 は null } }
デコンパイルして Java にしてみる
Show Kotlin bytecode
を押す
Decompile
を押す
Java に Decompile
されたコードが表示される。
以下抜粋した Java のコード
public final class Test { public final void test() { final class Loader2 { @NotNull private final String type; @NotNull public final String getType() { return this.type; } public Loader2(@NotNull String type) { this.type = type; } } Loader2 ret2 = (Loader2)(new Gson()).fromJson(jsonString, Loader2.class); } }
Java の local class が使われていることが確認できた。
続いて Gson が local class をどのように扱うのか調べる。
skipDeserialize
が true
なので null
を返す。
@Override public T read(JsonReader in) throws IOException { if (skipDeserialize) { in.skipValue(); return null; } return delegate().read(in); }
skipDeserialize
以下で excludeClass
が true
になっている。
boolean excludeClass = excludeClassChecks(rawType); final boolean skipSerialize = excludeClass || excludeClassInStrategy(rawType, true); final boolean skipDeserialize = excludeClass || excludeClassInStrategy(rawType, false);
excludeClass
に以下のコードでtrue
が代入されていた。
if (isAnonymousOrLocal(clazz)) { return true; }
isAnonymousOrLocal
の実装は以下のようになっておりLoader2.class.isLocalClass() == true
なので fromJson
できなかった。
private boolean isAnonymousOrLocal(Class<?> clazz) { return !Enum.class.isAssignableFrom(clazz) && (clazz.isAnonymousClass() || clazz.isLocalClass()); }
なぜGsonはAnonymousかLocalクラスを使ってロードできないのか調べていたら以下のissueにたどり着いた。
Don't use double brace initialization. It prevents serialization and Gson is designed for symmetric serialization and serialization. Original comment by limpbizkit on 7 Feb 2013 at 1:02 Changed state: WontFix
で、最終的にちゃんとユーザーガイドに書いてあることに気づいた。
Gson can also deserialize static nested classes. However, Gson can not automatically deserialize the pure inner classes since their no-args constructor also need a reference to the containing Object which is not available at the time of deserialization. You can address this problem by either making the inner class static or by providing a custom InstanceCreator for it. Here is an example:
結論: ちゃんとドキュメントを読みましょう。
HP Compaq Pro 6300 SFFを3500円で購入
秋葉原のジャンク通りを歩いていたら、こちらのパソコンが4500円から月曜特価で1000円引きされ3500円売られていた。どうせ使わないかなと思ったけどLinuxマシーンとして遊ぶのも悪くないかなと思い購入。
ちょうどBangoodでCore i7-4610Yのマシンが1万4824円で売られていることがニュースになっていて少し後悔した。
https://news.nicovideo.jp/watch/nw5676116news.nicovideo.jp
とりあえず上海問屋で120GBのSSDを2000円で購入した。
GPUはGTX1050tiを動かしている人もいたけど、250wの電源とマザーボード側がPCIe 2.0なのでオーバースペック気味と判断しHPのカタログに書かれていたRADEON HD7450(実際に購入したのは6450。これは7450と同じ)を選んだ。
パーツは安いのを探してたら結果的に全部メルカリからの購入になった。(メルカリから買ったのは合計 18500円分)
本体とSSDも合わせると合計 23000円になった。
消費電力はこんな感じ。
パーツ名 | 最大 | TDP(idle) |
---|---|---|
Intel core i7 3770 | 77W | |
Intel Q75 express | 6.7W | 6.7W? |
PC3-12800 32GB | 14W(推測) | |
RADEON HD6450 | 44w | 10w |
Core i7-4610Yよりかはパフォーマンスよい。
http://www.cpu-world.com/Compare/229/Intel_Core_i7_Mobile_i7-4610Y_vs_Intel_Core_i7_i7-3770K.html
PTAM
基本的なpackageはyumでインストール
- TooN
- libcvd
- gvars3
はREADMEのバージョンのものをCVSでとってくる。
すべてPTAMをビルドしても動作しない。どうもV4L2の設定に失敗している模様。
そこで libcvd
の解析する progs
に video_play_source
というvideoテストプログラムがあるのでこれでテストする。
使い方:
./video_play_source -mono v4l2:///dev/video0
or
./video_play_source -rgb8 v4l2:///dev/video0
VIDIOC_S_FMT
が失敗して異常終了する。
そこで cvd_src/Linux/v4lbuffer.cc
を解析し V4L2Client
メソッドがYUYVをサポートしていないのを発見。
f.pixelformat == fourcc("YVU9") || + f.pixelformat == fourcc("YUYV"))) { actual_fmt = f.pixelformat; }
こんな感じでYUYVを加えると、とりあえず-monoで絵がでるようになった。ただしゴーストがでる。。
どうもformatの設定がおかしい。
formatはfmt変数が要求のformatでv4l2から検索し存在したら actual_fmt
にセットする。
ただし、grayscale(つまり-mono)では"422P", "YU12", "YV12", "411P", "YUV9", "YVU9"のいずれかを選択できる。
引数に-rgb8を指定するとfmt=RGB4になり、v4l2から探し出せないので actual_fmt
は None
になる。で VIDIOC_S_FMT
に失敗する。
そこで libcvd
をYUYVに対応させるかuvcを他のformatに対応させる必要がある。
animEffectのlinux対応
animEffectはOpenCVで取り込んだ画像に手描き風エフェクトをかけます。 ただ、これはWindows上でしかコンパイルできなかったので ちょいと修正しました。 http://www11.atwiki.jp/fiji?cmd=upload&act=open&pageid=119&file=animEffect2.tar.gz オリジナルはこっち http://www.purple.dti.ne.jp/~t-ogura/animeEffect
MicrodiaのdriverでYUYVがVIDIOC_S_FMTできない
ioctl
で VIDIOC_S_FMT
をセットするとerrno 22が返ってくるので調べてみた。
以下環境 - OS: Ubuntu 8.04 - Kernel: linux 2.6.24.22 - microdia driver: http://groups.google.com/group/microdia?hl=en - Groovy GR-CAM130N2 - ベンダーID及びプロダクトID 0c45:627b - Bridge : SN9C201 - Image Sensor : OV7660
まずはsystem callのioctl
を呼ぶとcallされるkernel内のv4lのioctl
関数を発見。
linux-source-2.6.24/drivers/media/video/videodev.c
433 static int __video_do_ioctl(struct inode *inode, struct file *file, 434 unsigned int cmd, void *arg) 435 {
VIDIOC_S_FMT
を ioctl
に渡すと以下のcase文にくる。どうも659行目が失敗しているかんじ。
647 case VIDIOC_S_FMT: 648 { 649 struct v4l2_format *f = (struct v4l2_format *)arg; 650 651 /* FIXME: Should be one dump per type */ 652 dbgarg (cmd, "type=%s\n", prt_names(f->type, 653 v4l2_type_names_FIXME)); 654 655 switch (f->type) { 656 case V4L2_BUF_TYPE_VIDEO_CAPTURE: 657 v4l_print_pix_fmt(vfd,&f->fmt.pix); 658 if (vfd->vidioc_s_fmt_cap) 659 ret=vfd->vidioc_s_fmt_cap(file, fh, f); 660 break;
vidioc_s_fmt_cap
は vfd
のメンバ変数なので調べてみる。以下の157目が呼ばれる。
84 struct video_device 85 { ・・・ 155 /* VIDIOC_S_FMT handlers */ 156 int (*vidioc_s_fmt_cap) (struct file *file, void *fh, 157 struct v4l2_format *f);
続いて microdia driver内のコードで vidioc_s_fmt_cap
に実体を代入している箇所を調べる。
microdia-v4l.c
1353 int v4l_microdia_register_video_device(struct usb_microdia *dev) 1354 { ・・・ 1382 dev->vdev->vidioc_s_fmt_cap = microdia_vidioc_s_fmt_cap;
v4l_microdia_register_video_device
関数内で microdia_vidioc_s_fmt_cap
を代入しているので実体を調べる。
1026 int microdia_vidioc_s_fmt_cap(struct file *file, void *priv, 1027 struct v4l2_format *fmt) 1028 { ・・・ 1042 ret = microdia_vidioc_try_fmt_cap(file, priv, fmt); 1043 if (ret) 1044 return -EINVAL;
1042行目があやしい・・
ついに、printk
を仕込み977行目で EINVAL
を返しているのを確認。どうもここが NULL
なのがダメみたい。
956 int microdia_vidioc_try_fmt_cap(struct file *file, void *priv, 957 struct v4l2_format *fmt) 958 { ・・・ 970 for (index = 0; index < dev->camera.nfmts; index++) 971 if (dev->camera.fmts[index].pix_fmt == fmt->fmt.pix.pixelformat) 972 break; 973 974 if (index >= dev->camera.nfmts) 975 return -EINVAL; 976 977 if (dev->camera.fmts[index].set_format == NULL) 978 return -EINVAL;
ちょっと fmts
の構造体を調べてみる。
microdia-dev.c
208 static struct microdia_video_format default_fmts[] = { 209 { ・・・ 243 { 244 .pix_fmt = V4L2_PIX_FMT_YUYV, 245 .desc = "YUV 4:2:2 (YUYV)", 246 .depth = 16, 247 .modes = { 248 {160, 120, SN9C20X_1_4_SCALE, 249 {0, 0, 1280, 480}, 250 {0, 0, 320, 120} }, 251 {320, 240, SN9C20X_1_2_SCALE, 252 {0, 0, 1280, 480}, 253 {0, 0, 640, 240} }, 254 {640, 480, SN9C20X_NO_SCALE, 255 {0, 0, 1280, 480}, 256 {0, 0, 1280, 480} }, 257 }, 258 .set_format = NULL 259 },
V4L2_PIX_FMT_YUYV
のところをみると .set_format
に NULL
が・・・。
これは絶対上記の977行目ではじかれるんじゃね?っと思いつつもう少しコードを読んでみるとどうも後から .set_format
をセットしてるような箇所を発見した。
262 int dev_microdia_assign_fmts(struct usb_microdia *dev) 263 { 264 int i, j; 265 266 dev->camera.fmts = default_fmts; 267 dev->camera.nfmts = ARRAY_SIZE(default_fmts); 268 269 for (i = 0; i < ARRAY_SIZE(default_fmts); i++) { 270 if (dev->camera.sensor->set_yuv422 != NULL) && 271 (dev->camera.fmts[i].pix_fmt == V4L2_PIX_FMT_YUYV) 272 dev->camera.fmts[i].set_format = 273 dev->camera.sensor->set_yuv422; 274 if (dev->camera.sensor->set_bayer != NULL) && 275 (dev->camera.fmts[i].pix_fmt == V4L2_PIX_FMT_SBGGR8) 276 dev->camera.fmts[i].set_format = 277 dev->camera.sensor->set_bayer; 278 for (j = 0; j < N_MODES; j++) { 279 dev->camera.fmts[i].modes[j].hw_window[0] = 280 dev->camera.sensor->hstart; 281 dev->camera.fmts[i].modes[j].hw_window[1] = 282 dev->camera.sensor->vstart; 283 } 284 } 285 286 return 0; 287 }
pix_fmt == V4L2_PIX_FMT_YUYV
なので pix_fmt == V4L2_PIX_FMT_YUYV
が存在していたら set_format
にセットするようなので sensor
変数を見てみた。
36 static struct sensor_info sensors[] = { ・・・ 76 { 77 .id = OV7660_SENSOR, 78 .name = "OV7660", 79 .address = 0x21, 80 .initialize = ov_initialize, 81 .set_exposure = ov7660_set_exposure, 82 .set_auto_gain = ov_set_autogain, 83 .hstart = 1, 84 .vstart = 1, 85 .get_yavg = ov965x_get_yavg, 86 .min_yavg = 30, 87 .max_yavg = 60, 88 .min_stable_yavg = 32, 89 .max_stable_yavg = 58, 90 },
set_format
がない。。つまり未定義なので NULL
。
ここまできてなんとなくわかったのはYUYVは基本的に未サポートでセンサーごとに実装するようなつくりになっているということ。
つまり、現段階ではOV7660のYUYVは未サポートでした。
(http://groups.google.com/group/microdia/web/project-status?hl=enのStatusはSupportedになっているのに。)
ちなみに以下の箇所をコメントアウトして動作させるとノイズだらけの映像が出力されたとさ
977 if (dev->camera.fmts[index].set_format == NULL) 978 return -EINVAL;