radek-k / FFMediaToolkit

FFMediaToolkit is a cross-platform video decoder/encoder library for .NET that uses FFmpeg native libraries. It supports video frames extraction, reading stream metadata and creating videos from bitmaps in any format supported by FFmpeg.
MIT License
352 stars 56 forks source link

Cannot handle exception when extract frame and encode video #73

Open huyphamquang opened 3 years ago

huyphamquang commented 3 years ago

I use this package to do some video task like extract frame and remake video from frame image. My code sometime raise exception like below. I try to add try-catch block to handle it but no luck. Pls show me how to handle exception from ffmpeg lib.

Exception info: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt. at FFMediaToolkit.Decoding.Internal.InputContainer.ReadPacket() in C:\projects\ffmediatoolkit\FFMediaToolkit\Decoding\Internal\InputContainer.cs:line 174 at FFMediaToolkit.Decoding.Internal.InputContainer.GetPacketFromStream(Int32 streamIndex) in C:\projects\ffmediatoolkit\FFMediaToolkit\Decoding\Internal\InputContainer.cs:line 90 at FFMediaToolkit.Decoding.Internal.Decoder.DecodePacket() in C:\projects\ffmediatoolkit\FFMediaToolkit\Decoding\Internal\Decoder.cs:line 146 at FFMediaToolkit.Decoding.Internal.Decoder.ReadNextFrame() in C:\projects\ffmediatoolkit\FFMediaToolkit\Decoding\Internal\Decoder.cs:line 136 at FFMediaToolkit.Decoding.VideoStream.GetNextFrame() in C:\projects\ffmediatoolkit\FFMediaToolkit\Decoding\VideoStream.cs:line 51 at FFMediaToolkit.Decoding.VideoStream.TryGetNextFrame(ImageData& bitmap) in C:\projects\ffmediatoolkit\FFMediaToolkit\Decoding\VideoStream.cs:line 68

jrz371 commented 3 years ago

Can you provide a code snippet and the video file? It's a bit hard to tell what's going on from just this

huyphamquang commented 3 years ago

here is the source for extract frame:

`[HandleProcessCorruptedStateExceptions] [SecurityCritical] private void timerCallback(object state) { MediaFile file = null; long startTick = DateTime.Now.Ticks; try { //int duration = 1000 / Properties.Settings.Default.FrameProcess; if (PlayListInfo == null || PlayListInfo.Count == 0) return; int idx = 0; bool newVideo = true; TimeSpan endTime = new TimeSpan(); double time_4_frame_ms = 0; while (idx < PlayListInfo.Count && !request_stop) { var startProcess = DateTime.Now; var curVideo = PlayListInfo[idx]; bool firstFrame = false; if (newVideo) { if (file != null) file.Dispose(); startTick = DateTime.Now.Ticks; file = MediaFile.Open(curVideo.fileName); newVideo = false; endTime = curVideo.stopTime < 0 ? file.Info.Duration : TimeSpan.FromSeconds(curVideo.stopTime); if (!file.HasVideo) { Console.WriteLine($"Cannot load video file: {curVideo.fileName}"); } else { Console.WriteLine($"Process video: {curVideo.fileName}, frame rate: {file.Video.Info.AvgFrameRate}"); time_4_frame_ms = file.Video.Info.NumberOfFrames == null ? 0 : file.Video.Info.Duration.TotalMilliseconds / file.Video.Info.NumberOfFrames.Value; firstFrame = true; } } TimeSpan sp = new TimeSpan(DateTime.Now.Ticks - startTick); sp.Add(TimeSpan.FromSeconds(curVideo.startTime <= file.Info.StartTime.TotalSeconds ? file.Info.StartTime.TotalSeconds : curVideo.startTime)); ImageData img; if (sp > endTime) { idx++; newVideo = true; continue; } if (file != null && file.HasVideo) { var t1 = DateTime.Now; bool ck = false; if (firstFrame) { ck = file.Video.TryGetFrame(sp, out img); firstFrame = false; } else { do { ck = file.Video.TryGetNextFrame(out img); } while (ck && file.Video.Position < sp); } if (!ck) { Console.WriteLine($"Cannot read frame at {sp} of {curVideo.fileName}"); idx++; newVideo = true; continue; } else using (var bitmap = ToBitmap(img)) { var frametime = DateTime.Now - t1; //Console.WriteLine($"Take {frametime.TotalMilliseconds} to extract frame of {curVideo.fileName}"); // dataShare.WriteFrameData(img.ImageSize.Width, img.ImageSize.Height, //DataUtils.PixelFormatToBitCount(bitmap.PixelFormat), img.Data.ToArray()); if (checkBlankFrame(bitmap)) { Console.WriteLine($"Found black frame at {sp} of {curVideo.fileName}"); } else ProcessFrame(bitmap); } } var processTime = DateTime.Now - startProcess; //Console.WriteLine($"Process time of {curVideo.fileName}: {processTime.TotalMilliseconds}/ms"); int sleeptime = (int)(time_4_frame_ms - processTime.TotalMilliseconds); if (sleeptime > 0) System.Threading.Thread.Sleep(sleeptime); } } catch (AccessViolationException ex) { Console.WriteLine(ex.ToString()); } catch {

        }

        finally
        {
            if (file != null)
            {
                try
                {
                    file.Dispose();
                }
                catch
                {

                }
                file = null;
            }
        }

    }`

