0

I use opencv to read a frame from a video file, edit it, then write it to a new video file. In this way I can process large videos without the need to have the whole video in memory.
Something like this for each frame of the video -

success, img = vidObj.read()
img = processImg(img)
vidWriter.write(img)  

The problem is this doesn't save the audio. I tried using moviePy to add in the audio after but it is extremely slow since it has to make a whole new video.

def addAudio(audioSource, videoSource, savePath):
    source_audio = AudioFileClip(audioSource)
    target_video = VideoFileClip(videoSource)
    target_video = target_video.set_audio(source_audio)
    target_video.write_videofile(savePath, audio_codec='aac')  

Is there a way to write the video frame by frame the way I can with opencv but include the audio too? Or just a way to edit the frames without having to have them all loaded into RAM?

Christoph Rackwitz
  • 11,317
  • 4
  • 27
  • 36
Frobot
  • 1,224
  • 3
  • 16
  • 33
  • For a faster Answer you need to [mention the video format](https://stackoverflow.com/posts/76174368/edit) you are working with. Anyways **(1)** OpenCV does not handle audio... **(2)** The solution is to mux (not re-encode) the audio part. This means just copy/pasting the original audio bytes into the new video file. It's fast because it's a copy/paste action. Either find a Python library (on Github?) that does XYZ audio muxing (where XYZ is the format), or else write your own code but you'll need to learn the file format structure. Better if others know what _"A video file"_ means here. – VC.One May 04 '23 at 18:02
  • 1
    @VC.One The video format doesn't matter, with both opencv and moviePy I can just write out whatever extension is needed and it saves as that. Right now the code writes to an mp4 file. I will look into muxing. Thank you for your comment. – Frobot May 04 '23 at 19:58

1 Answers1

1

I found several very slow solutions that re-encode the whole video. Here is a way to do it with ffmpeg that takes well under one second.

import subprocess
def addAudio(audioSource, videoSource, savePath):
    subprocess.run(f'ffmpeg -y -i "{videoSource}" -i "{audioSource}" -c copy "{savePath}"')
Frobot
  • 1,224
  • 3
  • 16
  • 33