Transizione a Windows Media Foundation (WMF)

Rimosso il supporto a `System.Drawing` e FFmpeg, sostituendoli con Windows Media Foundation per la gestione dei video.

- Aggiornato `FrameExtractor.cs` e `VideoAnalyzer.cs` per utilizzare il `Source Reader` di WMF.
- Aggiunta la classe `MFVideoReader` per l'estrazione dei frame.
- Introdotto il file `MFInterfaces.cs` con nuove interfacce COM per WMF.
- Rimosse interfacce COM obsolete e metodi non più utilizzati.
- Migliorata la gestione delle eccezioni e ottimizzate le dipendenze.
- Aggiunto supporto per il formato video RGB32.
- Pulizia del codice e rimozione di commenti obsoleti.

Questa modifica riduce le dipendenze esterne e migliora l'integrazione con le API native di Windows.
This commit is contained in:
2025-12-08 17:51:14 +01:00
parent 627a157762
commit fdf540a69b
9 changed files with 906 additions and 583 deletions

View File

@@ -31,8 +31,5 @@
</ItemGroup>
<!-- Native Windows libraries (included in Windows) -->
<ItemGroup>
<Reference Include="System.Drawing" />
</ItemGroup>
</Project>

View File

@@ -1,4 +0,0 @@
namespace Ganimede.Models
{
// Modelli futuri (es. VideoInfo, FrameInfo)
}

View File

@@ -1,75 +0,0 @@
# Download FFmpeg binaries for Ganimede
# This script downloads FFmpeg shared libraries from official BtbN builds
$ErrorActionPreference = "Stop"
$ffmpegDir = Join-Path $PSScriptRoot "..\ffmpeg"
$tempZip = Join-Path $env:TEMP "ffmpeg-download.zip"
$tempExtract = Join-Path $env:TEMP "ffmpeg-extract"
# FFmpeg download URL (latest 7.x shared build)
$ffmpegUrl = "https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-win64-gpl-shared.zip"
Write-Host "Downloading FFmpeg libraries for Ganimede..." -ForegroundColor Cyan
try {
# Check if already downloaded
if (Test-Path $ffmpegDir) {
$dllCount = (Get-ChildItem -Path $ffmpegDir -Filter "*.dll" -ErrorAction SilentlyContinue).Count
if ($dllCount -ge 5) {
Write-Host "FFmpeg libraries already exist ($dllCount DLLs found). Skipping download." -ForegroundColor Green
exit 0
}
}
Write-Host "Downloading from: $ffmpegUrl" -ForegroundColor Yellow
# Download
$ProgressPreference = 'SilentlyContinue'
Invoke-WebRequest -Uri $ffmpegUrl -OutFile $tempZip -UseBasicParsing
$ProgressPreference = 'Continue'
Write-Host "Download completed. Extracting..." -ForegroundColor Yellow
# Clean temp folder
if (Test-Path $tempExtract) {
Remove-Item $tempExtract -Recurse -Force
}
New-Item -ItemType Directory -Path $tempExtract | Out-Null
# Extract
Expand-Archive -Path $tempZip -DestinationPath $tempExtract -Force
Write-Host "Extraction completed. Copying DLL files..." -ForegroundColor Yellow
# Find bin folder
$binFolder = Get-ChildItem -Path $tempExtract -Filter "bin" -Recurse -Directory | Select-Object -First 1
if (-not $binFolder) {
throw "Could not find 'bin' folder in FFmpeg archive"
}
# Create ffmpeg directory
if (-not (Test-Path $ffmpegDir)) {
New-Item -ItemType Directory -Path $ffmpegDir | Out-Null
}
# Copy all DLL files
$dllFiles = Get-ChildItem -Path $binFolder.FullName -Filter "*.dll"
foreach ($dll in $dllFiles) {
Copy-Item -Path $dll.FullName -Destination $ffmpegDir -Force
Write-Host " Copied: $($dll.Name)" -ForegroundColor Green
}
# Cleanup
Remove-Item $tempZip -Force -ErrorAction SilentlyContinue
Remove-Item $tempExtract -Recurse -Force -ErrorAction SilentlyContinue
Write-Host "FFmpeg libraries installed successfully!" -ForegroundColor Green
Write-Host "Location: $ffmpegDir" -ForegroundColor Cyan
} catch {
Write-Host "Error downloading FFmpeg: $_" -ForegroundColor Red
Write-Host "Please download manually from: https://github.com/BtbN/FFmpeg-Builds/releases" -ForegroundColor Yellow
exit 1
}

View File

@@ -2,7 +2,7 @@ using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using Ganimede.VideoProcessing.MediaFoundation;
namespace Ganimede.VideoProcessing
{
@@ -25,14 +25,36 @@ namespace Ganimede.VideoProcessing
if (!File.Exists(videoPath))
throw new FileNotFoundException($"Video file not found: {videoPath}");
// For now, this is a placeholder implementation
// Full Windows Media Foundation frame extraction is very complex
// and requires several thousand lines of P/Invoke code
throw new NotImplementedException(
"Frame extraction with Windows Media Foundation requires extensive implementation. " +
"This feature will be added in a future update. " +
"For now, please use alternative methods or third-party tools.");
try
{
using (var reader = new MFVideoReader(videoPath))
{
// Read frame at specified time
using (var bitmap = reader.ReadFrameAtTime(timePosition))
{
if (bitmap == null)
throw new InvalidOperationException($"Could not extract frame at position {timePosition}");
// Resize if needed
if (targetWidth > 0 && targetHeight > 0 &&
(targetWidth != bitmap.Width || targetHeight != bitmap.Height))
{
using (var resized = new Bitmap(bitmap, targetWidth, targetHeight))
{
SaveBitmapAsPng(resized, outputPath);
}
}
else
{
SaveBitmapAsPng(bitmap, outputPath);
}
}
}
}
catch (Exception ex)
{
throw new InvalidOperationException($"Failed to extract frame: {ex.Message}", ex);
}
}
/// <summary>
@@ -53,10 +75,61 @@ namespace Ganimede.VideoProcessing
if (!Directory.Exists(outputFolder))
Directory.CreateDirectory(outputFolder);
// For now, this is a placeholder implementation
throw new NotImplementedException(
"Full frame extraction with Windows Media Foundation requires extensive implementation. " +
"This feature will be added in a future update.");
try
{
using (var reader = new MFVideoReader(videoPath))
{
// Calculate total frames
int totalFrames = (int)(reader.Duration.TotalSeconds * reader.FrameRate);
int frameIndex = 0;
TimeSpan currentTime = TimeSpan.Zero;
while (true)
{
// Read next frame
using (var bitmap = reader.ReadFrame())
{
if (bitmap == null)
break; // End of stream
// Generate filename
var fileName = fileNameGenerator(frameIndex, currentTime);
var fullPath = Path.Combine(outputFolder, fileName);
// Check if frame should be skipped
if (shouldSkipFrame != null && shouldSkipFrame(fullPath))
{
frameIndex++;
currentTime = TimeSpan.FromSeconds(frameIndex / reader.FrameRate);
onProgress?.Invoke(frameIndex, totalFrames);
continue;
}
// Resize if needed
if (targetWidth > 0 && targetHeight > 0 &&
(targetWidth != bitmap.Width || targetHeight != bitmap.Height))
{
using (var resized = new Bitmap(bitmap, targetWidth, targetHeight))
{
SaveBitmapAsPng(resized, fullPath);
}
}
else
{
SaveBitmapAsPng(bitmap, fullPath);
}
frameIndex++;
currentTime = TimeSpan.FromSeconds(frameIndex / reader.FrameRate);
onProgress?.Invoke(frameIndex, totalFrames);
}
}
}
}
catch (Exception ex)
{
throw new InvalidOperationException($"Failed to extract frames: {ex.Message}", ex);
}
}
/// <summary>

View File

