PyAV-Org / PyAV

Pythonic bindings for FFmpeg's libraries.
https://pyav.basswood-io.com/
BSD 3-Clause "New" or "Revised" License
2.53k stars 366 forks source link

400s vs 2s compare pyav and ffmepg #983

Closed wanghaisheng closed 2 years ago

wanghaisheng commented 2 years ago

IMPORTANT: Be sure to replace all template sections {{ like this }} or your issue may be discarded.

Overview

{{ A clear and concise description of what the bug is. }}

Expected behavior

{{ A clear and concise description of what you expected to happen. }}

Actual behavior

{{ A clear and concise description of what actually happened. }}

Traceback:

{{ Include complete tracebacks if there are any exceptions. }}

Investigation

{{ What you did to isolate the problem. }}

Reproduction

{{ Steps to reproduce the behavior. If the problem is media specific, include a link to it. Only send media that you have the rights to. }}

Versions

Research

I have done the following:

Additional context

{{ Add any other context about the problem here. }} i was trying to extract audio part from video

def video2audio(video_path,audio_path):

    input_container = av.open(
        video_path)
    input_stream = input_container.streams.get(audio=0)[0]

    output_container = av.open(audio_path, 'w')
    output_stream = output_container.add_stream('aac')

    for frame in input_container.decode(input_stream):
        frame.pts = None
        for packet in output_stream.encode(frame):
            output_container.mux(packet)

    for packet in output_stream.encode(None):
        output_container.mux(packet)

    output_container.close()

but pyav method is way too slow, am i doing that wrong

subprocess.Popen(f'ffmpeg -y -i "{basepath+os.sep+f}" -vn -codec copy "{new}"',shell=True, stderr=subprocess.DEVNULL,stdout=subprocess.DEVNULL).wait()

uvjustin commented 2 years ago

Your code is decoding and reencoding the audio while the ffmpeg command is just copying (remuxing) the audio. You can just remux the packets directly without decoding to frames and reencoding to packets by using input_container.demux() instead of input_container.decode(). However, using ffmpeg directly is probably still faster, so if you can do what you need with ffmpeg in a process, just use ffmpeg.

wanghaisheng commented 2 years ago

@uvjustin you mean like this input_container = av.open( video_path) input_stream = input_container.streams.get(audio=0)[0]

output_container = av.open(audio_path, 'w')

for packet in input_container.demux():
    output_container.mux(packet)

output_container.close()
uvjustin commented 2 years ago
output_container = av.open(audio_path, 'w')
output_stream = output_container.add_stream(template=input_stream)

for packet in input_container.demux(input_stream):
    packet.stream = output_stream
    output_container.mux(packet)

output_container.close()
jlaine commented 2 years ago

Also.. see the README: if the FFmpeg CLI does what you want, why use PyAV?