without meaning

組み込み系SIerのメモ。

GV-USB2/HQとOBSStudioでVHSビデオのデータ化を行う

一度断捨離した時にやりたいと思ってやれてなかったVHSのデータ化を実施。
これで心置きなくVHSを捨てられる。。
ググると、「GV-USB2/HQ」というUSB接続ビデオキャプチャーの情報をよく見かけるが、そのせいか少し高騰気味なので本体のみの中古を購入。
そのため、新品購入時に付属している動画編集ソフト(PowerDirector)は使わず、フリーソフトであるOBSStudioを使用してデータ化を実施した。
備忘録を残す。

1. 事前準備

前提

  • S-VHSは持っていないので対象外。

必要なハードウェア

  • GV-USB2/HQ
    • 今高騰気味なので、中古を購入するのも手。
  • ビデオデッキ(再生できればなんでもOK)
    • 自分が使ったのはこれ。これをメルカリでGV-USB2/HQと一緒にセット売りしてくれている出品者様がいたのでそちらを購入
  • RCAオスーオスケーブル
    • GV-USB2/HQがUSB(TypeA)-RCAメス端子のため、ビデオデッキとGV-USB2/HQを繋げるRCAオス-オスケーブルが必要。

必要なソフトウェア

  • GV-USB2/HQのドライバ Ver1.12
  • OBSStudio Ver29.13
    ※どちらも2023/08時点での最新を使用。特にバージョンにこだわりなし。

2. ソフトのインストール

2.1. GV-USB2/HQのドライバのインストール

以下のリンクからダウンロード可能。
ソフトウェア | サポートライブラリ | IODATA アイ・オー・データ機器

ダウンロードには製品のシリアル番号が必要なので、本体に記載しているシリアル番号を入力するとダウンロード可能。

インストールはダウンロード後、ファイルを実行してウィザード通り進めるだけのため省略

2.2. OBSStudioのインストール

以下のリンクからダウンロード可能。こちらもインストールはウィザード通り進めるだけのため省略
ダウンロード | OBS

3. データ化手順

3.1. ビデオデッキとGV-USB2/HQとPCを接続する

以下の流れで接続する。

  • ビデオデッキ(外部出力) - RCAオスオスケーブル - GV-USB2/HQ - PC

3.2. OBSStudioを起動して録画設定を行う

  • ソースの設定
    ソース項目の「+」を押して、映像キャプチャデバイスを選択する

    以下の画面は特に何も触らずOKを押す

    以下の画面ではデバイスを「GV-USB2」になっていることを確認する。
    それ以外は弄らなくてOK。
    ※スクショが映像キャプチャデバイス2になってるのは、気にしないでよい。
  • 音声ミキサー
    初期設定では、録画中、パソコンから流れる音やマイクの声も録画に入ってしまうため、
    それぞれボリュームアイコンを押して「デスクトップ音声」と「マイク」をミュートにする。

    こうする

  • 録画設定
    「ファイル」タブから「設定」を押す。

    出力設定で、録画品質を「配信と同じ」、録画フォーマットを「MPEG-4(.mp4)」に選択してOKを押す。
    ※録画ファイルのパスはスクショでは記載削除しているが既定値のままだとビデオフォルダになっているはず。

  • その他
    再生画面は、元々こんな感じになってると思うので、後述の手順を踏み、実際の再生画面を見ながら
    適宜サイズを調整する

    自分はこんな感じにしてた

3.3. ビデオデッキに録画したいVHSを入れる

表題通り。録画の先頭に巻き戻されていることの確認を忘れないように。

3.4. OBSStudioのコントロール項目の録画開始を押す

表題通り。

3.5. ビデオデッキの再生ボタンを押す

表題通り。

3.6. 再生終了後、OBSStudioのコントロール項目の録画終了を押す

表題通り。ビデオの停止も忘れずに。

備考

音声ミキサーの歯車アイコンを押すと、「オーディオの詳細プロパティ」ダイアログが表示される。
そちらの音声モニタリング設定を変更することで録画中の音の確認が可能

