CoolFace
Apppublic

suraj-ml-projects/Video_editing

sourceHugging Facemitupdated 4d agoView on Hugging Face
0likes
video_utils.py121 linesDownload Raw Back to root
1"""2utils/video_utils.py3────────────────────4Merge dubbed Hindi audio back into the original video.5 6Strategy:7  1. Use ffmpeg to mix dubbed speech + original BGM (at reduced volume)8  2. Replace the video's audio track with the mixed result9  3. Copy video codec (no re-encoding) → fast even on CPU10 11This avoids MoviePy for the final merge (MoviePy re-encodes, very slow on CPU).12We use raw ffmpeg subprocess calls instead — much faster.13"""14 15import os16import tempfile17import subprocess18 19 20def merge_audio_video(21    video_path: str,22    dubbed_audio_path: str,23    original_audio_path: str,24    bgm_volume: float = 0.15,25) -> str:26    """27    Create final dubbed video:28      - Video stream: copied from original (no re-encode)29      - Audio stream: Hindi speech mixed with faint original BGM30 31    Parameters:32        video_path         – path to original MP433        dubbed_audio_path  – path to Hindi dubbed WAV34        original_audio_path – path to extracted original audio WAV35        bgm_volume         – 0.0–1.0, volume of background music36 37    Returns path to output MP4.38    """39    output_path = os.path.join(tempfile.gettempdir(), "hindi_dubbed_output.mp4")40 41    # ffmpeg filter graph:42    #   [0:a] = original audio (background music)43    #   [1:a] = Hindi dubbed speech44    #45    #   Step 1: lower original audio volume → bgm46    #   Step 2: mix bgm + dubbed speech together47    #   Step 3: mux with video stream (copy, no re-encode)48 49    bgm_vol_str = str(round(bgm_volume, 3))50 51    cmd = [52        "ffmpeg", "-y",53        "-i", video_path,            # input 0: original video (video + audio)54        "-i", dubbed_audio_path,     # input 1: Hindi dubbed audio55        "-filter_complex",56        (57            # Lower original audio volume for BGM58            f"[0:a]volume={bgm_vol_str}[bgm];"59            # Mix BGM with Hindi speech60            "[bgm][1:a]amix=inputs=2:duration=first:dropout_transition=3[mixed]"61        ),62        "-map", "0:v",               # video stream from original63        "-map", "[mixed]",           # audio stream = mixed result64        "-c:v", "copy",              # copy video codec — NO re-encoding (fast!)65        "-c:a", "aac",               # encode mixed audio as AAC66        "-b:a", "192k",              # audio bitrate67        "-shortest",                 # trim to shortest stream68        output_path,69    ]70 71    result = subprocess.run(72        cmd,73        stdout=subprocess.PIPE,74        stderr=subprocess.PIPE,75    )76 77    if result.returncode != 0:78        # Try a simpler fallback: just replace audio entirely (no BGM mix)79        output_path = _simple_replace_audio(video_path, dubbed_audio_path)80 81    return output_path82 83 84def _simple_replace_audio(video_path: str, audio_path: str) -> str:85    """86    Fallback: simply replace video audio with dubbed audio.87    Used when the complex filter fails.88    """89    output_path = os.path.join(tempfile.gettempdir(), "hindi_dubbed_output_simple.mp4")90 91    cmd = [92        "ffmpeg", "-y",93        "-i", video_path,94        "-i", audio_path,95        "-map", "0:v",          # take video from original96        "-map", "1:a",          # take audio from dubbed file97        "-c:v", "copy",         # copy video stream (fast)98        "-c:a", "aac",99        "-b:a", "192k",100        "-shortest",101        output_path,102    ]103 104    subprocess.run(cmd, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)105    return output_path106 107 108def get_video_duration(video_path: str) -> float:109    """Return video duration in seconds using ffprobe."""110    cmd = [111        "ffprobe", "-v", "error",112        "-show_entries", "format=duration",113        "-of", "default=noprint_wrappers=1:nokey=1",114        video_path,115    ]116    result = subprocess.run(cmd, capture_output=True, text=True)117    try:118        return float(result.stdout.strip())119    except Exception:120        return 0.0121