Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions src/CoreMedia/CMBlockBuffer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,27 @@ public CMBlockBufferError AccessDataBytes (nuint offset, nuint length, IntPtr te

public CMBlockBufferError CopyDataBytes (nuint offsetToData, nuint dataLength, IntPtr destination)
{
if (Handle == IntPtr.Zero)
throw new ObjectDisposedException ("BlockBuffer");

return CMBlockBufferCopyDataBytes (handle, offsetToData, dataLength, destination);
}

public CMBlockBufferError CopyDataBytes (nuint offsetToData, nuint dataLength, out byte [] destination)
{
if (Handle == IntPtr.Zero)
throw new ObjectDisposedException ("BlockBuffer");

destination = new byte [dataLength];
GCHandle destPinned = GCHandle.Alloc (destination, GCHandleType.Pinned);
IntPtr destPtr = destPinned.AddrOfPinnedObject ();
var error = CMBlockBufferCopyDataBytes (handle, offsetToData, dataLength, destPtr);
if (error != CMBlockBufferError.None)
destination = default (byte []);
destPinned.Free ();
return error;
}

[DllImport(Constants.CoreMediaLibrary)]
extern static /* OSStatus */ CMBlockBufferError CMBlockBufferReplaceDataBytes (
/* void* */ IntPtr sourceBytes,
Expand All @@ -196,6 +214,21 @@ public CMBlockBufferError ReplaceDataBytes (IntPtr sourceBytes, nuint offsetInto
return CMBlockBufferReplaceDataBytes (sourceBytes, handle, offsetIntoDestination, dataLength);
}

public CMBlockBufferError ReplaceDataBytes (byte [] sourceBytes, nuint offsetIntoDestination)
{
if (Handle == IntPtr.Zero)
throw new ObjectDisposedException ("BlockBuffer");
if (Handle == IntPtr.Zero)
throw new ArgumentNullException (nameof (sourceBytes));

GCHandle replacePinned = GCHandle.Alloc (sourceBytes, GCHandleType.Pinned);
IntPtr replacePtr = replacePinned.AddrOfPinnedObject ();

var error = ReplaceDataBytes (replacePtr, offsetIntoDestination, (nuint) sourceBytes.Length);
replacePinned.Free ();
return error;
}

[DllImport(Constants.CoreMediaLibrary)]
extern static /* OSStatus */ CMBlockBufferError CMBlockBufferFillDataBytes (
/* char */ byte fillByte,
Expand Down Expand Up @@ -307,6 +340,15 @@ public static CMBlockBuffer FromMemoryBlock (IntPtr memoryBlock, nuint blockLeng
return block;
}

public static CMBlockBuffer FromMemoryBlock (byte [] data, nuint offsetToData, CMBlockBufferFlags flags, out CMBlockBufferError error)
{
if (data == null)
throw new ArgumentNullException (nameof (data));

var allocator = new CMManagedArrayBlockAllocator (data);
return FromMemoryBlock (IntPtr.Zero, (uint) data.Length, allocator, offsetToData, (uint) data.Length, flags, out error);
}

[DllImport(Constants.CoreMediaLibrary)]
extern static /* OSStatus */ CMBlockBufferError CMBlockBufferCreateContiguous (
/* CFAllocatorRef */ IntPtr structureAllocator,
Expand Down Expand Up @@ -381,5 +423,16 @@ public CMBlockBufferError AppendMemoryBlock (IntPtr memoryBlock, nuint blockLeng
else
return CMBlockBufferAppendMemoryBlock (Handle, memoryBlock, blockLength, blockAllocator, ref customBlockSource.Cblock, offsetToData, dataLength, flags);
}

public CMBlockBufferError AppendMemoryBlock (byte [] data, nuint offsetToData, CMBlockBufferFlags flags)
{
if (Handle == IntPtr.Zero)
throw new ObjectDisposedException ("BlockBuffer");
if (data == null)
throw new ArgumentNullException (nameof (data));

var allocator = new CMManagedArrayBlockAllocator (data);
return AppendMemoryBlock (IntPtr.Zero, (uint) data.Length, allocator, offsetToData, (uint) data.Length, flags);
}
}
}
22 changes: 22 additions & 0 deletions src/CoreMedia/CMCustomBlockAllocator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,5 +90,27 @@ protected virtual void Dispose (bool disposing)
gch.Free();
}
}

// This class is used internally by a couple of CMBlockBuffer methods
// that take a managed array as input parameter
internal class CMManagedArrayBlockAllocator : CMCustomBlockAllocator {

GCHandle dataHandle;
public CMManagedArrayBlockAllocator (byte [] data)
{
dataHandle = GCHandle.Alloc (data, GCHandleType.Pinned);
}

public override IntPtr Allocate (nuint sizeInBytes)
{
return dataHandle.AddrOfPinnedObject ();
}

public override void Free (IntPtr doomedMemoryBlock, nuint sizeInBytes)
{
if (dataHandle.IsAllocated)
dataHandle.Free ();
}
}
}