here is the source code for making video from bitmap: `private unsafe void PushFrame(Bitmap bitmap) { try { lock (this) { var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); try { int len = data.Stride * data.Height; byte[] bitmapData = new byte[len]; Marshal.Copy(data.Scan0, bitmapData, 0, len); if (frameList.Count == 0) startTime = DateTime.Now.Ticks; frameList.Add(bitmapData); } finally { bitmap.UnlockBits(data); } //ImageData data = VideoProcessEx.ToImageData(bitmap); //mediaFile.Video.AddFrame(data); TimeSpan sp = new TimeSpan(DateTime.Now.Ticks - startTime); if (sp.TotalSeconds >= Properties.Settings.Default.LiveVideoDuration) { if (frameList.Count == 0) return; videoCount++; videoIndex = videoCount % 10;

                    var settings = new VideoEncoderSettings(width: bitmap.Width, height: bitmap.Height,
                        framerate: (int)(frameList.Count / sp.TotalSeconds), codec: VideoCodec.H264);
                    settings.EncoderPreset = EncoderPreset.Fast;
                    settings.CRF = 17;
                    //settings.VideoFormat = ImagePixelFormat.Rgb24;
                    string path = $"{VideoFolder}\\{videoIndex}.{videoExt}";
                    using (var mediaFile = MediaBuilder.CreateContainer(path)/*.UseFormatOption("g", "10").UseFormatOption("movflags", "frag_keyframe+empty_moov")*/.WithVideo(settings).Create())
                    {
                        Console.WriteLine($"create video: {MappingFile}.{videoIndex}.{videoExt} -- duration: {sp.TotalSeconds}, total frame: {frameList.Count}");
                        foreach (var item in frameList)
                        {
                            Span<byte> imgData = new Span<byte>(item, 0, item.Length);
                            //return new ImageData(imgData, ImagePixelFormat.Rgb24, bitmap.Size);
                            mediaFile.Video.AddFrame(new ImageData(imgData, ImagePixelFormat.Bgr24, bitmap.Size));

                            //mediaFile.Video.Configuration.Framerate = (int)(mediaFile.Video.FramesCount / sp.TotalSeconds);
                        }
                        AddFileToPlayList(videoCount, $"{videoIndex}.{videoExt}", (decimal)sp.TotalSeconds);
                        //Task.Delay((int)(2) * 1000)
                        //    .ContinueWith((t) =>
                        //    {

                        //        AddFileToPlayList(videoCount, $"{videoIndex}.{videoExt}", (decimal)sp.TotalSeconds);
                        //    });
                    }
                    frameList.Clear();
                }
            }
        }
        catch(Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }
    }`
huyphamquang commented 3 years ago

my application process a list of video file and that exeption occur ramdom, i'm not sure about the reson but I only want to catch if it raise exception