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>
|
||||
|
||||
<!-- Native Windows libraries (included in Windows) -->
|
||||
<ItemGroup>
|
||||
<Reference Include="System.Drawing" />
|
||||
</ItemGroup>
|
||||
|
||||
</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.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>
|
||||
|
||||
@@ -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.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
|
||||
|
||||
@@ -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