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:
@@ -31,8 +31,5 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<!-- Native Windows libraries (included in Windows) -->
|
<!-- Native Windows libraries (included in Windows) -->
|
||||||
<ItemGroup>
|
|
||||||
<Reference Include="System.Drawing" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
namespace Ganimede.Models
|
|
||||||
{
|
|
||||||
// Modelli futuri (es. VideoInfo, FrameInfo)
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
@@ -2,7 +2,7 @@ using System;
|
|||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Drawing.Imaging;
|
using System.Drawing.Imaging;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.InteropServices;
|
using Ganimede.VideoProcessing.MediaFoundation;
|
||||||
|
|
||||||
namespace Ganimede.VideoProcessing
|
namespace Ganimede.VideoProcessing
|
||||||
{
|
{
|
||||||
@@ -25,14 +25,36 @@ namespace Ganimede.VideoProcessing
|
|||||||
if (!File.Exists(videoPath))
|
if (!File.Exists(videoPath))
|
||||||
throw new FileNotFoundException($"Video file not found: {videoPath}");
|
throw new FileNotFoundException($"Video file not found: {videoPath}");
|
||||||
|
|
||||||
// For now, this is a placeholder implementation
|
try
|
||||||
// Full Windows Media Foundation frame extraction is very complex
|
{
|
||||||
// and requires several thousand lines of P/Invoke code
|
using (var reader = new MFVideoReader(videoPath))
|
||||||
|
{
|
||||||
throw new NotImplementedException(
|
// Read frame at specified time
|
||||||
"Frame extraction with Windows Media Foundation requires extensive implementation. " +
|
using (var bitmap = reader.ReadFrameAtTime(timePosition))
|
||||||
"This feature will be added in a future update. " +
|
{
|
||||||
"For now, please use alternative methods or third-party tools.");
|
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>
|
/// <summary>
|
||||||
@@ -53,10 +75,61 @@ namespace Ganimede.VideoProcessing
|
|||||||
if (!Directory.Exists(outputFolder))
|
if (!Directory.Exists(outputFolder))
|
||||||
Directory.CreateDirectory(outputFolder);
|
Directory.CreateDirectory(outputFolder);
|
||||||
|
|
||||||
// For now, this is a placeholder implementation
|
try
|
||||||
throw new NotImplementedException(
|
{
|
||||||
"Full frame extraction with Windows Media Foundation requires extensive implementation. " +
|
using (var reader = new MFVideoReader(videoPath))
|
||||||
"This feature will be added in a future update.");
|
{
|
||||||
|
// 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>
|
/// <summary>
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.InteropServices.ComTypes;
|
|
||||||
|
|
||||||
namespace Ganimede.VideoProcessing
|
namespace Ganimede.VideoProcessing
|
||||||
{
|
{
|
||||||
@@ -12,7 +11,7 @@ namespace Ganimede.VideoProcessing
|
|||||||
public class VideoAnalyzer
|
public class VideoAnalyzer
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <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>
|
/// </summary>
|
||||||
public static VideoMetadata Analyze(string videoPath)
|
public static VideoMetadata Analyze(string videoPath)
|
||||||
{
|
{
|
||||||
@@ -25,140 +24,103 @@ namespace Ganimede.VideoProcessing
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
IMFSourceResolver? sourceResolver = null;
|
IntPtr pSourceReader = IntPtr.Zero;
|
||||||
IMFMediaSource? mediaSource = null;
|
IMFSourceReader? sourceReader = null;
|
||||||
IMFPresentationDescriptor? presentationDescriptor = null;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Create source resolver
|
// Create source reader from URL
|
||||||
hr = MFExtern.MFCreateSourceResolver(out sourceResolver);
|
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);
|
Marshal.ThrowExceptionForHR(hr);
|
||||||
|
|
||||||
// Create media source from file
|
IMFMediaType? mediaType = null;
|
||||||
MFObjectType objectType;
|
try
|
||||||
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++)
|
|
||||||
{
|
{
|
||||||
IMFStreamDescriptor? streamDescriptor = null;
|
mediaType = (IMFMediaType)Marshal.GetObjectForIUnknown(pMediaType);
|
||||||
bool selected;
|
|
||||||
|
|
||||||
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);
|
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
|
try
|
||||||
{
|
{
|
||||||
// Get media type handler
|
hr = sourceReader.GetPresentationAttribute(
|
||||||
IMFMediaTypeHandler? handler = null;
|
MFSourceReaderIndex.MediaSource,
|
||||||
hr = streamDescriptor!.GetMediaTypeHandler(out handler);
|
MFAttributesClsid.MF_PD_DURATION,
|
||||||
Marshal.ThrowExceptionForHR(hr);
|
varDuration);
|
||||||
|
|
||||||
try
|
TimeSpan duration = TimeSpan.Zero;
|
||||||
|
if (hr >= 0)
|
||||||
{
|
{
|
||||||
// Get major type
|
// Read PROPVARIANT (VT_I8)
|
||||||
Guid majorType;
|
long durationTicks = Marshal.ReadInt64(varDuration, 8);
|
||||||
hr = handler!.GetMajorType(out majorType);
|
duration = TimeSpan.FromTicks(durationTicks / 10); // Convert from 100-nanosecond units
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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
|
finally
|
||||||
{
|
{
|
||||||
if (streamDescriptor != null) Marshal.ReleaseComObject(streamDescriptor);
|
Marshal.FreeHGlobal(varDuration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
throw new InvalidOperationException("No video stream found in the file");
|
{
|
||||||
|
if (mediaType != null) Marshal.ReleaseComObject(mediaType);
|
||||||
|
if (pMediaType != IntPtr.Zero) Marshal.Release(pMediaType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if (presentationDescriptor != null) Marshal.ReleaseComObject(presentationDescriptor);
|
if (sourceReader != null) Marshal.ReleaseComObject(sourceReader);
|
||||||
if (mediaSource != null) Marshal.ReleaseComObject(mediaSource);
|
if (pSourceReader != IntPtr.Zero) Marshal.Release(pSourceReader);
|
||||||
if (sourceResolver != null) Marshal.ReleaseComObject(sourceResolver);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@@ -204,300 +166,77 @@ namespace Ganimede.VideoProcessing
|
|||||||
private const uint MF_API_VERSION = 0x0070;
|
private const uint MF_API_VERSION = 0x0070;
|
||||||
internal const uint MF_VERSION = (MF_SDK_VERSION << 16) | MF_API_VERSION;
|
internal const uint MF_VERSION = (MF_SDK_VERSION << 16) | MF_API_VERSION;
|
||||||
|
|
||||||
[DllImport("mfplat.dll", ExactSpelling = true, PreserveSig = false)]
|
[DllImport("mfplat.dll", ExactSpelling = true, PreserveSig = true)]
|
||||||
internal static extern void MFStartup(uint Version, uint dwFlags = 0);
|
internal static extern int MFStartup(uint Version, uint dwFlags = 0);
|
||||||
|
|
||||||
[DllImport("mfplat.dll", ExactSpelling = true, PreserveSig = false)]
|
[DllImport("mfplat.dll", ExactSpelling = true, PreserveSig = true)]
|
||||||
internal static extern void MFShutdown();
|
internal static extern int MFShutdown();
|
||||||
|
|
||||||
[DllImport("mfplat.dll", ExactSpelling = true, PreserveSig = false)]
|
[DllImport("mfreadwrite.dll", ExactSpelling = true, PreserveSig = true)]
|
||||||
internal static extern void MFCreateSourceResolver(
|
internal static extern int MFCreateSourceReaderFromURL(
|
||||||
[MarshalAs(UnmanagedType.Interface)] out IMFSourceResolver ppISourceResolver);
|
[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)]
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||||
internal interface IMFSourceResolver
|
internal interface IMFSourceReader
|
||||||
{
|
{
|
||||||
[PreserveSig]
|
[PreserveSig] int GetStreamSelection(int dwStreamIndex, out bool pfSelected);
|
||||||
int CreateObjectFromURL(
|
[PreserveSig] int SetStreamSelection(int dwStreamIndex, bool fSelected);
|
||||||
[In, MarshalAs(UnmanagedType.LPWStr)] string pwszURL,
|
[PreserveSig] int GetNativeMediaType(int dwStreamIndex, int dwMediaTypeIndex, out IntPtr ppMediaType);
|
||||||
[In] MFResolution dwFlags,
|
[PreserveSig] int GetCurrentMediaType(int dwStreamIndex, out IntPtr ppMediaType);
|
||||||
[In, MarshalAs(UnmanagedType.Interface)] IPropertyStore? pProps,
|
[PreserveSig] int SetCurrentMediaType(int dwStreamIndex, IntPtr pdwReserved, IntPtr pMediaType);
|
||||||
[Out] out MFObjectType pObjectType,
|
[PreserveSig] int SetCurrentPosition(Guid guidTimeFormat, IntPtr varPosition);
|
||||||
[Out, MarshalAs(UnmanagedType.IUnknown)] out object ppObject);
|
[PreserveSig] int ReadSample(int dwStreamIndex, int dwControlFlags, out int pdwActualStreamIndex,
|
||||||
|
out int pdwStreamFlags, out long pllTimestamp, out IntPtr ppSample);
|
||||||
[PreserveSig]
|
[PreserveSig] int Flush(int dwStreamIndex);
|
||||||
int CreateObjectFromByteStream(
|
[PreserveSig] int GetServiceForStream(int dwStreamIndex, Guid guidService, Guid riid, out IntPtr ppvObject);
|
||||||
[In, MarshalAs(UnmanagedType.Interface)] IMFByteStream pByteStream,
|
[PreserveSig] int GetPresentationAttribute(int dwStreamIndex, Guid guidAttribute, IntPtr pvarAttribute);
|
||||||
[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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[ComImport, Guid("279A808D-AEC7-40C8-9C6B-A6B492C78A66")]
|
internal static class MFSourceReaderIndex
|
||||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
|
||||||
internal interface IMFMediaSource : IMFMediaEventGenerator
|
|
||||||
{
|
{
|
||||||
#region IMFMediaEventGenerator methods
|
public const int FirstVideoStream = unchecked((int)0xFFFFFFFC);
|
||||||
new void GetEvent(uint dwFlags, out IMFMediaEvent ppEvent);
|
public const int FirstAudioStream = unchecked((int)0xFFFFFFFD);
|
||||||
new void BeginGetEvent(IMFAsyncCallback pCallback, object punkState);
|
public const int MediaSource = unchecked((int)0xFFFFFFFF);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[ComImport, Guid("2CD2D921-C447-44A7-A13C-4ADABFC247E3")]
|
[ComImport, Guid("2CD2D921-C447-44A7-A13C-4ADABFC247E3")]
|
||||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||||
internal interface IMFAttributes
|
internal interface IMFAttributes
|
||||||
{
|
{
|
||||||
void GetItem(Guid guidKey, IntPtr pValue);
|
[PreserveSig] int GetItem(Guid guidKey, IntPtr pValue);
|
||||||
void GetItemType(Guid guidKey, out ushort pType);
|
[PreserveSig] int GetItemType(Guid guidKey, out ushort pType);
|
||||||
void CompareItem(Guid guidKey, IntPtr Value, out bool pbResult);
|
[PreserveSig] int CompareItem(Guid guidKey, IntPtr Value, out bool pbResult);
|
||||||
void Compare(IMFAttributes pTheirs, int MatchType, out bool pbResult);
|
[PreserveSig] int Compare(IMFAttributes pTheirs, int MatchType, out bool pbResult);
|
||||||
void GetUINT32(Guid guidKey, out int punValue);
|
[PreserveSig] int GetUINT32(Guid guidKey, out int punValue);
|
||||||
void GetUINT64(Guid guidKey, out long punValue);
|
[PreserveSig] int GetUINT64(Guid guidKey, out long punValue);
|
||||||
void GetDouble(Guid guidKey, out double pfValue);
|
[PreserveSig] int GetDouble(Guid guidKey, out double pfValue);
|
||||||
void GetGUID(Guid guidKey, out Guid pguidValue);
|
[PreserveSig] int GetGUID(Guid guidKey, out Guid pguidValue);
|
||||||
void GetStringLength(Guid guidKey, out int pcchLength);
|
[PreserveSig] int GetStringLength(Guid guidKey, out int pcchLength);
|
||||||
void GetString(Guid guidKey, IntPtr pwszValue, int cchBufSize, IntPtr pcchLength);
|
[PreserveSig] int GetString(Guid guidKey, IntPtr pwszValue, int cchBufSize, IntPtr pcchLength);
|
||||||
void GetAllocatedString(Guid guidKey, out IntPtr ppwszValue, out int pcchLength);
|
[PreserveSig] int GetAllocatedString(Guid guidKey, out IntPtr ppwszValue, out int pcchLength);
|
||||||
void GetBlobSize(Guid guidKey, out int pcbBlobSize);
|
[PreserveSig] int GetBlobSize(Guid guidKey, out int pcbBlobSize);
|
||||||
void GetBlob(Guid guidKey, IntPtr pBuf, int cbBufSize, IntPtr pcbBlobSize);
|
[PreserveSig] int GetBlob(Guid guidKey, IntPtr pBuf, int cbBufSize, IntPtr pcbBlobSize);
|
||||||
void GetAllocatedBlob(Guid guidKey, out IntPtr ppBuf, out int pcbSize);
|
[PreserveSig] int GetAllocatedBlob(Guid guidKey, out IntPtr ppBuf, out int pcbSize);
|
||||||
void GetUnknown(Guid guidKey, Guid riid, out IntPtr ppv);
|
[PreserveSig] int GetUnknown(Guid guidKey, Guid riid, out IntPtr ppv);
|
||||||
void SetItem(Guid guidKey, IntPtr Value);
|
[PreserveSig] int SetItem(Guid guidKey, IntPtr Value);
|
||||||
void DeleteItem(Guid guidKey);
|
[PreserveSig] int DeleteItem(Guid guidKey);
|
||||||
void DeleteAllItems();
|
[PreserveSig] int DeleteAllItems();
|
||||||
void SetUINT32(Guid guidKey, int unValue);
|
[PreserveSig] int SetUINT32(Guid guidKey, int unValue);
|
||||||
void SetUINT64(Guid guidKey, long unValue);
|
[PreserveSig] int SetUINT64(Guid guidKey, long unValue);
|
||||||
void SetDouble(Guid guidKey, double fValue);
|
[PreserveSig] int SetDouble(Guid guidKey, double fValue);
|
||||||
void SetGUID(Guid guidKey, Guid guidValue);
|
[PreserveSig] int SetGUID(Guid guidKey, Guid guidValue);
|
||||||
void SetString(Guid guidKey, [MarshalAs(UnmanagedType.LPWStr)] string wszValue);
|
[PreserveSig] int SetString(Guid guidKey, [MarshalAs(UnmanagedType.LPWStr)] string wszValue);
|
||||||
void SetBlob(Guid guidKey, IntPtr pBuf, int cbBufSize);
|
[PreserveSig] int SetBlob(Guid guidKey, IntPtr pBuf, int cbBufSize);
|
||||||
void SetUnknown(Guid guidKey, [MarshalAs(UnmanagedType.IUnknown)] object pUnknown);
|
[PreserveSig] int SetUnknown(Guid guidKey, [MarshalAs(UnmanagedType.IUnknown)] object pUnknown);
|
||||||
void LockStore();
|
[PreserveSig] int LockStore();
|
||||||
void UnlockStore();
|
[PreserveSig] int UnlockStore();
|
||||||
void GetCount(out int pcItems);
|
[PreserveSig] int GetCount(out int pcItems);
|
||||||
void GetItemByIndex(int unIndex, out Guid pguidKey, IntPtr pValue);
|
[PreserveSig] int GetItemByIndex(int unIndex, out Guid pguidKey, IntPtr pValue);
|
||||||
void CopyAllItems(IMFAttributes pDest);
|
[PreserveSig] int 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[ComImport, Guid("44AE0FA8-EA31-4109-8D2E-4CAE4997C555")]
|
[ComImport, Guid("44AE0FA8-EA31-4109-8D2E-4CAE4997C555")]
|
||||||
@@ -505,96 +244,43 @@ namespace Ganimede.VideoProcessing
|
|||||||
internal interface IMFMediaType : IMFAttributes
|
internal interface IMFMediaType : IMFAttributes
|
||||||
{
|
{
|
||||||
#region IMFAttributes methods
|
#region IMFAttributes methods
|
||||||
new void GetItem(Guid guidKey, IntPtr pValue);
|
[PreserveSig] new int GetItem(Guid guidKey, IntPtr pValue);
|
||||||
new void GetItemType(Guid guidKey, out ushort pType);
|
[PreserveSig] new int GetItemType(Guid guidKey, out ushort pType);
|
||||||
new void CompareItem(Guid guidKey, IntPtr Value, out bool pbResult);
|
[PreserveSig] new int CompareItem(Guid guidKey, IntPtr Value, out bool pbResult);
|
||||||
new void Compare(IMFAttributes pTheirs, int MatchType, out bool pbResult);
|
[PreserveSig] new int Compare(IMFAttributes pTheirs, int MatchType, out bool pbResult);
|
||||||
new void GetUINT32(Guid guidKey, out int punValue);
|
[PreserveSig] new int GetUINT32(Guid guidKey, out int punValue);
|
||||||
new void GetUINT64(Guid guidKey, out long punValue);
|
[PreserveSig] new int GetUINT64(Guid guidKey, out long punValue);
|
||||||
new void GetDouble(Guid guidKey, out double pfValue);
|
[PreserveSig] new int GetDouble(Guid guidKey, out double pfValue);
|
||||||
new void GetGUID(Guid guidKey, out Guid pguidValue);
|
[PreserveSig] new int GetGUID(Guid guidKey, out Guid pguidValue);
|
||||||
new void GetStringLength(Guid guidKey, out int pcchLength);
|
[PreserveSig] new int GetStringLength(Guid guidKey, out int pcchLength);
|
||||||
new void GetString(Guid guidKey, IntPtr pwszValue, int cchBufSize, IntPtr pcchLength);
|
[PreserveSig] new int GetString(Guid guidKey, IntPtr pwszValue, int cchBufSize, IntPtr pcchLength);
|
||||||
new void GetAllocatedString(Guid guidKey, out IntPtr ppwszValue, out int pcchLength);
|
[PreserveSig] new int GetAllocatedString(Guid guidKey, out IntPtr ppwszValue, out int pcchLength);
|
||||||
new void GetBlobSize(Guid guidKey, out int pcbBlobSize);
|
[PreserveSig] new int GetBlobSize(Guid guidKey, out int pcbBlobSize);
|
||||||
new void GetBlob(Guid guidKey, IntPtr pBuf, int cbBufSize, IntPtr pcbBlobSize);
|
[PreserveSig] new int GetBlob(Guid guidKey, IntPtr pBuf, int cbBufSize, IntPtr pcbBlobSize);
|
||||||
new void GetAllocatedBlob(Guid guidKey, out IntPtr ppBuf, out int pcbSize);
|
[PreserveSig] new int GetAllocatedBlob(Guid guidKey, out IntPtr ppBuf, out int pcbSize);
|
||||||
new void GetUnknown(Guid guidKey, Guid riid, out IntPtr ppv);
|
[PreserveSig] new int GetUnknown(Guid guidKey, Guid riid, out IntPtr ppv);
|
||||||
new void SetItem(Guid guidKey, IntPtr Value);
|
[PreserveSig] new int SetItem(Guid guidKey, IntPtr Value);
|
||||||
new void DeleteItem(Guid guidKey);
|
[PreserveSig] new int DeleteItem(Guid guidKey);
|
||||||
new void DeleteAllItems();
|
[PreserveSig] new int DeleteAllItems();
|
||||||
new void SetUINT32(Guid guidKey, int unValue);
|
[PreserveSig] new int SetUINT32(Guid guidKey, int unValue);
|
||||||
new void SetUINT64(Guid guidKey, long unValue);
|
[PreserveSig] new int SetUINT64(Guid guidKey, long unValue);
|
||||||
new void SetDouble(Guid guidKey, double fValue);
|
[PreserveSig] new int SetDouble(Guid guidKey, double fValue);
|
||||||
new void SetGUID(Guid guidKey, Guid guidValue);
|
[PreserveSig] new int SetGUID(Guid guidKey, Guid guidValue);
|
||||||
new void SetString(Guid guidKey, [MarshalAs(UnmanagedType.LPWStr)] string wszValue);
|
[PreserveSig] new int SetString(Guid guidKey, [MarshalAs(UnmanagedType.LPWStr)] string wszValue);
|
||||||
new void SetBlob(Guid guidKey, IntPtr pBuf, int cbBufSize);
|
[PreserveSig] new int SetBlob(Guid guidKey, IntPtr pBuf, int cbBufSize);
|
||||||
new void SetUnknown(Guid guidKey, [MarshalAs(UnmanagedType.IUnknown)] object pUnknown);
|
[PreserveSig] new int SetUnknown(Guid guidKey, [MarshalAs(UnmanagedType.IUnknown)] object pUnknown);
|
||||||
new void LockStore();
|
[PreserveSig] new int LockStore();
|
||||||
new void UnlockStore();
|
[PreserveSig] new int UnlockStore();
|
||||||
new void GetCount(out int pcItems);
|
[PreserveSig] new int GetCount(out int pcItems);
|
||||||
new void GetItemByIndex(int unIndex, out Guid pguidKey, IntPtr pValue);
|
[PreserveSig] new int GetItemByIndex(int unIndex, out Guid pguidKey, IntPtr pValue);
|
||||||
new void CopyAllItems(IMFAttributes pDest);
|
[PreserveSig] new int CopyAllItems(IMFAttributes pDest);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
void GetMajorType(out Guid pguidMajorType);
|
[PreserveSig] int GetMajorType(out Guid pguidMajorType);
|
||||||
void IsCompressedFormat(out bool pfCompressed);
|
[PreserveSig] int IsCompressedFormat(out bool pfCompressed);
|
||||||
void IsEqual(IMFMediaType pIMediaType, out uint pdwFlags);
|
[PreserveSig] int IsEqual(IMFMediaType pIMediaType, out uint pdwFlags);
|
||||||
void GetRepresentation(Guid guidRepresentation, out IntPtr ppvRepresentation);
|
[PreserveSig] int GetRepresentation(Guid guidRepresentation, out IntPtr ppvRepresentation);
|
||||||
void FreeRepresentation(Guid guidRepresentation, IntPtr pvRepresentation);
|
[PreserveSig] int 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static class MFAttributesClsid
|
internal static class MFAttributesClsid
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
namespace Ganimede.ViewModels
|
|
||||||
{
|
|
||||||
// ViewModel principale e futuri ViewModel
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
namespace Ganimede.Views
|
|
||||||
{
|
|
||||||
// Views aggiuntive se necessario
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user