ATH-MaaS/Pixelle-Video · error · RuntimeError

Failed to add BGM: {error_msg}

Error message

Failed to add BGM: {error_msg}

What it means

add_bgm mixes background music under a video's existing audio (with optional volume/loop/fade) using an amix/afilter graph. ffmpeg.Error is caught and re-raised as this RuntimeError with decoded stderr. The real cause is in the FFmpeg stderr text.

Source

Thrown at pixelle_video/services/video.py:762

                ffmpeg
                .output(
                    input_video.video,
                    mixed_audio,
                    output,
                    vcodec='copy',
                    acodec='aac',
                    audio_bitrate='192k'
                )
                .overwrite_output()
                .run(capture_stdout=True, capture_stderr=True)
            )
            
            logger.success(f"BGM added successfully: {output}")
            return output
        except ffmpeg.Error as e:
            error_msg = e.stderr.decode() if e.stderr else str(e)
            logger.error(f"FFmpeg BGM error: {error_msg}")
            raise RuntimeError(f"Failed to add BGM: {error_msg}")
    
    def _add_bgm_to_video(
        self,
        video: str,
        bgm_path: str,
        output: str,
        volume: float = 0.2,
        mode: Literal["once", "loop"] = "loop"
    ) -> str:
        """
        Internal helper to add BGM to video with path resolution
        
        Args:
            video: Video file path
            bgm_path: BGM path (can be preset name or custom path)
            output: Output file path
            volume: BGM volume (0.0-1.0)
            mode: "once" or "loop"

View on GitHub (pinned to 848b054e4f)

Solutions

  1. Read the FFmpeg stderr in the exception message to pinpoint the failing filter or stream.
  2. Confirm the BGM file exists, is non-empty, and ffprobe reports a decodable audio stream.
  3. If the video has no audio track, add one first or use merge_audio_video semantics instead of mixing.
  4. Re-encode the BGM to aac mp4 and a standard sample rate (44100/48000) before adding it.

Example fix

// before
service.add_bgm(silent_video, 'track.flac', 'out.mp4')  # no audio stream to mix
// after
service.merge_audio_video(silent_video, 'bed.m4a', 'with_audio.mp4')
service.add_bgm(with_audio, 'track.m4a', 'out.mp4')
Defensive patterns

Strategy: validation

Validate before calling

import ffmpeg
assert os.path.isfile(bgm) and os.path.getsize(bgm) > 0
assert has_audio_stream(video), 'video must have an audio stream to mix BGM into'
assert has_audio_stream(bgm)

Type guard

def has_audio_stream(path: str) -> bool:
    try:
        return any(s.get('codec_type') == 'audio' for s in ffmpeg.probe(path)['streams'])
    except Exception:
        return False

Try / catch

try:
    service.add_bgm(video, bgm, out)
except RuntimeError as e:
    if 'Failed to add BGM' in str(e):
        logger.error(f'BGM mix failed: {e}')
        # re-encode BGM to aac, ensure video has audio, retry
    else:
        raise

Prevention

When it happens

Trigger: BGM file missing, corrupt, or an unsupported codec; filter graph failing because the video has no audio stream to mix with; invalid volume/fade parameters; ffmpeg build lacking a filter (e.g. afade) or encoder used by the graph.

Common situations: BGM downloaded as m4p/DRM-protected or zero bytes; calling add_bgm on a silent video that needed merge_audio_video instead; extremely long BGM files causing memory pressure; exotic sample rates rejected by the mix filter.

Related errors


AI-assisted analysis of ATH-MaaS/Pixelle-Video@848b054e4f (2026-08-30). Data as JSON: /api/errors/7db4decec5e2b1fa. Report an issue: GitHub.