如何在Azure上用C#结合FFmpeg实现WebJob视频压缩处理?
Got it, let's break down how to build your VideoCompressor WebJob to handle automatic MP4 compression and trimming using the FFmpeg.stable.GZCR NuGet package—no manual FFmpeg updates needed, just clean, integrated code.
1. Install the FFmpeg.stable.GZCR NuGet Package
First, add the package to your Azure WebJob project (this embeds FFmpeg binaries directly, so you don't have to manage external downloads or updates):
- In Visual Studio, right-click your project > Manage NuGet Packages
- Search for
FFmpeg.stable.GZCRand install the latest stable version - Alternatively, run this in the Package Manager Console:
Install-Package FFmpeg.stable.GZCR
2. Set Up the Queue Trigger Function
Create a queue-triggered function that listens for new video notifications. We'll assume your queue messages contain the SAS URL of the source MP4 blob (adjust if you're using local file paths). Here's the basic structure:
using Microsoft.Azure.WebJobs; using Microsoft.Extensions.Logging; using System; using System.Diagnostics; using System.IO; using Azure.Storage.Blobs; public class VideoCompressor { private readonly BlobServiceClient _blobServiceClient; // Inject BlobServiceClient (configure via appsettings.json for Azure Blob Storage) public VideoCompressor(BlobServiceClient blobServiceClient) { _blobServiceClient = blobServiceClient; } [FunctionName("VideoCompressor")] public void Run( [QueueTrigger("video-compression-queue")] string videoBlobSasUrl, ILogger log) { log.LogInformation($"Starting compression for video: {videoBlobSasUrl}"); // Create temp directory to store source/compressed files var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); Directory.CreateDirectory(tempDir); var sourcePath = Path.Combine(tempDir, "source.mp4"); var outputPath = Path.Combine(tempDir, "compressed.mp4"); try { // Download source blob to local temp file var sourceBlob = new BlobClient(new Uri(videoBlobSasUrl)); sourceBlob.DownloadTo(sourcePath); // Run FFmpeg compression and trimming logic RunFfmpegProcessing(sourcePath, outputPath, log); // Upload compressed video back to storage (adjust destination as needed) var destBlobSasUrl = /* Your destination blob SAS URL or construct via BlobClient */; var destBlob = new BlobClient(new Uri(destBlobSasUrl)); destBlob.Upload(outputPath, overwrite: true); log.LogInformation($"Successfully processed video: {outputPath}"); } catch (Exception ex) { log.LogError(ex, $"Failed to process video: {videoBlobSasUrl}"); throw; // Re-throw to trigger queue retry (configure via host.json) } finally { // Clean up temp files to avoid disk bloat if (Directory.Exists(tempDir)) { Directory.Delete(tempDir, recursive: true); } } } }
3. Core FFmpeg Command Implementation
The RunFfmpegProcessing method executes the FFmpeg command that handles both scaling and trimming. Here's how to build it:
private void RunFfmpegProcessing(string sourcePath, string outputPath, ILogger log) { // Get path to the embedded FFmpeg executable from the NuGet package var ffmpegPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "tools", "ffmpeg.exe"); // Build FFmpeg arguments to meet your requirements: // - Scale to max 200px (preserve aspect ratio, no upscaling) // - Trim to first 2 minutes (120 seconds) // - Use efficient H.264/AAC encoding for MP4 var arguments = $"-i \"{sourcePath}\" " + $"-vf \"scale=min(200\\,iw):min(200\\,ih):force_original_aspect_ratio=decrease\" " + $"-t 120 " + $"-c:v libx264 -crf 23 -preset medium " + $"-c:a aac -b:a 128k " + $"-y \"{outputPath}\""; log.LogInformation($"Executing FFmpeg command: {ffmpegPath} {arguments}"); // Configure and run the FFmpeg process var process = new Process { StartInfo = new ProcessStartInfo { FileName = ffmpegPath, Arguments = arguments, UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, CreateNoWindow = true }, EnableRaisingEvents = true }; // Capture FFmpeg output for debugging process.OutputDataReceived += (sender, e) => { if (!string.IsNullOrEmpty(e.Data)) log.LogInformation(e.Data); }; process.ErrorDataReceived += (sender, e) => { if (!string.IsNullOrEmpty(e.Data)) log.LogWarning(e.Data); }; process.Start(); process.BeginOutputReadLine(); process.BeginErrorReadLine(); process.WaitForExit(); if (process.ExitCode != 0) { throw new InvalidOperationException($"FFmpeg failed with exit code {process.ExitCode}"); } }
Key FFmpeg Arguments Explained:
-vf "scale=min(200\,iw):min(200\,ih):force_original_aspect_ratio=decrease": Scales the video so the largest dimension (width/height) is at most 200px, preserving original aspect ratio. It won't upscale small videos.-t 120: Trims the video to the first 120 seconds (2 minutes). To trim from a specific start time, use-ss [start-time] -t 120(e.g.,-ss 60 -t 120for 2 minutes starting at 1 minute).-c:v libx264 -crf 23: Uses H.264 codec with a Constant Rate Factor of 23— a balanced setting for quality vs file size (lower CRF = better quality, larger file).-c:a aac -b:a 128k: Encodes audio with AAC at 128kbps, standard for MP4 compatibility.-y: Overwrites the output file if it exists, ideal for temporary files.
4. Important Configuration & Best Practices
- Queue Retry Policy: Configure retry logic in
host.jsonto handle transient failures:{ "version": "2.0", "extensions": { "queues": { "maxDequeueCount": 5, "visibilityTimeout": "00:05:00" } } } - Temp Storage: Always clean up temp files in the
finallyblock to avoid filling Azure WebJob disk space. - Logging: Use the built-in
ILoggerto track success/failure—this integrates with Azure Monitor for easy debugging. - Blob Permissions: Ensure your WebJob's managed identity or connection string has read access to source blobs and write access to destination blobs.
内容的提问来源于stack exchange,提问作者Cedric Arnould