モニターオフ:パソコン上で音を聞かず、録画を進める。
モニターのみ(出力はミュート):パソコン上では音が聞けるが、録画中にこれを選択しちゃうと音が録音できていないので注意。
モニターと出力:パソコン上で音を聞きつつ、録画も可能。音を聞いておきたい場合はこちらを選択。

(個人的な)WindowsGUIアプリのアーキテクチャ選択早見表

自分用に記載しているので、詳細は参考に貼ったリンク参照で。

クロスプラットフォームは意識していないため、QtやElectronは除外

 

項目名 Win32アプリ Windowフォーム WPF UWP
プログラミング言語 C/C++ C# C# C++/WinRT、C#
特徴 OS制御をWin32APIを通して
かなり自由に行うことができる。
画面の描画は面倒
ポチペタで画面作成できるので、
単純なGUIアプリなら簡単に作成可能。
Win32APIはラッパーを通して使用可能
C#なのでテストやソフトウェア開発に便利な機能は
揃っている。
Win32アプリ程ではないが、リッチUIの作成は
面倒くさい。
XAMLを使うことでリッチUIの作成が比較的簡単
しかし、UWPと違い、UI部品自体は揃っていないため自作する必要がある。
C#なのでテストやソフトウェア開発に便利な機能は揃っている。
Windowフォーム同様、Win32APIはラッパーを通して使用可能
UWPとWin32APIの間を取ったような存在
Win10で使用できるUI部品が
たくさん作られており、オシャレなUIが
作りやすい。
反面、Win32APIを呼べないため、
OS制御は不自由。
インストールも基本的にMicrosoftストアから
ダウンロードしないといけないなど結構面倒
MS一押し。
アーキテクチャ M+VC M+VC MVVM MVVM
(個人的に)
どんな時に選択するか
他装置と通信する、組み込みWindowsアプリなど、
リアルタイム性が要求される場合や
OS単位での制御が必要となる場合
※組み込み(FA系など)製品はタクトタイムが存在するので、
 ガベコレが働く言語は選択されづらい。
ツール作成

密にリアルタイム性が求められない場合の
中規模〜大規模アプリケーション作成

OS制御が不要でリッチなUIが必要な場合
※個人のPCに入れるようなBtoCアプリ作成時など

 

なお、Windows10 1903以降は、XamlIslandsという技術によって、

Win32アプリやWindowフォーム・WPFでもUWPのオシャレなUI部品が使用できるらしい。

 発表されて間もないので、知見が少ないが使いこなせると良さそう。

 

参考:

 

docs.microsoft.com

docs.microsoft.com

 

qiita.com

littlewing.hatenablog.com

 

 

パッケージ設計の原則

パッケージ内の凝集度に関する原則

再利用・リリース等価の原則(REP)

再利用の単位とリリースの単位は等価になる。

ライブラリを提供している作者に対して、使用者が求めること

  • 保守の保証。ライブラリのテストはしたくない。
  • 古いバージョンのサポートも対応してほしい

ライブラリは、それを再利用する人の視点に立って構造化する必要がある。

  • 1つのパッケージ内に入れるクラスは、同じ対象者によって再利用されるものに統一したい。
    • コンテナライブラリと、会計処理フレームワークが同一のパッケージにあっても、大体どちらか一つしか使わないよね。
  • パッケージ内のクラスは全て再利用可能なものか、全て再利用できないものかのどちらかに統一すべき。
    • 再利用可能なクラスのパッケージに、再利用できないクラスが存在しているとノイズでしかない。

全再利用の原則(CRP)

パッケージに含まれるクラスはすべて一緒に再利用される。つまりパッケージに含まれるいずれかのクラスを再利用するということは、その他のクラスも全て再利用することを意味する。

  • 互いに強い関連性を持たないクラスを、同じパッケージにまとめるべきではない。
  • パッケージを採用するときは、そこに含まれるすべてのクラスに依存することを確認する。
  • また、自分でパッケージを作るときも、あるパッケージに1つにまとめるクラスは互いに分離できない関係になるように、また、ユーザーがパッケージから抵抗されるすべてのクラスに依存しなければならないように設計する。

閉鎖性共通の原則(CCP)

