SIPSorceryMedia.FFmpeg
SIPSorceryMedia.FFmpeg copied to clipboard
Camera-specific Settings (Rsolution, FPS, & Oth. Decoder Options) for DirectShow
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
withCamera
:
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() { /// ... /// });