@@ -0,0 +1,315 @@
using System;
using System.Runtime.InteropServices;
namespace Ganimede.VideoProcessing.MediaFoundation
{
/// <summary>
/// Additional Media Foundation COM interfaces for frame extraction
/// These interfaces extend the basic WMF functionality for video decoding
/// </summary>
#region Source Reader Interfaces
[ComImport, Guid("70ae66f2-c809-4e4f-8915-bdcb406b7993")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IMFSourceReader
{
[PreserveSig]
int GetStreamSelection(
int dwStreamIndex,
out bool pfSelected);
[PreserveSig]
int SetStreamSelection(
int dwStreamIndex,
bool fSelected);
[PreserveSig]
int GetNativeMediaType(
int dwStreamIndex,
int dwMediaTypeIndex,
out IMFMediaType ppMediaType);
[PreserveSig]
int GetCurrentMediaType(
int dwStreamIndex,
out IMFMediaType ppMediaType);
[PreserveSig]
int SetCurrentMediaType(
int dwStreamIndex,
IntPtr pdwReserved,
IMFMediaType pMediaType);
[PreserveSig]
int SetCurrentPosition(
Guid guidTimeFormat,
IntPtr varPosition);
[PreserveSig]
int ReadSample(
int dwStreamIndex,
int dwControlFlags,
out int pdwActualStreamIndex,
out MF_SOURCE_READER_FLAG pdwStreamFlags,
out long pllTimestamp,
out IMFSample ppSample);
[PreserveSig]
int Flush(int dwStreamIndex);
[PreserveSig]
int GetServiceForStream(
int dwStreamIndex,
Guid guidService,
Guid riid,
out IntPtr ppvObject);
[PreserveSig]
int GetPresentationAttribute(
int dwStreamIndex,
Guid guidAttribute,
IntPtr pvarAttribute);
}
[Flags]
internal enum MF_SOURCE_READER_FLAG
{
None = 0,
Error = 0x00000001,
EndOfStream = 0x00000002,
NewStream = 0x00000004,
NativeMediaTypeChanged = 0x00000010,
CurrentMediaTypeChanged = 0x00000020,
StreamTick = 0x00000100,
AllEffectsRemoved = 0x00000200
}
internal static class MFSourceReaderIndex
{
public const int FirstVideoStream = unchecked((int)0xFFFFFFFC);
public const int FirstAudioStream = unchecked((int)0xFFFFFFFD);
public const int MediaSource = unchecked((int)0xFFFFFFFE);
public const int AnyStream = unchecked((int)0xFFFFFFFE);
}
#endregion
#region Sample and Buffer Interfaces
[ComImport, Guid("c40a00f2-b93a-4d80-ae8c-5a1c634f58e4")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IMFSample : IMFAttributes
{
#region IMFAttributes methods
[PreserveSig] new int GetItem(Guid guidKey, IntPtr pValue);
[PreserveSig] new int GetItemType(Guid guidKey, out ushort pType);
[PreserveSig] new int CompareItem(Guid guidKey, IntPtr Value, out bool pbResult);
[PreserveSig] new int Compare(IMFAttributes pTheirs, int MatchType, out bool pbResult);
[PreserveSig] new int GetUINT32(Guid guidKey, out int punValue);
[PreserveSig] new int GetUINT64(Guid guidKey, out long punValue);
[PreserveSig] new int GetDouble(Guid guidKey, out double pfValue);
[PreserveSig] new int GetGUID(Guid guidKey, out Guid pguidValue);
[PreserveSig] new int GetStringLength(Guid guidKey, out int pcchLength);
[PreserveSig] new int GetString(Guid guidKey, IntPtr pwszValue, int cchBufSize, IntPtr pcchLength);
[PreserveSig] new int GetAllocatedString(Guid guidKey, out IntPtr ppwszValue, out int pcchLength);
[PreserveSig] new int GetBlobSize(Guid guidKey, out int pcbBlobSize);
[PreserveSig] new int GetBlob(Guid guidKey, IntPtr pBuf, int cbBufSize, IntPtr pcbBlobSize);
[PreserveSig] new int GetAllocatedBlob(Guid guidKey, out IntPtr ppBuf, out int pcbSize);
[PreserveSig] new int GetUnknown(Guid guidKey, Guid riid, out IntPtr ppv);
[PreserveSig] new int SetItem(Guid guidKey, IntPtr Value);
[PreserveSig] new int DeleteItem(Guid guidKey);
[PreserveSig] new int DeleteAllItems();
[PreserveSig] new int SetUINT32(Guid guidKey, int unValue);
[PreserveSig] new int SetUINT64(Guid guidKey, long unValue);
[PreserveSig] new int SetDouble(Guid guidKey, double fValue);
[PreserveSig] new int SetGUID(Guid guidKey, Guid guidValue);
[PreserveSig] new int SetString(Guid guidKey, [MarshalAs(UnmanagedType.LPWStr)] string wszValue);
[PreserveSig] new int SetBlob(Guid guidKey, IntPtr pBuf, int cbBufSize);
[PreserveSig] new int SetUnknown(Guid guidKey, [MarshalAs(UnmanagedType.IUnknown)] object pUnknown);
[PreserveSig] new int LockStore();
[PreserveSig] new int UnlockStore();
[PreserveSig] new int GetCount(out int pcItems);
[PreserveSig] new int GetItemByIndex(int unIndex, out Guid pguidKey, IntPtr pValue);
[PreserveSig] new int CopyAllItems(IMFAttributes pDest);
#endregion
[PreserveSig] int GetSampleFlags(out int pdwSampleFlags);
[PreserveSig] int SetSampleFlags(int dwSampleFlags);
[PreserveSig] int GetSampleTime(out long phnsSampleTime);
[PreserveSig] int SetSampleTime(long hnsSampleTime);
[PreserveSig] int GetSampleDuration(out long phnsSampleDuration);
[PreserveSig] int SetSampleDuration(long hnsSampleDuration);
[PreserveSig] int GetBufferCount(out int pdwBufferCount);
[PreserveSig] int GetBufferByIndex(int dwIndex, out IMFMediaBuffer ppBuffer);
[PreserveSig] int ConvertToContiguousBuffer(out IMFMediaBuffer ppBuffer);
[PreserveSig] int AddBuffer(IMFMediaBuffer pBuffer);
[PreserveSig] int RemoveBufferByIndex(int dwIndex);
[PreserveSig] int RemoveAllBuffers();
[PreserveSig] int GetTotalLength(out int pcbTotalLength);
[PreserveSig] int CopyToBuffer(IMFMediaBuffer pBuffer);
}
[ComImport, Guid("045FA593-8799-42b8-BC8D-8968C6453507")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IMFMediaBuffer
{
[PreserveSig] int Lock(out IntPtr ppbBuffer, out int pcbMaxLength, out int pcbCurrentLength);
[PreserveSig] int Unlock();
[PreserveSig] int GetCurrentLength(out int pcbCurrentLength);
[PreserveSig] int SetCurrentLength(int cbCurrentLength);
[PreserveSig] int GetMaxLength(out int pcbMaxLength);
}
[ComImport, Guid("7DC9D5F9-9ED9-44ec-9BBF-0600BB589FBB")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IMF2DBuffer
{
[PreserveSig] int Lock2D(out IntPtr pbScanline0, out int plPitch);
[PreserveSig] int Unlock2D();
[PreserveSig] int GetScanline0AndPitch(out IntPtr pbScanline0, out int plPitch);
[PreserveSig] int IsContiguousFormat(out bool pfIsContiguous);
[PreserveSig] int GetContiguousLength(out int pcbLength);
[PreserveSig] int ContiguousCopyTo(IntPtr pbDestBuffer, int cbDestBuffer);
[PreserveSig] int ContiguousCopyFrom(IntPtr pbSrcBuffer, int cbSrcBuffer);
}
#endregion
#region Helper Functions and Constants
internal static class MFExternExtended
{
[DllImport("mfreadwrite.dll", ExactSpelling = true, PreserveSig = true)]
internal static extern int MFCreateSourceReaderFromURL(
[MarshalAs(UnmanagedType.LPWStr)] string pwszURL,
IMFAttributes pAttributes,
out IMFSourceReader ppSourceReader);
[DllImport("mfplat.dll", ExactSpelling = true, PreserveSig = true)]
internal static extern int MFCreateMediaType(out IMFMediaType ppMFType);
[DllImport("mfplat.dll", ExactSpelling = true, PreserveSig = true)]
internal static extern int MFCreateAttributes(out IMFAttributes ppMFAttributes, int cInitialSize);
[DllImport("mfplat.dll", ExactSpelling = true, PreserveSig = true)]
internal static extern int MFCreateMemoryBuffer(int cbMaxLength, out IMFMediaBuffer ppBuffer);
}
internal static class MFVideoFormat
{
// Uncompressed RGB formats
public static readonly Guid RGB32 = new Guid("00000016-0000-0010-8000-00aa00389b71");
public static readonly Guid RGB24 = new Guid("00000014-0000-0010-8000-00aa00389b71");
public static readonly Guid RGB555 = new Guid("00000018-0000-0010-8000-00aa00389b71");
public static readonly Guid RGB565 = new Guid("00000017-0000-0010-8000-00aa00389b71");
// YUV formats
public static readonly Guid NV12 = new Guid("3231564E-0000-0010-8000-00AA00389B71");
public static readonly Guid YUY2 = new Guid("32595559-0000-0010-8000-00AA00389B71");
public static readonly Guid UYVY = new Guid("59565955-0000-0010-8000-00AA00389B71");
public static readonly Guid YV12 = new Guid("32315659-0000-0010-8000-00AA00389B71");
public static readonly Guid I420 = new Guid("30323449-0000-0010-8000-00AA00389B71");
}
internal static class MFAttributesClsidExtended
{
// Source Reader attributes
public static readonly Guid MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING =
new Guid("fb394f3d-ccf1-42ee-bbb3-f9b845d5681d");
public static readonly Guid MF_SOURCE_READER_DISABLE_DXVA =
new Guid("aa456cfd-3943-4a1e-a77d-1838c0ea2e35");
public static readonly Guid MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING =
new Guid("0f81da2c-b537-4672-a8b2-a681b17307a3");
// Low latency mode
public static readonly Guid MF_LOW_LATENCY =
new Guid("9c27891a-ed7a-40e1-88e8-b22727a024ee");
}
#endregion
#region Base Interfaces (referenced from VideoAnalyzer)
[ComImport, Guid("2CD2D921-C447-44A7-A13C-4ADABFC247E3")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IMFAttributes
{
[PreserveSig] int GetItem(Guid guidKey, IntPtr pValue);
[PreserveSig] int GetItemType(Guid guidKey, out ushort pType);
[PreserveSig] int CompareItem(Guid guidKey, IntPtr Value, out bool pbResult);
[PreserveSig] int Compare(IMFAttributes pTheirs, int MatchType, out bool pbResult);
[PreserveSig] int GetUINT32(Guid guidKey, out int punValue);
[PreserveSig] int GetUINT64(Guid guidKey, out long punValue);
[PreserveSig] int GetDouble(Guid guidKey, out double pfValue);
[PreserveSig] int GetGUID(Guid guidKey, out Guid pguidValue);
[PreserveSig] int GetStringLength(Guid guidKey, out int pcchLength);
[PreserveSig] int GetString(Guid guidKey, IntPtr pwszValue, int cchBufSize, IntPtr pcchLength);
[PreserveSig] int GetAllocatedString(Guid guidKey, out IntPtr ppwszValue, out int pcchLength);
[PreserveSig] int GetBlobSize(Guid guidKey, out int pcbBlobSize);
[PreserveSig] int GetBlob(Guid guidKey, IntPtr pBuf, int cbBufSize, IntPtr pcbBlobSize);
[PreserveSig] int GetAllocatedBlob(Guid guidKey, out IntPtr ppBuf, out int pcbSize);
[PreserveSig] int GetUnknown(Guid guidKey, Guid riid, out IntPtr ppv);
[PreserveSig] int SetItem(Guid guidKey, IntPtr Value);
[PreserveSig] int DeleteItem(Guid guidKey);
[PreserveSig] int DeleteAllItems();
[PreserveSig] int SetUINT32(Guid guidKey, int unValue);
[PreserveSig] int SetUINT64(Guid guidKey, long unValue);
[PreserveSig] int SetDouble(Guid guidKey, double fValue);
[PreserveSig] int SetGUID(Guid guidKey, Guid guidValue);
[PreserveSig] int SetString(Guid guidKey, [MarshalAs(UnmanagedType.LPWStr)] string wszValue);
[PreserveSig] int SetBlob(Guid guidKey, IntPtr pBuf, int cbBufSize);
[PreserveSig] int SetUnknown(Guid guidKey, [MarshalAs(UnmanagedType.IUnknown)] object pUnknown);
[PreserveSig] int LockStore();
[PreserveSig] int UnlockStore();
[PreserveSig] int GetCount(out int pcItems);
[PreserveSig] int GetItemByIndex(int unIndex, out Guid pguidKey, IntPtr pValue);
[PreserveSig] int CopyAllItems(IMFAttributes pDest);
}
[ComImport, Guid("44AE0FA8-EA31-4109-8D2E-4CAE4997C555")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IMFMediaType : IMFAttributes
{
#region IMFAttributes methods
[PreserveSig] new int GetItem(Guid guidKey, IntPtr pValue);
[PreserveSig] new int GetItemType(Guid guidKey, out ushort pType);
[PreserveSig] new int CompareItem(Guid guidKey, IntPtr Value, out bool pbResult);
[PreserveSig] new int Compare(IMFAttributes pTheirs, int MatchType, out bool pbResult);
[PreserveSig] new int GetUINT32(Guid guidKey, out int punValue);
[PreserveSig] new int GetUINT64(Guid guidKey, out long punValue);
[PreserveSig] new int GetDouble(Guid guidKey, out double pfValue);
[PreserveSig] new int GetGUID(Guid guidKey, out Guid pguidValue);
[PreserveSig] new int GetStringLength(Guid guidKey, out int pcchLength);
[PreserveSig] new int GetString(Guid guidKey, IntPtr pwszValue, int cchBufSize, IntPtr pcchLength);
[PreserveSig] new int GetAllocatedString(Guid guidKey, out IntPtr ppwszValue, out int pcchLength);
[PreserveSig] new int GetBlobSize(Guid guidKey, out int pcbBlobSize);
[PreserveSig] new int GetBlob(Guid guidKey, IntPtr pBuf, int cbBufSize, IntPtr pcbBlobSize);
[PreserveSig] new int GetAllocatedBlob(Guid guidKey, out IntPtr ppBuf, out int pcbSize);
[PreserveSig] new int GetUnknown(Guid guidKey, Guid riid, out IntPtr ppv);
[PreserveSig] new int SetItem(Guid guidKey, IntPtr Value);
[PreserveSig] new int DeleteItem(Guid guidKey);
[PreserveSig] new int DeleteAllItems();
[PreserveSig] new int SetUINT32(Guid guidKey, int unValue);
[PreserveSig] new int SetUINT64(Guid guidKey, long unValue);
[PreserveSig] new int SetDouble(Guid guidKey, double fValue);
[PreserveSig] new int SetGUID(Guid guidKey, Guid guidValue);
[PreserveSig] new int SetString(Guid guidKey, [MarshalAs(UnmanagedType.LPWStr)] string wszValue);
[PreserveSig] new int SetBlob(Guid guidKey, IntPtr pBuf, int cbBufSize);
[PreserveSig] new int SetUnknown(Guid guidKey, [MarshalAs(UnmanagedType.IUnknown)] object pUnknown);
[PreserveSig] new int LockStore();
[PreserveSig] new int UnlockStore();
[PreserveSig] new int GetCount(out int pcItems);
[PreserveSig] new int GetItemByIndex(int unIndex, out Guid pguidKey, IntPtr pValue);
[PreserveSig] new int CopyAllItems(IMFAttributes pDest);
#endregion
[PreserveSig] int GetMajorType(out Guid pguidMajorType);
[PreserveSig] int IsCompressedFormat(out bool pfCompressed);
[PreserveSig] int IsEqual(IMFMediaType pIMediaType, out uint pdwFlags);
[PreserveSig] int GetRepresentation(Guid guidRepresentation, out IntPtr ppvRepresentation);
[PreserveSig] int FreeRepresentation(Guid guidRepresentation, IntPtr pvRepresentation);
}
#endregion
}

View File

@@ -0,0 +1,339 @@
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
namespace Ganimede.VideoProcessing.MediaFoundation
{
/// <summary>
/// Video reader class using Windows Media Foundation Source Reader
/// Handles frame extraction from video files
/// </summary>
public class MFVideoReader : IDisposable
{
private IMFSourceReader? _sourceReader;
private bool _disposed = false;
private int _videoStreamIndex = 0;
private int _width;
private int _height;
private double _frameRate;
private TimeSpan _duration;
public int Width => _width;
public int Height => _height;
public double FrameRate => _frameRate;
public TimeSpan Duration => _duration;
public MFVideoReader(string videoPath)
{
if (!File.Exists(videoPath))
throw new FileNotFoundException($"Video file not found: {videoPath}");
// Initialize Media Foundation
int hr = MFExtern.MFStartup(MFExtern.MF_VERSION, 0);
Marshal.ThrowExceptionForHR(hr);
try
{
// Create attributes for source reader
IMFAttributes? attributes = null;
hr = MFExternExtended.MFCreateAttributes(out attributes, 2);
Marshal.ThrowExceptionForHR(hr);
// Enable video processing
hr = attributes!.SetUINT32(MFAttributesClsidExtended.MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, 1);
Marshal.ThrowExceptionForHR(hr);
// Low latency mode
hr = attributes.SetUINT32(MFAttributesClsidExtended.MF_LOW_LATENCY, 1);
Marshal.ThrowExceptionForHR(hr);
// Create source reader
hr = MFExternExtended.MFCreateSourceReaderFromURL(videoPath, attributes, out _sourceReader);
Marshal.ThrowExceptionForHR(hr);
// Find first video stream
_videoStreamIndex = MFSourceReaderIndex.FirstVideoStream;
// Configure output media type (RGB32)
IMFMediaType? mediaType = null;
hr = MFExternExtended.MFCreateMediaType(out mediaType);
Marshal.ThrowExceptionForHR(hr);
try
{
hr = mediaType!.SetGUID(MFAttributesClsid.MF_MT_MAJOR_TYPE, MFMediaType.Video);
Marshal.ThrowExceptionForHR(hr);
hr = mediaType.SetGUID(MFAttributesClsid.MF_MT_SUBTYPE, MFVideoFormat.RGB32);
Marshal.ThrowExceptionForHR(hr);
hr = _sourceReader!.SetCurrentMediaType(_videoStreamIndex, IntPtr.Zero, mediaType);
Marshal.ThrowExceptionForHR(hr);
}
finally
{
if (mediaType != null) Marshal.ReleaseComObject(mediaType);
}
// Get actual output media type
IMFMediaType? currentMediaType = null;
hr = _sourceReader.GetCurrentMediaType(_videoStreamIndex, out currentMediaType);
Marshal.ThrowExceptionForHR(hr);
try
{
// Get frame size
long frameSize;
hr = currentMediaType!.GetUINT64(MFAttributesClsid.MF_MT_FRAME_SIZE, out frameSize);
Marshal.ThrowExceptionForHR(hr);
_width = (int)(frameSize >> 32);
_height = (int)(frameSize & 0xFFFFFFFF);
// Get frame rate
long frameRateRatio;
hr = currentMediaType.GetUINT64(MFAttributesClsid.MF_MT_FRAME_RATE, out frameRateRatio);
if (hr >= 0)
{
int numerator = (int)(frameRateRatio >> 32);
int denominator = (int)(frameRateRatio & 0xFFFFFFFF);
_frameRate = denominator > 0 ? (double)numerator / denominator : 30.0;
}
else
{
_frameRate = 30.0; // Default
}
}
finally
{
if (currentMediaType != null) Marshal.ReleaseComObject(currentMediaType);
}
// Get duration
IntPtr durationPtr = IntPtr.Zero;
hr = _sourceReader.GetPresentationAttribute(
MFSourceReaderIndex.MediaSource,
MFAttributesClsid.MF_PD_DURATION,
durationPtr);
if (hr >= 0 && durationPtr != IntPtr.Zero)
{
long durationTicks = Marshal.ReadInt64(durationPtr);
_duration = TimeSpan.FromTicks(durationTicks / 10);
}
else
{
_duration = TimeSpan.Zero;
}
// Cleanup attributes
if (attributes != null) Marshal.ReleaseComObject(attributes);
}
catch
{
Dispose();
throw;
}
}
/// <summary>
/// Seeks to a specific time position in the video
/// </summary>
public void SeekTo(TimeSpan position)
{
if (_disposed || _sourceReader == null)
throw new ObjectDisposedException(nameof(MFVideoReader));
long timeInHundredNanoseconds = position.Ticks * 10;
IntPtr varPosition = Marshal.AllocHGlobal(16); // PROPVARIANT size
try
{
// Write PROPVARIANT structure
// VT_I8 = 20 (64-bit signed integer)
Marshal.WriteInt16(varPosition, 0, 20); // vt
Marshal.WriteInt64(varPosition, 8, timeInHundredNanoseconds); // hVal
int hr = _sourceReader.SetCurrentPosition(Guid.Empty, varPosition);
Marshal.ThrowExceptionForHR(hr);
}
finally
{
Marshal.FreeHGlobal(varPosition);
}
}
/// <summary>
/// Reads the next video frame
/// </summary>
public Bitmap? ReadFrame()
{
if (_disposed || _sourceReader == null)
throw new ObjectDisposedException(nameof(MFVideoReader));
IMFSample? sample = null;
int streamIndex;
MF_SOURCE_READER_FLAG flags;
long timestamp;
int hr = _sourceReader.ReadSample(
_videoStreamIndex,
0,
out streamIndex,
out flags,
out timestamp,
out sample);
Marshal.ThrowExceptionForHR(hr);
// Check for end of stream
if ((flags & MF_SOURCE_READER_FLAG.EndOfStream) != 0)
{
return null;
}
if (sample == null)
{
return null;
}
try
{
return ConvertSampleToBitmap(sample);
}
finally
{
Marshal.ReleaseComObject(sample);
}
}
/// <summary>
/// Reads a frame at a specific time position
/// </summary>
public Bitmap? ReadFrameAtTime(TimeSpan position)
{
SeekTo(position);
return ReadFrame();
}
/// <summary>
/// Converts an IMFSample to a Bitmap
/// </summary>
private Bitmap ConvertSampleToBitmap(IMFSample sample)
{
IMFMediaBuffer? buffer = null;
int hr = sample.ConvertToContiguousBuffer(out buffer);
Marshal.ThrowExceptionForHR(hr);
try
{
IntPtr pData;
int cbMaxLength, cbCurrentLength;
hr = buffer!.Lock(out pData, out cbMaxLength, out cbCurrentLength);
Marshal.ThrowExceptionForHR(hr);
try
{
// Create bitmap
Bitmap bitmap = new Bitmap(_width, _height, PixelFormat.Format32bppRgb);
// Lock bitmap data
Rectangle rect = new Rectangle(0, 0, _width, _height);
BitmapData bmpData = bitmap.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format32bppRgb);
try
{
int stride = _width * 4; // 4 bytes per pixel (RGB32)
// Copy data line by line (bottom-up for RGB32)
for (int y = 0; y < _height; y++)
{
IntPtr srcLine = IntPtr.Add(pData, y * stride);
IntPtr dstLine = IntPtr.Add(bmpData.Scan0, (_height - 1 - y) * bmpData.Stride);
// Copy scanline
unsafe
{
Buffer.MemoryCopy(
srcLine.ToPointer(),
dstLine.ToPointer(),
bmpData.Stride,
stride);
}
}
}
finally
{
bitmap.UnlockBits(bmpData);
}
return bitmap;
}
finally
{
buffer.Unlock();
}
}
finally
{
if (buffer != null) Marshal.ReleaseComObject(buffer);
}
}
public void Dispose()
{
if (!_disposed)
{
if (_sourceReader != null)
{
Marshal.ReleaseComObject(_sourceReader);
_sourceReader = null;
}
MFExtern.MFShutdown();
_disposed = true;
}
GC.SuppressFinalize(this);
}
~MFVideoReader()
{
Dispose();
}
}
#region Helper Classes from VideoAnalyzer
internal static class MFExtern
{
private const uint MF_SDK_VERSION = 0x0002;
private const uint MF_API_VERSION = 0x0070;
internal const uint MF_VERSION = (MF_SDK_VERSION << 16) | MF_API_VERSION;
[DllImport("mfplat.dll", ExactSpelling = true, PreserveSig = true)]
internal static extern int MFStartup(uint Version, uint dwFlags = 0);
[DllImport("mfplat.dll", ExactSpelling = true, PreserveSig = true)]
internal static extern int MFShutdown();
}
internal static class MFAttributesClsid
{
public static readonly Guid MF_PD_DURATION = new Guid("6c990d33-bb8e-477a-8598-0d5d96fcd88a");
public static readonly Guid MF_MT_MAJOR_TYPE = new Guid("48eba18e-f8c9-4687-bf11-0a74c9f96a8f");
public static readonly Guid MF_MT_SUBTYPE = new Guid("f7e34c9a-42e8-4714-b74b-cb29d72c35e5");
public static readonly Guid MF_MT_FRAME_SIZE = new Guid("1652c33d-d6b2-4012-b834-72030849a37d");
public static readonly Guid MF_MT_FRAME_RATE = new Guid("c459a2e8-3d2c-4e44-b132-fee5156c7bb0");
}
internal static class MFMediaType
{
public static readonly Guid Video = new Guid("73646976-0000-0010-8000-00AA00389B71");
public static readonly Guid Audio = new Guid("73647561-0000-0010-8000-00AA00389B71");
}
#endregion
}

View File

@@ -1,7 +1,6 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
namespace Ganimede.VideoProcessing
{
@@ -12,7 +11,7 @@ namespace Ganimede.VideoProcessing
public class VideoAnalyzer
{
/// <summary>
/// Analyzes a video file and returns its metadata using Windows Media Foundation
/// Analyzes a video file and returns its metadata using Windows Media Foundation Source Reader
/// </summary>
public static VideoMetadata Analyze(string videoPath)
{
@@ -25,140 +24,103 @@ namespace Ganimede.VideoProcessing
try
{
IMFSourceResolver? sourceResolver = null;
IMFMediaSource? mediaSource = null;
IMFPresentationDescriptor? presentationDescriptor = null;
IntPtr pSourceReader = IntPtr.Zero;
IMFSourceReader? sourceReader = null;
try
{
// Create source resolver
hr = MFExtern.MFCreateSourceResolver(out sourceResolver);
// Create source reader from URL
hr = MFExtern.MFCreateSourceReaderFromURL(videoPath, IntPtr.Zero, out pSourceReader);
Marshal.ThrowExceptionForHR(hr);
// Convert to interface
sourceReader = (IMFSourceReader)Marshal.GetObjectForIUnknown(pSourceReader);
// Get native media type for first video stream
IntPtr pMediaType = IntPtr.Zero;
hr = sourceReader!.GetNativeMediaType(
MFSourceReaderIndex.FirstVideoStream,
0,
out pMediaType);
Marshal.ThrowExceptionForHR(hr);
// Create media source from file
MFObjectType objectType;
object source;
hr = sourceResolver!.CreateObjectFromURL(
videoPath,
MFResolution.MediaSource,
null,
out objectType,
out source);
Marshal.ThrowExceptionForHR(hr);
mediaSource = (IMFMediaSource)source;
// Get presentation descriptor
hr = mediaSource!.CreatePresentationDescriptor(out presentationDescriptor);
Marshal.ThrowExceptionForHR(hr);
// Get duration
long durationTicks;
hr = presentationDescriptor!.GetUINT64(MFAttributesClsid.MF_PD_DURATION, out durationTicks);
Marshal.ThrowExceptionForHR(hr);
TimeSpan duration = TimeSpan.FromTicks(durationTicks / 10); // Convert from 100-nanosecond units
// Find video stream
int streamCount;
hr = presentationDescriptor.GetStreamDescriptorCount(out streamCount);
Marshal.ThrowExceptionForHR(hr);
for (int i = 0; i < streamCount; i++)
IMFMediaType? mediaType = null;
try
{
IMFStreamDescriptor? streamDescriptor = null;
bool selected;
mediaType = (IMFMediaType)Marshal.GetObjectForIUnknown(pMediaType);
hr = presentationDescriptor.GetStreamDescriptorByIndex(i, out selected, out streamDescriptor);
// Get frame size
long frameSize;
hr = mediaType!.GetUINT64(MFAttributesClsid.MF_MT_FRAME_SIZE, out frameSize);
Marshal.ThrowExceptionForHR(hr);
int width = (int)(frameSize >> 32);
int height = (int)(frameSize & 0xFFFFFFFF);
// Get frame rate
long frameRateRatio;
hr = mediaType.GetUINT64(MFAttributesClsid.MF_MT_FRAME_RATE, out frameRateRatio);
Marshal.ThrowExceptionForHR(hr);
int frameRateNumerator = (int)(frameRateRatio >> 32);
int frameRateDenominator = (int)(frameRateRatio & 0xFFFFFFFF);
double fps = frameRateDenominator > 0 ? (double)frameRateNumerator / frameRateDenominator : 30.0;
// Get codec subtype
Guid subType;
hr = mediaType.GetGUID(MFAttributesClsid.MF_MT_SUBTYPE, out subType);
string codecName = GetCodecName(subType);
// Get duration from presentation attribute
IntPtr varDuration = Marshal.AllocHGlobal(16); // PROPVARIANT size
try
{
// Get media type handler
IMFMediaTypeHandler? handler = null;
hr = streamDescriptor!.GetMediaTypeHandler(out handler);
Marshal.ThrowExceptionForHR(hr);
hr = sourceReader.GetPresentationAttribute(
MFSourceReaderIndex.MediaSource,
MFAttributesClsid.MF_PD_DURATION,
varDuration);
try
TimeSpan duration = TimeSpan.Zero;
if (hr >= 0)
{
// Get major type
Guid majorType;
hr = handler!.GetMajorType(out majorType);
Marshal.ThrowExceptionForHR(hr);
// Check if this is a video stream
if (majorType == MFMediaType.Video)
{
// Get current media type
IMFMediaType? mediaType = null;
hr = handler.GetCurrentMediaType(out mediaType);
Marshal.ThrowExceptionForHR(hr);
try
{
// Get frame size
long frameSize;
hr = mediaType!.GetUINT64(MFAttributesClsid.MF_MT_FRAME_SIZE, out frameSize);
Marshal.ThrowExceptionForHR(hr);
int width = (int)(frameSize >> 32);
int height = (int)(frameSize & 0xFFFFFFFF);
// Get frame rate
long frameRate;
hr = mediaType.GetUINT64(MFAttributesClsid.MF_MT_FRAME_RATE, out frameRate);
Marshal.ThrowExceptionForHR(hr);
int frameRateNumerator = (int)(frameRate >> 32);
int frameRateDenominator = (int)(frameRate & 0xFFFFFFFF);
double fps = frameRateDenominator > 0 ? (double)frameRateNumerator / frameRateDenominator : 30.0;
// Calculate total frames
int totalFrames = (int)(duration.TotalSeconds * fps);
// Get bitrate (approximate from file size)
long fileSize = new FileInfo(videoPath).Length;
long bitrate = duration.TotalSeconds > 0 ? (long)((fileSize * 8) / duration.TotalSeconds) : 0;
// Get codec
Guid subType;
hr = mediaType.GetGUID(MFAttributesClsid.MF_MT_SUBTYPE, out subType);
string codecName = GetCodecName(subType);
return new VideoMetadata
{
Duration = duration,
FrameRate = fps,
TotalFrames = totalFrames,
Width = width,
Height = height,
BitRate = bitrate,
CodecName = codecName
};
}
finally
{
if (mediaType != null) Marshal.ReleaseComObject(mediaType);
}
}
// Read PROPVARIANT (VT_I8)
long durationTicks = Marshal.ReadInt64(varDuration, 8);
duration = TimeSpan.FromTicks(durationTicks / 10); // Convert from 100-nanosecond units
}
finally
// Calculate total frames
int totalFrames = (int)(duration.TotalSeconds * fps);
// Get bitrate (approximate from file size)
long fileSize = new FileInfo(videoPath).Length;
long bitrate = duration.TotalSeconds > 0 ? (long)((fileSize * 8) / duration.TotalSeconds) : 0;
return new VideoMetadata
{
if (handler != null) Marshal.ReleaseComObject(handler);
}
Duration = duration,
FrameRate = fps,
TotalFrames = totalFrames,
Width = width,
Height = height,
BitRate = bitrate,
CodecName = codecName
};
}
finally
{
if (streamDescriptor != null) Marshal.ReleaseComObject(streamDescriptor);
Marshal.FreeHGlobal(varDuration);
}
}
throw new InvalidOperationException("No video stream found in the file");
finally
{
if (mediaType != null) Marshal.ReleaseComObject(mediaType);
if (pMediaType != IntPtr.Zero) Marshal.Release(pMediaType);
}
}
finally
{
if (presentationDescriptor != null) Marshal.ReleaseComObject(presentationDescriptor);
if (mediaSource != null) Marshal.ReleaseComObject(mediaSource);
if (sourceResolver != null) Marshal.ReleaseComObject(sourceResolver);
if (sourceReader != null) Marshal.ReleaseComObject(sourceReader);
if (pSourceReader != IntPtr.Zero) Marshal.Release(pSourceReader);
}
}
finally
@@ -204,300 +166,77 @@ namespace Ganimede.VideoProcessing
private const uint MF_API_VERSION = 0x0070;
internal const uint MF_VERSION = (MF_SDK_VERSION << 16) | MF_API_VERSION;
[DllImport("mfplat.dll", ExactSpelling = true, PreserveSig = false)]
internal static extern void MFStartup(uint Version, uint dwFlags = 0);
[DllImport("mfplat.dll", ExactSpelling = true, PreserveSig = true)]
internal static extern int MFStartup(uint Version, uint dwFlags = 0);
[DllImport("mfplat.dll", ExactSpelling = true, PreserveSig = false)]
internal static extern void MFShutdown();
[DllImport("mfplat.dll", ExactSpelling = true, PreserveSig = true)]
internal static extern int MFShutdown();
[DllImport("mfplat.dll", ExactSpelling = true, PreserveSig = false)]
internal static extern void MFCreateSourceResolver(
[MarshalAs(UnmanagedType.Interface)] out IMFSourceResolver ppISourceResolver);
[DllImport("mfreadwrite.dll", ExactSpelling = true, PreserveSig = true)]
internal static extern int MFCreateSourceReaderFromURL(
[MarshalAs(UnmanagedType.LPWStr)] string pwszURL,
IntPtr pAttributes,
out IntPtr ppSourceReader);
}
[ComImport, Guid("FBE5A32D-A497-4b57-BB57-B1EF73A689E4")]
[ComImport, Guid("70ae66f2-c809-4e4f-8915-bdcb406b7993")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IMFSourceResolver
internal interface IMFSourceReader
{
[PreserveSig]
int CreateObjectFromURL(
[In, MarshalAs(UnmanagedType.LPWStr)] string pwszURL,
[In] MFResolution dwFlags,
[In, MarshalAs(UnmanagedType.Interface)] IPropertyStore? pProps,
[Out] out MFObjectType pObjectType,
[Out, MarshalAs(UnmanagedType.IUnknown)] out object ppObject);
[PreserveSig]
int CreateObjectFromByteStream(
[In, MarshalAs(UnmanagedType.Interface)] IMFByteStream pByteStream,
[In, MarshalAs(UnmanagedType.LPWStr)] string? pwszURL,
[In] MFResolution dwFlags,
[In, MarshalAs(UnmanagedType.Interface)] IPropertyStore? pProps,
[Out] out MFObjectType pObjectType,
[Out, MarshalAs(UnmanagedType.IUnknown)] out object ppObject);
[PreserveSig]
int BeginCreateObjectFromURL(
[In, MarshalAs(UnmanagedType.LPWStr)] string pwszURL,
[In] MFResolution dwFlags,
[In, MarshalAs(UnmanagedType.Interface)] IPropertyStore? pProps,
[Out, MarshalAs(UnmanagedType.IUnknown)] out object? ppIUnknownCancelCookie,
[In, MarshalAs(UnmanagedType.Interface)] IMFAsyncCallback pCallback,
[In, MarshalAs(UnmanagedType.IUnknown)] object? punkState);
[PreserveSig]
int EndCreateObjectFromURL(
[In, MarshalAs(UnmanagedType.Interface)] IMFAsyncResult pResult,
[Out] out MFObjectType pObjectType,
[Out, MarshalAs(UnmanagedType.IUnknown)] out object ppObject);
[PreserveSig]
int BeginCreateObjectFromByteStream(
[In, MarshalAs(UnmanagedType.Interface)] IMFByteStream pByteStream,
[In, MarshalAs(UnmanagedType.LPWStr)] string? pwszURL,
[In] MFResolution dwFlags,
[In, MarshalAs(UnmanagedType.Interface)] IPropertyStore? pProps,
[Out, MarshalAs(UnmanagedType.IUnknown)] out object? ppIUnknownCancelCookie,
[In, MarshalAs(UnmanagedType.Interface)] IMFAsyncCallback pCallback,
[In, MarshalAs(UnmanagedType.IUnknown)] object? punkState);
[PreserveSig]
int EndCreateObjectFromByteStream(
[In, MarshalAs(UnmanagedType.Interface)] IMFAsyncResult pResult,
[Out] out MFObjectType pObjectType,
[Out, MarshalAs(UnmanagedType.IUnknown)] out object ppObject);
[PreserveSig]
int CancelObjectCreation(
[In, MarshalAs(UnmanagedType.IUnknown)] object pIUnknownCancelCookie);
[PreserveSig] int GetStreamSelection(int dwStreamIndex, out bool pfSelected);
[PreserveSig] int SetStreamSelection(int dwStreamIndex, bool fSelected);
[PreserveSig] int GetNativeMediaType(int dwStreamIndex, int dwMediaTypeIndex, out IntPtr ppMediaType);
[PreserveSig] int GetCurrentMediaType(int dwStreamIndex, out IntPtr ppMediaType);
[PreserveSig] int SetCurrentMediaType(int dwStreamIndex, IntPtr pdwReserved, IntPtr pMediaType);
[PreserveSig] int SetCurrentPosition(Guid guidTimeFormat, IntPtr varPosition);
[PreserveSig] int ReadSample(int dwStreamIndex, int dwControlFlags, out int pdwActualStreamIndex,
out int pdwStreamFlags, out long pllTimestamp, out IntPtr ppSample);
[PreserveSig] int Flush(int dwStreamIndex);
[PreserveSig] int GetServiceForStream(int dwStreamIndex, Guid guidService, Guid riid, out IntPtr ppvObject);
[PreserveSig] int GetPresentationAttribute(int dwStreamIndex, Guid guidAttribute, IntPtr pvarAttribute);
}
[ComImport, Guid("279A808D-AEC7-40C8-9C6B-A6B492C78A66")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IMFMediaSource : IMFMediaEventGenerator
internal static class MFSourceReaderIndex
{
#region IMFMediaEventGenerator methods
new void GetEvent(uint dwFlags, out IMFMediaEvent ppEvent);
new void BeginGetEvent(IMFAsyncCallback pCallback, object punkState);
new void EndGetEvent(IMFAsyncResult pResult, out IMFMediaEvent ppEvent);
new void QueueEvent(uint met, Guid guidExtendedType, int hrStatus, IntPtr pvValue);
#endregion
void GetCharacteristics(out uint pdwCharacteristics);
[PreserveSig]
int CreatePresentationDescriptor(
[MarshalAs(UnmanagedType.Interface)] out IMFPresentationDescriptor ppPresentationDescriptor);
void Start(
IMFPresentationDescriptor pPresentationDescriptor,
IntPtr pguidTimeFormat,
IntPtr pvarStartPosition);
void Stop();
void Pause();
void Shutdown();
}
[ComImport, Guid("7FEE9E9A-4A89-47a6-899C-B6A53A70FB67")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IMFMediaEventGenerator
{
void GetEvent(uint dwFlags, out IMFMediaEvent ppEvent);
void BeginGetEvent(IMFAsyncCallback pCallback, object punkState);
void EndGetEvent(IMFAsyncResult pResult, out IMFMediaEvent ppEvent);
void QueueEvent(uint met, Guid guidExtendedType, int hrStatus, IntPtr pvValue);
}
[ComImport, Guid("DF598932-F10C-4E39-BBA2-C308F101DAA3")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IMFMediaEvent : IMFAttributes
{
#region IMFAttributes methods
new void GetItem(Guid guidKey, IntPtr pValue);
new void GetItemType(Guid guidKey, out ushort pType);
new void CompareItem(Guid guidKey, IntPtr Value, out bool pbResult);
new void Compare(IMFAttributes pTheirs, int MatchType, out bool pbResult);
new void GetUINT32(Guid guidKey, out int punValue);
new void GetUINT64(Guid guidKey, out long punValue);
new void GetDouble(Guid guidKey, out double pfValue);
new void GetGUID(Guid guidKey, out Guid pguidValue);
new void GetStringLength(Guid guidKey, out int pcchLength);
new void GetString(Guid guidKey, IntPtr pwszValue, int cchBufSize, IntPtr pcchLength);
new void GetAllocatedString(Guid guidKey, out IntPtr ppwszValue, out int pcchLength);
new void GetBlobSize(Guid guidKey, out int pcbBlobSize);
new void GetBlob(Guid guidKey, IntPtr pBuf, int cbBufSize, IntPtr pcbBlobSize);
new void GetAllocatedBlob(Guid guidKey, out IntPtr ppBuf, out int pcbSize);
new void GetUnknown(Guid guidKey, Guid riid, out IntPtr ppv);
new void SetItem(Guid guidKey, IntPtr Value);
new void DeleteItem(Guid guidKey);
new void DeleteAllItems();
new void SetUINT32(Guid guidKey, int unValue);
new void SetUINT64(Guid guidKey, long unValue);
new void SetDouble(Guid guidKey, double fValue);
new void SetGUID(Guid guidKey, Guid guidValue);
new void SetString(Guid guidKey, [MarshalAs(UnmanagedType.LPWStr)] string wszValue);
new void SetBlob(Guid guidKey, IntPtr pBuf, int cbBufSize);
new void SetUnknown(Guid guidKey, [MarshalAs(UnmanagedType.IUnknown)] object pUnknown);
new void LockStore();
new void UnlockStore();
new void GetCount(out int pcItems);
new void GetItemByIndex(int unIndex, out Guid pguidKey, IntPtr pValue);
new void CopyAllItems(IMFAttributes pDest);
#endregion
void GetType(out uint pmet);
void GetExtendedType(out Guid pguidExtendedType);
void GetStatus(out int phrStatus);
void GetValue(out object pvValue);
public const int FirstVideoStream = unchecked((int)0xFFFFFFFC);
public const int FirstAudioStream = unchecked((int)0xFFFFFFFD);
public const int MediaSource = unchecked((int)0xFFFFFFFF);
}
[ComImport, Guid("2CD2D921-C447-44A7-A13C-4ADABFC247E3")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IMFAttributes
{
void GetItem(Guid guidKey, IntPtr pValue);
void GetItemType(Guid guidKey, out ushort pType);
void CompareItem(Guid guidKey, IntPtr Value, out bool pbResult);
void Compare(IMFAttributes pTheirs, int MatchType, out bool pbResult);
void GetUINT32(Guid guidKey, out int punValue);
void GetUINT64(Guid guidKey, out long punValue);
void GetDouble(Guid guidKey, out double pfValue);
void GetGUID(Guid guidKey, out Guid pguidValue);
void GetStringLength(Guid guidKey, out int pcchLength);
void GetString(Guid guidKey, IntPtr pwszValue, int cchBufSize, IntPtr pcchLength);
void GetAllocatedString(Guid guidKey, out IntPtr ppwszValue, out int pcchLength);
void GetBlobSize(Guid guidKey, out int pcbBlobSize);
void GetBlob(Guid guidKey, IntPtr pBuf, int cbBufSize, IntPtr pcbBlobSize);
void GetAllocatedBlob(Guid guidKey, out IntPtr ppBuf, out int pcbSize);
void GetUnknown(Guid guidKey, Guid riid, out IntPtr ppv);
void SetItem(Guid guidKey, IntPtr Value);
void DeleteItem(Guid guidKey);
void DeleteAllItems();
void SetUINT32(Guid guidKey, int unValue);
void SetUINT64(Guid guidKey, long unValue);
void SetDouble(Guid guidKey, double fValue);
void SetGUID(Guid guidKey, Guid guidValue);
void SetString(Guid guidKey, [MarshalAs(UnmanagedType.LPWStr)] string wszValue);
void SetBlob(Guid guidKey, IntPtr pBuf, int cbBufSize);
void SetUnknown(Guid guidKey, [MarshalAs(UnmanagedType.IUnknown)] object pUnknown);
void LockStore();
void UnlockStore();
void GetCount(out int pcItems);
void GetItemByIndex(int unIndex, out Guid pguidKey, IntPtr pValue);
void CopyAllItems(IMFAttributes pDest);
}
[ComImport, Guid("03CB2711-24D7-4DB6-A17F-F3A7A479A536")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IMFPresentationDescriptor : IMFAttributes
{
#region IMFAttributes methods
new void GetItem(Guid guidKey, IntPtr pValue);
new void GetItemType(Guid guidKey, out ushort pType);
new void CompareItem(Guid guidKey, IntPtr Value, out bool pbResult);
new void Compare(IMFAttributes pTheirs, int MatchType, out bool pbResult);
new void GetUINT32(Guid guidKey, out int punValue);
new void GetUINT64(Guid guidKey, out long punValue);
new void GetDouble(Guid guidKey, out double pfValue);
new void GetGUID(Guid guidKey, out Guid pguidValue);
new void GetStringLength(Guid guidKey, out int pcchLength);
new void GetString(Guid guidKey, IntPtr pwszValue, int cchBufSize, IntPtr pcchLength);
new void GetAllocatedString(Guid guidKey, out IntPtr ppwszValue, out int pcchLength);
new void GetBlobSize(Guid guidKey, out int pcbBlobSize);
new void GetBlob(Guid guidKey, IntPtr pBuf, int cbBufSize, IntPtr pcbBlobSize);
new void GetAllocatedBlob(Guid guidKey, out IntPtr ppBuf, out int pcbSize);
new void GetUnknown(Guid guidKey, Guid riid, out IntPtr ppv);
new void SetItem(Guid guidKey, IntPtr Value);
new void DeleteItem(Guid guidKey);
new void DeleteAllItems();
new void SetUINT32(Guid guidKey, int unValue);
new void SetUINT64(Guid guidKey, long unValue);
new void SetDouble(Guid guidKey, double fValue);
new void SetGUID(Guid guidKey, Guid guidValue);
new void SetString(Guid guidKey, [MarshalAs(UnmanagedType.LPWStr)] string wszValue);
new void SetBlob(Guid guidKey, IntPtr pBuf, int cbBufSize);
new void SetUnknown(Guid guidKey, [MarshalAs(UnmanagedType.IUnknown)] object pUnknown);
new void LockStore();
new void UnlockStore();
new void GetCount(out int pcItems);
new void GetItemByIndex(int unIndex, out Guid pguidKey, IntPtr pValue);
new void CopyAllItems(IMFAttributes pDest);
#endregion
void GetStreamDescriptorCount(out int pdwDescriptorCount);
[PreserveSig]
int GetStreamDescriptorByIndex(
int dwIndex,
out bool pfSelected,
[MarshalAs(UnmanagedType.Interface)] out IMFStreamDescriptor ppDescriptor);
void SelectStream(int dwDescriptorIndex);
void DeselectStream(int dwDescriptorIndex);
void Clone(out IMFPresentationDescriptor ppPresentationDescriptor);
}
[ComImport, Guid("56C03D9C-9DBB-45F5-AB4B-D80F47C05938")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IMFStreamDescriptor : IMFAttributes
{
#region IMFAttributes methods
new void GetItem(Guid guidKey, IntPtr pValue);
new void GetItemType(Guid guidKey, out ushort pType);
new void CompareItem(Guid guidKey, IntPtr Value, out bool pbResult);
new void Compare(IMFAttributes pTheirs, int MatchType, out bool pbResult);
new void GetUINT32(Guid guidKey, out int punValue);
new void GetUINT64(Guid guidKey, out long punValue);
new void GetDouble(Guid guidKey, out double pfValue);
new void GetGUID(Guid guidKey, out Guid pguidValue);
new void GetStringLength(Guid guidKey, out int pcchLength);
new void GetString(Guid guidKey, IntPtr pwszValue, int cchBufSize, IntPtr pcchLength);
new void GetAllocatedString(Guid guidKey, out IntPtr ppwszValue, out int pcchLength);
new void GetBlobSize(Guid guidKey, out int pcbBlobSize);
new void GetBlob(Guid guidKey, IntPtr pBuf, int cbBufSize, IntPtr pcbBlobSize);
new void GetAllocatedBlob(Guid guidKey, out IntPtr ppBuf, out int pcbSize);
new void GetUnknown(Guid guidKey, Guid riid, out IntPtr ppv);
new void SetItem(Guid guidKey, IntPtr Value);
new void DeleteItem(Guid guidKey);
new void DeleteAllItems();
new void SetUINT32(Guid guidKey, int unValue);
new void SetUINT64(Guid guidKey, long unValue);
new void SetDouble(Guid guidKey, double fValue);
new void SetGUID(Guid guidKey, Guid guidValue);
new void SetString(Guid guidKey, [MarshalAs(UnmanagedType.LPWStr)] string wszValue);
new void SetBlob(Guid guidKey, IntPtr pBuf, int cbBufSize);
new void SetUnknown(Guid guidKey, [MarshalAs(UnmanagedType.IUnknown)] object pUnknown);
new void LockStore();
new void UnlockStore();
new void GetCount(out int pcItems);
new void GetItemByIndex(int unIndex, out Guid pguidKey, IntPtr pValue);
new void CopyAllItems(IMFAttributes pDest);
#endregion
void GetStreamIdentifier(out int pdwStreamIdentifier);
[PreserveSig]
int GetMediaTypeHandler(
[MarshalAs(UnmanagedType.Interface)] out IMFMediaTypeHandler ppMediaTypeHandler);
}
[ComImport, Guid("E93DCF6C-4B07-4E1E-8123-AA16ED6EADF5")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IMFMediaTypeHandler
{
void IsMediaTypeSupported(IMFMediaType pMediaType, out IMFMediaType ppMediaType);
void GetMediaTypeCount(out int pdwTypeCount);
void GetMediaTypeByIndex(int dwIndex, out IMFMediaType ppType);
[PreserveSig]
int SetCurrentMediaType(IMFMediaType pMediaType);
[PreserveSig]
int GetCurrentMediaType([MarshalAs(UnmanagedType.Interface)] out IMFMediaType ppMediaType);
[PreserveSig]
int GetMajorType(out Guid pguidMajorType);
[PreserveSig] int GetItem(Guid guidKey, IntPtr pValue);
[PreserveSig] int GetItemType(Guid guidKey, out ushort pType);
[PreserveSig] int CompareItem(Guid guidKey, IntPtr Value, out bool pbResult);
[PreserveSig] int Compare(IMFAttributes pTheirs, int MatchType, out bool pbResult);
[PreserveSig] int GetUINT32(Guid guidKey, out int punValue);
[PreserveSig] int GetUINT64(Guid guidKey, out long punValue);
[PreserveSig] int GetDouble(Guid guidKey, out double pfValue);
[PreserveSig] int GetGUID(Guid guidKey, out Guid pguidValue);
[PreserveSig] int GetStringLength(Guid guidKey, out int pcchLength);
[PreserveSig] int GetString(Guid guidKey, IntPtr pwszValue, int cchBufSize, IntPtr pcchLength);
[PreserveSig] int GetAllocatedString(Guid guidKey, out IntPtr ppwszValue, out int pcchLength);
[PreserveSig] int GetBlobSize(Guid guidKey, out int pcbBlobSize);
[PreserveSig] int GetBlob(Guid guidKey, IntPtr pBuf, int cbBufSize, IntPtr pcbBlobSize);
[PreserveSig] int GetAllocatedBlob(Guid guidKey, out IntPtr ppBuf, out int pcbSize);
[PreserveSig] int GetUnknown(Guid guidKey, Guid riid, out IntPtr ppv);
[PreserveSig] int SetItem(Guid guidKey, IntPtr Value);
[PreserveSig] int DeleteItem(Guid guidKey);
[PreserveSig] int DeleteAllItems();
[PreserveSig] int SetUINT32(Guid guidKey, int unValue);
[PreserveSig] int SetUINT64(Guid guidKey, long unValue);
[PreserveSig] int SetDouble(Guid guidKey, double fValue);
[PreserveSig] int SetGUID(Guid guidKey, Guid guidValue);
[PreserveSig] int SetString(Guid guidKey, [MarshalAs(UnmanagedType.LPWStr)] string wszValue);
[PreserveSig] int SetBlob(Guid guidKey, IntPtr pBuf, int cbBufSize);
[PreserveSig] int SetUnknown(Guid guidKey, [MarshalAs(UnmanagedType.IUnknown)] object pUnknown);
[PreserveSig] int LockStore();
[PreserveSig] int UnlockStore();
[PreserveSig] int GetCount(out int pcItems);
[PreserveSig] int GetItemByIndex(int unIndex, out Guid pguidKey, IntPtr pValue);
[PreserveSig] int CopyAllItems(IMFAttributes pDest);
}
[ComImport, Guid("44AE0FA8-EA31-4109-8D2E-4CAE4997C555")]
@@ -505,96 +244,43 @@ namespace Ganimede.VideoProcessing
internal interface IMFMediaType : IMFAttributes
{
#region IMFAttributes methods
new void GetItem(Guid guidKey, IntPtr pValue);
new void GetItemType(Guid guidKey, out ushort pType);
new void CompareItem(Guid guidKey, IntPtr Value, out bool pbResult);
new void Compare(IMFAttributes pTheirs, int MatchType, out bool pbResult);
new void GetUINT32(Guid guidKey, out int punValue);
new void GetUINT64(Guid guidKey, out long punValue);
new void GetDouble(Guid guidKey, out double pfValue);
new void GetGUID(Guid guidKey, out Guid pguidValue);
new void GetStringLength(Guid guidKey, out int pcchLength);
new void GetString(Guid guidKey, IntPtr pwszValue, int cchBufSize, IntPtr pcchLength);
new void GetAllocatedString(Guid guidKey, out IntPtr ppwszValue, out int pcchLength);
new void GetBlobSize(Guid guidKey, out int pcbBlobSize);
new void GetBlob(Guid guidKey, IntPtr pBuf, int cbBufSize, IntPtr pcbBlobSize);
new void GetAllocatedBlob(Guid guidKey, out IntPtr ppBuf, out int pcbSize);
new void GetUnknown(Guid guidKey, Guid riid, out IntPtr ppv);
new void SetItem(Guid guidKey, IntPtr Value);
new void DeleteItem(Guid guidKey);
new void DeleteAllItems();
new void SetUINT32(Guid guidKey, int unValue);
new void SetUINT64(Guid guidKey, long unValue);
new void SetDouble(Guid guidKey, double fValue);
new void SetGUID(Guid guidKey, Guid guidValue);
new void SetString(Guid guidKey, [MarshalAs(UnmanagedType.LPWStr)] string wszValue);
new void SetBlob(Guid guidKey, IntPtr pBuf, int cbBufSize);
new void SetUnknown(Guid guidKey, [MarshalAs(UnmanagedType.IUnknown)] object pUnknown);
new void LockStore();
new void UnlockStore();
new void GetCount(out int pcItems);
new void GetItemByIndex(int unIndex, out Guid pguidKey, IntPtr pValue);
new void CopyAllItems(IMFAttributes pDest);
[PreserveSig] new int GetItem(Guid guidKey, IntPtr pValue);
[PreserveSig] new int GetItemType(Guid guidKey, out ushort pType);
[PreserveSig] new int CompareItem(Guid guidKey, IntPtr Value, out bool pbResult);
[PreserveSig] new int Compare(IMFAttributes pTheirs, int MatchType, out bool pbResult);
[PreserveSig] new int GetUINT32(Guid guidKey, out int punValue);
[PreserveSig] new int GetUINT64(Guid guidKey, out long punValue);
[PreserveSig] new int GetDouble(Guid guidKey, out double pfValue);
[PreserveSig] new int GetGUID(Guid guidKey, out Guid pguidValue);
[PreserveSig] new int GetStringLength(Guid guidKey, out int pcchLength);
[PreserveSig] new int GetString(Guid guidKey, IntPtr pwszValue, int cchBufSize, IntPtr pcchLength);
[PreserveSig] new int GetAllocatedString(Guid guidKey, out IntPtr ppwszValue, out int pcchLength);
[PreserveSig] new int GetBlobSize(Guid guidKey, out int pcbBlobSize);
[PreserveSig] new int GetBlob(Guid guidKey, IntPtr pBuf, int cbBufSize, IntPtr pcbBlobSize);
[PreserveSig] new int GetAllocatedBlob(Guid guidKey, out IntPtr ppBuf, out int pcbSize);
[PreserveSig] new int GetUnknown(Guid guidKey, Guid riid, out IntPtr ppv);
[PreserveSig] new int SetItem(Guid guidKey, IntPtr Value);
[PreserveSig] new int DeleteItem(Guid guidKey);
[PreserveSig] new int DeleteAllItems();
[PreserveSig] new int SetUINT32(Guid guidKey, int unValue);
[PreserveSig] new int SetUINT64(Guid guidKey, long unValue);
[PreserveSig] new int SetDouble(Guid guidKey, double fValue);
[PreserveSig] new int SetGUID(Guid guidKey, Guid guidValue);
[PreserveSig] new int SetString(Guid guidKey, [MarshalAs(UnmanagedType.LPWStr)] string wszValue);
[PreserveSig] new int SetBlob(Guid guidKey, IntPtr pBuf, int cbBufSize);
[PreserveSig] new int SetUnknown(Guid guidKey, [MarshalAs(UnmanagedType.IUnknown)] object pUnknown);
[PreserveSig] new int LockStore();
[PreserveSig] new int UnlockStore();
[PreserveSig] new int GetCount(out int pcItems);
[PreserveSig] new int GetItemByIndex(int unIndex, out Guid pguidKey, IntPtr pValue);
[PreserveSig] new int CopyAllItems(IMFAttributes pDest);
#endregion
void GetMajorType(out Guid pguidMajorType);
void IsCompressedFormat(out bool pfCompressed);
void IsEqual(IMFMediaType pIMediaType, out uint pdwFlags);
void GetRepresentation(Guid guidRepresentation, out IntPtr ppvRepresentation);
void FreeRepresentation(Guid guidRepresentation, IntPtr pvRepresentation);
}
[ComImport, Guid("AC6B7889-0740-4D51-8619-905994A55CC6")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IMFAsyncResult
{
void GetState([MarshalAs(UnmanagedType.IUnknown)] out object ppunkState);
void GetStatus();
void SetStatus(int hrStatus);
void GetObject([MarshalAs(UnmanagedType.IUnknown)] out object ppObject);
[return: MarshalAs(UnmanagedType.IUnknown)]
object GetStateNoAddRef();
}
[ComImport, Guid("A27003CF-2354-4F2A-8D6A-AB7CFF15437E")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IMFAsyncCallback
{
void GetParameters(out uint pdwFlags, out uint pdwQueue);
void Invoke(IMFAsyncResult pAsyncResult);
}
[ComImport, Guid("AD4C1B00-4BF7-422F-9175-756693D9130D")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IMFByteStream
{
// Methods not needed for this implementation
}
[ComImport, Guid("886d8eeb-8cf2-4446-8d02-cdba1dbdcf99")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IPropertyStore
{
// Methods not needed for this implementation
}
internal enum MFResolution
{
MediaSource = 0x00000001,
ByteStream = 0x00000002,
ContentDoesNotHaveToMatchExtensionOrMimeType = 0x00000010,
KeepByteStreamAliveOnFail = 0x00000020,
DisableLocalPlugins = 0x00000040,
PluginControlPolicy = 0x00000080,
Read = 0x00010000,
Write = 0x00020000
}
internal enum MFObjectType
{
MediaSource = 0,
ByteStream = 1,
Unknown = 2
[PreserveSig] int GetMajorType(out Guid pguidMajorType);
[PreserveSig] int IsCompressedFormat(out bool pfCompressed);
[PreserveSig] int IsEqual(IMFMediaType pIMediaType, out uint pdwFlags);
[PreserveSig] int GetRepresentation(Guid guidRepresentation, out IntPtr ppvRepresentation);
[PreserveSig] int FreeRepresentation(Guid guidRepresentation, IntPtr pvRepresentation);
}
internal static class MFAttributesClsid

View File

@@ -1,4 +0,0 @@
namespace Ganimede.ViewModels
{
// ViewModel principale e futuri ViewModel
}

View File

@@ -1,4 +0,0 @@
namespace Ganimede.Views
{
// Views aggiuntive se necessario
}