Newest 'ffmpeg' Questions - Stack Overflow

http://stackoverflow.com/questions/tagged/ffmpeg

Les articles publiés sur le site

  • No udp being received on LAN after sending via ffmpeg [closed]

    1er mars, par g00se

    I'm trying to stream a webcam over my LAN with

    ffmpeg -s 640x480 -i /dev/video2 \
        -framerate 10 \
        -preset ultrafast -tune zerolatency codec libx264 \
        -f mpegts udp://192.168.1.237:8081
    

    This is all fine when consumed with

    ffplay -fflags nobuffer -flags low_delay -framedrop udp://192.168.1.237:8081
    

    on the same box, but when I try to run that same ffplay on another box on my LAN, then, nothing. Any ideas please? Also, the following as 'client' simply hangs:

    nc -u 192.168.1.237 8081 | xxd
    
  • How can I run FFPROBE in a Python script without triggering the Windows Command window ?

    1er mars, par fnord12

    I am using ffmeg/ffprobe to get video durations (in an addon for Kodi). The code:

    result = subprocess.run(["ffprobe", "-hide_banner", "-v", "quiet", "-show_entries",
                                     "format=duration", "-of",
                                     "default=noprint_wrappers=1:nokey=1", filename], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    

    The above code and the file importing that code both have a .pyw extension (after first trying regular .py).

    This works fine but in Windows 11 it causes the black Windows Command window to briefly flash for each video, despite the -hide_banner flag and loglevel being set to quiet. In Linux Mint it runs without any such window popping up.

    Found the answer: subprocess.run just needed a final shell=True as the last argument.

  • Can VLC's method for estimating the duration of a video be reproduced by the means of ffmpeg ?

    28 février, par archie

    This may seem to duplicate previous questions but it does not, as far as I can tell.

    I have a bash script for indexing images and videos to a thumbnails database. A user of my script complained that some videos of hers are skipped over with an error message "corrupted metadata" even though VLC can play them smoothly. These are about 10 videos out of some 15 thousand, but I'd like to solve the problem.

    I will focus on a single video from the bunch. File name: "Paper_and_discussion_M492.mkv", actual duration 02:03:47 (hh:mm:ss). The duration and bitrate fields in the video metadata are missing.

    ffmpeg  -hide_banner -i "Paper_and_discussion_M492.mkv" 2> ffmpeg_data.txt
    

    gives the following output:

      Input #0, matroska,webm, from 'Paper_and_discussion_M492.mkv':
      Metadata:
        COMPATIBLE_BRANDS: isomiso2avc1mp41
        MAJOR_BRAND     : isom
        MINOR_VERSION   : 512
        ENCODER         : Lavf58.76.100
      Duration: N/A, start: 0.000000, bitrate: N/A
      Stream #0:0: Video: hevc (Main), yuv420p(tv, progressive), 854x480 [SAR 1280:1281 DAR 16:9], 24 fps, 24 tbr, 1k tbn, 24 tbc (default)
        Metadata:
          HANDLER_NAME    : VideoHandler
          VENDOR_ID       : [0][0][0][0]
          ENCODER         : Lavc58.134.100 libx265
      Stream #0:1: Audio: vorbis, 44100 Hz, stereo, fltp (default)
        Metadata:
          HANDLER_NAME    : SoundHandler
          VENDOR_ID       : [0][0][0][0]
          ENCODER         : Lavc58.134.100 libvorbis
    At least one output file must be specified
    

    Therefore, as expected,

    ffprobe -i  -show_entries format=duration -v quiet -of csv="p=0"
    

    returns "N/A".

    Decoding the whole file does work:

    ffprobe -show_entries stream=r_frame_rate,nb_read_frames -select_streams v -count_frames -of compact=p=0:nk=1 -v 0 "Paper_and_discussion_M492.mkv"
    

    but it obviously takes a lot of time, especially for a > 2 hours video.

    The "faster answer" proposed by LSerni in https://superuser.com/questions/1179000/ffmpeg-get-duration-of-video-file-without-meta-data should give an estimate of duration based on bitrate; but bitrate is also "N/A" in the incriminated file(s). Their command-line solution based on ffmpeg ends with an error "division by zero".

    However, if I open the file with VLC, it plays ok and VLC immediately shows the duration of the file as 02:03:47. I have checked that duration is precise. Search and jump are also very fast: if I skip 1 hr, playback promptly resumes at the right time.

    So, a doubt is gnawing at me: How does VLC succeed where I consistently fail? It must have a way for recovering data that I might also be able to use to produce a correct estimate of duration.

    My question is: is it possible to reproduce VLC's method (or equivalent) by means of ffmpeg?

  • Bash script to automate FFmpeg operations fails when calling the command, but copy-pasting the generated command into the terminal works [duplicate]

    28 février, par GaboScharff99

    I wrote a bash script which automates a number of conversion operations on video files using FFmpeg. Oddly enough, the FFmpeg call itself now fails when running the script, with a very confusing error message, I might add, but when I copy the command generated by the script into the terminal and run it, it works flawlessly. I'm sorry to insert such a long code block here, but considering how strange this error is, it might be anywhere in the script, so here it is:

    #!/bin/bash
    
    audioTrack=1
    subSource=1
    subTrack=0
    transcodeVideo=1
    transcodeAudio=1
    volumeMultiplier=1
    degradeToStereo=0
    subLanguage="Japanese"
    
    while getopts "t:ns:vam:dl:h" opt; do
        case "$opt" in
            t) audioTrack=${OPTARG};;
            n) subSource=0;;
            s) subTrack=${OPTARG};;
            v) transcodeVideo=0;;
            a) transcodeAudio=0;;
            m) volumeMultiplier=${OPTARG};;
            d) degradeToStereo=1;;
            l) subLanguage=${OPTARG};;
            h)
                echo "Options:"
                echo "-t [integer]: Audio track number. Default: 1."
                echo "-n: If included, subtitles will be taken from internal source."
                echo "-s [integer]: Subtitles track number. Default: 0."
                echo "-v: If included, video source will be copied without transcoding."
                echo "-a: If included, audio source will be copied without transcoding."
                echo "-m [number]: Volume multiplier. If 1, volume is unaffected. Default: 1"
                echo "-d: If included, audio will be degraded to stereo."
                echo "-l [language]: Subtitles language. Only used for external subtitles source. Default: Japanese."
                exit 0
            ;;
        esac
    done
    
    echo "Audio track: $audioTrack."
    echo "Subtitles track: $subTrack."
    params="-map 0:0 -map 0:$audioTrack -map $subSource:$subTrack -c:v"
    
    if [[ $transcodeVideo -eq 1 ]]; then
        echo "Video will be transcoded."
        params="$params hevc"
    elif [[ $transcodeVideo -eq 0 ]]; then
        echo "Video will be copied without transcoding."
        params="$params copy"
    fi
    
    params="$params -c:a"
    
    if [[ $transcodeAudio -eq 1 ]]; then
        echo "Audio will be transcoded."
        params="$params libopus"
    elif [[ $transcodeAudio -eq 0 ]]; then
        echo "Audio will be copied without transcoding."
        params="$params copy"
    fi
    
    if [[ $volumeMultiplier -ne 1 ]]; then
        echo "Volume will be multiplied by a factor of $volumeMultiplier."
        params="$params -filter:a 'volume=$volumeMultiplier'"
    else
        echo "Volume will be unaffected."
    fi
    
    if [[ $degradeToStereo -eq 1 ]]; then
        echo "Audio will be degraded to stereo."
        params="$params -ac 2"
    elif [[ $degradeToStereo -eq 0 ]]; then
        echo "Audio will not be degraded to stereo."
    fi
    
    params="$params -c:s copy"
    
    if [[ $subSource -eq 1 ]]; then
        echo "Subtitles source is external."
        echo "Subtitles language is $subLanguage."
        params="$params -metadata:s:s:0 title='' -metadata:s:s:0 language='$subLanguage'"
    else
        echo "Subtitles source is internal."
    fi
    
    if [[ -f titles.txt ]]; then
        echo "A titles.txt file was found. Titles will be changed according to it."
        echo "Please check titles.txt to make sure the titles are correct."
        changeTitles=1
        counter=0
    else
        echo "A titles.txt file was not found. Titles will not be changed."
        changeTitles=0
    fi
    
    read -p "Are these options correct? (y/n) " choice
    
    case "$choice" in
        y|Y)
            echo "Initiating conversion sequence. This may take a while..."
    
            mkdir output
            currentParams=""
    
            shopt -s nullglob
            for i in *.mp4 *.mkv; do
                currentParams=$params
                fileNameNoExtension=$(echo $i | rev | cut -f 2- -d '.' | rev)
    
                if [[ $subSource -eq 1 ]]; then
                    currentParams="-f srt -i $fileNameNoExtension.srt $currentParams"
                fi
    
                if [[ $changeTitles -eq 1 ]]; then
                    ((counter++))
                    currentParams="$currentParams -metadata title='$(awk "NR==$counter" titles.txt)'"
                fi
    
                ffmpeg -i "$i" $currentParams "output/$fileNameNoExtension.mkv"
            done
    
            echo "Conversion finished!"
        ;;
        n|N) echo "Operation canceled. Exiting.";;
        *) echo "Invalid input. Try again.";;
    esac
    

    The directory I'm running this in contains six video files:

    1. E1 - The Pirates of Orion.mkv
    2. E2 - Bem.mkv
    3. E3 - The Practical Joker.mkv
    4. E4 - Albatross.mkv
    5. E5 - How Sharper Than a Serpent's Tooth.mkv
    6. E6 - The Counter-Clock Incident.mkv

    Here's the titles.txt file, for completion's sake:

    Star Trek: The Animated Series - Season 2, Episode 1 - The Pirates of Orion
    Star Trek: The Animated Series - Season 2, Episode 2 - Bem
    Star Trek: The Animated Series - Season 2, Episode 3 - The Practical Joker
    Star Trek: The Animated Series - Season 2, Episode 4 - Albatross
    Star Trek: The Animated Series - Season 2, Episode 5 - How Sharper Than a Serpent's Tooth
    Star Trek: The Animated Series - Season 2, Episode 6 - The Counter-Clock Incident
    

    And finally, here's the error message given by FFmpeg on the terminal for every video file when running the command:

    Unable to find a suitable output format for 'Trek:'
    Trek:: Invalid argument
    

    Maybe there are better ways to handle all of this, but first and foremost, I would like to figure out why the command fails with such a confusing error message. The only place where the string 'Trek:' is found is in the title taken from titles.txt, but I don't understand why that's seemingly being passed to the name of the output file instead of the title, and apparently only when running the script.

    Thanks a lot for your answers! I know this is quite a bit of text, so I really appreciate you taking your time to read through this.

  • How to parallelize ffmpeg setPTS filter when using GPU ? [closed]

    28 février, par Souvic Chakraborty

    We have a long python code which chunks the video into multiple parts and changes the speed using setPTS filter.

    import ffmpeg
    ffmpeg.input(segment_path).filter("setpts", f"{1/speed_factor}*PTS").output(
                                    adjusted_segment_path,vcodec="h264_nvenc", acodec="aac",preset="fast", crf=23, g=30, keyint_min=30, sc_threshold=0,r=30,vsync='cfr',threads=1
                                ).global_args("-hwaccel", "cuda").run(quiet=True, overwrite_output=True,capture_stdout=True, capture_stderr=True)
    

    Now, because this happens multiple times before concatenation, we thought, instead of sequential processing using a ThreadPool, it may help reduce the time. So we did that:

    import ffmpeg
    import concurrent.futures
    
    def process_video(segment_path, adjusted_segment_path, speed_factor):
        ffmpeg.input(segment_path).filter("setpts", f"{1/speed_factor}*PTS").output(
            adjusted_segment_path,
            vcodec="h264_nvenc",
            acodec="aac",
            preset="fast",
            crf=23,
            g=30,
            keyint_min=30,
            sc_threshold=0,
            r=30,
            vsync='cfr',
            threads=1
        ).global_args("-hwaccel", "cuda").run(
            quiet=True, overwrite_output=True, capture_stdout=True, capture_stderr=True
        )
    
    
    segment_paths = ["input1.mp4", "input2.mp4", "input3.mp4"]  # List of input video segments
    output_paths = ["output1.mp4", "output2.mp4", "output3.mp4"]  # Corresponding output paths
    speed_factor = 1.5  
    
    # Using ThreadPoolExecutor for concurrent processing
    with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
        futures = [
            executor.submit(process_video, seg, out, speed_factor)
            for seg, out in zip(segment_paths, output_paths)
        ]
        
        # Wait for all tasks to complete
        for future in concurrent.futures.as_completed(futures):
            try:
                future.result()  # This will raise any exceptions encountered in the thread
            except Exception as e:
                print(f"Error processing video: {e}")
    

    But the time required did not reduce. Previously, it was 50 seconds for a long video input, now too, it remains the same.

    Is there any other way I can improve the code?

    I also noticed the GPU utilization is low and the code is still executed sequentially (I can see when I run nvtop, which processes are running)

    I am using an L4 GPU with CUDA Version: 12.4, nvcc CUDA Toolkit is also at 12.4