自作液晶コントローラで動画再生(階調表示編)

## はじめに

こちらは鈴鹿高専 Advent Calendar 2021の3日目の記事です．

https://qiita.com/advent-calendar/2021/snct

注意事項としては，ここで記載されているコードを他のプロダクトでそのまま使うのは**禁止**とします．

何かバグがあっても責任を取れないためです．

また，実際に何かを制作する際には必ず一次情報(データシートなど)を参考にしてください．


## 作ったもの

https://twitter.com/LunaTsukinashi/status/1462500228750143491

自作液晶コントローラを利用して3階調で動画を再生できるようにしました．



## 概念

このデジット液晶には(S)TN液晶が使用されています．

みなさんのパソコンの画面は多くがTFT液晶だと思いますが，TN液晶は反応速度が遅く残像が残ります．

今回はこの残像を利用し，明るさに応じて点灯，消灯を制御し階調表示を実現しました．

下にイメージを示します．

![frm.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545164/fcc8ce92-c2d2-caa2-85c4-47216d361cb0.png)
出典:ELM(elm-chan.org)

## 改修

### コントローラ

従来の独自フォーマット4bit通信では明らかに速度が不足(必要な速度の半分程度)しているので通信フォーマットをより乱暴で速い手法に変更しました．

ここでもフォーマットの詳細は述べませんがコレにより単色表示時には約90fps相当の高速通信が可能になりました．

また，以前より高いフレームレートで駆動(単純に３倍の速度)させる必要があるため，液晶の表示更新まわりも高速化しました．

データシートの上限を遥かに上回っていますが，動作に問題がないことを確認しています．

マージンを食い潰すのは本当は良くないのでやめましょう(汗

無論，代償が伴いました．90fps表示をさせた際に走査線のようなものがうっすら見えてしまうようになりましたが問題なく見えるレベルなので無視します．

若干動作を高速化させるためにクロック供給まわりも変更，下のようになりました．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545164/eae21895-c62e-9ea7-10c3-7cb5cd135a95.png)

## ホストソフトウェア

今回もC#でソフトウェアを作成しました．
![2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545164/4e675a98-d7d4-e573-e7a0-e5fa67eb686f.png)

大きな変更点としてはディザリング処理をやめ，階調表示用のデータを生成するようにしました．

また，これまでは横着してシングルスレッドで処理していた変換をマルチスレッド対応にし単純にスレッド数倍の速度で処理が可能になりました．

GUIは個人的に使いにくかったためコンソールで操作します．

そして自分しか使わないのにUsageなんかもちゃんと書いています．
![a.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545164/fd1a4a18-87fc-b84a-6537-f40a96a06f6d.png)

開発環境もWin7+VisualStudio 2015に変更しましたが特に理由はありません．

例によってmp4を入力するだけで全自動でデータ生成から再生までやってくれる優れものです．

また，前回までは全てを表示したかったため縦方向に合わせてかなり小さい画面でしたが，見切れることを受け入れて全画面表示をしています．

以下に画像の変換処理を示します．

```cs
static void createData()
        {
            separateMovie();

            total = Directory.GetFiles(Path.GetFileNameWithoutExtension(inputFilePath), "*.png",SearchOption.TopDirectoryOnly).Length * 3;
            byte[] tmp = new byte[1920];
            buffers.AddRange(Enumerable.Repeat(tmp, total));

            object lockBmp = new object();
            object lockBuffer = new object();
            object lockCurrent = new object();

            Parallel.For(0, total, frame => {
                Bitmap bitmap;
                int bitpos = 0;
                int bytepos = 0;
                byte data = 0x00;

                lock (lockBmp)
                {
                    bitmap = new Bitmap(Path.GetFileNameWithoutExtension(inputFilePath) + "/image_" +((frame / 3)+1).ToString("D4") + ".png");
                }

                byte[] pixels = new byte[1920];

                for (int y = 0; y < 64; y++)
                {
                    for (int x = 0; x < 240; x++)
                    {
                            data <<= 1;
                            data |= (0.4 + 0.20 * (frame % 3) >= bitmap.GetPixel(x, y).GetBrightness()) ? (byte)1 : (byte)0;
                        bitpos++;
                            if(bitpos == 8)
                            {
                                pixels[bytepos++] = (data == 0x7F) ? (byte)0xFF : data;
                                bitpos = 0;
                            }
                    }
                }

                bitmap.Dispose();

                lock (lockBuffer)
                {
                    buffers[frame] = pixels;
                }

                lock (lockCurrent)
                {
                    current++;
                    if(current % 500 == 0)
                    {
                        showPercentage();
                    }
                }
            });
        
            System.IO.FileStream fs = new System.IO.FileStream(outputFilePath, System.IO.FileMode.Create, System.IO.FileAccess.Write);
            for (int index = 0; index < buffers.Count; index++)
            {
                fs.Write(buffers[index], 0,1920);
            }
            fs.Close();
        }
```

単純にピクセルごとの明るさをもとにデータを作成しています．

並列処理に関してもC#のParalellを使用することにより容易に実現ができました．



## テスト

https://twitter.com/LunaTsukinashi/status/1462787735857467392

https://twitter.com/LunaTsukinashi/status/1462787756099137544

うまく動いていますね．

## 終わりに

ジャンク部品でここまで楽しめるとは思っていませんでした．
データを生成するのは結局書いたプログラムなので，予想以上に綺麗に表示されて自分でも驚いています．