Investigating Client-Side Video Quality Instability

Investigating Client-Side Video Quality Instability

Summary

I’ve been investigating differences between videos recorded directly by Janus Gateway and those recorded from the WebRTC element in the browser.
In my tests, the Janus recordings maintain consistently higher and smoother visual quality, while the browser-side recordings show occasional drops or spiky variations.

I’d love to understand what might be causing this difference — whether it’s related to how Janus handles streams internally, encoder settings, or something else entirely.

Thanks for your time and for maintaining such a powerful project :folded_hands:t3:


Open Questions

  1. What could explain the frame-level spikiness in client-side recordings compared to the stable Janus output?
  2. Are there configuration parameters that can reduce these quality dips?

Experiment Setup

Goal: Understand and minimize client-side quality degradation when streaming via Janus Gateway.
Repo: janus-demo

Prerequisites

  • Docker - For running the Janus server
  • Node.js and npm - For the middleware and client
  • Python 3 - For VMAF analysis tools
  • FFmpeg - For video processing

How to Reproduce

  1. Clone the repo:

    git clone https://github.com/linadarwish/janus-demo
    cd janus-demo
    
  2. Ensure your system is idle — no heavy background CPU/network processes.

  3. Run the demo:

    ./run-demo.sh
    

    This automatically:

    • Builds the Janus Docker image
    • Installs all dependencies
    • Starts all services (Janus server, Node.js middleware, React client)
    • Opens the demo at http://localhost:3000
  4. Perform the test:

    1. In the web interface, check the box “Enable Janus recording”
    2. Click “Start Connection”
    3. Immediately click “Start Recording” to begin browser-side media recording
    4. Let both recordings run for at least 90 seconds (until the sample video completes its loop)
    5. Click “Stop Connection”
    6. Click “Stop Recording” to finish browser recording
    7. Wait for both recordings to download:
      • media-rec-[timestamp].webm → browser media recording (downloads immediately)
      • [timestamp]-janus-rec-[id]-video.mjr → Janus recording (downloads after ~1 minute processing)
    8. Do not refresh the page until the Janus recording has downloaded

VMAF Analysis

VMAF (Video Multi-Method Assessment Fusion) is a perceptual video quality metric developed by Netflix that scores videos 0-100 based on reference comparison.

Setup VMAF Tools

# Install Python dependencies
cd scripts/vmaf
uv sync

# Pull Docker image for VMAF analysis
docker pull gfdavila/easyvmaf

Convert Janus Recording

First, convert the .mjr file to a standard video format:

# From project root - replace with your actual .mjr filename
bash scripts/mjr-to-webm.sh [timestamp]-janus-rec-[id]-video.mjr

This creates a .webm file in the same directory.

Run VMAF Comparison

# Compare recordings using the video sync VMAF script
python3 scripts/vmaf/video_sync_vmaf.py scripts/vmaf/reference-video.mp4 media-rec-[timestamp].webm

# For the Janus recording comparison
python3 scripts/vmaf/video_sync_vmaf.py scripts/vmaf/reference-video.mp4 [timestamp]-janus-rec-[id]-video.webm

Script Output

The analysis creates timestamped directories like vmaf_results_[filename]_YYYYMMDD_HHMMSS/ containing:

  • VMAF analysis JSON results (*_vmaf.json)
  • Frame-by-frame quality plots (*_vmaf_frames.png)
  • Quality distribution histograms (*_vmaf_histogram.png)

Observed Quality Trends

Janus Gateway Recording

  • Consistently high VMAF scores
  • Smooth quality curve with few significant drops or spikes
  • Almost stable encoding throughout the recording duration

Browser Media Recording

  • Highly variable VMAF scores with frequent spikes and drops
  • Early recording instability - significant quality dips in first 30 seconds
  • Quality fluctuations throughout recording

Source Video Media Recording

To rule out that the media recording mechanism itself is significantly dropping quality, the code was temporarily altered to capture the source video element directly instead of the WebRTC stream. This shows that the overall trend is stable and within the excellent quality bucket.

Results:

  • Stable VMAF scores
  • No significant quality drops

1 Like

Sorry, not going to do all that :grin: But thanks for sharing, it looks like a cool analysis!

The main difference that comes to mind is that when we’re recording in Janus, we’re recording the same exact frames that get to the browser, without decoding them, and then putting them into a playable file. When you record in the browser, you’re recording decoded media and then encoding it again to put in a webm file. This means it goes through a transformation process, and it’s not the same data, just the same visual content.