Developing Video Post Publishing in a Mobile App
Video in posts is not just file upload. The entire path is important: selection, trimming, transcoding, upload with progress, thumbnail generation, and finally — playback in feed without stutters. Each step has nuances.
Video Selection and Trimming
PHPickerViewController with filter: .videos on iOS. For social posts, typically limit length — 60–90 seconds. Check duration through PHAsset.duration in picker before loading data.
Trimming — AVPlayerViewController with built-in trim editor (iOS 14+, AVPlayerViewController.allowedPictureInPictureMediaTypes), or custom trimmer via AVPlayer + AVPlayerLayer with drag-handles for CMTimeRange. Custom trimmer gives full UI control but requires ~2–3 days development separately.
On Android — VideoTrimmingView via MediaPlayer + MediaMetadataRetriever for timeline generation. Or use isoviewer / mp4parser for trimming without full decoding.
Transcoding: Mandatory, Not Optional
Video from iPhone 14 Pro camera in 4K/60fps — 400 MB per minute. For 60-second post that's 400 MB. Transcode before upload.
Target parameters for posts: 1080p, H.264, 4–6 Mbps, AAC 128 kbps. This gives ~35–45 MB for 60-second clip — reasonable compromise between quality and size.
On iOS — AVAssetExportSession with AVAssetExportPreset1920x1080:
let export = AVAssetExportSession(asset: asset, presetName: AVAssetExportPreset1920x1080)!
export.outputURL = tempOutputURL
export.outputFileType = .mp4
export.exportAsynchronously {
// completion
}
Monitor transcoding progress via export.progress — AVAssetExportSession has no delegate for progress, only polling. On iPhone SE 2nd gen transcoding 60-second video — 20–30 seconds. Need explicit progress indicator, otherwise user thinks app froze.
On Android — FFmpegKit for flexible transcoding or MediaTranscoder (Natario1) — more modern library on MediaCodec without FFmpeg. MediaTranscoder weighs ~500 KB vs ~15 MB for FFmpegKit — important for APK size.
Upload
Video for post — large file, upload must support resumption. S3 Multipart Upload: divide file into 5–10 MB chunks, upload each in parallel (2–3 parallel requests speed upload without network overload).
On iOS — URLSession with BackgroundConfiguration to continue upload when minimized. Completion handler via application(_:handleEventsForBackgroundURLSession:) in AppDelegate.
On Android — WorkManager with UploadWorker and setConstraints(Constraints.Builder().setRequiredNetworkType(CONNECTED).build()). WorkManager guarantees execution even after device restart — if user exits app mid-upload, next launch continues upload.
Thumbnail and Player in Feed
Generate preview frame before upload — from original video via AVAssetImageGenerator (iOS) or MediaMetadataRetriever (Android), frame at 1-second mark. Upload preview separately, quickly — user sees post in feed with preview while video still processes.
Player in feed — autoplay when entering viewport. Don't use AVPlayer for each feed cell — one shared AVPlayer, reassigned during scroll (AVQueuePlayer for preload next). On Android — ExoPlayer with ExoPlayer.Builder().setLoadControl(DefaultLoadControl()) and PlayerView in RecyclerView. Preload next video on scroll via MediaSource in ConcatenatingMediaSource.
Mute by default — standard for autoplay in feed. Sound enabled by tap.
Timeline
Selection + transcoding + upload + thumbnail + feed playback — 3–5 days with ready backend. Video trimming + background upload + optimistic UI — another 2–3 days. Cost calculated individually.







