kkroening / ffmpeg-python

Python bindings for FFmpeg - with complex filtering support
Apache License 2.0
9.88k stars 883 forks source link

How to cut (`trim`) video and audio with timestamps #184

Open rsomani95 opened 5 years ago

rsomani95 commented 5 years ago

Great work!

I'm confused as to how to solve this problem, but am sure that it is solvable with a little guidance. I'm trying to trim a clip that should be 600/25(fps) = 24s long.

(
    input_video
    .trim   (start_frame=10000, end_frame=10600) # output len --> 600 frames long
    .output ('out.mp4' )
    .run()
) 

However, the output gives me a file that is 10600 frames long, where the first 10000 frames don't play in some video players while they skip over in others. Nevertheless, what I wish for is a clip that is only 600 frames long.

Additionally, my output files do not have any audio. This isn't an issue though, but a solution would be a nice bonus.

Thanks!

dlond commented 5 years ago

I have the same issue with start=, end= arguments

edvstellar commented 5 years ago

I also have the same issue with start and end kwargs. As stated about end seems to be working, but start does not select the start of the video. I tried some of the earlier release, with no success.

edvstellar commented 5 years ago

Update: I tried this with ffmpeg directly, and it doesn't work either. Looks like this library isn't the issue. As a workaround you can use the "start+duration" method. Some people discussing here: https://stackoverflow.com/questions/18444194/cutting-the-videos-based-on-start-and-end-time-using-ffmpeg

rsomani95 commented 5 years ago

I found a solution:

(
    input_vid
    .trim   (start_frame = 10000, end_frame = 10600)
    .setpts ('PTS-STARTPTS')
    .output (f'output.mp4')
    .run()
) 

.setpts ('PTS-STARTPTS') basically resets the timestamp to 0 after a trim filter has been passed. This fixes the first issue I raised.

The above output, however, does not have any audio attached to the output. This is due to ffmpeg's behavior, as has been discussed in detail in #26 , #208 and shown in this example. Mysteriously the input.audio or input.video didn't work for me, but the following code can be used as a template to do the same:

vid = (
    input_vid
    .trim(start = 100, end = 160)
    .setpts('PTS-STARTPTS')
)
aud = (
    input_vid
    .filter_('atrim', start = 100, end = 160)
    .filter_('asetpts', 'PTS-STARTPTS')
)

joined = ffmpeg.concat(vid, aud, v=1, a=1)
output = ffmpeg.output(joined[0], joined[1], 'out.mp4')
output.run()
j-min commented 5 years ago

@rsomani95 's snippet gave me the error below.

TypeError: Expected string index (e.g. 'a'); got 0

In my case, adding .node after joined solved the problem.

def trim(input_path, output_path, start=30, end=60):
    input_stream = ffmpeg.input(input_path)

    vid = (
        input_stream.video
        .trim(start=start, end=end)
        .setpts('PTS-STARTPTS')
    )
    aud = (
        input_stream.audio
        .filter_('atrim', start=start, end=end)
        .filter_('asetpts', 'PTS-STARTPTS')
    )

    joined = ffmpeg.concat(vid, aud, v=1, a=1).node
    output = ffmpeg.output(joined[0], joined[1], output_path)
    output.run()
rsomani95 commented 5 years ago

Did you need .node even if you weren't adding .audio and .video to input_stream ?

Mysteriously, adding .audio or .video for me gives me an error that I haven't bothered figuring out, so I use ~.audio~[a] and ~.video~[v] when needed.

j-min commented 5 years ago

Removing .node gave me TypeError, regardless of adding .audio and .video or not. Experiments were done with ffmpeg-python==0.1.18, Python 3.6 in macOS Mohave and Ubuntu 16.04

Anasadarsh commented 4 years ago

it couldn't wok on Google colab I had found one cutting code , but it is too slow But in android vidtrim is superfast I need a superfast cutting code Python

rajib-raiyat commented 2 years ago

@TanvirMobasshir see this https://github.com/kkroening/ffmpeg-python/issues/184#issuecomment-504390452