FFMediaToolkit
FFMediaToolkit copied to clipboard
Cannot handle exception when extract frame and encode video
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
Can you provide a code snippet and the video file? It's a bit hard to tell what's going on from just this
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());
}
}`
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