C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[3]: DirectShowでデスクトップのキャプチャーするには


(過去ログ 100 を表示中)

[トピック内 4 記事 (1 - 4 表示)]  << 0 >>

■59950 / inTopicNo.1)  DirectShowでデスクトップのキャプチャーするには
  
□投稿者/ ひろし (8回)-(2011/06/13(Mon) 20:17:48)

分類:[.NET 全般] 

OS:WindowsVista HomeEdition
開発言語:VB2010
PC:eMachine J3210

度々お世話になります。

現在、DirectShow を利用して、動画の再生、録画の機能を持ったアプリケーションを開発しています。
動画の再生、WEBカメラの映像をwmvに録画するところまでは、なんとか作る事ができました。

ですが、あと2点ほど、どうしても解決できない問題があります。

1.デスクトップの内容をwmv型式で録画する。

  正確には、フォームの TransparencyKeyプロパティーにて透過させた状態で、
  そのフォームに映っているものを録画できればと考えています。


2.wmv型式でのカメラの解像度及びビットレートを変更する。

  解像度については、録画の型式を avi にすると変更できました。
  しかし、wmv型式にすると変更できません。

  ↓変更できる
  result = _captureGraphBuilder.SetOutputFileName(MediaSubType.Avi, fileName, muxFilter, sinkFilter)
  ↓変更できない
  result = _captureGraphBuilder.SetOutputFileName(MediaSubType.Asf, fileName, muxFilter, sinkFilter)


  ビットレートについては、avi、wmv 共にできません。



以下が解像度及びビットレートを変更する関数の全体です。

------------------------------------------------------------------------
Private Sub SetConfigParms(ByVal iFrameRate As Integer, ByVal bitRate As Integer, ByVal iWidth As Integer, ByVal iHeight As Integer)
Dim hr As Integer

Dim IMyInterfaceAttribute As Attribute = Attribute.GetCustomAttribute(GetType(IAMStreamConfig), GetType(GuidAttribute))
Dim iid As Guid = New Guid(CType(IMyInterfaceAttribute, GuidAttribute).Value)
Dim o As Object = Nothing
Dim media As AMMediaType = Nothing
Dim videoStreamConfig As IAMStreamConfig
Dim videoControl As IAMVideoControl = DirectCast(_captureFilter, IAMVideoControl)

' Find the stream config interface
hr = _captureGraphBuilder.FindInterface(New DsGuid(PinCategory.Capture), New DsGuid(MediaType.Video), _captureFilter, iid, o)

videoStreamConfig = DirectCast(o, IAMStreamConfig)
Try
If (videoStreamConfig Is Nothing) Then
Throw New Exception("Failed to get IAMStreamConfig")
End If

'フォーマット取得
hr = videoStreamConfig.GetFormat(media)
DsError.ThrowExceptionForHR(hr)

'ビデオヘッダー取得
Dim vHeader As VideoInfoHeader = New VideoInfoHeader()
Marshal.PtrToStructure(media.formatPtr, vHeader)

'サンプルレート設定
If (iFrameRate > 0) Then
vHeader.AvgTimePerFrame = CLng(10000000 / iFrameRate)
End If
'ビットレート設定
If bitRate > 0 Then
vHeader.BitRate = bitRate
End If
'幅設定
If (iWidth > 0) Then
vHeader.BmiHeader.Width = iWidth
End If
'高さ設定
If (iHeight > 0) Then
vHeader.BmiHeader.Height = iHeight
End If

' Copy the media structure back
Marshal.StructureToPtr(vHeader, media.formatPtr, False)

' Set the new format
hr = videoStreamConfig.SetFormat(media)
DsError.ThrowExceptionForHR(hr)

DsUtils.FreeAMMediaType(media)
media = Nothing

' Fix upsidedown video
If (Not videoControl Is Nothing) Then
Dim pCapsFlags As VideoControlFlags

Dim pPin As IPin = DsFindPin.ByCategory(_captureFilter, PinCategory.Capture, 0)
hr = videoControl.GetCaps(pPin, pCapsFlags)
DsError.ThrowExceptionForHR(hr)

