Skip to content

Commit

Permalink
Merge branch 'develop' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
kekyo committed Jun 9, 2023
2 parents 1900c85 + 7a9289c commit 6ced3c3
Show file tree
Hide file tree
Showing 16 changed files with 126 additions and 69 deletions.
2 changes: 1 addition & 1 deletion FSharp.FlashCap/FSharp.FlashCap.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

<ItemGroup>
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="All" />
<PackageReference Update="FSharp.Core" Version="6.0.0" />
<PackageReference Update="FSharp.Core" Version="5.0.0" />
</ItemGroup>

<ItemGroup>
Expand Down
6 changes: 6 additions & 0 deletions FlashCap.Core/CaptureDeviceDescriptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ internal async Task<CaptureDevice> InternalOnOpenWithFrameProcessorAsync(
FrameProcessor frameProcessor,
CancellationToken ct)
{
if (characteristics.PixelFormat == PixelFormats.Unknown)
{
throw new ArgumentException(
$"FlashCap: Couldn't use unknown pixel format: {characteristics} ({characteristics.RawPixelFormat})");
}

using var _ = await this.locker.LockAsync(ct);

try
Expand Down
6 changes: 2 additions & 4 deletions FlashCap.Core/Devices/V4L2Devices.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,9 @@ private static IEnumerable<v4l2_fmtdesc> EnumerateFormatDesc(
fmtdesc.type = (uint)v4l2_buf_type.VIDEO_CAPTURE;
return
ioctl(fd, Interop.VIDIOC_ENUM_FMT, fmtdesc) == 0 &&
IsKnownPixelFormat(fmtdesc.pixelformat) ?
(v4l2_fmtdesc?)fmtdesc : null;
ioctl(fd, Interop.VIDIOC_ENUM_FMT, fmtdesc) == 0 ? (v4l2_fmtdesc?)fmtdesc : null;
}).
ToArray(); // Important: Iteration process must be continuous, avoid ioctl calls with other requests.
ToArray(); // Important: Iteration process must be continuous, avoid ioctl calls with other requests.

private struct FrameSize
{
Expand Down
32 changes: 13 additions & 19 deletions FlashCap.Core/Internal/NativeMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@ public static string GetFourCCString(int fourcc)
bool isDiscrete = true,
string? rawPixelFormat = null)
{
static PixelFormats? GetRGBPixelFormat(int clrBits) =>
static PixelFormats GetRGBPixelFormat(int clrBits) =>
clrBits switch
{
8 => PixelFormats.RGB8,
Expand All @@ -479,10 +479,10 @@ public static string GetFourCCString(int fourcc)
16 => PixelFormats.RGB15,
24 => PixelFormats.RGB24,
32 => PixelFormats.ARGB32,
_ => null,
_ => PixelFormats.Unknown,
};
if (compression switch

var pixelFormat = compression switch
{
Compression.BI_RGB => GetRGBPixelFormat(clrBits),
Compression.RGB2 => GetRGBPixelFormat(clrBits),
Expand All @@ -498,21 +498,15 @@ public static string GetFourCCString(int fourcc)
Compression.UYVY => PixelFormats.UYVY,
Compression.YUYV => PixelFormats.YUYV,
Compression.YUY2 => PixelFormats.YUYV,
_ => null,
} is { } pixelFormat)
{
return new VideoCharacteristics(
pixelFormat, width, height,
framesPerSecond,
compression.ToString(),
isDiscrete,
rawPixelFormat ?? GetFourCCString((int)compression));
}
else
{
Trace.WriteLine($"FlashCap: Unknown format: Compression={compression}, [{width},{height}], {framesPerSecond}");
return null;
}
_ => PixelFormats.Unknown,
};

return new VideoCharacteristics(
pixelFormat, width, height,
framesPerSecond,
compression.ToString(),
isDiscrete,
rawPixelFormat ?? GetFourCCString((int)compression));
}

public static unsafe VideoCharacteristics? CreateVideoCharacteristics(
Expand Down
20 changes: 8 additions & 12 deletions FlashCap.Core/Internal/NativeMethods_V4L2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -288,20 +288,16 @@ public struct utsname
string description,
bool isDiscrete)
{
if (pixelFormats.TryGetValue(pix_fmt, out var pixelFormat))
if (!pixelFormats.TryGetValue(pix_fmt, out var pixelFormat))
{
return new VideoCharacteristics(
pixelFormat, width, height,
framesPerSecond.Reduce(),
description,
isDiscrete,
NativeMethods.GetFourCCString((int)pix_fmt));
}
else
{
Trace.WriteLine($"FlashCap: Unknown format: pix_fmt={NativeMethods.GetFourCCString((int)pix_fmt)}, [{width},{height}], {framesPerSecond}");
return null;
pixelFormat = PixelFormats.Unknown;
}
return new VideoCharacteristics(
pixelFormat, width, height,
framesPerSecond.Reduce(),
description,
isDiscrete,
NativeMethods.GetFourCCString((int)pix_fmt));
}

