1

I am developing a chat application in WPF .NET Framework 4.7.2. I want to implement video recording functionality using the web camera of the PC. Up to now, I have done this: I use AForge.Video and AForge.Video.DirectShow to use the webcam and get the frames. Aforge creates a new thread for every frame. I'm receiving where I save the image and pass it on the UI thread to show the image.

 private void Cam_NewFrame(object sender, NewFrameEventArgs eventArgs)
        {
            //handle frames from camera
            try
            {
                //New task to save the bitmap (new frame) into an image
                Task.Run(() =>
                {
                    if (_recording)
                    {
                        
                        currentreceivedframebitmap = (Bitmap)eventArgs.Frame.Clone();
                        currentreceivedframebitmap.Save($@"{CurrentRecordingFolderForImages}/{imgNumber}-{guidName}.png", ImageFormat.Png);
                        imgNumber++;
                    }
                });
                //convert bitmap to bitmapImage to show it on the ui
                BitmapImage bi;
                CurrentFrame = new Bitmap(eventArgs.Frame);
                using (var bitmap = (Bitmap)eventArgs.Frame.Clone())
                {
                    bi = new BitmapImage();
                    bi.BeginInit();
                    MemoryStream ms = new MemoryStream();
                    bitmap.Save(ms, ImageFormat.Bmp);
                    bi.StreamSource = ms;
                    bi.CacheOption = BitmapCacheOption.OnLoad;
                    bi.EndInit();

                }
                bi.Freeze();
                Dispatcher.BeginInvoke(new ThreadStart(delegate
                {
                    imageFrames.Source = bi;
                }));
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

When the record finishes i take the image and make the video using ffmpeg.

 public static void ImagesToVideo(string ffmpegpath, string guid, string CurrentRecordingFolderForImages, string outputPath, int frameRate, int quality, int avgFrameRate)
        {
            
            Process process;
            process = new Process
            {

                StartInfo = new ProcessStartInfo
                {
                    FileName = $@"{ffmpegpath}",
                    //-r framerate , vcodec video codec, -crf video quality 0-51
                    Arguments = $@" -r {frameRate} -i {CurrentRecordingFolderForImages}\%d-{guid}.png -r {avgFrameRate} -vcodec libx264 -crf {quality} -pix_fmt yuv420p  {outputPath}",
                    UseShellExecute = false,
                    RedirectStandardOutput = true,
                    CreateNoWindow = true,
                    RedirectStandardError = true
                },
                EnableRaisingEvents = true,

            };
            process.Exited += ExeProcess_Exited;
            process.Start();

            string processOutput = null;
            while ((processOutput = process.StandardError.ReadLine()) != null)
            {
                //TO-DO handle errors
                Debug.WriteLine(processOutput);
            }
        }

For the sound i use Naudio to record it and save it

waveSource = new WaveIn();
            waveSource.StartRecording();
            waveFile = new WaveFileWriter(AudioFilePath, waveSource.WaveFormat);

            waveSource.WaveFormat = new WaveFormat(8000, 1);
            waveSource.DataAvailable += new EventHandler<WaveInEventArgs>(waveSource_DataAvailable);
            waveSource.RecordingStopped += new EventHandler<StoppedEventArgs>(waveSource_RecordingStopped);

private void waveSource_DataAvailable(object sender, WaveInEventArgs e)
        {
            if (waveFile != null)
            {
                waveFile.Write(e.Buffer, 0, e.BytesRecorded);
                waveFile.Flush();
            }
        }

and then ffmpeg again to merge video with sound

public static void AddAudioToVideo(string ffmpegpath, string VideoPath, string AudioPath, string outputPath)
        {
            _videoPath = VideoPath;
            _audioPath = AudioPath;
            Process process;

            process = new Process
            {

                StartInfo = new ProcessStartInfo
                {
                    FileName = $@"{ffmpegpath}",
                    Arguments = $" -i {VideoPath} -i {AudioPath} -map 0:v -map 1:a -c:v copy -shortest {outputPath} -y",
                    UseShellExecute = false,
                    RedirectStandardOutput = true,
                    CreateNoWindow = true,
                    RedirectStandardError = true
                },
                EnableRaisingEvents = true,

            };
            process.Exited += ExeProcess_Exited;
            process.Start();

            string processOutput = null;
            while ((processOutput = process.StandardError.ReadLine()) != null)
            {
                // do something with processOutput
                Debug.WriteLine(processOutput);
            }

        }

Questions:

  1. Is there a better approach to achieve what im trying to do?
  2. My camera has 30 fps capability but i receive only 16 fps how could this happen?
  3. Sometimes video and sound are not synchronized.

i created a sample project github.com/dinos19/WPFVideoRecorder

  • There are a few things you could do to improve performance. It seems pointless to call `eventArgs.Frame.Clone()` when you could directly use `CurrentFrame`. Instead of decoding and encoding a BMP frame, you could write the raw pixels of CurrentFrame into the buffer of a WriteableBitmap, which you would assign only once to the Source property of the Image element. See e.g. here: https://stackoverflow.com/q/30727343/1136211 – Clemens Aug 02 '22 at 11:29
  • I followed your example but im still getting low number of fps and the cpu usage is high, i created a small sample project to take a look https://github.com/dinos19/WPFVideoRecorder – Kostas Kontaras Aug 04 '22 at 10:07
  • If your program still has performance issues, consider using a professional SDK like LEADTOOLS Multimedia. (Disclosure: I work for its vendor). The SDK has controls and classes for capturing from audio and video devices, recording to disk, streaming and videoconferencing and many others. It can be used with WPF as explained [here]https://leadtools.com/support/forum/posts/m42831-#post42831). There’s a [free evaluation here](https://leadtools.com/downloads) which includes documentation, sample code projects and free technical support. – Amin Dodin Sep 22 '22 at 20:54

0 Answers0