パッケージに含まれるクラスは、皆同じ種類の変更に対して閉じているべきである。パッケージに影響する変更はパッケージ内のすべてのクラスに影響を及ぼすが、他のパッケージには影響しない。

  • 単一責務の原則のパッケージ版。パッケージも変更の理由を複数持っていてはいけない。
  • 変更箇所が1 つのパッケージにしておけば、再リリースは変更されたパッケージで済む。
  • 開放閉鎖の原則と密接な関係がある。同じ理由で修正されるクラスは一つのパッケージにしておく。そうすることで、ソフトウェアの再評価、再リリースに掛かる負担を最小限に抑えることができる。

パッケージ内の原則結論

  • パッケージ内には、極力同じ理由で修正されるクラスを一つのパッケージにしておくこと
  • パッケージは再利用予定のクラス一覧と、再利用予定が無いクラス一覧で分割する。

パッケージ間の結合度に関する原則

非循環依存関係の原則(ADP)

パッケージ依存グラフに循環を持ち込んではならない

  • 中規模以上のプロジェクトになると、規約を守らない開発チームの場合、誰もが、誰かが行った最後の変更を使ってコードが動くように変更を重ねてしまう。そのため、安定したバージョンのプロジェクトをビルドすることが出来ない。

これに対する対処法が「ウィークリービルド」と「非循環依存関係の原則」

  • ウィークリービルド
    • 週に一度結合ビルドする日を設けて、それ以外の日は意識せず開発を行う。
    • この作業の仕方では、規模が大きくなるにつれてどうしても結合する時間が大きくなっていく。
  • 非循環依存関係の原則
    • 開発環境をリリース可能なパッケージに分割する。開発者たちがそれぞれを独立して開発できるようにする。
    • 注意点:パッケージを循環させない。相互依存させない。
    • 循環してしまってると:
      • 依存関係逆転の原則を適用して、上位モジュールは下位モジュールが用意するインタフェースを使用する。下位モジュールは、これまで上位モジュール部品を使用してしまっていた箇所をインタフェース化により、実体を持つことがなくなるため上位モジュールへの依存がなくなる。
      • 且つ、必要であれば、上位モジュール・下位モジュールが両方とも依存するようなパッケージを新たに追加して、両方が依存するクラスをこの新しいパッケージに移行する。
    • パッケージ構造はトップダウン設計で行うのは不可能。クラスの設計もできていないのに、パッケージ設計は難しい。この段階では、何に対して共通な閉鎖性をもたせるのかわからないし、再利用する要素についても気づかない。

結論

  • 依存関係逆転の原則適用を意識する。
  • パッケージは開発初期から必要以上に分割せず、再利用したい要素がわかってきたり、どの部分のクラスをパッケージ化するかわかってきた時に分割する。

安定依存の原則(SDP)

安定する方向に依存せよ。

変更すること意識して作られたパッケージが、変更が難しいパッケージに依存されるような立場になってはならない。

変更することを意識して作られたはずのパッケージまで変更が難しくなるため。

  • 安定性は変更の回数とは直接無関係。
  • 安定しているとは容易に動かないことである。
  • パッケージ全てが安定している必要はない。変更することができなくなってしまうため。
    • 不安定なパッケージと安定したパッケージが混在しているのが理想的なパッケージ構造
    • 不安定なパッケージは上位レベルのパッケージにする。下位レベルのパッケージはユーティリティ的な汎用クラスを置く。
    • 上位レベルのパッケージが安定してしまうと、設計が固まってしまう=柔軟性がなくなり、改造しにくい状態になる。

結論

  • 依存関係逆転の原則を適用する
  • 安定性を保ちつつ、変更に耐える柔軟性を持たせるには開放閉鎖の原則を適用する。
    • 修正を加えずに拡張することができる状態を作る。=インタフェースを用意する。

安定度・抽象度等価の原則(SAP)

パッケージの抽象度と安定度は同程度でなければならない。

  • パッケージを安定させる場合、パッケージはインタフェースで構成されるべきである。
    • 拡張できるようにするため
  • 不安定なパッケージに具体的なコードを記載する。

パッケージ間の原則結論

  • 安定度・抽象度等価の原則と安定依存の原則をまとめると、パッケージ版の依存関係逆転の原則となる。
    • 安定依存の原則は依存関係が安定する方向に依存することを主張
    • 安定度・抽象度等価の原則は安定するということは抽象化されていることを意味する。
  • 安定性と抽象度は測定する事ができる。

安定性

I = Ce / (Ca + Ce)

I:不安定度(0〜1の値を取る。0に近いほど安定したパッケージ。1に近いほど不安定なパッケージとなる。)

Ca:内側に向かう結合度(このパッケージの外にあり、このパッケージの中にあるクラスに依存するクラスの数)

Ce:外側に向かう結合度(このパッケージの中にあり、このパッケージの外にあるクラスに依存するクラスの数)

抽象度

A = Na / Nc

A:抽象度(0〜1の値を取る。0はパッケージが抽象クラスを全く持たないことを意味する。1はパッケージが抽象クラスしか持たないことを意味する)

Na:パッケージ中の抽象クラスの数。抽象クラスとは、最低一つの純粋インタフェースを持ち、インスタンス化出来ないクラスのこと。

Nc:パッケージ中のクラスの数

インタフェース分離の原則(ISP)

インタフェース分離の原則とは

  • クライアントに、クライアントが利用しないメソッドへの依存を強制してはならない。

利用しないメソッドに依存してしまうと、クライアントはそういったメソッドの変更の影響を受けやすくなってしまう。=無駄にテストする必要が出てくる。

分離方法

  • 委譲を使って分離する方法
  • インタフェースを多重継承して分離する方法

基本は委譲を使って分離したほうが良いかな。

単一形式(Monad)よりも複数形式(Polyad)

複数形式の場合、同じインスタンスを複数回渡す事があるかもしれないが、

それでも、不必要なインタフェースを渡してしまう可能性がある単一形式よりも範囲を制限できる複数形式の方が良い。

InterfaceSoup アンチパターン

  • インタフェースを集約(複数継承)して、インターフェイスを作成しても、なんの意味もないのでやめる

結論

単一責務の原則に似ているが、インタフェースを太くしないということが重要。
クライアントごとに特化したインタフェースを用意する。
委譲を使用する場合と複数継承使用する場合の判断がまだ曖昧だが、
基本は委譲を使用して、親子関係にすべきと判断したものを多重継承にしたら良いと思う。

依存性反転の原則(DIP)

依存性反転の原則とは

  • 上位のモジュールは下位のモジュールに依存してはならない。どちらのモジュールも「抽象」に依存するべきである。
  • 「抽象」は実装の詳細に依存してはならない。実装の詳細が「抽象」に依存するべきである

上位モジュールに依存しない場合のメリットとして、

パターン

  • Poor Man's Dependency Injection
    • アプリケーションのエントリポイントに近い場所で、具象クラスをまとめて注入する(合成ルート)
      • コードが読みやすい=依存関係がわかりやすい
      • インターフェースが入れると具象クラス入れる作業が単純作業で多くなる。
    • コンストラクタ注入
      • 多々使用する依存関係の場合はコンストラクタで注入する
    • メソッド注入
      • 一部メソッドでしか使用しない場合は、メソッドで注入する
    • プロパティ注入
      • 実行時にプロパティ変更したい場合はプロパティで注入する
  • IoCコンテナ(制御の反転)
    • DIコンテナで依存関係のクラスの認識を自動で行う。
      • Registerでリストに具象クラス追加
      • Resolveでリスト内の具象クラスをインターフェースの継承先として自動で判別させる。
      • Releaseでインスタンス開放
      • Disposeはアプリケーション終了時に呼ばれる
  • 宣言型の登録
    • 実体をXMLに記載して、コードでXML読みこむ。そうすることで、実行時に読む実体を切り替えることができる
    • ただし、記載がすごく多くなってしまう。
    • また、タイポなどは実行時までわからない
  • Service Locatorアンチパターン
  • Illegitimate Injectionアンチパターン
    • コンストラクタの引数で、インターフェースに実体注入できるようになっていても、引数なしのコンストラクタで、デフォルト設定用の実体クラス生成している場合がある。それをしてしまうと、結局依存してしまってることになるので全く意味がない。
  • 規約手法
    • DIコンテナを使って、明示的にインスタンス名を記載せずに完全に自動で依存関係を判断させる方法
        • binフォルダに格納されているアセンブリに含まれるクラスを全て登録
        • それらのクラスを、クラスの名前とマッチするインターフェースにマッピング

結論

結局は、他の原則で作成したインターフェースの実体をどこで作るかという話。

簡単なソフトウェアなら、「PoorMan'sDI」を使用し、複雑でインスタンスが増大しているソフトウェアなら「規約」

を使用すれば良い。

参照

アジャイルソフトウェア開発の奥義
C#実践開発手法

リスコフの置換原則(LSP)

リスコフの置換原則とは

- 派生クラスは、その基本クラスと置き換え可能でなければならない。継承関係を作成するためのガイドラインの集まり。
- でないとクライアントは、RTTI(キャスト)と条件分岐を使用して、その派生クラスのみ通る処理を用意しないといけないが、それは開放閉鎖の原則に違反することが多い。
- こちらも、インターフェース・ジェネリックを使用して、原則を守る。

経験則と約束事

- 基本クラスと派生クラスで置き換え可能にするため、派生クラスで事前条件の追加・事後条件の緩和を行わない。
    - 事前条件とは入力値チェック、事後条件とは出力値チェック
- 不変条件は維持しなければならない。
    - 基底クラスのコンストラクタ以降、値が読み取り専用のメンバ変数の場合、派生クラスでも引き継ぐ必要がある。
- 派生型の戻り値の型には共変性がなければならない
    - 共変性:戻り値の型がクラス型の参照かポインタで、かつis-a関係にあるものは、戻り値が異なっていてもオーバーライド可能
- 派生型のメソッドの引数には反変性がなければならない。
    - 反変性:引数の型がクラス型の参照かポインタで、かつis-a関係にあるものは、引数が異なっていてもオーバーライド可能
  • 基本クラスで出来ていたことが、派生クラスで出来ないようになっていてはいけない
  • 派生クラスで例外処理を追加してはいけない。(基本クラスよりも制約を増やしてはいけない)

結論

  • 派生クラスで公開メソッドを追加しない。クライアント側で呼ばれると、基本クラスと置き換えできなくなるため。
  • 派生クラスで例外処理を追加しない。基本クラスでは許可された動きが派生クラスで禁止されてしまうことになるため。 とりあえず、上記2点を意識すれば良いと思われる。

参考:
アジャイルソフトウェア開発の奥義

C#実践開発手法

開放/閉鎖の原則(OCP)

開放/閉鎖の原則とは

  • 拡張に対して開かれている
  • 修正に対して閉じている
  • ★既存のコードはできる限り触らず、クラスのメンバ変数やインターフェイスの派生クラス追加などで対応できるように設計すること。
  • 閉じたモジュールであっても、閉じることのできない変更が必ずある。つまり、全てのケースに適用できる自然なモデルなど存在しない。
  • そのために、「先を見越した構造」と「自然な構造」を検討する必要がある。
    • この機能は今後、修正の余地がないから閉じている必要がない。
    • この機能はコア機能で、今後とも機能追加を行いたいから、修正に対して閉じていたほうが良い。など。。
  • また、抽象化自体がソフトウェアの可読性を下げる可能性もあるため、やりすぎに注意

結論

結論と言いつつ、書けない。。 ドメイン知識を理解して、どこを修正しやすくするべきか判断して、
インタフェース・ジェネリックを使用すれば良いと思う。。

例えば、リスト内の要素別の処理も、リスト数分のforループを行い、リスト内の要素をSwitch文で一々判断するという仕組みであれば、
逐次、新しい要素が追加されるたびに、Switch文の条件を追加する必要があるが、
インタフェース 型をforeachで回すような処理にしておけば、逐次Switch文の条件を追加する必要がなくなる。

参考:
アジャイルソフトウェア開発の奥義

C#実践開発手法