Access raw video stream from Webcam - DirectShow, C# - c#

I'm trying to build a video conference desktop software using DirectShow.Net libraries
I have been able to preview the live footage on a panel locally.
Now I need this raw data feed to go over the network.
Sorry for the noob question but I cannot figure how to get access to this feed.
Code so far:
public partial class Form1 : Form
{
private LiveJob job;
private LiveDeviceSource livedevicesource;
private bool startedrecording;
List<object> lstVideoDevices = new List<object>(10);
List<object> lstAudioDevices = new List<object>(10);
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
foreach (EncoderDevice edv in EncoderDevices.FindDevices(EncoderDeviceType.Video)) {
lstVideoDevices.Add(edv.Name);
label1.Text=label1.Text+" "+ edv.Name;
}
foreach (EncoderDevice eda in EncoderDevices.FindDevices(EncoderDeviceType.Audio))
{
lstVideoDevices.Add(eda.Name);
label2.Text = label2.Text + " " + eda.Name;
}
}
private void btnStartPreview_Click(object sender, EventArgs e)
{
EncoderDevice video = EncoderDevices.FindDevices(EncoderDeviceType.Video).ElementAt(1);
EncoderDevice audio = EncoderDevices.FindDevices(EncoderDeviceType.Audio).ElementAt(0);
if (video == null)
{
return;
}
job = new LiveJob();
if (video != null && audio != null) {
livedevicesource = job.AddDeviceSource(video, audio);
livedevicesource.PickBestVideoFormat(new Size(640,480), 15);
SourceProperties sourceprop = livedevicesource.SourcePropertiesSnapshot();
pnlVideoUs.Size = new Size(sourceprop.Size.Width, sourceprop.Size.Height);
//This line here sets panel as the preview window
livedevicesource.PreviewWindow = new PreviewWindow(new HandleRef(pnlVideoUs, pnlVideoUs.Handle));
job.ActivateSource(livedevicesource);
}
}

