### Development Setup for V_Video_Compressor Source: https://pub.dev/packages/v_video_compressor Instructions for cloning the repository, navigating to the project directory, and installing dependencies for both the main project and the example application. ```bash git clone https://github.com/your-repo/v_video_compressor.git cd v_video_compressor flutter pub get cd example && flutter pub get ``` -------------------------------- ### Start Global Listener in a Service Source: https://pub.dev/packages/v_video_compressor Implement a static method in a service class to start listening to the global progress stream. Ensure to provide a corresponding method to cancel the subscription when it's no longer needed to prevent memory leaks. ```dart class VideoCompressionService { static StreamSubscription? _subscription; static void startGlobalListener() { _subscription = VVideoCompressor.progressStream.listen((event) { // Update your state management, emit to other streams, etc. print('Service: ${event.progressFormatted}'); }); } static void stopGlobalListener() { _subscription?.cancel(); } } ``` -------------------------------- ### v_video_compressor Dependency in pubspec.yaml Source: https://pub.dev/packages/v_video_compressor/install This is an example of how the v_video_compressor dependency will appear in your pubspec.yaml file after running the add command. ```yaml dependencies: v_video_compressor: ^2.0.0 ``` -------------------------------- ### Comprehensive Advanced Video Configuration Source: https://pub.dev/packages/v_video_compressor A comprehensive example showcasing various advanced configuration options for video compression, including custom bitrates, dimensions, rotation, frame rate, audio removal, and visual adjustments. ```dart VVideoAdvancedConfig( videoBitrate: 1500000, // Custom video bitrate audioBitrate: 128000, // Custom audio bitrate customWidth: 1280, // Custom width (use with height) customHeight: 720, // Custom height (use with width) rotation: 90, // Manual rotation (0, 90, 180, 270) frameRate: 30.0, // Target frame rate removeAudio: false, // Remove audio track brightness: 0.1, // Brightness adjustment (-1.0 to 1.0) contrast: 0.1, // Contrast adjustment (-1.0 to 1.0) autoCorrectOrientation: true, // Auto-correct video orientation dimensionHandling: VDimensionHandling.autoAlign, // NEW: Auto-align dimensions to 16-pixel boundaries // ... other options ) ``` -------------------------------- ### Import v_video_compressor in Dart Source: https://pub.dev/packages/v_video_compressor/install Import the package into your Dart files to start using its functionalities. Ensure this line is present at the top of your Dart file. ```dart import 'package:v_video_compressor/v_video_compressor.dart'; ``` -------------------------------- ### Get Video Thumbnails (Multiple) Source: https://pub.dev/packages/v_video_compressor Generates multiple thumbnails for a given video file based on a list of configurations. ```APIDOC ## getVideoThumbnails ### Description Generates multiple thumbnails for a given video file based on a list of configurations. ### Method Signature `Future> getVideoThumbnails(String videoPath, List configs)` ### Parameters - **videoPath** (String) - The path to the video file. - **configs** (List) - A list of configurations for thumbnail generation. ``` -------------------------------- ### Get Video Thumbnail Source: https://pub.dev/packages/v_video_compressor Generates a thumbnail for a given video file based on the specified configuration. ```APIDOC ## getVideoThumbnail ### Description Generates a thumbnail for a given video file based on the specified configuration. ### Method Signature `Future getVideoThumbnail(String videoPath, VVideoThumbnailConfig config)` ### Parameters - **videoPath** (String) - The path to the video file. - **config** (VVideoThumbnailConfig) - The configuration for thumbnail generation. ``` -------------------------------- ### Add v_video_compressor to pubspec.yaml Source: https://pub.dev/packages/v_video_compressor/changelog Declare the v_video_compressor package and its dependencies in your pubspec.yaml file. Ensure you run `flutter pub get` after updating. ```yaml dependencies: v_video_compressor: ^1.0.0 # Only for compression image_picker: ^1.0.7 # For video selection file_picker: ^8.0.0 # Alternative file selection path_provider: ^2.1.0 # For custom paths (optional) ``` -------------------------------- ### Get Video Info Source: https://pub.dev/packages/v_video_compressor Retrieves information about a video file. ```APIDOC ## getVideoInfo ### Description Retrieves information about a video file. ### Method Signature `Future getVideoInfo(String videoPath)` ### Parameters - **videoPath** (String) - The path to the video file. ``` -------------------------------- ### Pick Video from Gallery Source: https://pub.dev/packages/v_video_compressor/example Handles picking a video from the device's gallery using ImagePicker. It retrieves the video path, gets video information, and updates the UI state. Includes error handling for the picking process. ```dart Future _pickVideo() async { try { final pickedVideo = await ImagePicker().pickVideo( source: ImageSource.gallery, ); if (pickedVideo == null) return; final path = pickedVideo.path; final info = await _compressor.getVideoInfo(path); if (info == null) throw Exception('Invalid video'); setState(() { _selectedVideoPath = path; _videoInfo = info; _result = null; _thumbnailPath = null; _compressionProgress = 0.0; _isCompressing = false; }); } catch (e) { if (mounted) { ScaffoldMessenger.of( context, ).showSnackBar(SnackBar(content: Text('Error picking video: $e'))); } } } ``` -------------------------------- ### Get Video Information Source: https://pub.dev/packages/v_video_compressor Retrieves metadata about a video file. Ensure the video path is valid. ```dart Future getVideoInfo(String videoPath); ``` -------------------------------- ### Get Compression Estimate Source: https://pub.dev/packages/v_video_compressor Estimates the compression details for a video based on the desired quality. ```APIDOC ## getCompressionEstimate ### Description Estimates the compression details for a video based on the desired quality. ### Method Signature `Future getCompressionEstimate(String videoPath, VVideoCompressQuality quality, {VVideoAdvancedConfig? advanced})` ### Parameters - **videoPath** (String) - The path to the video file. - **quality** (VVideoCompressQuality) - The desired compression quality. - **advanced** (VVideoAdvancedConfig, optional) - Advanced configuration options for compression. ``` -------------------------------- ### Get Video Information Source: https://pub.dev/packages/v_video_compressor Retrieves detailed information about a video file, including duration, resolution, and file size. ```APIDOC ## Get Video Information ### Description Retrieves metadata for a given video file. ### Method `getVideoInfo(String videoPath)` ### Parameters #### Path Parameters - **videoPath** (String) - Required - The path to the video file. ### Response #### Success Response - **videoInfo** (VideoInfo object or null) - An object containing video details or null if the video cannot be processed. - **durationFormatted** (String) - Formatted duration of the video. - **width** (int) - The width of the video resolution. - **height** (int) - The height of the video resolution. - **fileSizeFormatted** (String) - Formatted file size of the video. ### Request Example ```dart final videoInfo = await _compressor.getVideoInfo('/path/to/your/video.mp4'); if (videoInfo != null) { print('Duration: ${videoInfo.durationFormatted}'); print('Resolution: ${videoInfo.width}x${videoInfo.height}'); print('File size: ${videoInfo.fileSizeFormatted}'); } ``` ``` -------------------------------- ### Get Video Information Source: https://pub.dev/packages/v_video_compressor Retrieve details about a video file, such as duration, resolution, and file size. This is useful for displaying video metadata before processing. ```dart final videoInfo = await _compressor.getVideoInfo(videoPath); if (videoInfo != null) { print('Duration: ${videoInfo.durationFormatted}'); print('Resolution: ${videoInfo.width}x${videoInfo.height}'); print('File size: ${videoInfo.fileSizeFormatted}'); } ``` -------------------------------- ### Initialize and Configure Logging Source: https://pub.dev/packages/v_video_compressor/example Configure logging for development to see detailed output from the VVideoCompressor. This should be called before running the app. ```dart import 'package:flutter/material.dart'; import 'package:v_video_compressor/v_video_compressor.dart'; import 'package:image_picker/image_picker.dart'; import 'package:gal/gal.dart'; import 'four_k_test_page.dart'; void main() { // Configure logging for development VVideoCompressor.configureLogging(VVideoLogConfig.development()); runApp(const MyApp()); } ``` -------------------------------- ### Compress Video with Progress Callback Source: https://pub.dev/packages/v_video_compressor/example Initiates video compression using the VVideoCompressor. It accepts a quality configuration and provides an onProgress callback to update the UI with the compression progress. Includes state management for compression status and error handling. ```dart Future _compressVideo(VVideoCompressQuality quality) async { if (_selectedVideoPath == null) return; setState(() { _isCompressing = true; _compressionProgress = 0.0; _result = null; }); try { final config = VVideoCompressionConfig(quality: quality); final result = await _compressor.compressVideo( _selectedVideoPath!, config, onProgress: (progress) => setState(() => _compressionProgress = progress), ); setState(() { _isCompressing = false; _result = result; }); if (result != null) { if (_saveToGallery) { await _saveCompressedToGallery(result.compressedFilePath); } if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Compression successful!')), ); } } } catch (e) { setState(() => _isCompressing = false); if (mounted) { ScaffoldMessenger.of( context, ).showSnackBar(SnackBar(content: Text('Compression failed: $e'))); } } } ``` -------------------------------- ### Listen to Simple Progress Callback Source: https://pub.dev/packages/v_video_compressor/changelog This method provides a simplified callback for basic progress updates. It's suitable when only the overall progress percentage is needed. ```dart VVideoCompressor.listenToProgress((progress) { print('Progress: ${(progress * 100).toInt()}%'); }); ``` -------------------------------- ### Basic Video Compression with Progress Tracking Source: https://pub.dev/packages/v_video_compressor Compresses a selected video using VVideoCompressor, displaying progress and reporting compression details. Requires file_picker for video selection. ```dart import 'package:v_video_compressor/v_video_compressor.dart'; import 'package:file_picker/file_picker.dart'; class VideoCompressionExample extends StatefulWidget { @override _VideoCompressionExampleState createState() => _VideoCompressionExampleState(); } class _VideoCompressionExampleState extends State { final VVideoCompressor _compressor = VVideoCompressor(); double _progress = 0.0; bool _isCompressing = false; Future _compressVideo() async { // 1. Pick video using file_picker FilePickerResult? result = await FilePicker.platform.pickFiles( type: FileType.video, ); if (result == null || result.files.single.path == null) return; final videoPath = result.files.single.path!; setState(() { _isCompressing = true; _progress = 0.0; }); try { // 2. Compress with progress tracking final compressionResult = await _compressor.compressVideo( videoPath, const VVideoCompressionConfig.medium(), onProgress: (progress) { setState(() => _progress = progress); }, ); if (compressionResult != null) { print('✅ Compression completed!'); print('Original: ${compressionResult.originalSizeFormatted}'); print('Compressed: ${compressionResult.compressedSizeFormatted}'); print('Space saved: ${compressionResult.spaceSavedFormatted}'); print('Output path: ${compressionResult.outputPath}'); } } catch (e) { print('❌ Compression failed: $e'); } finally { setState(() => _isCompressing = false); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Video Compressor')), body: Center( child: _isCompressing ? Column( mainAxisAlignment: MainAxisAlignment.center, children: [ CircularProgressIndicator(value: _progress), const SizedBox(height: 16), Text('${(_progress * 100).toInt()}%'), ], ) : ElevatedButton( onPressed: _compressVideo, child: const Text('Pick & Compress Video'), ), ), ); } } ``` -------------------------------- ### Listen to Global Progress Stream in a StatefulWidget Source: https://pub.dev/packages/v_video_compressor Set up a listener for the global progress stream within a StatefulWidget to receive and display compression progress updates. Remember to cancel the subscription when the widget is disposed. ```dart import 'package:v_video_compressor/v_video_compressor.dart'; class MyApp extends StatefulWidget { @override _MyAppState createState() => _MyAppState(); } class _MyAppState extends State { StreamSubscription? _progressSubscription; VVideoProgressEvent? _currentProgress; @override void initState() { super.initState(); _setupGlobalProgressListener(); } void _setupGlobalProgressListener() { // Listen to global progress stream from anywhere _progressSubscription = VVideoCompressor.progressStream.listen( (event) { setState(() { _currentProgress = event; }); print('Progress: ${event.progressFormatted}'); if (event.isBatchOperation) { print('Batch: ${event.batchProgressDescription}'); } }, ); } @override void dispose() { _progressSubscription?.cancel(); super.dispose(); } } ``` -------------------------------- ### Convenience Methods for Progress Callbacks Source: https://pub.dev/packages/v_video_compressor Utilize convenience methods to listen for progress updates with simple callbacks for individual files or batch operations. These methods offer a streamlined way to handle progress notifications without direct stream subscription management. ```dart // Method 1: Simple progress callback VVideoCompressor.listenToProgress((progress) { print('Progress: ${(progress * 100).toInt()}%'); }); // Method 2: Batch progress callback VVideoCompressor.listenToBatchProgress((progress, currentIndex, total) { print('Batch: Video ${currentIndex + 1}/$total - ${(progress * 100).toInt()}%'); }); // Method 3: Full event callback VVideoCompressor.listen((event) { print('Progress: ${event.progressFormatted}'); print('Video: ${event.videoPath}'); if (event.isBatchOperation) { print('Batch: ${event.batchProgressDescription}'); } }); ``` -------------------------------- ### Handle Compression Errors Source: https://pub.dev/packages/v_video_compressor Demonstrates how to handle potential errors during video compression using a try-catch block. Check development console logs for detailed error information. ```dart try { final result = await _compressor.compressVideo(videoPath, config); if (result == null) { print('Compression failed - check logs for details'); } } catch (e, stackTrace) { print('Error: $e'); print('Stack trace: $stackTrace'); // The plugin automatically logs detailed error information // Check your development console for full context } ``` -------------------------------- ### Basic Video Compression with Progress Source: https://pub.dev/packages/v_video_compressor/changelog Compress a video using a medium quality preset and monitor the compression progress. The `onProgress` callback provides real-time updates. ```dart // Basic compression with progress final result = await compressor.compressVideo( videoPath, VVideoCompressionConfig.medium(), onProgress: (progress) { print('Progress: ${(progress * 100).toInt()}%'); }, ); ``` -------------------------------- ### Listen to Batch Progress Callback Source: https://pub.dev/packages/v_video_compressor/changelog Use this callback for tracking progress specifically during batch video compression operations. It provides the current video index and total count. ```dart VVideoCompressor.listenToBatchProgress((progress, currentIndex, total) { print('Batch: Video ${currentIndex + 1}/$total - ${(progress * 100).toInt()}%'); }); ``` -------------------------------- ### Use Preset Configurations for Video Compression Source: https://pub.dev/packages/v_video_compressor Utilize predefined advanced configurations like maximum compression, social media optimized, or mobile optimized. These presets simplify common compression tasks. ```dart // Maximum compression for smallest files final maxCompression = VVideoAdvancedConfig.maximumCompression( targetBitrate: 300000, // 300 kbps keepAudio: false, // Remove audio ); // Social media optimized final socialMedia = VVideoAdvancedConfig.socialMediaOptimized(); // Mobile optimized final mobile = VVideoAdvancedConfig.mobileOptimized(); final result = await _compressor.compressVideo( videoPath, VVideoCompressionConfig( quality: VVideoCompressQuality.medium, advanced: maxCompression, // Use preset ), ); ``` -------------------------------- ### Add v_video_compressor to pubspec.yaml Source: https://pub.dev/packages/v_video_compressor Include the v_video_compressor package and a video selection plugin (file_picker or image_picker) in your project's dependencies. ```yaml dependencies: v_video_compressor: ^1.2.0 file_picker: ^8.0.0 # For video selection # OR image_picker: ^1.0.7 # Alternative for video selection ``` -------------------------------- ### Configure Advanced Video Compression Settings Source: https://pub.dev/packages/v_video_compressor Use VVideoAdvancedConfig to customize compression parameters like resolution, bitrate, codecs, and video effects. This configuration can be passed to the compressVideo method for fine-grained control. ```dart final advancedConfig = VVideoAdvancedConfig( // Resolution & Quality customWidth: 1280, customHeight: 720, videoBitrate: 2000000, // 2 Mbps frameRate: 30.0, // 30 FPS // Codec & Encoding videoCodec: VVideoCodec.h265, // Better compression audioCodec: VAudioCodec.aac, encodingSpeed: VEncodingSpeed.medium, crf: 25, // Quality factor (lower = better) twoPassEncoding: true, // Better quality hardwareAcceleration: true, // Use GPU // Audio Settings audioBitrate: 128000, // 128 kbps audioSampleRate: 44100, // 44.1 kHz audioChannels: 2, // Stereo // Video Effects brightness: 0.1, // Slight brightness boost contrast: 0.05, // Slight contrast increase saturation: 0.1, // Slight saturation increase // Editing trimStartMs: 2000, // Skip first 2 seconds trimEndMs: 60000, // End at 1 minute rotation: 90, // Rotate 90 degrees ); final result = await _compressor.compressVideo( videoPath, VVideoCompressionConfig( quality: VVideoCompressQuality.medium, advanced: advancedConfig, ), ); ``` -------------------------------- ### Video Compression Configuration with Automatic Dimension Alignment Source: https://pub.dev/packages/v_video_compressor/changelog Demonstrates how to configure video compression with custom dimensions. The 'autoAlign' option, which is the default, automatically adjusts dimensions to be divisible by 16 to prevent artifacts. Logs will indicate dimension adjustments. ```dart // Old code still works exactly the same const config = VVideoCompressionConfig.medium( advanced: VVideoAdvancedConfig( customWidth: 1082, // Now automatically aligns to 1072 customHeight: 1278, // Now automatically aligns to 1264 ), ); // Optional: Explicit control (default is autoAlign) const config = VVideoCompressionConfig.medium( advanced: VVideoAdvancedConfig( customWidth: 1082, customHeight: 1278, dimensionHandling: VDimensionHandling.autoAlign, // Explicit (same as default) ), ); // Get actual dimensions after alignment (optional) // Check logs for dimension adjustment messages // Format: "Dimension alignment: 1082x1278 → 1072x1264 (16-pixel boundary)" ``` -------------------------------- ### Video Compression Options Source: https://pub.dev/packages/v_video_compressor/example Provides UI elements for compressing a selected video. Users can choose compression quality via buttons and toggle saving the compressed video to the gallery. ```Dart if (_selectedVideoPath != null) ...[ // Compression Options Card( child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Compress Video', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 8), Wrap( spacing: 8, runSpacing: 8, children: VVideoCompressQuality.values.map((quality) { return ElevatedButton( onPressed: () => _compressVideo(quality), child: Text(quality.name.toUpperCase()), ); }).toList(), ), const SizedBox(height: 8), SwitchListTile( title: const Text('Save to Gallery after Compression'), value: _saveToGallery, onChanged: (value) => setState(() => _saveToGallery = value), ), ], ), ), ), const SizedBox(height: 16), // Thumbnail Generation Card( child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Generate Thumbnail', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 8), ElevatedButton( onPressed: _generateThumbnail, child: const Text('Generate Thumbnail at 5s'), ), if (_thumbnailPath != null) ...[ const SizedBox(height: 8), Text('Thumbnail saved at: $_thumbnailPath'), const SizedBox(height: 8), ElevatedButton( onPressed: _saveThumbnailToGallery, child: const Text('Save Thumbnail to Gallery'), ), ], ], ), ), ), const SizedBox(height: 16), ], ``` -------------------------------- ### Batch Compress Videos with Progress Source: https://pub.dev/packages/v_video_compressor Compresses multiple videos simultaneously and provides overall progress updates. Ideal for processing large numbers of videos efficiently. ```dart final results = await _compressor.compressVideos( [videoPath1, videoPath2, videoPath3], const VVideoCompressionConfig.medium(), onProgress: (progress, currentIndex, total) { print('Overall: ${(progress * 100).toInt()}% (${currentIndex + 1}/$total)'); }, ); print('Successfully compressed ${results.length} videos'); for (final result in results) { print('${result.originalPath} → ${result.outputPath}'); print('Space saved: ${result.spaceSavedFormatted}'); } ``` -------------------------------- ### Thumbnail Generation Methods Source: https://pub.dev/packages/v_video_compressor/changelog Enables the extraction of single or multiple video thumbnails at specified timestamps with configurable output formats and quality. ```dart Future getVideoThumbnail( String videoPath, VVideoThumbnailConfig config ); Future> getVideoThumbnails( String videoPath, List configs ); ``` -------------------------------- ### Resource Management Methods Source: https://pub.dev/packages/v_video_compressor/changelog Provides methods for complete resource cleanup or selective deletion of generated thumbnails, compressed videos, and cached files. ```dart Future cleanup(); Future cleanupFiles({ bool deleteThumbnails = true, bool deleteCompressedVideos = false, bool clearCache = true, }); ``` -------------------------------- ### New Progress Callback Method (After Typed Stream) Source: https://pub.dev/packages/v_video_compressor/changelog This shows the simplified and type-safe approach to listening to progress using the new global stream. It directly uses the typed `VVideoProgressEvent`. ```dart // New way - simple and type-safe VVideoCompressor.progressStream.listen((event) { print('Progress: ${event.progressFormatted}'); }); ``` -------------------------------- ### Multiple Widgets Listening to Global Stream Source: https://pub.dev/packages/v_video_compressor Demonstrates how multiple independent widgets can simultaneously listen to the global progress stream using StreamBuilder. Each widget can independently react to progress updates. ```dart // Widget A class ProgressIndicator extends StatelessWidget { @override Widget build(BuildContext context) { return StreamBuilder( stream: VVideoCompressor.progressStream, builder: (context, snapshot) { if (!snapshot.hasData) return SizedBox(); return LinearProgressIndicator(value: snapshot.data!.progress); }, ); } } // Widget B - completely separate class ProgressText extends StatelessWidget { @override Widget build(BuildContext context) { return StreamBuilder( stream: VVideoCompressor.progressStream, builder: (context, snapshot) { if (!snapshot.hasData) return Text('Ready'); return Text(snapshot.data!.progressFormatted); }, ); } } ``` -------------------------------- ### Core Compression Methods Source: https://pub.dev/packages/v_video_compressor/changelog Methods for retrieving video information, estimating compression size, compressing single or multiple videos, and controlling compression operations. ```APIDOC ## Core Compression Methods ### `getVideoInfo` Gets information about a video file. - **Parameters** - `videoPath` (String) - The path to the video file. - **Returns** - `Future` - An object containing video information or null if an error occurs. ### `getCompressionEstimate` Estimates the compressed size of a video file. - **Parameters** - `videoPath` (String) - The path to the video file. - `quality` (VVideoCompressQuality) - The desired compression quality preset. - `advanced` (VVideoAdvancedConfig?, optional) - Advanced configuration options. - **Returns** - `Future` - An object with the estimated compression details or null. ### `compressVideo` Compresses a single video file with progress updates. - **Parameters** - `videoPath` (String) - The path to the video file. - `config` (VVideoCompressionConfig) - The configuration for video compression. - `onProgress` (Function(double)?, optional) - A callback function to receive compression progress updates. - **Returns** - `Future` - The result of the compression or null if an error occurs. ### `compressVideos` Compresses multiple video files sequentially with overall progress tracking. - **Parameters** - `videoPaths` (List) - A list of paths to the video files. - `config` (VVideoCompressionConfig) - The configuration for video compression. - `onProgress` (Function(double, int, int)?, optional) - A callback for overall progress, current index, and total count. - **Returns** - `Future>` - A list of compression results for each video. ### `cancelCompression` Cancels any ongoing compression operation. - **Returns** - `Future` ### `isCompressing` Checks if a compression operation is currently in progress. - **Returns** - `Future` - True if compressing, false otherwise. ``` -------------------------------- ### Core Video Compression Methods Source: https://pub.dev/packages/v_video_compressor/changelog Provides methods for retrieving video information, estimating compression size, compressing single or multiple videos with progress tracking, and controlling ongoing operations. ```dart Future getVideoInfo(String videoPath); Future getCompressionEstimate( String videoPath, VVideoCompressQuality quality, {VVideoAdvancedConfig? advanced} ); Future compressVideo( String videoPath, VVideoCompressionConfig config, {Function(double)? onProgress} ); Future> compressVideos( List videoPaths, VVideoCompressionConfig config, {Function(double, int, int)? onProgress} ); Future cancelCompression(); Future isCompressing(); ``` -------------------------------- ### Listen to Global Progress Stream Directly Source: https://pub.dev/packages/v_video_compressor/changelog Use this method to subscribe directly to the global progress stream for detailed event information. The `VVideoProgressEvent` provides comprehensive data about the compression progress. ```dart VVideoCompressor.progressStream.listen((event) { print('Progress: ${event.progressFormatted}'); if (event.isBatchOperation) { print('Batch: ${event.batchProgressDescription}'); } }); ``` -------------------------------- ### Is Compressing Source: https://pub.dev/packages/v_video_compressor Checks if any video compression tasks are currently in progress. ```APIDOC ## isCompressing ### Description Checks if any video compression tasks are currently in progress. ### Method Signature `Future isCompressing()` ``` -------------------------------- ### Old Progress Callback Method (Before Typed Stream) Source: https://pub.dev/packages/v_video_compressor/changelog This demonstrates the previous, more complex method of handling progress updates using raw Maps and manual type checking. It is error-prone and less type-safe. ```dart // Old way - complex and error-prone progressSubscription = eventChannel.receiveBroadcastStream().listen((event) { if (event is Map && event.containsKey('progress')) { final progress = (event['progress'] as num).toDouble(); onProgress(progress); } }); ``` -------------------------------- ### Generate Single Video Thumbnail Source: https://pub.dev/packages/v_video_compressor Generates a single thumbnail from a video at a specified time. Configure format, quality, and dimensions. Returns null if generation fails. ```dart final thumbnail = await _compressor.getVideoThumbnail( videoPath, VVideoThumbnailConfig( timeMs: 5000, // 5 seconds into video maxWidth: 300, maxHeight: 200, format: VThumbnailFormat.jpeg, quality: 85, // JPEG quality (0-100) ), ); if (thumbnail != null) { print('Thumbnail: ${thumbnail.thumbnailPath}'); print('Size: ${thumbnail.width}x${thumbnail.height}'); print('File size: ${thumbnail.fileSizeFormatted}'); } ``` -------------------------------- ### Video Dimension Handling Options Source: https://pub.dev/packages/v_video_compressor Enum defining how video dimensions are handled during compression. `autoAlign` is the default, `letterbox` adds black bars, and `exact` maintains original dimensions potentially causing artifacts. ```dart enum VDimensionHandling { autoAlign, // ✅ Default: Smart alignment, only aligns when needed letterbox, // Adds black bars to maintain aspect ratio during alignment exact, // Keep exact dimensions (may cause artifacts with odd dimensions) } ``` -------------------------------- ### Generate Video Thumbnail Source: https://pub.dev/packages/v_video_compressor/example Generates a thumbnail for a selected video using VVideoCompressor. Allows configuration of thumbnail properties such as time, dimensions, format, and quality. Requires the video path to be set. ```dart Future _generateThumbnail() async { if (_selectedVideoPath == null) return; try { final config = VVideoThumbnailConfig( timeMs: 5000, maxWidth: 300, maxHeight: 200, format: VThumbnailFormat.jpeg, quality: 85, ); final thumbnail = await _compressor.getVideoThumbnail( _selectedVideoPath!, config, ); ``` -------------------------------- ### Save Compressed Video to Gallery Source: https://pub.dev/packages/v_video_compressor/example Attempts to save a compressed video file to the device's gallery using the 'Gal' package. Provides user feedback through SnackBars for success or failure. ```dart Future _saveCompressedToGallery(String path) async { try { await Gal.putVideo(path); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Compressed video saved to gallery!')), ); } } catch (e) { if (mounted) { ScaffoldMessenger.of( context, ).showSnackBar(SnackBar(content: Text('Failed to save video: $e'))); } } } ``` -------------------------------- ### Compress Videos (Batch) Source: https://pub.dev/packages/v_video_compressor Compresses multiple video files in a batch according to the specified configuration. ```APIDOC ## compressVideos ### Description Compresses multiple video files in a batch according to the specified configuration. ### Method Signature `Future> compressVideos(List videoPaths, VVideoCompressionConfig config, {Function(double progress, int currentIndex, int total)? onProgress})` ### Parameters - **videoPaths** (List) - A list of paths to the video files to be compressed. - **config** (VVideoCompressionConfig) - The configuration for video compression. - **onProgress** (Function(double progress, int currentIndex, int total), optional) - A callback function to track batch compression progress. ``` -------------------------------- ### Video Compression with Auto-Correct Orientation Source: https://pub.dev/packages/v_video_compressor/changelog This snippet demonstrates how to use the video compressor with auto-correct orientation enabled. The `autoCorrectOrientation` flag now functions more reliably after the update. ```dart // Existing code automatically benefits from orientation fixes final result = await compressor.compressVideo( videoPath, VVideoCompressionConfig( quality: VVideoCompressQuality.medium, advanced: VVideoAdvancedConfig( autoCorrectOrientation: true, // Now works more reliably ), ), ); ``` -------------------------------- ### Video Compression App Structure Source: https://pub.dev/packages/v_video_compressor/example Basic Flutter app structure using MaterialApp and StatefulWidget to manage the video compression UI and state. ```dart class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'V Video Compressor Example', theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), useMaterial3: true, ), home: const MyHomePage(title: 'V Video Compressor Example'), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({super.key, required this.title}); final String title; @override State createState() => _MyHomePageState(); } class _MyHomePageState extends State { final VVideoCompressor _compressor = VVideoCompressor(); String? _selectedVideoPath; double _compressionProgress = 0.0; bool _isCompressing = false; VVideoInfo? _videoInfo; VVideoCompressionResult? _result; bool _saveToGallery = false; String? _thumbnailPath; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: Theme.of(context).colorScheme.inversePrimary, title: Text(widget.title), actions: [ IconButton( onPressed: () { Navigator.push( context, MaterialPageRoute(builder: (context) => const FourKTestPage()), ); }, icon: const Icon(Icons.science), tooltip: '4K Compression Test', ), ], ), body: SingleChildScrollView( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const Text( 'V Video Compressor Example', style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold), textAlign: TextAlign.center, ), const SizedBox(height: 8), Card( color: Colors.blue.shade50, child: Padding( padding: const EdgeInsets.all(12.0), child: Row( children: [ const Icon(Icons.info, color: Colors.blue), const SizedBox(width: 8), const Expanded( child: Text( 'For 4K video compression testing, tap the test tube icon above.', style: TextStyle(color: Colors.blue), ), ), TextButton( onPressed: () { Navigator.push( context, MaterialPageRoute(builder: (context) => const FourKTestPage()), ); }, child: const Text('4K Test'), ), ], ), ), ), const SizedBox(height: 16), // Video Selection ElevatedButton.icon( onPressed: _pickVideo, icon: const Icon(Icons.video_library), label: const Text('Pick Video from Gallery'), ), const SizedBox(height: 16), ``` -------------------------------- ### Display Compression Progress and Results Source: https://pub.dev/packages/v_video_compressor/example Conditionally displays UI elements for compression progress (LinearProgressIndicator) and results (Card with details) based on the state variables _isCompressing and _result. Includes a cancel button and a save to gallery button. ```dart if (_isCompressing) ...[ // Progress Card( child: Padding( padding: const EdgeInsets.all(16.0), child: Column( children: [ const Text( 'Compressing...', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), ), LinearProgressIndicator(value: _compressionProgress), Text('${(_compressionProgress * 100).toInt()}%'), const SizedBox(height: 8), ElevatedButton( onPressed: _cancelCompression, style: ElevatedButton.styleFrom( backgroundColor: Colors.red, ), child: const Text('Cancel'), ), ], ), ), ), const SizedBox(height: 16), ], if (_result != null) ...[ // Result Card( child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Compression Result', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), ), Text('Original Size: ${_result!.originalSizeFormatted}'), Text( 'Compressed Size: ${_result!.compressedSizeFormatted}', ), Text( 'Saved: ${_result!.spaceSavedFormatted} (${_result!.compressionPercentage}%) ), Text('Time: ${_result!.timeTakenFormatted}'), Text('Path: ${_result!.compressedFilePath}'), const SizedBox(height: 8), ElevatedButton( onPressed: () => _saveCompressedToGallery( _result!.compressedFilePath, ), child: const Text('Save Compressed Video to Gallery'), ), ], ), ), ), ], ``` -------------------------------- ### Listen to Global Progress Stream Source: https://pub.dev/packages/v_video_compressor/changelog Listen to video compression progress events from anywhere in your application using the global progress stream. This is useful for updating state management or emitting events to other streams. ```dart // Replace individual progress callbacks VVideoCompressor.progressStream.listen((event) { // Handle progress from anywhere in your app }); // Use in services/controllers class VideoService { static void startGlobalListener() { VVideoCompressor.progressStream.listen((event) { // Update state management, emit to other streams, etc. }); } } // Use with state management class VideoNotifier extends ChangeNotifier { void startListening() { VVideoCompressor.progressStream.listen((event) { // Update state and notify listeners notifyListeners(); }); } } ``` -------------------------------- ### Add v_video_compressor Dependency Source: https://pub.dev/packages/v_video_compressor/install Use this command to add the package to your Flutter project's dependencies. This command automatically updates your pubspec.yaml file. ```bash $ flutter pub add v_video_compressor ``` -------------------------------- ### Display Video Information Source: https://pub.dev/packages/v_video_compressor/example Displays detailed information about a selected video, including its path, duration, file size, and resolution. This snippet is shown when video info is available. ```Dart if (_videoInfo != null) ...[ // Video Info Card Card( child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Video Information', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), ), Text('Path: $_selectedVideoPath'), Text('Duration: ${_videoInfo!.durationFormatted}'), Text('Size: ${_videoInfo!.fileSizeFormatted}'), Text( 'Resolution: ${_videoInfo!.width}x${_videoInfo!.height}', ), ], ), ), ), const SizedBox(height: 16), ], ``` -------------------------------- ### Handle Thumbnail Generation and Gallery Save Source: https://pub.dev/packages/v_video_compressor/example Handles the generation of a thumbnail, updates the UI state, and shows a success or failure message. If successful, it attempts to save the thumbnail to the device's gallery. ```dart setState(() { _thumbnailPath = thumbnail?.thumbnailPath; }); if (thumbnail != null && mounted) { ScaffoldMessenger.of( context, ).showSnackBar(const SnackBar(content: Text('Thumbnail generated!'))); } } catch (e) { if (mounted) { ScaffoldMessenger.of( context, ).showSnackBar(SnackBar(content: Text('Thumbnail failed: $e'))); } } } Future _saveThumbnailToGallery() async { if (_thumbnailPath == null) return; try { await Gal.putImage(_thumbnailPath!); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Thumbnail saved to gallery!')), ); } } catch (e) { if (mounted) { ScaffoldMessenger.of( context, ).showSnackBar(SnackBar(content: Text('Failed to save thumbnail: $e'))); } } } ``` -------------------------------- ### Selective Resource Cleanup Source: https://pub.dev/packages/v_video_compressor Allows for granular control over file cleanup, enabling the retention of compressed videos or thumbnails while clearing cache. Use with caution, especially when deleting compressed videos. ```dart // Safe cleanup - keep compressed videos await _compressor.cleanupFiles( deleteThumbnails: true, deleteCompressedVideos: false, // Keep compressed videos clearCache: true, ); // Full cleanup - ⚠️ removes all compressed videos await _compressor.cleanupFiles( deleteThumbnails: true, deleteCompressedVideos: true, // ⚠️ This deletes your videos! clearCache: true, ); ``` -------------------------------- ### Resource Management Source: https://pub.dev/packages/v_video_compressor Manages the cleanup of temporary and compressed video files generated during operations. ```APIDOC ## Resource Management ### Description Provides methods for cleaning up generated files, including thumbnails, compressed videos, and cache. ### Methods #### Complete Cleanup - **`cleanup()`**: Cleans up all temporary and generated files. Should be called when the application closes. #### Selective Cleanup - **`cleanupFiles({bool deleteThumbnails, bool deleteCompressedVideos, bool clearCache})`**: Allows for selective deletion of files. - **deleteThumbnails** (bool) - Required - Whether to delete generated thumbnails. - **deleteCompressedVideos** (bool) - Required - Whether to delete the compressed video files. - **clearCache** (bool) - Required - Whether to clear the cache. ### Usage Example ```dart // Safe cleanup - keep compressed videos await _compressor.cleanupFiles( deleteThumbnails: true, deleteCompressedVideos: false, // Keep compressed videos clearCache: true, ); // Full cleanup - ⚠️ removes all compressed videos await _compressor.cleanupFiles( deleteThumbnails: true, deleteCompressedVideos: true, // ⚠️ This deletes your videos! clearCache: true, ); // Complete cleanup when app closes @override void dispose() { _compressor.cleanup(); super.dispose(); } ``` ``` -------------------------------- ### Advanced Video Compression Configuration Source: https://pub.dev/packages/v_video_compressor/changelog Perform video compression with custom advanced settings, including resolution, bitrate, codec, and audio removal. This allows for fine-grained control over the output. ```dart // Advanced compression final advancedConfig = VVideoAdvancedConfig( customWidth: 1280, customHeight: 720, videoBitrate: 4000000, videoCodec: VVideoCodec.h265, removeAudio: false, brightness: 0.1, ); final result = await compressor.compressVideo( videoPath, VVideoCompressionConfig( quality: VVideoCompressQuality.medium, advanced: advancedConfig, ), ); ``` -------------------------------- ### Use Preset Configurations for Orientation Correction Source: https://pub.dev/packages/v_video_compressor/changelog For new projects, utilize the enhanced preset configurations that include automatic orientation correction by default. These presets are optimized for various use cases, such as social media or mobile applications. ```dart // Use preset configurations (orientation correction included by default) VVideoAdvancedConfig.socialMediaOptimized() // Perfect for vertical videos VVideoAdvancedConfig.mobileOptimized() // Ideal for mobile apps ``` -------------------------------- ### Resource Management Source: https://pub.dev/packages/v_video_compressor/changelog Methods for managing and cleaning up resources used by the compressor, including temporary files and cache. ```APIDOC ## Resource Management ### `cleanup` Performs a complete cleanup of all temporary files, cache, and compressed videos generated by the plugin. - **Returns** - `Future` ### `cleanupFiles` Performs selective cleanup of resources based on specified options. - **Parameters** - `deleteThumbnails` (bool, optional) - Whether to delete generated thumbnails. Defaults to true. - `deleteCompressedVideos` (bool, optional) - Whether to delete compressed video files. Defaults to false. - `clearCache` (bool, optional) - Whether to clear the plugin's cache. Defaults to true. - **Returns** - `Future` ``` -------------------------------- ### Cleanup Files Source: https://pub.dev/packages/v_video_compressor Manages file cleanup operations. Allows selective deletion of thumbnails, compressed videos, and clearing the cache. ```dart Future cleanup(); ``` ```dart Future cleanupFiles({ bool deleteThumbnails = true, bool deleteCompressedVideos = false, bool clearCache = true, }); ``` -------------------------------- ### Track Video Compression with Custom IDs Source: https://pub.dev/packages/v_video_compressor Assign a unique ID to compression operations for better logging, tracking, and debugging. If no ID is provided, the plugin will auto-generate one. ```dart // Compress with custom ID final result = await _compressor.compressVideo( videoPath, const VVideoCompressionConfig.medium(), onProgress: (progress) { print('Compression progress: ${(progress * 100).toInt()}%'); }, id: 'my-video-compression-${DateTime.now().millisecondsSinceEpoch}', ); // Or let the plugin auto-generate an ID final result2 = await _compressor.compressVideo( videoPath, const VVideoCompressionConfig.medium(), onProgress: (progress) { print('Progress: ${(progress * 100).toInt()}%'); }, // No ID provided - will auto-generate one ); ``` -------------------------------- ### Cleanup Source: https://pub.dev/packages/v_video_compressor Performs a complete cleanup of temporary files and cached data. ```APIDOC ## cleanup ### Description Performs a complete cleanup of temporary files and cached data. ### Method Signature `Future cleanup()` ```