If (CLng(pCapsFlags & VideoControlFlags.FlipVertical) > 0) Then
hr = videoControl.GetMode(pPin, pCapsFlags)
DsError.ThrowExceptionForHR(hr)

hr = videoControl.SetMode(pPin, 0)
End If
End If
Finally
Marshal.ReleaseComObject(videoStreamConfig)
End Try
End Sub
------------------------------------------------------------------------

ご存知の方、よろしくお願いいたします。

引用返信 編集キー/
■60097 / inTopicNo.2)  Re[1]: DirectShowでデスクトップのキャプチャーするには
□投稿者/ ひろし (9回)-(2011/06/20(Mon) 19:54:49)
質問者のひろしです。

DirectShowを使ってデスクトップのレコーディングする方法が解決できなかった為
他の方法で対応することにしました。

http://www.adp-gmbh.ch/csharp/avi/write_avi.html

上記ののページを参考にデスクトップのレコーディングする部分は何とか出来ました。
音声の録音についてはDirectShowを使って、映像とは別々のファイル(avi)に出力し、

http://homepage1.nifty.com/nekora/soft/howto/avi.html

上記のページを参考にして、映像と音声を合成すると言う方法で解決しました。

しかし、またどうしても解決できない問題にぶつかってしまいました。
デスクトップの映像を録画する際に、何故か上下が反転してしまうのです。
原因をご存知の方、ご教授よろしくお願いいたします。

(最悪、bitmap を回転させて AddFram 関数を呼ぶことも考えています・・・)



private void CreateStream() {
AVISTREAMINFOW strhdr = new AVISTREAMINFOW();
strhdr.fccType = streamtypeVIDEO;
strhdr.fccHandler = _fccHandler_MP4V2;
strhdr.dwFlags = 0;
strhdr.dwCaps = 0;
strhdr.wPriority = 0;
strhdr.wLanguage = 0;
strhdr.dwScale = 1;
strhdr.dwRate = _frameRate; // Frames per Second
strhdr.dwStart = 0;
strhdr.dwLength = 0;
strhdr.dwInitialFrames = 0;
strhdr.dwSuggestedBufferSize = (uint)(_stride * _height);
strhdr.dwQuality = 0xffffffff; //-1; // Use default
strhdr.dwSampleSize = 0;
strhdr.rect_top = 0;
strhdr.rect_left = 0;
strhdr.rect_bottom = _height;
strhdr.rect_right = _width;
strhdr.dwEditCount = 0;
strhdr.dwFormatChangeCount = 0;
strhdr.szName0 = 0;
strhdr.szName1 = 0;
int hr = AVIFileCreateStream(_pFile, out _pStream, ref strhdr);

if (hr != 0) {
throw new AviException("AVIFileCreateStream");
}
}

unsafe private void SetOptions() {
int hr = 0;

AVICOMPRESSOPTIONS opts = new AVICOMPRESSOPTIONS();
opts.fccType = 0; //fccType_;
opts.fccHandler = _fccHandler_MP4V2; //fccHandler_;
opts.dwKeyFrameEvery = 0;
opts.dwQuality = 7500; // 0 .. 10000
opts.dwFlags = 8; // AVICOMRPESSF_KEYFRAMES = 4
opts.dwBytesPerSecond = 0;
opts.lpFormat = IntPtr.Zero;
opts.cbFormat = 0;
opts.lpParms = new IntPtr(5611280); // IntPtr.Zero;
opts.cbParms = 120;
opts.dwInterleaveEvery = 0;


// 圧縮方法選択ダイアログを表示する場合は以下のコメントをはずす
//AVICOMPRESSOPTIONS* p = &opts;
//AVICOMPRESSOPTIONS** pp = &p;
//IntPtr x = _pStream;
//IntPtr* ptr_ps = &x;
//AVISaveOptions(0, 0, 1, ptr_ps, pp);
//


// TODO: AVISaveOptionsFree(...)

hr = AVIMakeCompressedStream(out _psCompressed, _pStream, ref opts, 0);
if (hr != 0) {
throw new AviException("AVIMakeCompressedStream");
}

BITMAPINFOHEADER bi = new BITMAPINFOHEADER();
bi.biSize = 40;
bi.biWidth = (Int32)_width;
bi.biHeight = (Int32)_height;
bi.biPlanes = 1;
bi.biBitCount = 24;
bi.biCompression = 0; // 0 = BI_RGB
bi.biSizeImage = (uint)(_stride * _height);
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;

hr = AVIStreamSetFormat(_psCompressed, 0, ref bi, 40);
if (hr != 0) {
throw new AviException("AVIStreamSetFormat", hr);
}
}

