Skip to main content
Frame provides comprehensive audio conversion and processing capabilities, supporting both audio-only formats and audio streams within video files.

Audio-Only Containers

Frame supports the following audio-only container formats:

MP3

Universal lossy audio format

M4A

MPEG-4 audio container (AAC/ALAC)

WAV

Uncompressed PCM audio

FLAC

Lossless audio compression

Audio Codecs

Frame supports both lossy and lossless audio codecs:

Lossy Codecs

CodecContainersBitrateDescription
aacmp4, m4a, mov, mkv64-320 kbpsAdvanced Audio Coding - universal compatibility
ac3mp4, mkv, mov64-640 kbpsDolby Digital - surround sound support
libopuswebm, mp4, mkv64-256 kbpsOpus - best quality at low bitrates
mp3mp3, mp4, mkv, mov64-320 kbpsMPEG Audio Layer III - universal

Lossless Codecs

CodecContainersDescription
alacm4a, mp4, mkv, movApple Lossless - iTunes/Apple ecosystem
flacflac, mkv, movFree Lossless Audio Codec
pcm_s16lewav, mov, mkvUncompressed 16-bit PCM
Lossless codecs do not use bitrate settings. The audioBitrate parameter is ignored for flac, alac, and pcm_s16le.
Implementation (codec.rs:57-66):
pub fn add_audio_codec_args(args: &mut Vec<String>, config: &ConversionConfig) {
    args.push("-c:a".to_string());
    args.push(config.audio_codec.clone());

    let lossless_audio_codecs = ["flac", "alac", "pcm_s16le"];
    if !lossless_audio_codecs.contains(&config.audio_codec.as_str()) {
        args.push("-b:a".to_string());
        args.push(format!("{}k", config.audio_bitrate));
    }
}

Bitrate Configuration

For lossy codecs, configure audio bitrate in kilobits per second:
config.audioCodec = 'aac';
config.audioBitrate = '128'; // kbps
Recommended bitrates by codec: AAC:
  • 96 kbps - Low quality, podcasts
  • 128 kbps - Standard quality (default)
  • 192 kbps - High quality
  • 256-320 kbps - Very high quality
Opus (libopus):
  • 64 kbps - Speech
  • 96 kbps - Standard quality
  • 128-192 kbps - High quality music
MP3:
  • 128 kbps - Standard quality
  • 192 kbps - High quality
  • 320 kbps - Maximum quality
AC3:
  • 192 kbps - Stereo
  • 384 kbps - 5.1 surround
  • 448-640 kbps - High quality surround

Channel Configuration

Control the output channel layout:
config.audioChannels = 'original'; // Preserve source channels (default)
config.audioChannels = 'stereo';   // Downmix to stereo (2.0)
config.audioChannels = 'mono';     // Downmix to mono (1.0)
Implementation (codec.rs:67-77):
match config.audio_channels.as_str() {
    "stereo" => {
        args.push("-ac".to_string());
        args.push("2".to_string());
    }
    "mono" => {
        args.push("-ac".to_string());
        args.push("1".to_string());
    }
    _ => {}
}
Downmixing multi-channel audio (5.1, 7.1) to stereo is useful for compatibility with devices that don’t support surround sound.

Audio Track Selection

Many video files contain multiple audio tracks (different languages, commentary, etc.). Frame allows you to select specific tracks:
// Select all audio tracks (default)
config.selectedAudioTracks = [];

// Select specific tracks by index
config.selectedAudioTracks = [0, 2]; // Keep tracks 0 and 2, discard others
Track metadata is available in the source file probe data:
interface AudioTrack {
  index: number;         // Stream index
  codec: string;         // Source codec (e.g., "aac", "ac3")
  channels: string;      // Channel layout (e.g., "stereo", "5.1")
  language?: string;     // Language code (e.g., "eng", "spa")
  label?: string;        // Track label/title
  bitrateKbps?: number;  // Source bitrate
  sampleRate?: string;   // Sample rate (e.g., "48000")
}
Validation (args.rs:23-47):
fn collect_selected_audio_tracks<'a>(
    config: &ConversionConfig,
    probe: &'a ProbeMetadata,
) -> Result<Vec<&'a AudioTrack>, ConversionError> {
    if config.selected_audio_tracks.is_empty() {
        return Ok(probe.audio_tracks.iter().collect());
    }

    config.selected_audio_tracks.iter().map(|index| {
        probe.audio_tracks.iter()
            .find(|track| track.index == *index)
            .ok_or_else(|| ConversionError::InvalidInput(
                format!("Selected audio track #{} was not found in source", index)
            ))
    }).collect()
}

Volume Adjustment

