情報アイランド

「情報を制する者は世界を制す」をモットーに様々な情報を提供することを目指すブログです。現在はプログラミング関連情報が多めですが、投資関連情報も取り扱っていきたいです。

動画のサムネイルを作成

DirectShowを使って動画のサムネイルを作ります。

.NET環境でDirectShowを利用するためにDirectShow.NETを使いました。

GDI+のBitmapクラスとWPFのBitmapSourceクラスでは作り方が違います。

デフォルトではBitmapSourceクラスを返すようになっていますが、Bitmapクラスを返すようにしたい場合はコメントアウトしてある方を使ってください。

public static class ThumbnailCreator2
{
    public static BitmapSource GetThumbnail(string _videoFileName, int _wait)
    {
        IGraphBuilder graphBuilder = null;
        ISampleGrabber sampleGrabber = null;
        IBaseFilter sampleGrabberFiltter = null;
        IMediaControl mediaControl = null;
        IMediaEvent mediaEvent = null;
        IVideoWindow videoWindow = null;

        VideoInfoHeader videoInfoHeader = null;

        BitmapSource bitmapSource = null;

        try
        {
            //DirectXのチェック
            if (!DsUtils.IsCorrectDirectXVersion())
                throw new Exception("DirectX 8.1以上がインストールされていません。");

            Type comType = null;
            object comObject = null;
            try
            {
                //グラフビルダーを生成
                comType = Type.GetTypeFromCLSID(Clsid.FilterGraph);
                if (comType == null)
                    throw new NotImplementedException("DirectShow FilterGraphがインストールまたは登録されていません。");
                comObject = Activator.CreateInstance(comType);
                graphBuilder = (IGraphBuilder)comObject;
                comObject = null;

                //サンプルグラバーを生成
                comType = Type.GetTypeFromCLSID(Clsid.SampleGrabber);
                if (comType == null)
                    throw new NotImplementedException("DirectShow SampleGrabberがインストールまたは登録されていません。");
                comObject = Activator.CreateInstance(comType);
                sampleGrabber = (ISampleGrabber)comObject;
                comObject = null;

                videoWindow = (IVideoWindow)graphBuilder;
                mediaEvent = (IMediaEvent)graphBuilder;
                sampleGrabberFiltter = (IBaseFilter)sampleGrabber;
                mediaControl = (IMediaControl)graphBuilder;
            }
            catch (Exception ex)
            {
                throw new Exception("初期化に失敗しました。", ex);
            }
            finally
            {
                if (comObject != null)
                {
                    Marshal.ReleaseComObject(comObject);
                    comObject = null;
                }
            }

            int hResult;
            try
            {
                //サンプルグラバーを接続するフォーマットを指定
                AMMediaType amMediaType = new AMMediaType();
                amMediaType.majorType = MediaType.Video;
                amMediaType.subType = MediaSubType.RGB24;
                amMediaType.formatType = FormatType.VideoInfo;
                hResult = sampleGrabber.SetMediaType(amMediaType);
                DsUtils.FreeAMMediaType(amMediaType);
                if (hResult < 0)
                    Marshal.ThrowExceptionForHR(hResult);

                //グラフにサンプルグラバーフィルターを追加
                hResult = graphBuilder.AddFilter(sampleGrabberFiltter, "Ds.NET Sample Grabber");
                if (hResult < 0)
                    Marshal.ThrowExceptionForHR(hResult);

                //グラフを生成
                hResult = mediaControl.RenderFile(_videoFileName);
                if (hResult < 0)
                    Marshal.ThrowExceptionForHR(hResult);

                //接続情報取得
                amMediaType = new AMMediaType();
                hResult = sampleGrabber.GetConnectedMediaType(amMediaType);
                if (hResult < 0)
                    Marshal.ThrowExceptionForHR(hResult);
                if ((amMediaType.formatType != FormatType.VideoInfo) || (amMediaType.formatPtr == IntPtr.Zero))
                    throw new NotSupportedException("不明なフォーマットです。");
                videoInfoHeader = (VideoInfoHeader)Marshal.PtrToStructure(amMediaType.formatPtr, typeof(VideoInfoHeader));
                DsUtils.FreeAMMediaType(amMediaType);

                //グラブを行うことを設定
                hResult = sampleGrabber.SetBufferSamples(true);
                if (hResult < 0)
                    Marshal.ThrowExceptionForHR(hResult);

                //画像を1枚だけ取得して停止状態にするよう設定する
                hResult = sampleGrabber.SetOneShot(true);
                if (hResult < 0)
                    Marshal.ThrowExceptionForHR(hResult);

                //ダミーパネルの作成
                Panel dummyPanel = new Panel();
                //ダミーパネルの中に表示
                hResult = videoWindow.put_Owner(dummyPanel.Handle);
                if (hResult < 0)
                    Marshal.ThrowExceptionForHR(hResult);

                //再生開始
                hResult = mediaControl.Run();
                if (hResult < 0)
                    Marshal.ThrowExceptionForHR(hResult);

                //待機
                Thread.Sleep(_wait);

                //バッファを確保
                int bufferSize = amMediaType.sampleSize;
                byte[] buffer = new byte[bufferSize];
                IntPtr pBuffer = Marshal.AllocCoTaskMem(bufferSize);
                try
                {
                    //現在(1フレーム目)の静止画を取得
                    hResult = sampleGrabber.GetCurrentBuffer(ref bufferSize, pBuffer);
                    if (hResult < 0)
                        Marshal.ThrowExceptionForHR(hResult);
                    Marshal.Copy(pBuffer, buffer, 0, bufferSize);
                }
                catch (Exception)
                {
                    throw new Exception();
                }
                finally
                {
                    //バッファを解放
                    Marshal.FreeCoTaskMem(pBuffer);
                    pBuffer = IntPtr.Zero;
                }

                //幅・高さ・一行当たりのバイト数(ストライド)
                int width = videoInfoHeader.BmiHeader.Width;
                int height = videoInfoHeader.BmiHeader.Height;
                int stride = videoInfoHeader.BmiHeader.BitCount / 8 * width;

                //ビットマップ生成
                //BitmapSourceクラスを生成する場合
                bitmapSource = BitmapSource.Create(width, height, 96, 96, PixelFormats.Rgb24, null, buffer, stride);

                //Bitmapクラスを生成する場合
                /*GCHandle GcHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
                IntPtr scan0 = (IntPtr)(GcHandle.AddrOfPinnedObject().ToInt32() + (height - 1) * stride);
                bitmap = new Bitmap(width, height, -stride, PixelFormat.Format24bppRgb, scan0);
                GcHandle.Free();*/
            }
            catch (Exception ex)
            {
                throw new Exception("失敗しました。", ex);
            }
        }
        catch (Exception)
        {
        }
        finally
        {
            //リソースを解放
            if (sampleGrabber != null)
            {
                Marshal.ReleaseComObject(sampleGrabber);
                sampleGrabber = null;
            }
            if (graphBuilder != null)
            {
                Marshal.ReleaseComObject(graphBuilder);
                graphBuilder = null;
            }
        }

        return bitmapSource;
    }
}
pizyumi
プログラミング歴19年のベテランプログラマー。業務システム全般何でも作れます。現在はWeb系の技術を勉強中。
スポンサーリンク

-C#, DirectShow