如何在Cloud Functions中调整视频尺寸并压缩视频?
Great question—handling video resizing and compression in Cloud Functions is totally manageable, and I’ve helped build similar workflows for iOS-focused apps before. Let’s break down exactly how to meet all your requirements, step by step.
First: Choose Your Core Tool
For video processing, FFmpeg is the industry standard—it’s flexible, powerful, and works seamlessly in Cloud Functions. We’ll use the fluent-ffmpeg Node.js wrapper (plus a pre-built FFmpeg binary for Cloud Functions) to simplify code.
1. Resize Videos for Consistent iPhone Display
To ensure videos look uniform across all iPhones, pick a target resolution that balances compatibility and quality. The sweet spot for iOS is 1080p (1920x1080, 16:9)—it’s supported by every modern iPhone, and matches the default video capture resolution for most models.
Key rules for resizing:
- Never stretch the video—preserve the original aspect ratio
- For videos with non-16:9 aspect ratios (e.g., 4:3), add black bars (letterboxing/pillarboxing) to fill the 16:9 frame
Here’s the FFmpeg filter to achieve this:
scale=w=1920:h=1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2
scaleshrinks the video to fit within 1920x1080 without stretchingpadadds black bars to center the video in the 16:9 frame
2. Compress Videos & Enforce 50MB Limit (Prioritize HD Quality)
A 30-second 1080p HD video can easily stay under 50MB with smart encoding choices. Here’s how to balance quality and file size:
Use H.264 Encoding (Best Compatibility + Quality)
H.264 is supported by all iPhones and offers excellent compression. We’ll use two key settings:
- CRF (Constant Rate Factor): Controls quality directly. A value of 23-25 gives great HD quality while keeping file sizes small. Lower = better quality, larger file; higher = smaller file, slightly reduced quality.
- Preset: Balances compression speed and efficiency.
mediumis a great middle ground—fast enough for Cloud Functions, with solid compression.
Audio Compression
Don’t forget audio! Use AAC encoding (iOS’s preferred format) with a 128kbps bitrate—this is more than enough for clear audio without wasting space.
Enforce 50MB Hard Limit
To guarantee you never exceed 50MB, calculate the maximum allowed bitrate:50MB = (50 * 8 * 1024 * 1024) bits / 30 seconds ≈ 13.98 Mbps
Add these FFmpeg options to cap the bitrate:
-maxrate 13M -bufsize 26M
bufsize ensures the bitrate stays consistent across variable-content videos (e.g., fast action vs. static scenes).
3. Full Cloud Functions Implementation (Node.js)
Here’s a complete, production-ready function that triggers when a video is uploaded to Cloud Storage, processes it, and saves the result.
Step 1: Install Dependencies
In your Cloud Functions project folder, run:
npm install @ffmpeg-installer/ffmpeg fluent-ffmpeg @google-cloud/storage
Step 2: The Function Code
const functions = require('firebase-functions'); const ffmpeg = require('fluent-ffmpeg'); const ffmpegPath = require('@ffmpeg-installer/ffmpeg').path; const { Storage } = require('@google-cloud/storage'); const storage = new Storage(); const os = require('os'); const path = require('path'); const fs = require('fs'); // Set FFmpeg path for Cloud Functions environment ffmpeg.setFfmpegPath(ffmpegPath); exports.processUserVideo = functions.storage.object().onFinalize(async (object) => { // Skip non-video files and avatar images if (!object.contentType.startsWith('video/') || object.name.includes('avatar')) { functions.logger.log('Skipping non-video or avatar file'); return null; } // Validate video duration (optional but recommended) // You can add a check here using FFmpeg to get duration and reject if over 30s const bucket = storage.bucket(object.bucket); const filePath = object.name; const fileName = path.basename(filePath); // Temp storage for Cloud Functions (auto-cleaned after function finishes) const tempLocalFile = path.join(os.tmpdir(), fileName); const processedFileName = `processed/${fileName}`; const tempLocalProcessedFile = path.join(os.tmpdir(), processedFileName); try { // Download original video to temp directory await bucket.file(filePath).download({ destination: tempLocalFile }); functions.logger.log('Downloaded source file to:', tempLocalFile); // Run FFmpeg processing await new Promise((resolve, reject) => { ffmpeg(tempLocalFile) // Resize to 1080p with aspect ratio preservation .videoFilter('scale=w=1920:h=1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2') // Video encoding settings for HD quality + compression .outputOptions('-c:v libx264') .outputOptions('-crf 24') .outputOptions('-preset medium') // Bitrate cap to ensure <50MB for 30s videos .outputOptions('-maxrate 13M') .outputOptions('-bufsize 26M') // Audio compression .outputOptions('-c:a aac') .outputOptions('-b:a 128k') // Output to temp processed file .output(tempLocalProcessedFile) .on('end', resolve) .on('error', (err) => { functions.logger.error('FFmpeg processing failed:', err); reject(err); }) .run(); }); // Upload processed video back to Cloud Storage await bucket.upload(tempLocalProcessedFile, { destination: processedFileName, contentType: 'video/mp4', metadata: { cacheControl: 'public, max-age=31536000' } }); functions.logger.log('Successfully uploaded processed video to:', processedFileName); // Optional: Delete original file to save storage space // await bucket.file(filePath).delete(); return null; } catch (err) { functions.logger.error('Overall processing failed:', err); return err; } finally { // Clean up temp files to avoid storage leaks if (fs.existsSync(tempLocalFile)) fs.unlinkSync(tempLocalFile); if (fs.existsSync(tempLocalProcessedFile)) fs.unlinkSync(tempLocalProcessedFile); } });
Critical Configuration Tips
- Memory & Timeout: Video processing is resource-heavy. Set your function to use 2GB of memory and a 540-second timeout (the maximum allowed for Cloud Functions) to handle 4K source videos.
- Permissions: Ensure your Cloud Functions service account has
storage.objects.getandstorage.objects.createpermissions for your Cloud Storage bucket. - Testing: Test with diverse videos (4K, 1080p, 4:3 aspect ratio) to verify sizing, quality, and file size stay under 50MB.
- H.265 Alternative: If you need even smaller files (and your app supports iOS 11+), replace
libx264withlibx265and use CRF 28—this cuts file sizes by ~50% with nearly identical quality.
内容的提问来源于stack exchange,提问作者Nat