I need this raw data feed
Have a look at \Samples\Capture\DxLogo sample coming with DirectShow.NET:
A sample application showing how to superimpose a logo on a data stream. It uses
a capture device for the video source, and outputs the result to a file.
Nevertheless the sample's main goal is a bit different, it features access to raw video data:
int ISampleGrabberCB.BufferCB( double SampleTime, IntPtr pBuffer, int BufferLen )
{
// ...
CopyMemory(ipDest, ipSource, (uint)m_bmdLogo.Stride);

Related

How can i extract frames from video using directshowlib-2005?

With this code i can play video files from my hard disk and show the video in pictureBox1. But i wonder how can i save all the frames of the video to images files on the hard disk ? While playing the video or without playing i need somehow to extract the frames and save them.
This is my used code so far:
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
IGraphBuilder m_graphBuilder = null;
IMediaControl m_mediaCtrl = null;
IMediaEventEx m_mediaEvt = null;
IMediaPosition m_mediaPos = null;
IMediaSeeking m_mediaSeeking = null;
public Form1()
{
InitializeComponent();
}
void InitInterfaces()
{
try
{
m_graphBuilder = (IGraphBuilder)new FilterGraph();
m_mediaCtrl = (IMediaControl)m_graphBuilder;
m_mediaEvt = (IMediaEventEx)m_graphBuilder;
m_mediaPos = (IMediaPosition)m_graphBuilder;
m_mediaSeeking = (IMediaSeeking)m_graphBuilder;
}
catch (Exception)
{
MessageBox.Show("Couldn't start directshow graph");
}
}
void CloseInterfaces()
{
if (m_mediaCtrl != null)
{
m_mediaCtrl.StopWhenReady();
}
m_mediaCtrl = null;
m_mediaEvt = null;
m_mediaPos = null;
m_mediaSeeking = null;
if (m_graphBuilder != null)
Marshal.ReleaseComObject(this.m_graphBuilder);
m_graphBuilder = null;
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void SetuupVideoRenderer()
{
IBaseFilter vmrFilter = null;
vmrFilter = (IBaseFilter)new VideoMixingRenderer();
m_graphBuilder.AddFilter(vmrFilter, "Video Renderer");
IVMRFilterConfig FilterConfig = (IVMRFilterConfig)vmrFilter;
FilterConfig.SetRenderingMode(VMRMode.Windowless);
IVMRWindowlessControl windowlessCtrl = (IVMRWindowlessControl)vmrFilter;
windowlessCtrl.SetVideoClippingWindow(this.pictureBox1.Handle);
windowlessCtrl.SetVideoPosition(null, DsRect.FromRectangle(pictureBox1.ClientRectangle));
windowlessCtrl.SetAspectRatioMode(VMRAspectRatioMode.LetterBox);
}
private void buttonLoad_Click(object sender, EventArgs e)
{
openFileDialog1.Filter = "All Files (*.*)|*.*|mp4 (*.mp4)|*.mp4|mov (*.mov)|*.mov||";
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
CloseInterfaces();
InitInterfaces();
SetuupVideoRenderer();
m_graphBuilder.RenderFile(openFileDialog1.FileName, null);
textBoxDur.Text = ( getDuration() * 0.0000001).ToString();
m_mediaCtrl.Run();
timer1.Enabled = true;
}
}
private void GetPosition(out long CurrentPos,out long StopPos)
{
m_mediaSeeking.GetPositions(out CurrentPos, out StopPos);
}
private long getDuration()
{
long duration;
m_mediaSeeking.GetDuration(out duration);
return duration;
}
private void SetPos(double fPos)
{
DsLong startPosition = (DsLong)(10000000 * fPos);
m_mediaSeeking.SetPositions(startPosition, AMSeekingSeekingFlags.AbsolutePositioning, null, AMSeekingSeekingFlags.NoPositioning);
}
private void buttonPause_Click(object sender, EventArgs e)
{
m_mediaCtrl.Pause();
}
private void buttonPlay_Click(object sender, EventArgs e)
{
m_mediaCtrl.Run();
}
private void OnVideoCompleted()
{
MessageBox.Show("Video Playback Completed");
}
private void timer1_Tick(object sender, EventArgs e)
{
long iCurPos, iStopPos;
GetPosition(out iCurPos, out iStopPos);
if (iCurPos >= iStopPos)
{
timer1.Enabled = false;
OnVideoCompleted();
return;
}
textBoxCurPos.Text = (iCurPos * 0.0000001 ).ToString();
}
private void buttonGo_Click(object sender, EventArgs e)
{
SetPos(Convert.ToDouble(textBoxNewPos.Text));
timer1.Enabled = true;
}
}
}
I think this is excatly what you are looking for:
extract frames of a video
Have a look as well at this SO question and the links provided on this webpage.
The easiest way to do it is indeed using an FFMPEG, since its alredy includes some of the most common codecs (if you dont mind extra 30+Mb added to your app). As for wrappers, i used AForge wrapper in the past and really liked it, because of how simple it is to work with. Here is an example from its docs:
// create instance of video reader
VideoFileReader reader = new VideoFileReader();
// open video file
reader.Open( "test.avi");
// read 100 video frames out of it
for ( int i = 0; i < 100; i++)
{
Bitmap videoFrame = reader.ReadVideoFrame();
videoFrame.Save(i + ".bmp")
// dispose the frame when it is no longer required
videoFrame.Dispose( );
}
reader.Close();

Windows form, display dynamic google map instead of static map in .NET

I am trying to display a dynamic google map on a windows form in .NET
I have succeeded in implementing a windows form asking a request on google map as followed :
public Form1()
{
InitializeComponent();
}
private void find_data_Click_1(object sender, EventArgs e)
{
string street = txt_street.Text;
string city = txt_city.Text;
try
{
StringBuilder queryaddress = new StringBuilder();
queryaddress.Append("http://maps.google.com/maps?q=");
if (street != string.Empty)
{
queryaddress.Append(street + "," + "+");
}
if (city != string.Empty)
{
queryaddress.Append(city + "," + "+");
}
webBrowser1.Navigate(queryaddress.ToString());
}
catch
{
MessageBox.Show("Error");
}
}
Then I succeeded in having a staticmap with google api with multiple markers doing this :
private void button2_Click(object sender, EventArgs e)
{
try
{
StringBuilder queryaddress = new StringBuilder();
queryaddress.Append("https://maps.googleapis.com/maps/api/staticmap?center=63.259591,-144.667969&zoom=6&size=400x400&markers=color:blue%7Clabel:S%7C62.107733,-145.541936&markers=size:tiny%7Ccolor:green%7CDelta+Junction,AK&markers=size:mid%7Ccolor:0xFFFF00%7Clabel:C%7CTok,AK&key=myApiKey");
webBrowser1.Navigate(queryaddress.ToString());
}
catch
{
MessageBox.Show("Error");
}
}
What I would like to have is the same output as the staticmap with multiple markers but with the interaction offers as in google map like in the first code portions.
I use to code with R and python, using the library leaflet to ease the implementation.
I don't know how to do multiple plot markers on interactive maps in C#.
I finally found a turnkey solution with tutorials at this address :
http://www.independent-software.com/gmap-net-tutorial-maps-markers-and-polygons/

