SIPSorceryMedia.FFmpeg icon indicating copy to clipboard operation
SIPSorceryMedia.FFmpeg copied to clipboard

Camera-specific Settings (Rsolution, FPS, & Oth. Decoder Options) for DirectShow

Open ha-ves opened this issue 6 months ago • 0 comments

May resolve #79.

Summary:

  • [x] DirectShow camera/input devices formats/options parsing from FFmpeg,
  • [x] Camera settings (video resolution, framerates, & other decoder-related options), It is added as an additional functions instead of in the constructor for simplicity,
    • (Simple) Restricts filter for formats to be used (pixel_format, resolution, & fps),
    • (Advanced) Restricts filter for device options to be used (specific to the input format),
    • (Pre-configured Advanced) Sets the device options manually which usually is a preconfigured set of options (specific to the input format),
  • [ ] Not yet tested for other input formats (avfoundation, v4l2, etc.), but they should be compatible by default.

A bit considerations:

  • [ ] Caches the found cameras? Because the backward compatibility will need to re-parse the FFmpeg output. But unless the backward compatibility users spawn multiple camera sources in a loop as fast as possible, I don't think it's worth it,
  • [ ] Though there is no confirmation on the actual resolution and framerate being used also no exception handle yet.

Additions:

  • New Camera properties
public class Camera
{
    // general purpose pixel_format structure
    public struct CameraFormat
    {
        public AVPixelFormat PixelFormat;
        public int Width;
        public int Height;
        public double FPS;
    }
    // formats from FFmpeg
    public List<CameraFormat>? AvailableFormats {  get; set; }

    // Other specific non-pixel_format (e.g. vcodec/etc.)
    public List<Dictionary<string, string>>? AvailableOptions { get; set; }
/// ... ///
}

  • New methods & constructor to FFmpegCameraSource with Camera:
public unsafe class FFmpegCameraSource : FFmpegVideoSource
{
    // Cameras now have formats, so get the camera object instead of only the path
    public FFmpegCameraSource(Camera camera) { /// ... /// }

    // Backward compatibility for providing only path is to re-enumerate the cameras to get the corresponding camera
    // and fallback to just the path
    public FFmpegCameraSource(string path) : this(FFmpegCameraManager.GetCameraByPath(path) ?? new() { Path = path }) { /// ... /// }

// Simple, filter from the generally available rawvideo formats
public void RestrictCameraFormats(Predicate<Camera.CameraFormat> formatFilter) { /// ... /// }

// Advanced, filter from all available format options
public void RestrictCameraOptions(Predicate<Dictionary<string, string>> optFilter) { /// ... /// }
/// ... ///
}
/// ... ///
public unsafe class FFmpegCameraManager
{
    // re-parse FFmpeg camera devices to "reverse lookup" for a path
    static public Camera? GetCameraByPath(string path) => GetCameraDevices()?.FirstOrDefault(x => x.Path == path);
    /// ... ///
}
  • New methods usage example
var localvid = new FFmpegCameraSource(FFmpegCameraManager.GetCameraDevices()!.First());
/// ... ///
// Simple, set the camera resolution to anything up to 480 with fps more than 15
localvid.RestrictCameraFormats(cam => cam.Width <= 480 && cam.Height <= 480 && cam.FPS >= 15);

// Advanced, set the decoder to use any vcodec=mjpeg option
localvid.RestrictCameraOptions(opts =>
{
    return opts.Keys.Contains("vcodec") && opts["vcodec"] == "mjpeg";
});

// Most advanced set the options manually, you probably know FFmpeg/libAV* enough to use this.
localvid.SetCameraDeviceOptions(new() { /// ... /// });

ha-ves avatar Aug 12 '24 23:08 ha-ves