Adjust output volume as a percentage of the original:
config.audioVolume = 100;  // Original volume (default)
config.audioVolume = 150;  // Increase by 50%
config.audioVolume = 50;   // Reduce to 50%
config.audioVolume = 200;  // Double volume
Implementation (filters.rs:92-95):
if (config.audio_volume - 100.0).abs() > VOLUME_EPSILON {
    let volume_factor = config.audio_volume / 100.0;
    filters.push(format!("volume={:.2}", volume_factor));
}
The VOLUME_EPSILON constant (0.01) prevents applying the filter for negligible changes.
Volume adjustment requires re-encoding. It is not available in stream copy mode.

Audio Normalization

Enable loudness normalization for consistent volume levels:
config.audioNormalize = true;
Frame uses the loudnorm filter with EBU R128 standards: Implementation (filters.rs:88-90):
if config.audio_normalize {
    filters.push("loudnorm=I=-16:TP=-1.5:LRA=11".to_string());
}
Parameters:
  • I=-16 - Integrated loudness target (-16 LUFS)
  • TP=-1.5 - True peak limit (-1.5 dBTP)
  • LRA=11 - Loudness range (11 LU)
Normalization is especially useful for:
  • Mixing content from different sources
  • Ensuring consistent volume across a playlist
  • Preparing content for streaming platforms (YouTube, podcasts, etc.)

Audio Filter Chain

Audio filters are applied in the following order:
  1. Normalization (if enabled)
  2. Volume adjustment (if not 100%)
Implementation (filters.rs:85-98):
pub fn build_audio_filters(config: &ConversionConfig) -> Vec<String> {
    let mut filters = Vec::new();

    if config.audio_normalize {
        filters.push("loudnorm=I=-16:TP=-1.5:LRA=11".to_string());
    }

    if (config.audio_volume - 100.0).abs() > VOLUME_EPSILON {
        let volume_factor = config.audio_volume / 100.0;
        filters.push(format!("volume={:.2}", volume_factor));
    }

    filters
}

Container-Codec Compatibility

Each container supports specific audio codecs. Frame validates compatibility and provides helpful error messages: MP3 container:
  • Only supports mp3 codec
M4A container:
  • aac (default)
  • alac (lossless)
WAV container:
  • Only pcm_s16le (uncompressed PCM)
FLAC container:
  • Only flac codec
MP4 container:
  • aac (default)
  • ac3
  • libopus
  • mp3
  • alac
MKV/MOV containers:
  • All codecs supported (wildcard *)
WebM container:
  • libopus (default)
  • vorbis
Default codec mapping (media-rules.json:86-92):
{
  "defaultAudioCodec": {
    "mp3": "mp3",
    "wav": "pcm_s16le",
    "flac": "flac",
    "m4a": "aac",
    "webm": "libopus"
  },
  "defaultAudioCodecFallback": "aac"
}

Audio-Only Conversion

When converting to an audio-only container, video streams are automatically discarded:
config.container = 'mp3';
config.audioCodec = 'mp3';
config.audioBitrate = '192';
config.audioChannels = 'stereo';
FFmpeg args (args.rs:235-248):
if is_audio_only {
    args.push("-vn".to_string()); // No video

    if !config.selected_audio_tracks.is_empty() {
        for track_index in &config.selected_audio_tracks {
            args.push("-map".to_string());
            args.push(format!("0:{}", track_index));
        }
    } else {
        args.push("-map".to_string());
        args.push("0:a?".to_string());
    }

    add_audio_codec_args(&mut args, config);
}

Example Configurations

Extract Audio to MP3

{
  container: 'mp3',
  audioCodec: 'mp3',
  audioBitrate: '192',
  audioChannels: 'stereo',
  audioVolume: 100,
  audioNormalize: true
}

Lossless Audio Archive

{
  container: 'flac',
  audioCodec: 'flac',
  audioChannels: 'original',
  audioVolume: 100,
  audioNormalize: false
}

Podcast Optimization

{
  container: 'mp3',
  audioCodec: 'mp3',
  audioBitrate: '96',
  audioChannels: 'mono',
  audioVolume: 100,
  audioNormalize: true
}

Apple Ecosystem (Lossless)

{
  container: 'm4a',
  audioCodec: 'alac',
  audioChannels: 'original',
  audioVolume: 100,
  audioNormalize: false
}

Web Streaming (Opus)

{
  container: 'webm',
  audioCodec: 'libopus',
  audioBitrate: '128',
  audioChannels: 'stereo',
  audioVolume: 100,
  audioNormalize: true
}

Built-in Audio Presets

Frame includes several built-in audio presets (presets.ts:218-380): Audio MP3 (preset ID: audio-only):
  • MP3 container with 128 kbps stereo
Audio FLAC (preset ID: audio-flac):
  • Lossless FLAC compression
Audio ALAC (preset ID: audio-alac):
  • Apple Lossless in M4A container
Audio WAV (preset ID: audio-wav):
  • Uncompressed PCM audio

Video Conversion

Configure video codecs and settings

Presets

Save and reuse audio conversion settings

Batch Processing

Convert multiple audio files efficiently

Build docs developers (and LLMs) love