SeeShark icon indicating copy to clipboard operation
SeeShark copied to clipboard

FFmpeg error with Logitech C925e

Open TJYSunset opened this issue 1 year ago • 2 comments

Initializing camera with default settings

When initializing the camera without an explicit format requirement, I get the following exception on calling TryGetFrame():

System.ApplicationException: End of file
   at SeeShark.FFmpeg.FFmpegHelper.ThrowExceptionIfError(Int32 error)
   at SeeShark.Decode.VideoStreamDecoder.TryDecodeNextFrame(Frame& nextFrame)
   at SeeShark.Device.VideoDevice.TryGetFrame(Frame& frame)
   at <MY CODE>

Soon the program would crash with another ApplicationException:

Unhandled exception. System.ApplicationException: Invalid data found when processing input
   at SeeShark.FFmpeg.FFmpegHelper.ThrowExceptionIfError(Int32 error)
   at SeeShark.Decode.VideoStreamDecoder.TryDecodeNextFrame(Frame& nextFrame)
   at SeeShark.Device.VideoDevice.TryGetFrame(Frame& frame)
   at SeeShark.Device.VideoDevice.DecodeLoop()
Initialization code
var cameraInfo = CameraManager.Devices.FirstOrDefault(
    x => x.Name?.Contains(cameraNameSegment) ?? false
);
if (ReferenceEquals(cameraInfo, null))
    return;
Camera = CameraManager.GetDevice(cameraInfo);
Camera.StartCapture();

Initializing with yuyv422 640x480

If I instead specify the format to be yuyv422 640x480 (I already dumped AvailableVideoInputOptions so I know for sure it's supported), GetDevice() will fail with the following:

System.ApplicationException: I/O error
   at SeeShark.FFmpeg.FFmpegHelper.ThrowExceptionIfError(Int32 error)
   at SeeShark.Decode.VideoStreamDecoder..ctor(String url, AVInputFormat* inputFormat, IDictionary`2 options)
   at SeeShark.Device.VideoDevice..ctor(VideoDeviceInfo info, DeviceInputFormat inputFormat, VideoInputOptions options)
   at SeeShark.Device.CameraManager.GetDevice(CameraInfo info, VideoInputOptions options)
   at <MY CODE>
Initialization code
Camera = CameraManager.GetDevice(
    cameraInfo,
    cameraInfo.AvailableVideoInputOptions!.First(
        x => x.InputFormat == "yuyv422" && x.VideoSize == (640, 480)
    )
);

Initializing with mjpeg 640x480

Interestingly, using mjpeg will throw a different exception:

System.ApplicationException: Invalid argument
   at SeeShark.FFmpeg.FFmpegHelper.ThrowExceptionIfError(Int32 error)
   at SeeShark.Decode.VideoStreamDecoder..ctor(String url, AVInputFormat* inputFormat, IDictionary`2 options)
   at SeeShark.Decode.VideoStreamDecoder..ctor(String url, DeviceInputFormat inputFormat, IDictionary`2 options)
   at SeeShark.Device.VideoDevice..ctor(VideoDeviceInfo info, DeviceInputFormat inputFormat, VideoInputOptions options)
   at SeeShark.Device.Camera..ctor(VideoDeviceInfo info, DeviceInputFormat inputFormat, VideoInputOptions options)
   at SeeShark.Device.CameraManager.GetDevice(CameraInfo info, VideoInputOptions options)
   at <MY CODE>
Initialization code
Camera = CameraManager.GetDevice(
    cameraInfo,
    cameraInfo.AvailableVideoInputOptions!.First(
        x => x.InputFormat == "mjpeg" && x.VideoSize == (640, 480)
    )
);

Initializing with yuyv422 1920x1080

... And if I use the full resolution the program crashes with a memory error...

Fatal error. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
   at FFmpeg.AutoGen.ffmpeg.av_read_frame(FFmpeg.AutoGen.AVFormatContext*, FFmpeg.AutoGen.AVPacket*)
   at SeeShark.Decode.VideoStreamDecoder.TryDecodeNextFrame(SeeShark.Frame ByRef)
   at SeeShark.Device.VideoDevice.TryGetFrame(SeeShark.Frame ByRef)
   at SeeShark.Device.VideoDevice.DecodeLoop()

Maybe another minor issue?

Also unrelated, but Microsoft officially discourages the use of ApplicationException.

Environment Info

Windows 11 22H2 (22621.963) Logitech C925e net7.0 with Microsoft.NET.Sdk.Web, AnyCPU or x64, Debug or Release prebuilt FFmpeg binaries from https://github.com/BtbN/FFmpeg-Builds/releases/download/autobuild-2023-05-23-12-46/ffmpeg-n5.1.3-10-g33ed503e59-win64-gpl-shared-5.1.zip or https://www.gyan.dev/ffmpeg/builds/packages/ffmpeg-5.1.2-full_build-shared.7z

TJYSunset avatar May 24 '23 02:05 TJYSunset

...Well that's really weird... A different error each time. And the error messages don't help.

I need to do something about it. I have no clue if I can fix this bug though. I still don't have any Windows installation.

Also thanks, didn't know they discouraged ApplicationException.

Speykious avatar May 24 '23 07:05 Speykious

For the time being, I switched to calling FFmpeg directly using rosenbjerg/FFMpegCore, and it works perfectly fine as long as I'm using their StreamPipeSink instead of implementing my own IPipeSink (which FFmpeg fails with av_interleaved_write_frame(): Invalid argument etc etc):

var args = FFMpegArguments
    .FromDeviceInput("video=\"Logitech Webcam C925e\"", a => a.ForceFormat("dshow"))
    .OutputToPipe(
        new StreamPipeSink(FrameStream),
        a =>
            a.WithVideoCodec("rawvideo")
                .ForceFormat("rawvideo")
                .WithCustomArgument("-pix_fmt rgb24")
                .WithVideoFilters(f => f.Scale(new Size(640, 480)))
                .WithFramerate(12)
    )
    .WithLogLevel(FFMpegLogLevel.Info);
Log.Information("{Args}", args.Arguments);
args.ProcessSynchronously();

The code above produces the following command line arguments:

-f dshow -i video="Logitech Webcam C925e" -c:v rawvideo -f rawvideo -pix_fmt rgb24 -vf "scale=640:480" -r 12 "\\.\pipe\FFMpegCore_4c4d8" -y

I know it's too vague but I'm exhausted to find the root cause myself, so hope this info somewhat helps?

Some quick Ctrl+LMB's:

  • They create named pipes as seen here
  • And call Stream.CopyToAsync() as seen here
    • My IPipeSink implementation calls Stream.ReadExactlyAsync() or Stream.ReadAsync() and won't work

TJYSunset avatar May 25 '23 03:05 TJYSunset