public static uint[] GetPixelFormats(
Expand Down
1 change: 1 addition & 0 deletions FlashCap.Core/VideoCharacteristics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ namespace FlashCap;

public enum PixelFormats
{
Unknown,
RGB8,
RGB15,
RGB16,
Expand Down
2 changes: 1 addition & 1 deletion FlashCap.V4L2Generator/FlashCap.V4L2Generator.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>

<ItemGroup>
Expand Down
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,25 @@ await File.WriteAllBytesAsync("oneshot", imageData);

See [sample code](samples/FlashCap.OneShot/) for a complete implementation.

### Exclusion of unsupported formats

The video characteristics contain a list of formats supported by the camera.
FlashCap does not support all formats, so you must select the correct format before opening the device.
Unsupported formats are indicated by `PixelFormats.Unknown`.

```csharp
// Select a device:
var descriptor0 = devices.EnumerateDescriptors().ElementAt(0);

// Exclude unsupported formats:
var characteristics = descriptor0.Characteristics.
Where(c => c.PixelFormat ! = PixelFormats.Unknown).
ToArray();
```

FlashCap enumerates all formats returned by the device.
Therefore, by checking the information in `VideoCharacteristics` with `PixelFormats.Unknown`, you can analyze what formats the device supports.


----

Expand Down Expand Up @@ -622,6 +641,10 @@ Apache-v2.

## History

* 1.6.0:
* Fixed problem with some formats not being enumerated in V4L2.
* Unsupported formats are now visible as `PixelFormats.Unknown` instead of being implicitly excluded.
* Downgraded dependent F# packages to 5.0.0.
* 1.5.0:
* Added `TakeOneShotAsync()` method to easily take a single image, and added corresponding sample project.
* Avalonia sample code now displays FPS and taken image information in real time.
Expand Down
23 changes: 23 additions & 0 deletions README_ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,25 @@ await File.WriteAllBytesAsync("oneshot", imageData);

完全な実装は、[サンプルコード](samples/FlashCap.OneShot/)を参照して下さい。

### 対応できないフォーマットの除外

映像特性には、そのカメラがサポートしているフォーマットの一覧が入っています。
FlashCapは全てのフォーマットに対応しているわけではないため、デバイスをオープンする前に、正しいフォーマットを選択する必要があります。
対応していないフォーマットは、 `PixelFormats.Unknown` で示されるため、これを除外します:

```csharp
// 映像特性を指定して、デバイスを開きます:
var descriptor0 = devices.EnumerateDescriptors().ElementAt(0);

// 対応していないフォーマットを除外する:
var characteristics = descriptor0.Characteristics.
Where(c => c.PixelFormat != PixelFormats.Unknown).
ToArray();
```

FlashCapは、デバイスが返す全てのフォーマットを列挙します。
従って、 `PixelFormats.Unknown` である `VideoCharacteristics` の情報を確認する事で、デバイスがどのようなフォーマットに対応しているのかを分析することが出来ます。


----

Expand Down Expand Up @@ -562,6 +581,10 @@ Apache-v2.

## 履歴

* 1.6.0:
* V4L2で一部のフォーマットが列挙されない問題を修正しました。
* 未対応のフォーマットを暗黙に除外しないで、`PixelFormats.Unknown` として可視化されるようにしました。
* 依存するF#パッケージを5.0.0にダウングレードしました。
* 1.5.0:
* 簡単にイメージを一枚だけ撮影する、 `TakeOneShotAsync()` メソッドを追加し、対応するサンプルプロジェクトを追加しました。
* Avaloniaサンプルコードで、FPSと撮影したイメージの情報をリアルタイムに表示するようにしました。
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Avalonia" Version="0.10.18" />
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.18" />
<PackageReference Include="Avalonia" Version="0.10.21" />
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.21" />
<PackageReference Include="Epoxy.Avalonia" Version="1.9.0" />
<PackageReference Include="SkiaImageView.Avalonia" Version="1.4.0" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,13 @@ private ValueTask OnDeviceListChangedAsync(CaptureDeviceDescriptor? descriptor)
this.CharacteristicsList.Clear();
foreach (var characteristics in descriptor.Characteristics)
{
this.CharacteristicsList.Add(characteristics);
if (characteristics.PixelFormat != PixelFormats.Unknown)
{
this.CharacteristicsList.Add(characteristics);
}
}

this.Characteristics = descriptor.Characteristics.FirstOrDefault();
this.Characteristics = this.CharacteristicsList.FirstOrDefault();
#endif
}
else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@

<ItemGroup>
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="All" />
<PackageReference Include="Avalonia" Version="0.10.18" />
<PackageReference Include="Avalonia.Desktop" Version="0.10.18" />
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.18" />
<PackageReference Include="Avalonia" Version="0.10.21" />
<PackageReference Include="Avalonia.Desktop" Version="0.10.21" />
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.21" />
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion samples/FlashCap.OneShot/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ private static async Task<int> TakeOneShotToFileAsync(
// Step 2-2: Or, you could choice from device descriptor:
var characteristics0 = descriptor0.Characteristics.
//Where(c => c.PixelFormat == PixelFormats.JPEG). // Only MJPEG characteristics.
FirstOrDefault();
FirstOrDefault(c => c.PixelFormat != PixelFormats.Unknown);
if (characteristics0 == null)
{
Console.WriteLine($"Could not select primary characteristics.");
Expand Down
28 changes: 16 additions & 12 deletions samples/FlashCap.WindowsForms/MainForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,19 +53,23 @@ private async void MainForm_Load(object sender, EventArgs e)
#else
// Or, you could choice from device descriptor:
// Hint: Show up video characteristics into ComboBox and like.
var characteristics = descriptor0.Characteristics[0];
var characteristics = descriptor0.Characteristics.
FirstOrDefault(c => c.PixelFormat != PixelFormats.Unknown);
#endif
// Show status.
this.deviceLabel.Text = descriptor0.ToString();
this.characteristicsLabel.Text = characteristics.ToString();

// Open capture device:
this.captureDevice = await descriptor0.OpenAsync(
characteristics,
this.OnPixelBufferArrived);

// Start capturing.
await this.captureDevice.StartAsync();
if (characteristics != null)
{
// Show status.
this.deviceLabel.Text = descriptor0.ToString();
this.characteristicsLabel.Text = characteristics.ToString();

// Open capture device:
this.captureDevice = await descriptor0.OpenAsync(
characteristics,
this.OnPixelBufferArrived);

// Start capturing.
await this.captureDevice.StartAsync();
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion samples/FlashCap.Wpf/FlashCap.Wpf.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="All" />
<PackageReference Include="SkiaImageView.Wpf" Version="1.4.0" />
<PackageReference Include="Epoxy.Wpf" Version="1.9.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>

<ItemGroup>
Expand Down
31 changes: 20 additions & 11 deletions samples/FlashCap.Wpf/ViewModels/MainWindowViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ public MainWindowViewModel()
// Use first device.
if (descriptors.ElementAtOrDefault(0) is { } descriptor0)
{
this.Device = descriptor0.ToString();
#if false
// Request video characteristics strictly:
// Will raise exception when parameters are not accepted.
Expand All @@ -54,23 +56,30 @@ public MainWindowViewModel()
#else
// Or, you could choice from device descriptor:
// Hint: Show up video characteristics into ComboBox and like.
var characteristics = descriptor0.Characteristics[0];
var characteristics = descriptor0.Characteristics.
FirstOrDefault(c => c.PixelFormat != PixelFormats.Unknown);
#endif
// Show status.
this.Device = descriptor0.ToString();
this.Characteristics = characteristics.ToString();
if (characteristics != null)
{
// Show status.
this.Characteristics = characteristics.ToString();
// Open capture device:
this.captureDevice = await descriptor0.OpenAsync(
characteristics,
this.OnPixelBufferArrivedAsync);
// Open capture device:
this.captureDevice = await descriptor0.OpenAsync(
characteristics,
this.OnPixelBufferArrivedAsync);
// Start capturing.
await this.captureDevice.StartAsync();
// Start capturing.
await this.captureDevice.StartAsync();
}
else
{
this.Characteristics = "(Formats are not found)";
}
}
else
{
this.Device = "(Device Not found)";
this.Device = "(Devices are not found)";
}
});
}
Expand Down

0 comments on commit 6ced3c3

Please sign in to comment.