DEV Community

Cover image for VideoPipeline 1.1.0: Cap the Clip, Transcode on the OS, Then Encrypt
NuvyntraLabs
NuvyntraLabs

Posted on

VideoPipeline 1.1.0: Cap the Clip, Transcode on the OS, Then Encrypt

A 40-second 4K clip should not leave the device at full size. The app needs a duration cap, a smaller frame, a thumbnail, and a file it can encrypt before upload.

Plugin.Maui.VideoPipeline is that path. Version 1.1.0 is on nuget.org. FromCamera and FromGallery pick the clip. MaxDuration, MaxResolution, and MaxBytes are the gates. Over budget, the plugin asks the OS encoder to shrink it. If the device cannot encode, the result is CannotTranscode. There is no FFmpeg binary in the package.

This post is the walkthrough: how to register the defaults, run the builder, and what each platform actually transcodes.

What VideoPipeline is

VideoPipeline is the video counterpart to MediaPipeline for .NET MAUI on Android, iOS, Mac Catalyst, and Windows. MIT licensed. It targets net10.0, net10.0-android (API 21+), net10.0-ios, net10.0-maccatalyst, and net10.0-windows10.0.17763.0.

It does one job: pick a video, enforce the budget, thumbnail it, and optionally encrypt it.

Package Plugin.Maui.VideoPipeline 1.1.0
Registration UseVideoPipeline
Entry VideoPipeline.FromCamera, FromGallery, FromFile
Encrypt Encrypt(key) writes AES-256-GCM .vault
Source github.com/nuvyntralabs/Plugin.Maui.VideoPipeline
Docs nuvyntralabs.github.io/packages/plugin-maui-video-pipeline/

Images stay on Plugin.Maui.MediaPipeline. There is no Current singleton. Tests inject a processor with UseProcessor.

Install and register

dotnet add package Plugin.Maui.VideoPipeline --version 1.1.0
Enter fullscreen mode Exit fullscreen mode
using Plugin.Maui.VideoPipeline;

builder
    .UseMauiApp<App>()
    .UseVideoPipeline(options =>
    {
        options.DefaultMaxDuration = TimeSpan.FromSeconds(30);
    });
Enter fullscreen mode Exit fullscreen mode

DefaultMaxDuration applies when the builder does not call MaxDuration. The options default is already 30 seconds.

Pick, limit, thumbnail, encrypt

var result = await VideoPipeline.FromGallery()
    .MaxDuration(TimeSpan.FromSeconds(30))
    .MaxResolution(1280, 720)
    .MaxBytes(12 * 1024 * 1024)
    .ThumbnailAt(TimeSpan.FromSeconds(1))
    .Encrypt(key)
    .SaveAsync();

if (!result.Succeeded)
{
    // result.Status: Cancelled, TooLarge, TooLong, CannotTranscode, Unsupported
}
Enter fullscreen mode Exit fullscreen mode

FromCamera() records. FromFile(path) and FromSource skip the picker. SaveAsync returns VideoPipelineResult. Succeeded is true only for VideoPipelineStatus.Ok. The artifact then carries ThumbnailPath when a frame could be decoded, and Encrypted when Encrypt ran.

Encrypt takes an AES key and writes a .vault file. DecryptFileAsync reverses that file. UploadWith accepts an IMediaUploader. StoreIn accepts an IMediaVault. Chunked upload that must resume after process death stays on SmartUpload once you have a path.

1.1.0 is the release that thumbnails and asks the OS to transcode when the clip is over budget. Android transcode honors cancel and times out.

What each platform encodes

Platform Probe and thumbnail Transcode
Android MediaMetadataRetriever MediaCodec and MediaMuxer. Many devices return CannotTranscode.
iOS and Mac Catalyst AVAsset and AVAssetImageGenerator AVAssetExportSession at 640×480 or 1280×720, with an optional duration trim.
Windows File size CannotTranscode, plus a copy and thumbnail floor.
net10.0 tests File size CannotTranscode unless a test injects UseProcessor.

CannotTranscode is a typed result. The call does not throw, and the package does not fall back to a bundled encoder. If every Android device must shrink the file, an FFmpeg binding is the tool that makes that guarantee. VideoPipeline is the path when the OS encoder is enough and a failed encode must stay a status.

Permissions the host still requests

Android, in Platforms/Android/AndroidManifest.xml:

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
Enter fullscreen mode Exit fullscreen mode

Camera capture needs CAMERA and usually RECORD_AUDIO. Gallery pick on API 33+ uses READ_MEDIA_VIDEO.

iOS, in Platforms/iOS/Info.plist:

<key>NSCameraUsageDescription</key>
<string>This app records video.</string>
<key>NSMicrophoneUsageDescription</key>
<string>This app records audio with video.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>This app reads videos from your library.</string>
Enter fullscreen mode Exit fullscreen mode

Mac Catalyst and Windows use the camera and photo capabilities the MAUI host already declares.

When something looks wrong

What you see What to do
Cancelled The picker was dismissed.
TooLong or TooLarge after transcode The OS encode still missed MaxDuration or MaxBytes. Lower the capture budget or reject the clip.
CannotTranscode on Android That device's MediaCodec path could not encode. Show the status. Do not expect FFmpeg behavior.
CannotTranscode on Windows Windows transcode is the typed result. Probe is file size.
No ThumbnailPath The platform could not decode a frame at ThumbnailAt.
Encrypted is false Encrypt(key) was not on the builder.
The upload restarts after a kill VideoPipeline hands off a file. Resume belongs to SmartUpload.

Where VideoPipeline sits next to the other tools

Need Tool
Camera or gallery video, limits, thumbnail, OS transcode, encrypt VideoPipelinePlugin.Maui.VideoPipeline
Camera-to-upload images Plugin.Maui.MediaPipeline
Resumable upload of the file you just wrote Plugin.Maui.SmartUpload
A guaranteed encode on every Android device An FFmpeg binding

MAUI MediaPicker is enough when you only need the original file. VideoPipeline is the pipeline when the budget, the thumbnail, and the .vault file are part of the same call.

Try it

dotnet add package Plugin.Maui.VideoPipeline --version 1.1.0
Enter fullscreen mode Exit fullscreen mode

Register UseVideoPipeline, call FromGallery with a 30-second cap and a 12 MB ceiling, and branch on result.Status. samples/Plugin.Maui.VideoPipeline.Sample covers camera, gallery, encrypt, thumbnail, and a CannotTranscode result that does not crash.


By Admin

Top comments (0)