How transfer system mic audio stream to attached device mic audio stream

I am trying to attach USB device used for tele calling which have pnp sound controller for mic and speaker. Now i have two speaker and two mic for input output as shown in image below.. Now my motive is to transfer audio stream from system mic to usb mic and from usb speaker to system speaker.
I tried to solve this issue with virtual cable software but with this i need to depend on third party. What can be the possible solution that can attained using c#.
I don't have knowledge about this, so don't know how to start. After googling i found
CS Core
N Audio
Can help me i don't know how.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
List<NAudio.Wave.WaveInCapabilities> sources = new List<NAudio.Wave.WaveInCapabilities>();
for (int i = 0; i < NAudio.Wave.WaveIn.DeviceCount; i++)
{
sources.Add(NAudio.Wave.WaveIn.GetCapabilities(i));
}
sourceList.Items.Clear();
foreach (var source in sources)
{
ListViewItem item = new ListViewItem(source.ProductName);
item.SubItems.Add(new ListViewItem.ListViewSubItem(item, source.Channels.ToString()));
sourceList.Items.Add(item);
}
}
NAudio.Wave.WaveIn sourceStream,sourceStream1 = null;
NAudio.Wave.DirectSoundOut waveOut = null;
private void button2_Click(object sender, EventArgs e)
{
if (sourceList.SelectedItems.Count == 0) return;
int deviceNumber = sourceList.SelectedItems[0].Index;
sourceStream = new NAudio.Wave.WaveIn();
sourceStream.DeviceNumber = 0;
sourceStream.WaveFormat = new NAudio.Wave.WaveFormat(44100, NAudio.Wave.WaveIn.GetCapabilities(deviceNumber).Channels);
NAudio.Wave.WaveInProvider waveIn = new NAudio.Wave.WaveInProvider(sourceStream1);
sourceStream.
waveOut = new NAudio.Wave.DirectSoundOut();
waveOut.Init(waveIn);
sourceStream1.StartRecording();
waveOut.Play();
}
private void button3_Click(object sender, EventArgs e)
{
if (waveOut != null)
{
waveOut.Stop();
waveOut.Dispose();
waveOut = null;
}
if (sourceStream != null)
{
sourceStream.StopRecording();
sourceStream.Dispose();
sourceStream = null;
}
}
private void button4_Click(object sender, EventArgs e)
{
button3_Click(sender, e);
this.Close();
}
}
Using this code i can send mic audio to speaker but how can i implement my task using this.
Actually there is no way to do this without writing any custom driver. You can not render audio data to a input device. Input devices are meant to read data from. Output devices (speakers) are meant to write data to.
There are programs like virtual audio cable, which are using custom drivers to bypass these limitations.

C# Add WMP dynamically to form (currently: audio playing, not showing video)