public Bitmap Open(string fileName, UInt32 frameRate, int width, int height) {
_rect = new Rectangle(0, 0, width, height);
_frameRate = frameRate;
_width = (UInt32)width;
_height = (UInt32)height;

_bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb);
BitmapData bmpDat = _bmp.LockBits(_rect, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
_stride = bmpDat.Stride;
_bmp.UnlockBits(bmpDat);

AVIFileInit();
int hr = AVIFileOpenW(ref _pFile, fileName, 4097 /* OF_WRITE | OF_CREATE (winbase.h) */, 0);
if (hr != 0) {
throw new AviException("error for AVIFileOpenW");
}

CreateStream();

SetOptions();

return _bmp;
}

public void AddFrame() {

BitmapData bmpDat = _bmp.LockBits(_rect, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

int hr = AVIStreamWrite(
_psCompressed, _count, 1, bmpDat.Scan0, (int)(_stride * _height), 0, 0, 0);
//_pStream, _count, 1, bmpDat.Scan0, (int)(_stride * _height), 0, 0, 0);

if (hr != 0) {
throw new AviException("AVIStreamWrite");
}

_bmp.UnlockBits(bmpDat);

_count++;
}


引用返信 編集キー/
■60110 / inTopicNo.3)  Re[2]: DirectShowでデスクトップのキャプチャーするには
□投稿者/ やじゅ (1921回)-(2011/06/21(Tue) 03:07:38)
やじゅ さんの Web サイト
No60097 (ひろし さん) に返信
> デスクトップの映像を録画する際に、何故か上下が反転してしまうのです。
> 原因をご存知の方、ご教授よろしくお願いいたします。

BITMAPINFOHEADERのbiHeightの項を見ると、
ビットマップの高さをピクセル単位で指定する。biHeight の値が正である場合、ビットマップはボトムアップ DIB であり、左下隅が原点となる。
biHeight の値が負である場合、ビットマップはトップダウン DIB であり、左上隅が原点となる。

bi.biHeight = (Int32)_height * -1; と値を負にしてみるとか

「上下が反転 BITMAP」のキーワードで検索
引用返信 編集キー/
■60151 / inTopicNo.4)  Re[3]: DirectShowでデスクトップのキャプチャーするには
□投稿者/ ひろし (10回)-(2011/06/22(Wed) 01:20:38)
No60110 (やじゅ さん) に返信
> ■No60097 (ひろし さん) に返信
>>デスクトップの映像を録画する際に、何故か上下が反転してしまうのです。
>>原因をご存知の方、ご教授よろしくお願いいたします。
>
> BITMAPINFOHEADERのbiHeightの項を見ると、
> ビットマップの高さをピクセル単位で指定する。biHeight の値が正である場合、ビットマップはボトムアップ DIB であり、左下隅が原点となる。
> biHeight の値が負である場合、ビットマップはトップダウン DIB であり、左上隅が原点となる。
>
> bi.biHeight = (Int32)_height * -1; と値を負にしてみるとか
>
> 「上下が反転 BITMAP」のキーワードで検索

やじゅ様

回答いただきまして、ありがとうございます。

Height を使っている部分のいろんなところで、-1をかけて見ましたがダメでした。
「上下が反転 BITMAP」で検索もしてみたのですが、結局、解決できませんでした。orz

ひとまず、AddFrame する前に

_bmp.RotateFlip(RotateFlipType.Rotate180FlipX);

として、無理やり反転させて対応することにしましたが、
他になにか情報がありましたら、教えて頂けるとありがたいです。

よろしくお願いいたします。

引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -