# Pro Video Editor H.264 Configuration Guide

**Project:** Sojorn - Friend's Only Social Platform  
**Date:** January 24, 2026  
**Status:** Configuration Specification Ready

---

## Overview

This document provides the technical specifications and configuration requirements for implementing the `pro_video_editor` package with H.264 codec support via FFmpeg in the Sojorn application.

---

## Required ProVideoEditorConfig Settings

### Complete Configuration

```dart
ProVideoEditorConfigs _buildConfigs() {
  return ProVideoEditorConfigs(
    // ==================== THEME CONFIGURATION ====================
    theme: _buildEditorTheme(), // Custom dark theme with AppTheme.brightNavy
    
    videoEditorTheme: VideoEditorTheme(
      background: Color(0xFF0B0B0B),              // Matte black
      appBarBackgroundColor: Color(0xFF0B0B0B),   // Matte black
      appBarForegroundColor: Colors.white,
      bottomBarBackgroundColor: Color(0xFF0B0B0B), // Matte black
    ),

    // ==================== CROP & ROTATION ====================
    cropRotateEditorConfigs: CropRotateEditorConfigs(
      enabled: true,
      cropRotateEditorTheme: CropRotateEditorTheme(
        appBarBackgroundColor: Color(0xFF0B0B0B),
        appBarForegroundColor: Colors.white,
        background: Color(0xFF0B0B0B),
        cropCornerColor: Color(0xFF1974D1),        // AppTheme.brightNavy
        helperLineColor: Color(0xFF1974D1),        // AppTheme.brightNavy
      ),
    ),

    // ==================== FILTER EDITOR ====================
    filterEditorConfigs: FilterEditorConfigs(
      enabled: true,
      filterEditorTheme: FilterEditorTheme(
        appBarBackgroundColor: Color(0xFF0B0B0B),
        appBarForegroundColor: Colors.white,
        background: Color(0xFF0B0B0B),
        previewTextColor: Colors.white70,
        previewSelectedTextColor: Color(0xFF1974D1), // AppTheme.brightNavy
      ),
    ),

    // ==================== DISABLE DISTRACTING FEATURES ====================
    // Per 'Friend's Only' philosophy - focus on quality over clutter
    stickerEditorConfigs: const StickerEditorConfigs(
      enabled: false,
    ),
    
    textEditorConfigs: const TextEditorConfigs(
      enabled: false,
    ),

    // ==================== EXPORT CONFIGURATION (CRITICAL) ====================
    exportConfigs: ExportConfigs(
      // REQUIRED: Generate export in separate thread for non-blocking UI
      generateInsideSeparateThread: true,
      
      // REQUIRED: Export to .mp4 format
      exportFormat: ExportFormat.mp4,
      
      // REQUIRED: H.264 codec for compatibility
      videoCodec: VideoCodec.h264,
      
      // High quality output
      videoQuality: VideoQuality.high,
      
      // Audio settings
      audioCodec: AudioCodec.aac,
      audioQuality: AudioQuality.high,
      
      // Resolution settings (optional - maintains original by default)
      // maxWidth: 1920,
      // maxHeight: 1080,
      
      // Frame rate (optional - maintains original by default)
      // targetFrameRate: 30,
    ),

    // ==================== CUSTOM WIDGETS ====================
    customWidgets: VideoEditorCustomWidgets(
      appBar: (editor, rebuildStream) => ReactiveCustomAppbar(
        stream: rebuildStream,
        builder: (context) {
          return AppBar(
            backgroundColor: Color(0xFF0B0B0B),
            foregroundColor: Colors.white,
            leading: IconButton(
              tooltip: 'Cancel',
              icon: const Icon(Icons.close),
              onPressed: editor.closeEditor,
            ),
            actions: [
              TextButton(
                onPressed: editor.doneEditing,
                style: TextButton.styleFrom(
                  foregroundColor: Color(0xFF1974D1), // AppTheme.brightNavy
                ),
                child: const Text('Save'),
              ),
              const SizedBox(width: 6),
            ],
          );
        },
      ),
    ),
  );
}
```

---

## FFmpeg Requirements

### 1. FFmpeg Kit Flutter Integration

**NOTE:** The `ffmpeg_kit_flutter` package has been temporarily removed due to build issues with Maven repository availability. When you're ready to implement the full video editor, you'll need to add it back:

```yaml
dependencies:
  ffmpeg_kit_flutter: ^6.0.3
```

Or use an alternative video processing solution. The current video editor is a placeholder that passes through videos without editing.

### 2. Platform-Specific Configuration

#### Android (`android/app/build.gradle`)

```gradle
android {
    // ...
    
    defaultConfig {
        // ...
        ndk {
            // Specify ABIs to include (reduces APK size)
            abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86_64'
        }
    }
    
    packagingOptions {
        // Prevent duplicate FFmpeg libraries
        pickFirst 'lib/armeabi-v7a/libc++_shared.so'
        pickFirst 'lib/arm64-v8a/libc++_shared.so'
        pickFirst 'lib/x86_64/libc++_shared.so'
    }
}
```

#### iOS (`ios/Podfile`)

```ruby
# Minimum iOS version for FFmpeg support
platform :ios, '12.1'

target 'Runner' do
  use_frameworks!
  use_modular_headers!

  flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
  
  # FFmpeg pod is automatically handled by ffmpeg_kit_flutter
end

post_install do |installer|
  installer.pods_project.targets.each do |target|
    flutter_additional_ios_build_settings(target)
    
    # Ensure proper architecture support
    target.build_configurations.each do |config|
      config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '12.1'
      config.build_settings['ONLY_ACTIVE_ARCH'] = 'NO'
    end
  end
end
```

### 3. Permissions

#### Android (`android/app/src/main/AndroidManifest.xml`)

```xml
<manifest>
    <!-- Required for video processing -->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
        android:maxSdkVersion="32" />
    
    <!-- ... -->
</manifest>
```

#### iOS (`ios/Runner/Info.plist`)

```xml
<key>NSPhotoLibraryUsageDescription</key>
<string>We need access to your photo library to edit videos.</string>
<key>NSCameraUsageDescription</key>
<string>We need access to your camera to record videos.</string>
<key>NSMicrophoneUsageDescription</key>
<string>We need access to your microphone to record audio.</string>
```

---

## H.264 Codec Specifications

### Video Settings
- **Codec:** H.264 (AVC)
- **Profile:** High Profile (for best quality/compression ratio)
- **Level:** 4.1 (supports 1080p @ 30fps)
- **Container:** MP4
- **Bitrate:** Variable (VBR) - automatically adjusted based on quality setting

### Audio Settings
- **Codec:** AAC-LC
- **Sample Rate:** 44.1 kHz or 48 kHz
- **Bitrate:** 128 kbps (high quality)
- **Channels:** Stereo (2 channels)

### Quality Presets

| Quality | Resolution | Target Bitrate | Use Case |
|---------|-----------|----------------|----------|
| **High** | Up to 1080p | 8-12 Mbps | Default - Best quality |
| **Medium** | Up to 720p | 4-6 Mbps | Balanced |
| **Low** | Up to 480p | 1-2 Mbps | Quick uploads |

---

## Implementation Steps

### Step 1: Initialize Video Editor

```dart
// In your video_editor_screen.dart
ProVideoEditor.file(
  File(videoPath),
  configs: _buildConfigs(),
  callbacks: ProVideoEditorCallbacks(
    onVideoEditingComplete: (String outputPath) async {
      // outputPath contains the exported .mp4 file with H.264 codec
      // Move to temp directory
      final tempDir = await getTemporaryDirectory();
      final timestamp = DateTime.now().millisecondsSinceEpoch;
      final tempFile = File('${tempDir.path}/sojorn_video_$timestamp.mp4');
      await File(outputPath).copy(tempFile.path);
      
      // Return result
      Navigator.pop(context, SojornMediaResult.video(
        filePath: tempFile.path,
        name: 'sojorn_video_$timestamp.mp4',
      ));
    },
    
    onVideoExporting: () {
      // Show progress indicator
      print('Video exporting...');
    },
    
    onVideoExported: () {
      // Export completed
      print('Video export completed');
    },
    
    onExportProgress: (double progress) {
      // Update progress indicator (0.0 to 1.0)
      print('Export progress: ${(progress * 100).toInt()}%');
    },
  ),
);
```

### Step 2: Handle Export Progress

```dart
class _VideoEditorState extends State<VideoEditorScreen> {
  double _exportProgress = 0.0;
  bool _isExporting = false;
  
  Widget _buildExportOverlay() {
    if (!_isExporting) return SizedBox.shrink();
    
    return Container(
      color: Colors.black54,
      child: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            CircularProgressIndicator(
              value: _exportProgress,
              color: AppTheme.brightNavy,
            ),
            SizedBox(height: 16),
            Text(
              'Exporting... ${(_exportProgress * 100).toInt()}%',
              style: TextStyle(color: Colors.white),
            ),
          ],
        ),
      ),
    );
  }
}
```

### Step 3: Test H.264 Export

```dart
// Verify exported video codec
Future<void> verifyVideoCodec(String videoPath) async {
  final result = await FFmpegKit.execute(
    '-i $videoPath -hide_banner'
  );
  
  final output = await result.getOutput();
  print('Video info: $output');
  
  // Should show: Video: h264, Audio: aac
}
```

---

## Troubleshooting

### Issue: FFmpeg Not Found
**Solution:** Run `flutter clean` and `flutter pub get`, then rebuild the app.

### Issue: Export Fails on iOS
**Solution:** Ensure iOS deployment target is >= 12.1 in `ios/Podfile`.

### Issue: Large APK Size
**Solution:** Use `abiFilters` in `android/app/build.gradle` to include only necessary architectures.

### Issue: Slow Export
**Solution:** Verify `generateInsideSeparateThread: true` is set. Consider lowering quality preset.

### Issue: Audio Missing in Export
**Solution:** Ensure `audioCodec: AudioCodec.aac` is specified in exportConfigs.

---

## Performance Considerations

1. **Threading:** Always use `generateInsideSeparateThread: true` to prevent UI freezing
2. **Memory:** Monitor memory usage during export, especially on low-end devices
3. **Storage:** Exported videos are saved to temp directory and cleaned up automatically by OS
4. **Battery:** Video encoding is CPU-intensive; warn users on low battery

---

## Testing Checklist

- [ ] Export video with H.264 codec
- [ ] Verify .mp4 container format
- [ ] Test crop and rotation
- [ ] Test filter application
- [ ] Verify stickers/text are disabled
- [ ] Test on Android device
- [ ] Test on iOS device
- [ ] Verify temp storage implementation
- [ ] Test upload integration
- [ ] Verify exported video plays in standard players

---

## Related Files

- **Video Editor Implementation:** `sojorn_app/lib/screens/compose/video_editor_screen.dart`
- **Quip Video Editor:** `sojorn_app/lib/screens/quips/create/quip_editor_screen.dart`
- **Upload Service:** `sojorn_app/lib/services/image_upload_service.dart`
- **Result Class:** `sojorn_app/lib/models/sojorn_media_result.dart`

---

## References

- [pro_video_editor Documentation](https://pub.dev/packages/pro_video_editor)
- [ffmpeg_kit_flutter Documentation](https://pub.dev/packages/ffmpeg_kit_flutter)
- [H.264 Specification](https://www.itu.int/rec/T-REC-H.264)
- [MP4 Container Format](https://en.wikipedia.org/wiki/MP4_file_format)

---

**Last Updated:** January 24, 2026  
**Next Review:** After FFmpeg configuration is completed