I'm trying to load the WindowsMediaPlayer control dynamically, but I can't get it to work properly.
The code as is, seems to play the audio (and probably video) but does not show the video on the form. The form keeps blank and the audio is playing. (playing a WVM file, cant be encoder issue) I'm importing the WMPLib.
WindowsMediaPlayer videoPlayer;
public void createContent(Form form) {
PlayFile("F:\\Videos\\CantTouchThis.wmv");
}
private void PlayFile(string url) {
videoPlayer = new WindowsMediaPlayer();
videoPlayer.PlayStateChange +=
new WMPLib._WMPOCXEvents_PlayStateChangeEventHandler(Player_PlayStateChange);
videoPlayer.MediaError +=
new WMPLib._WMPOCXEvents_MediaErrorEventHandler(Player_MediaError);
videoPlayer.URL = url;
videoPlayer.controls.play();
}
private void Player_PlayStateChange(int NewState) {
if ((WMPLib.WMPPlayState)NewState == WMPLib.WMPPlayState.wmppsStopped) {
}
}
private void Player_MediaError(object pMediaObject) {
MessageBox.Show("Cannot play media file.");
}
Help with getting this to work would be highly appreciated.
I've found the solution. Here it is for anyone who ever needs it in the future.
The code is:
private static AxWMPLib.AxWindowsMediaPlayer wmPlayer;
public static void AddMediaPlayer(Form form1) {
Button b1 = new Button();
b1.Text = "Button";
try {
wmPlayer = new AxWMPLib.AxWindowsMediaPlayer();
((System.ComponentModel.ISupportInitialize)(wmPlayer)).BeginInit();
wmPlayer.Name = "wmPlayer";
wmPlayer.Enabled = true;
wmPlayer.Dock = System.Windows.Forms.DockStyle.Fill;
form1.Controls.Add(wmPlayer);
((System.ComponentModel.ISupportInitialize)(wmPlayer)).EndInit();
// After initialization you can customize the Media Player
wmPlayer.uiMode = "none";
wmPlayer.URL = #"C:\ProjectSilver\assets\RadarDetectie\general\inlog_confirm.ogv";
wmPlayer.Ctlcontrols.play();
}
catch { }
Don't forget to import the library AxWMPLib.
After this you'll need to add [STAThread] on top of your class, otherwise you will get an exception.
Goodluck!

Capture Sound from microphone using Directx DirectSound

I am creating a simple application that records input from the microphone and store it into array of bytes. So I have searched a lot about this and eventually ended up using Directx DirectSound. Here is the code I am using:
using Microsoft.DirectX;
using Microsoft.DirectX.DirectSound;
private Thread CaptureSoundThread = null;
public CaptureBuffer applicationBuffer = null;
private SecondaryBuffer soundBuffer = null;
private Device soundDevice = null;
private void Form1_Load(object sender, EventArgs e)
{
soundDevice = new Device();
soundDevice.SetCooperativeLevel(this, CooperativeLevel.Normal);
// Set up our wave format to 44,100Hz, with 16 bit resolution
WaveFormat wf = new WaveFormat();
wf.FormatTag = WaveFormatTag.Pcm;
wf.SamplesPerSecond = 44100;
wf.BitsPerSample = 16;
wf.Channels = 1;
wf.BlockAlign = (short)(wf.Channels * wf.BitsPerSample / 8);
wf.AverageBytesPerSecond = wf.SamplesPerSecond * wf.BlockAlign;
int samplesPerUpdate = 512;
// Create a buffer with 2 seconds of sample data
BufferDescription bufferDesc = new BufferDescription(wf);
bufferDesc.BufferBytes = samplesPerUpdate * wf.BlockAlign * 2;
bufferDesc.ControlPositionNotify = true;
bufferDesc.GlobalFocus = true;
soundBuffer = new SecondaryBuffer(bufferDesc, soundDevice);
}
private void button1_Click(object sender, EventArgs e)
{
CaptureSoundThread = new Thread(new ThreadStart(WaitThread));
CaptureSoundThread.Start();
}
private void WaitThread()
{
while (true)
{
byte[] CaptureData = null;
CaptureData = (byte[])applicationBuffer.Read(0,
typeof(byte), LockFlag.None);
soundBuffer.Write(0, CaptureData, LockFlag.None);
// Start it playing
soundBuffer.Play(0, BufferPlayFlags.Looping);
}
}
But when I try to run the application, I get this annoying error:
BadImageFormatException
Could not load file or assembly 'Microsoft.DirectX.DirectSound.dll' or one
of its dependencies. is not a valid Win32 application. (Exception from
HRESULT: 0x800700C1)
I actually had to download the Microsoft.DirectX.DirectSound.dll from the internet because I couldn't find them in the Visual Studio assemblies.
EDIT : I JUST SOLVED THAT by reading this article : http://www.codeproject.com/Articles/383138/BadImageFormatException-x86-i-x64
EDIT : I JUST SOLVED THAT by reading this article : http://www.codeproject.com/Articles/383138/BadImageFormatException-x86-i-x64

Categories