静止画とAVI動画保存
概要
動画ファイルを作成しながら、静止画を撮影する方法を説明します。通常MediastreamSinkを使用している場合、画像保存のためのコールバックを並列に持つことはできません。別スレッドにて画像保存を行うため、FrameFilterを使用しています。IC Imaging ControlではFrameFilterだけが二つのシンクを制御する唯一の方法です。
サンプルプログラム
Software | IC Imaging Control 3.5, Visual Studio™ 2019 |
---|---|
サンプル(C#) | Image_And_AVI_Capture_cs_3.5.zip |
サンプルツールの外観
グローバル変数を宣言
private FrameFilter _saveImageFrameFilter;
通常ICImagingControlでは動画保存と静止画保存を同時に行う事はできませんが、このサンプルではJPEGファイル保存を行う特別なフレームフィルタを使用する事で動画保存しながら静止画保存できるようになっています。FrameFilterクラスの_saveImageFrameFilterを定義し、静止画保存フィルタへのアクセスできるようにしています。
Formをロード(各コントローラーを初期化、フィルタの読み込み)
private MediaStreamSink _aviSink;
private void Form1_Load(object sender, EventArgs e)
{
_aviSink = new MediaStreamSink();
//
foreach (AviCompressor codec in AviCompressor.AviCompressors)
{
comboBox1.Items.Add(codec);
if (codec.Name == "DV Video Encoder")
{
_aviSink.Codec = codec;
comboBox1.SelectedIndex = comboBox1.FindStringExact("DV Video Encoder");
}
}
_saveImageFrameFilter = FrameFilter.Create("Save Image");
if (_saveImageFrameFilter == null)
{
MessageBox.Show($"Failed to load the \"Save Image\" frame filter!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
icImagingControl1.DeviceFrameFilters.Add(_saveImageFrameFilter);
cboMediaStreamContainer.DataSource = TIS.Imaging.MediaStreamContainer.MediaStreamContainers;
try
{
icImagingControl1.LoadDeviceStateFromFile("device.xml", true);
_aviSink.Filename = System.IO.Path.ChangeExtension($"{icImagingControl1.Device.ToString()}.avi", CurrentMediaStreamContainer.PreferredFileExtension);
}
catch
{
// xmlファイルの読み込み、接続したカメラを開くのに失敗した時の処理
}
if (m_bFitImageToWindow)
{
// ライブ表示のサイズをフォームのサイズに調整する
icImagingControl1.LiveDisplayDefault = false;
icImagingControl1.LiveDisplaySize = icImagingControl1.Size;
}
//GUI上のボタンの有効化/無効化を制御
UpdateControls();
}
MediaStreamSinkのシンクを使って録画をするため、【_aviSink = new MediaStreamSink】で録画するためのシンクを宣言します。File AVIのコンボボックスには利用可能な全MediaStreamContainerを、Video CodecのコンボボックスにAVIコンプレッサ(ビデオコーデック)のコレクションを追加し、コンボボックスから選択できるようにしています。
これとは別に、ICImagingControlの追加機能として静止画保存するフィルタを使うため、アプリケーションパスにある"Save Image" フィルタ を【_saveImageFrameFilter = FrameFilter.Create("Save Image")】で読み込みます。この"Save Image" フィルタはC++にて作成した静止画保存するライブラリで、アプリケーションと同じフォルダ内にあるSaveImageFrameFilter64.ftf(32bitの場合、SaveImageFrameFilter32.ftf)を参照しています。ftfファイルを読み込み後、DeviceFrameFiltersのコレクションに"Save Image" フィルタを追加することで、静止画保存の機能をICImagingControlに実装することができます。
[Start Live]ボタンをクリック(録画開始)
private void StartLiveVideo()
{
_aviSink=new TIS.Imaging.MediaStreamSink(CurrentMediaStreamContainer, CurrentVideoCodec, System.IO.Path.ChangeExtension($"{icImagingControl1.Device.ToString()}.avi", CurrentMediaStreamContainer.PreferredFileExtension) );
_aviSink.SinkModeRunning = !checkBoxAVIPause.Checked;
icImagingControl1.Sink = _aviSink;
icImagingControl1.LiveStart();
//GUI上のボタンの有効化/無効化を制御
UpdateControls();
}
ライブ開始時にリングバッファに取りためる数を変数_FramesToCapture(フレームレート×3)で計算しておく。
[AVI Pause]チェックボックス
private void checkBoxAVIPause_CheckedChanged(object sender, EventArgs e)
{
icImagingControl1.Sink.SinkModeRunning = !icImagingControl1.Sink.SinkModeRunning;
}
[Pause]ボタンはチェックボックスをクリックした時には、SinkModeRunningをFalseにすることで画像ストリームのシンクパスのみが停止され、録画を一時停止することができます。ライブ画像は表示されますが、ビデオファイルとして保存はされません。SinkModeRunningをTrueにすることで、前に作成されたAVIファイルが引き続き使用されます。
[Snap]ボタンをクリックしたとき
private void buttonSnap_Click(object sender, EventArgs e)
{
if(_saveImageFrameFilter != null && icImagingControl1.DeviceValid && icImagingControl1.LiveVideoRunning)
{
imageCounter++;
string imageFileName = String.Format("Image{0}.jpg",imageCounter);
_saveImageFrameFilter.SetStringParameter("ImageName", imageFileName);
}
}
アプリケーションフォームのボタンによって静止画像を保存できるようにするため、ボタンのハンドラーbuttonSnap_Clickを追加します。
Form1_Loadのイベントハンドラーで静止画保存がデバイスフレームフィルタ_saveImageFrameFilterとして設定されています。_saveImageFrameFilterを呼び出すにはSetStringParameterを使用します。第一引数にはパラメータ "ImageName"を、第二引数にはファイルのパスを指定します。_saveImageFrameFilter が別スレッドでイメージを保存することができるので、動画ファイルをとりながら静止画保存することができます。