We needed to turn long-form content into TikTok/Reels/Shorts automatically. No human editors, no manual review — just drop a 10-minute video and get 5-10 vertical clips with captions, ready to post.

Architecture Overview

Video Upload → Queue → AI Analysis → FFmpeg Clip → MediaConvert → S3 → CDN → Webhook → DB

Step 1: AI Clip Selection

We use a vision model (GPT-4V / Claude 3.5) to analyze video frames and score segments for "viral potential": hook strength, visual change density, speech density, emotional peaks.

# Python service (FastAPI)
@app.post("/analyze")
async def analyze_video(video_url: str):
    frames = extract_keyframes(video_url, interval=2)  # 1 frame/2s
    scores = await vision_model.batch_score(frames, prompt=VIRAL_PROMPT)
    return select_top_clips(scores, max_duration=60, count=5)

Step 2: FFmpeg Precision Clipping

Frame-accurate cuts without re-encoding where possible:

# Lossless cut (keyframe-aware)
ffmpeg -ss {start} -i input.mp4 -t {duration} -c copy -avoid_negative_ts make_zero output.mp4

# Re-encode for vertical (9:16) with captions baked in
ffmpeg -i input.mp4 -vf "
  crop=ih*9/16:ih,
  subtitles=captions.srt:force_style='Fontsize=24,PrimaryColour=&HFFFFFF'
" -c:a copy output.mp4

Step 3: AWS MediaConvert for Multi-Platform

MediaConvert handles the heavy lifting — transcoding to H.264/HEVC, multiple bitrates, HLS/DASH packaging:

# Job template (JSON)
{
  "Role": "arn:aws:iam::123456789:role/MediaConvertRole",
  "Settings": {
    "OutputGroups": [{
      "Name": "Apple HLS",
      "OutputGroupSettings": {
        "Type": "HLS_GROUP_SETTINGS",
        "HlsGroupSettings": {"Destination": "s3://bucket/hls/", "SegmentLength": 6}
      },
      "Outputs": [
        {"Width": 1080, "Height": 1920, "Codec": "H_264", "Bitrate": 4000000},
        {"Width": 720, "Height": 1280, "Codec": "H_264", "Bitrate": 2500000},
        {"Width": 480, "Height": 854, "Codec": "H_264", "Bitrate": 1200000}
      ]
    }]
  }
}

Laravel Queue Integration

Everything runs on Laravel Horizon (Redis). Jobs are chained:

VideoUploaded::dispatch($video)
    ->chain([
        AnalyzeVideoJob::class,
        ClipVideoJob::class,
        TranscodeJob::class,
        PublishJob::class,
    ]);

Cost & Performance

  • MediaConvert: ~$0.02/min for 1080p HLS
  • FFmpeg (EC2 spot): ~$0.003/min
  • AI analysis: ~$0.10/video (GPT-4V)
  • End-to-end: ~$0.15/video, 2-3 min for 10-min source

Monitoring

Custom metrics in Laravel Pulse: queue depth, job duration, error rate, cost/video. Alerts on queue depth > 100.


Full code: GitHub.