Recherche avancée

Médias (1)

Mot : - Tags -/copyleft

Autres articles (96)

  • MediaSPIP 0.1 Beta version

    25 avril 2011, par

    MediaSPIP 0.1 beta is the first version of MediaSPIP proclaimed as "usable".
    The zip file provided here only contains the sources of MediaSPIP in its standalone version.
    To get a working installation, you must manually install all-software dependencies on the server.
    If you want to use this archive for an installation in "farm mode", you will also need to proceed to other manual (...)

  • Les formats acceptés

    28 janvier 2010, par

    Les commandes suivantes permettent d’avoir des informations sur les formats et codecs gérés par l’installation local de ffmpeg :
    ffmpeg -codecs ffmpeg -formats
    Les format videos acceptés en entrée
    Cette liste est non exhaustive, elle met en exergue les principaux formats utilisés : h264 : H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 m4v : raw MPEG-4 video format flv : Flash Video (FLV) / Sorenson Spark / Sorenson H.263 Theora wmv :
    Les formats vidéos de sortie possibles
    Dans un premier temps on (...)

  • Multilang : améliorer l’interface pour les blocs multilingues

    18 février 2011, par

    Multilang est un plugin supplémentaire qui n’est pas activé par défaut lors de l’initialisation de MediaSPIP.
    Après son activation, une préconfiguration est mise en place automatiquement par MediaSPIP init permettant à la nouvelle fonctionnalité d’être automatiquement opérationnelle. Il n’est donc pas obligatoire de passer par une étape de configuration pour cela.

Sur d’autres sites (11676)

  • Python opencv ffmpeg threading exit functions

    29 novembre 2020, par scacchi

    i'm trying to finish the audio/video recording loop by pressing a key (or by other event), if i use the simple time.sleep() in the main loop work perfectly, after 5 second stop video and create file, if i use the function keyboard_pressed() doesnt execute stop_AVrecording() correctly and file_manager().
What's im doing wrong ?
Thanks in advance

    


    from __future__ import print_function, division
import numpy as np
import cv2
import pyaudio
import wave
import threading
import time
import subprocess
import os
import keyboard

class VideoRecorder:
    "Video class based on openCV"
    def __init__(self, name="temp_video.avi", fourcc="MJPG", sizex=640, sizey=480, fps=30):
        self.open = True
        self.fps = fps                  # fps should be the minimum constant rate at which the camera can
        self.fourcc = fourcc            # capture images (with no decrease in speed over time; testing is required)
        self.frameSize = (sizex, sizey) # video formats and sizes also depend and vary according to the camera used
        self.video_filename = name
        self.video_cap = cv2.VideoCapture(1, cv2.CAP_DSHOW)
        self.video_writer = cv2.VideoWriter_fourcc(*self.fourcc)
        self.video_out = cv2.VideoWriter(self.video_filename, self.video_writer, self.fps, self.frameSize)
        self.frame_counts = 1
        self.start_time = time.time()

    def record(self):
        "Video starts being recorded"
        counter = 1
        timer_start = time.time()
        timer_current = 0
        while self.open:
            ret, video_frame = self.video_cap.read()
            if ret:
                self.video_out.write(video_frame)
                # print(str(counter) + " " + str(self.frame_counts) + " frames written " + str(timer_current))
                self.frame_counts += 1
                counter += 1
                timer_current = time.time() - timer_start
                #time.sleep(1/self.fps)
                # gray = cv2.cvtColor(video_frame, cv2.COLOR_BGR2GRAY)
                cv2.imshow('video_frame', video_frame)
                cv2.waitKey(1)
            else:
                break

    def stop(self):
        "Finishes the video recording therefore the thread too"
        if self.open:
            self.open=False
            self.video_out.release()
            self.video_cap.release()
            cv2.destroyAllWindows()

    def start(self):
        "Launches the video recording function using a thread"
        video_thread = threading.Thread(target=self.record)
        video_thread.start()

class AudioRecorder():
    "Audio class based on pyAudio and Wave"
    def __init__(self, filename="temp_audio.wav", rate=44100, fpb=1024, channels=2):
        self.open = True
        self.rate = rate
        self.frames_per_buffer = fpb
        self.channels = channels
        self.format = pyaudio.paInt16
        self.audio_filename = filename
        self.audio = pyaudio.PyAudio()
        self.stream = self.audio.open(format=self.format,
                                      channels=self.channels,
                                      rate=self.rate,
                                      input=True,
                                      frames_per_buffer = self.frames_per_buffer)
        self.audio_frames = []

    def record(self):
        "Audio starts being recorded"
        self.stream.start_stream()
        while self.open:
            data = self.stream.read(self.frames_per_buffer)
            self.audio_frames.append(data)
            if not self.open:
                break

    def stop(self):
        "Finishes the audio recording therefore the thread too"
        if self.open:
            self.open = False
            self.stream.stop_stream()
            self.stream.close()
            self.audio.terminate()
            waveFile = wave.open(self.audio_filename, 'wb')
            waveFile.setnchannels(self.channels)
            waveFile.setsampwidth(self.audio.get_sample_size(self.format))
            waveFile.setframerate(self.rate)
            waveFile.writeframes(b''.join(self.audio_frames))
            waveFile.close()

    def start(self):
        "Launches the audio recording function using a thread"
        audio_thread = threading.Thread(target=self.record)
        audio_thread.start()

def start_AVrecording(filename="test"):
    global video_thread
    global audio_thread
    video_thread = VideoRecorder()
    audio_thread = AudioRecorder()
    audio_thread.start()
    video_thread.start()
    return filename


def start_video_recording(filename="test"):
    global video_thread
    video_thread = VideoRecorder()
    video_thread.start()
    return filename

def start_audio_recording(filename="test"):
    global audio_thread
    audio_thread = AudioRecorder()
    audio_thread.start()
    return filename

def stop_AVrecording(filename="test"):
    audio_thread.stop()
    frame_counts = video_thread.frame_counts
    elapsed_time = time.time() - video_thread.start_time
    recorded_fps = frame_counts / elapsed_time
    print("total frames " + str(frame_counts))
    print("elapsed time " + str(elapsed_time))
    print("recorded fps " + str(recorded_fps))
    video_thread.stop()

    # Makes sure the threads have finished
    while threading.active_count() > 1:
        time.sleep(1)

    # Merging audio and video signal
    if abs(recorded_fps - 6) >= 0.01:    # If the fps rate was higher/lower than expected, re-encode it to the expected
        print("Re-encoding")
        cmd = "ffmpeg -r " + str(recorded_fps) + " -i temp_video.avi -pix_fmt yuv420p -r 6 temp_video2.avi"
        subprocess.call(cmd, shell=True)
        print("Muxing")
        cmd = "ffmpeg -y -ac 2 -channel_layout stereo -i temp_audio.wav -i temp_video2.avi -pix_fmt yuv420p " + filename + ".avi"
        subprocess.call(cmd, shell=True)
    else:
        print("Normal recording\nMuxing")
        cmd = "ffmpeg -y -ac 2 -channel_layout stereo -i temp_audio.wav -i temp_video.avi -pix_fmt yuv420p " + filename + ".avi"
        subprocess.call(cmd, shell=True)
        print("..")

def file_manager(filename="test"):
    "Required and wanted processing of final files"
    local_path = os.getcwd()
    if os.path.exists(str(local_path) + "/temp_audio.wav"):
        os.remove(str(local_path) + "/temp_audio.wav")
    if os.path.exists(str(local_path) + "/temp_video.avi"):
        os.remove(str(local_path) + "/temp_video.avi")
    if os.path.exists(str(local_path) + "/temp_video2.avi"):
        os.remove(str(local_path) + "/temp_video2.avi")
    # if os.path.exists(str(local_path) + "/" + filename + ".avi"):
    #     os.remove(str(local_path) + "/" + filename + ".avi")

def keyboard_pressed():
    while True:
        if keyboard.is_pressed('q'):  # if key 'q' is pressed
            print('------------You Pressed Q Key!--------------')
            #time.sleep(5)
            break


if __name__ == '__main__':
    start_AVrecording()
    #time.sleep(5)
    keyboard_pressed()
    print('-------------Time Sleep-------------------')
    time.sleep(5)
    print('-------------Stop AVrecording-------------')
    stop_AVrecording()
    print('-------------File Manager-----------------')
    file_manager()
    print('-----------------End----------------------')


    


    '''

    


  • How to play and seek fragmented MP4 audio using MSE SourceBuffer ?

    29 juin 2024, par Stefan Falk

    Note :

    


    


    If you end up here, you might want to take a look at shaka-player and the accompanying shaka-streamer. Use it. Don't implement this yourself unless you really have to.

    


    


    I am trying for quite some time now to be able to play an audio track on Chrome, Firefox, Safari, etc. but I keep hitting brick walls. My problem is currently that I am just not able to seek within a fragmented MP4 (or MP3).

    


    At the moment I am converting audio files such as MP3 to fragmented MP4 (fMP4) and send them chunk-wise to the client. What I do is defining a CHUNK_DURACTION_SEC (chunk duration in seconds) and compute a chunk size like this :

    


    chunksTotal = Math.ceil(this.track.duration / CHUNK_DURATION_SEC);
chunkSize = Math.ceil(this.track.fileSize / this.chunksTotal);


    


    With this I partition the audio file and can fetch it entirely jumping chunkSize-many bytes for each chunk :

    


    -----------------------------------------
| chunk 1 | chunk 2 |   ...   | chunk n |
-----------------------------------------


    


    How audio files are converted to fMP4

    


    ffmpeg -i input.mp3 -acodec aac -b:a 256k -f mp4 \
       -movflags faststart+frag_every_frame+empty_moov+default_base_moof \
        output.mp4


    


    This seems to work with Chrome and Firefox (so far).

    


    How chunks are appended

    


    After following this example, and realizing that it's simply not working as it is explained here, I threw it away and started over from scratch. Unfortunately without success. It's still not working.

    


    The following code is supposed to play a track from the very beginning to the very end. However, I also need to be able to seek. So far, this is simply not working. Seeking will just stop the audio after the seeking event got triggered.

    


    The code

    


    /* Desired chunk duration in seconds. */&#xA;const CHUNK_DURATION_SEC = 20;&#xA;&#xA;const AUDIO_EVENTS = [&#xA;  &#x27;ended&#x27;,&#xA;  &#x27;error&#x27;,&#xA;  &#x27;play&#x27;,&#xA;  &#x27;playing&#x27;,&#xA;  &#x27;seeking&#x27;,&#xA;  &#x27;seeked&#x27;,&#xA;  &#x27;pause&#x27;,&#xA;  &#x27;timeupdate&#x27;,&#xA;  &#x27;canplay&#x27;,&#xA;  &#x27;loadedmetadata&#x27;,&#xA;  &#x27;loadstart&#x27;,&#xA;  &#x27;updateend&#x27;,&#xA;];&#xA;&#xA;&#xA;class ChunksLoader {&#xA;&#xA;  /** The total number of chunks for the track. */&#xA;  public readonly chunksTotal: number;&#xA;&#xA;  /** The length of one chunk in bytes */&#xA;  public readonly chunkSize: number;&#xA;&#xA;  /** Keeps track of requested chunks. */&#xA;  private readonly requested: boolean[];&#xA;&#xA;  /** URL of endpoint for fetching audio chunks. */&#xA;  private readonly url: string;&#xA;&#xA;  constructor(&#xA;    private track: Track,&#xA;    private sourceBuffer: SourceBuffer,&#xA;    private logger: NGXLogger,&#xA;  ) {&#xA;&#xA;    this.chunksTotal = Math.ceil(this.track.duration / CHUNK_DURATION_SEC);&#xA;    this.chunkSize = Math.ceil(this.track.fileSize / this.chunksTotal);&#xA;&#xA;    this.requested = [];&#xA;    for (let i = 0; i &lt; this.chunksTotal; i&#x2B;&#x2B;) {&#xA;      this.requested[i] = false;&#xA;    }&#xA;&#xA;    this.url = `${environment.apiBaseUrl}/api/tracks/${this.track.id}/play`;&#xA;  }&#xA;&#xA;  /**&#xA;   * Fetch the first chunk.&#xA;   */&#xA;  public begin() {&#xA;    this.maybeFetchChunk(0);&#xA;  }&#xA;&#xA;  /**&#xA;   * Handler for the "timeupdate" event. Checks if the next chunk should be fetched.&#xA;   *&#xA;   * @param currentTime&#xA;   *  The current time of the track which is currently played.&#xA;   */&#xA;  public handleOnTimeUpdate(currentTime: number) {&#xA;&#xA;    const nextChunkIndex = Math.floor(currentTime / CHUNK_DURATION_SEC) &#x2B; 1;&#xA;    const hasAllChunks = this.requested.every(val => !!val);&#xA;&#xA;    if (nextChunkIndex === (this.chunksTotal - 1) &amp;&amp; hasAllChunks) {&#xA;      this.logger.debug(&#x27;Last chunk. Calling mediaSource.endOfStream();&#x27;);&#xA;      return;&#xA;    }&#xA;&#xA;    if (this.requested[nextChunkIndex] === true) {&#xA;      return;&#xA;    }&#xA;&#xA;    if (currentTime &lt; CHUNK_DURATION_SEC * (nextChunkIndex - 1 &#x2B; 0.25)) {&#xA;      return;&#xA;    }&#xA;&#xA;    this.maybeFetchChunk(nextChunkIndex);&#xA;  }&#xA;&#xA;  /**&#xA;   * Fetches the chunk if it hasn&#x27;t been requested yet. After the request finished, the returned&#xA;   * chunk gets appended to the SourceBuffer-instance.&#xA;   *&#xA;   * @param chunkIndex&#xA;   *  The chunk to fetch.&#xA;   */&#xA;  private maybeFetchChunk(chunkIndex: number) {&#xA;&#xA;    const start = chunkIndex * this.chunkSize;&#xA;    const end = start &#x2B; this.chunkSize - 1;&#xA;&#xA;    if (this.requested[chunkIndex] == true) {&#xA;      return;&#xA;    }&#xA;&#xA;    this.requested[chunkIndex] = true;&#xA;&#xA;    if ((end - start) == 0) {&#xA;      this.logger.warn(&#x27;Nothing to fetch.&#x27;);&#xA;      return;&#xA;    }&#xA;&#xA;    const totalKb = ((end - start) / 1000).toFixed(2);&#xA;    this.logger.debug(`Starting to fetch bytes ${start} to ${end} (total ${totalKb} kB). Chunk ${chunkIndex &#x2B; 1} of ${this.chunksTotal}`);&#xA;&#xA;    const xhr = new XMLHttpRequest();&#xA;    xhr.open(&#x27;get&#x27;, this.url);&#xA;    xhr.setRequestHeader(&#x27;Authorization&#x27;, `Bearer ${AuthenticationService.getJwtToken()}`);&#xA;    xhr.setRequestHeader(&#x27;Range&#x27;, &#x27;bytes=&#x27; &#x2B; start &#x2B; &#x27;-&#x27; &#x2B; end);&#xA;    xhr.responseType = &#x27;arraybuffer&#x27;;&#xA;    xhr.onload = () => {&#xA;      this.logger.debug(`Range ${start} to ${end} fetched`);&#xA;      this.logger.debug(`Requested size:        ${end - start &#x2B; 1}`);&#xA;      this.logger.debug(`Fetched size:          ${xhr.response.byteLength}`);&#xA;      this.logger.debug(&#x27;Appending chunk to SourceBuffer.&#x27;);&#xA;      this.sourceBuffer.appendBuffer(xhr.response);&#xA;    };&#xA;    xhr.send();&#xA;  };&#xA;&#xA;}&#xA;&#xA;export enum StreamStatus {&#xA;  NOT_INITIALIZED,&#xA;  INITIALIZING,&#xA;  PLAYING,&#xA;  SEEKING,&#xA;  PAUSED,&#xA;  STOPPED,&#xA;  ERROR&#xA;}&#xA;&#xA;export class PlayerState {&#xA;  status: StreamStatus = StreamStatus.NOT_INITIALIZED;&#xA;}&#xA;&#xA;&#xA;/**&#xA; *&#xA; */&#xA;@Injectable({&#xA;  providedIn: &#x27;root&#x27;&#xA;})&#xA;export class MediaSourcePlayerService {&#xA;&#xA;  public track: Track;&#xA;&#xA;  private mediaSource: MediaSource;&#xA;&#xA;  private sourceBuffer: SourceBuffer;&#xA;&#xA;  private audioObj: HTMLAudioElement;&#xA;&#xA;  private chunksLoader: ChunksLoader;&#xA;&#xA;  private state: PlayerState = new PlayerState();&#xA;&#xA;  private state$ = new BehaviorSubject<playerstate>(this.state);&#xA;&#xA;  public stateChange = this.state$.asObservable();&#xA;&#xA;  private currentTime$ = new BehaviorSubject<number>(null);&#xA;&#xA;  public currentTimeChange = this.currentTime$.asObservable();&#xA;&#xA;  constructor(&#xA;    private httpClient: HttpClient,&#xA;    private logger: NGXLogger&#xA;  ) {&#xA;  }&#xA;&#xA;  get canPlay() {&#xA;    const state = this.state$.getValue();&#xA;    const status = state.status;&#xA;    return status == StreamStatus.PAUSED;&#xA;  }&#xA;&#xA;  get canPause() {&#xA;    const state = this.state$.getValue();&#xA;    const status = state.status;&#xA;    return status == StreamStatus.PLAYING || status == StreamStatus.SEEKING;&#xA;  }&#xA;&#xA;  public playTrack(track: Track) {&#xA;    this.logger.debug(&#x27;playTrack&#x27;);&#xA;    this.track = track;&#xA;    this.startPlayingFrom(0);&#xA;  }&#xA;&#xA;  public play() {&#xA;    this.logger.debug(&#x27;play()&#x27;);&#xA;    this.audioObj.play().then();&#xA;  }&#xA;&#xA;  public pause() {&#xA;    this.logger.debug(&#x27;pause()&#x27;);&#xA;    this.audioObj.pause();&#xA;  }&#xA;&#xA;  public stop() {&#xA;    this.logger.debug(&#x27;stop()&#x27;);&#xA;    this.audioObj.pause();&#xA;  }&#xA;&#xA;  public seek(seconds: number) {&#xA;    this.logger.debug(&#x27;seek()&#x27;);&#xA;    this.audioObj.currentTime = seconds;&#xA;  }&#xA;&#xA;  private startPlayingFrom(seconds: number) {&#xA;    this.logger.info(`Start playing from ${seconds.toFixed(2)} seconds`);&#xA;    this.mediaSource = new MediaSource();&#xA;    this.mediaSource.addEventListener(&#x27;sourceopen&#x27;, this.onSourceOpen);&#xA;&#xA;    this.audioObj = document.createElement(&#x27;audio&#x27;);&#xA;    this.addEvents(this.audioObj, AUDIO_EVENTS, this.handleEvent);&#xA;    this.audioObj.src = URL.createObjectURL(this.mediaSource);&#xA;&#xA;    this.audioObj.play().then();&#xA;  }&#xA;&#xA;  private onSourceOpen = () => {&#xA;&#xA;    this.logger.debug(&#x27;onSourceOpen&#x27;);&#xA;&#xA;    this.mediaSource.removeEventListener(&#x27;sourceopen&#x27;, this.onSourceOpen);&#xA;    this.mediaSource.duration = this.track.duration;&#xA;&#xA;    this.sourceBuffer = this.mediaSource.addSourceBuffer(&#x27;audio/mp4; codecs="mp4a.40.2"&#x27;);&#xA;    // this.sourceBuffer = this.mediaSource.addSourceBuffer(&#x27;audio/mpeg&#x27;);&#xA;&#xA;    this.chunksLoader = new ChunksLoader(&#xA;      this.track,&#xA;      this.sourceBuffer,&#xA;      this.logger&#xA;    );&#xA;&#xA;    this.chunksLoader.begin();&#xA;  };&#xA;&#xA;  private handleEvent = (e) => {&#xA;&#xA;    const currentTime = this.audioObj.currentTime.toFixed(2);&#xA;    const totalDuration = this.track.duration.toFixed(2);&#xA;    this.logger.warn(`MediaSource event: ${e.type} (${currentTime} of ${totalDuration} sec)`);&#xA;&#xA;    this.currentTime$.next(this.audioObj.currentTime);&#xA;&#xA;    const currentStatus = this.state$.getValue();&#xA;&#xA;    switch (e.type) {&#xA;      case &#x27;playing&#x27;:&#xA;        currentStatus.status = StreamStatus.PLAYING;&#xA;        this.state$.next(currentStatus);&#xA;        break;&#xA;      case &#x27;pause&#x27;:&#xA;        currentStatus.status = StreamStatus.PAUSED;&#xA;        this.state$.next(currentStatus);&#xA;        break;&#xA;      case &#x27;timeupdate&#x27;:&#xA;        this.chunksLoader.handleOnTimeUpdate(this.audioObj.currentTime);&#xA;        break;&#xA;      case &#x27;seeking&#x27;:&#xA;        currentStatus.status = StreamStatus.SEEKING;&#xA;        this.state$.next(currentStatus);&#xA;        if (this.mediaSource.readyState == &#x27;open&#x27;) {&#xA;          this.sourceBuffer.abort();&#xA;        }&#xA;        this.chunksLoader.handleOnTimeUpdate(this.audioObj.currentTime);&#xA;        break;&#xA;    }&#xA;  };&#xA;&#xA;  private addEvents(obj, events, handler) {&#xA;    events.forEach(event => obj.addEventListener(event, handler));&#xA;  }&#xA;&#xA;}&#xA;</number></playerstate>

    &#xA;

    Running it will give me the following output :

    &#xA;

    enter image description here

    &#xA;

    &#xA;

    Apologies for the screenshot but it's not possible to just copy the output without all the stack traces in Chrome.

    &#xA;

    &#xA;

    What I also tried was following this example and call sourceBuffer.abort() but that didn't work. It looks more like a hack that used to work years ago but it's still referenced in the docs (see "Example" -> "You can see something similar in action in Nick Desaulnier's bufferWhenNeeded demo ..").

    &#xA;

    case &#x27;seeking&#x27;:&#xA;  currentStatus.status = StreamStatus.SEEKING;&#xA;  this.state$.next(currentStatus);        &#xA;  if (this.mediaSource.readyState === &#x27;open&#x27;) {&#xA;    this.sourceBuffer.abort();&#xA;  } &#xA;  break;&#xA;

    &#xA;

    Trying with MP3

    &#xA;

    I have tested the above code under Chrome by converting tracks to MP3 :

    &#xA;

    ffmpeg -i input.mp3 -acodec aac -b:a 256k -f mp3 output.mp3&#xA;

    &#xA;

    and creating a SourceBuffer using audio/mpeg as type :

    &#xA;

    this.mediaSource.addSourceBuffer(&#x27;audio/mpeg&#x27;)&#xA;

    &#xA;

    I have the same problem when seeking.

    &#xA;

    The issue wihout seeking

    &#xA;

    The above code has another issue :

    &#xA;

    After two minutes of playing, the audio playback starts to stutter and comes to a halt prematurely. So, the audio plays up to a point and then it stops without any obvious reason.

    &#xA;

    For whatever reason there is another canplay and playing event. A few seconds after, the audio simply stops..

    &#xA;

    enter image description here

    &#xA;

  • ffmpeg takes too long to start

    17 octobre 2020, par Suspended

    I have this command in python script, in a loop :

    &#xA;

    ffmpeg -i somefile.mp4 -ss 00:03:12 -t 00:00:35 piece.mp4 -loglevel error -stats&#xA;

    &#xA;

    It cuts out pieces of input file (-i). Input filename, as well as start time (-ss) and length of the piece I cut out (-t) varies, so it reads number of mp4 files and cuts out number of pieces from each one. During execution of the script it might be called around 100 times. My problem is that each time before it starts, there is a delay of 6-15 seconds and it adds up to significant time. How can I get it to start immediately ?

    &#xA;

    Initially I thought it was process priority problem, but I noticed that even during the "pause", all processors work at 100%, so apparently some work is being done.

    &#xA;

    The script (process_videos.py) :

    &#xA;

    import subprocess&#xA;import sys&#xA;import math&#xA;import time&#xA;&#xA;class TF:&#xA;    """TimeFormatter class (TF).&#xA;This class&#x27; reason for being is to convert time in short&#xA;form, e.g. 1:33, 0:32, or 23 into long form accepted by&#xA;mp4cut function in bash, e.g. 00:01:22, 00:00:32, etc"""&#xA;&#xA;def toLong(self, shrt):&#xA;    """Converts time to its long form"""&#xA;    sx = &#x27;00:00:00&#x27;&#xA;    ladd = 8 - len(shrt)&#xA;    n = sx[:ladd] &#x2B; shrt&#xA;    return n&#xA;&#xA;def toShort(self, lng):&#xA;    """Converts time to short form"""&#xA;    if lng[0] == &#x27;0&#x27; or lng[0] == &#x27;:&#x27;:&#xA;        return self.toShort(lng[1:])&#xA;    else:&#xA;        return lng&#xA;&#xA;def toSeconds(self, any_time):&#xA;    """Converts time to seconds"""&#xA;    if len(any_time) &lt; 3:&#xA;        return int(any_time)&#xA;    tt = any_time.split(&#x27;:&#x27;)&#xA;    if len(any_time) &lt; 6:            &#xA;        return int(tt[0])*60 &#x2B; int(tt[1])&#xA;    return int(tt[0])*3600 &#x2B; int(tt[1])*60 &#x2B; int(tt[2])&#xA;&#xA;def toTime(self, secsInt):&#xA;    """"""&#xA;    tStr = &#x27;&#x27;&#xA;    hrs, mins, secs = 0, 0, 0&#xA;    if secsInt >= 3600:&#xA;        hrs = math.floor(secsInt / 3600)&#xA;        secsInt = secsInt % 3600&#xA;    if secsInt >= 60:&#xA;        mins = math.floor(secsInt / 60)&#xA;        secsInt = secsInt % 60&#xA;    secs = secsInt&#xA;    return str(hrs).zfill(2) &#x2B; &#x27;:&#x27; &#x2B; str(mins).zfill(2) &#x2B; &#x27;:&#x27; &#x2B; str(secs).zfill(2)&#xA;&#xA;def minus(self, t_start, t_end):&#xA;    """"""&#xA;    t_e = self.toSeconds(t_end)&#xA;    t_s = self.toSeconds(t_start)&#xA;    t_r = t_e - t_s&#xA;    hrs, mins, secs = 0, 0, 0&#xA;    if t_r >= 3600:&#xA;        hrs = math.floor(t_r / 3600)&#xA;        t_r = t_r - (hrs * 3600)&#xA;    if t_r >= 60:&#xA;        mins = math.floor(t_r / 60)&#xA;        t_r = t_r - (mins * 60)&#xA;    secs = t_r&#xA;    hrsf = str(hrs).zfill(2)&#xA;    minsf = str(mins).zfill(2)&#xA;    secsf = str(secs).zfill(2)&#xA;    t_fnl = hrsf &#x2B; &#x27;:&#x27; &#x2B; minsf &#x2B; &#x27;:&#x27; &#x2B; secsf&#xA;    return t_fnl&#xA;&#xA;def go_main():&#xA;    tf = TF()&#xA;    vid_n = 0&#xA;    arglen = len(sys.argv)&#xA;    if arglen == 2:&#xA;        with open(sys.argv[1], &#x27;r&#x27;) as f_in:&#xA;            lines = f_in.readlines()&#xA;            start = None&#xA;            end = None&#xA;            cnt = 0&#xA;            for line in lines:&#xA;                if line[:5] == &#x27;BEGIN&#x27;:&#xA;                    start = cnt&#xA;                if line[:3] == &#x27;END&#x27;:&#xA;                    end = cnt&#xA;                cnt &#x2B;= 1&#xA;            if start == None or end == None:&#xA;                print(&#x27;Invalid file format. start = {}, end = {}&#x27;.format(start,end))&#xA;                return&#xA;            else:&#xA;                lines_r = lines[start&#x2B;1:end]&#xA;                del lines&#xA;                print(&#x27;videos to process: {}&#x27;.format(len(lines_r)))&#xA;                f_out_prefix = ""&#xA;                for vid in lines_r:&#xA;                     vid_n &#x2B;= 1&#xA;                    print(&#x27;\nProcessing video {}/{}&#x27;.format(vid_n, len(lines_r)))&#xA;                    f_out_prefix = &#x27;v&#x27; &#x2B; str(vid_n) &#x2B; &#x27;-&#x27;&#xA;                    dat = vid.split(&#x27;!&#x27;)[1:3]&#xA;                    title = dat[0]&#xA;                    dat_t = dat[1].split(&#x27;,&#x27;)&#xA;                    v_pieces = len(dat_t)&#xA;                    piece_n = 0&#xA;                    video_pieces = []&#xA;                    cmd1 = "echo -n \"\" > tmpfile"&#xA;                    subprocess.run(cmd1, shell=True)                    &#xA;                    print(&#x27;  new tmpfile created&#x27;)&#xA;                    for v_times in dat_t:&#xA;                        piece_n &#x2B;= 1&#xA;                        f_out = f_out_prefix &#x2B; str(piece_n) &#x2B; &#x27;.mp4&#x27;&#xA;                        video_pieces.append(f_out)&#xA;                        print(&#x27;  piece filename {} added to video_pieces list&#x27;.format(f_out))&#xA;                        v_times_spl = v_times.split(&#x27;-&#x27;)&#xA;                        v_times_start = v_times_spl[0]&#xA;                        v_times_end = v_times_spl[1]&#xA;                        t_st = tf.toLong(v_times_start)&#xA;                        t_dur = tf.toTime(tf.toSeconds(v_times_end) - tf.toSeconds(v_times_start))&#xA;                        cmd3 = ["ffmpeg", "-i", title, "-ss", t_st, "-t", t_dur, f_out, "-loglevel", "error", "-stats"]&#xA;                        print(&#x27;  cutting out piece {}/{} - {}&#x27;.format(piece_n, len(dat_t), t_dur))&#xA;                        subprocess.run(cmd3)&#xA;                    for video_piece_name in video_pieces:&#xA;                        cmd4 = "echo \"file " &#x2B; video_piece_name &#x2B; "\" >> tmpfile"&#xA;                        subprocess.run(cmd4, shell=True)&#xA;                        print(&#x27;  filename {} added to tmpfile&#x27;.format(video_piece_name))&#xA;                    vname = f_out_prefix[:-1] &#x2B; ".mp4"&#xA;                    print(&#x27;  name of joined file: {}&#x27;.format(vname))&#xA;                    cmd5 = "ffmpeg -f concat -safe 0 -i tmpfile -c copy joined.mp4 -loglevel error -stats"&#xA;                    to_be_joined = " ".join(video_pieces)&#xA;                    print(&#x27;  joining...&#x27;)&#xA;                    join_cmd = subprocess.Popen(cmd5, shell=True)&#xA;                    join_cmd.wait()&#xA;                    print(&#x27;  joined!&#x27;)&#xA;                    cmd6 = "mv joined.mp4 " &#x2B; vname&#xA;                    rename_cmd = subprocess.Popen(cmd6, shell=True)&#xA;                    rename_cmd.wait()&#xA;                    print(&#x27;  File joined.mp4 renamed to {}&#x27;.format(vname))&#xA;                    cmd7 = "rm " &#x2B; to_be_joined&#xA;                    rm_cmd = subprocess.Popen(cmd7, shell=True)&#xA;                    rm_cmd.wait()&#xA;                    print(&#x27;rm command completed - pieces removed&#x27;)&#xA;                cmd8 = "rm tmpfile"&#xA;                subprocess.run(cmd8, shell=True)&#xA;                print(&#x27;tmpfile removed&#x27;)&#xA;                print(&#x27;All done&#x27;)&#xA;    else:&#xA;        print(&#x27;Incorrect number of arguments&#x27;)&#xA;&#xA;############################&#xA;if __name__ == &#x27;__main__&#x27;:&#xA;    go_main()&#xA;

    &#xA;

    process_videos.py is called from bash terminal like this :

    &#xA;

    $ python process_videos.py video_data   &#xA;

    &#xA;

    video_data file has the following format :

    &#xA;

    BEGIN&#xA;!first_video.mp4!3-23,55-1:34,2:01-3:15,3:34-3:44!&#xA;!second_video.mp4!2-7,12-44,1:03-1:33!&#xA;END&#xA;

    &#xA;

    My system details :

    &#xA;

    System:    Host: snowflake Kernel: 5.4.0-52-generic x86_64 bits: 64 Desktop: Gnome 3.28.4&#xA;           Distro: Ubuntu 18.04.5 LTS&#xA;Machine:   Device: desktop System: Gigabyte product: N/A serial: N/A&#xA;Mobo:      Gigabyte model: Z77-D3H v: x.x serial: N/A BIOS: American Megatrends v: F14 date: 05/31/2012&#xA;CPU:       Quad core Intel Core i5-3570 (-MCP-) cache: 6144 KB &#xA;           clock speeds: max: 3800 MHz 1: 1601 MHz 2: 1601 MHz 3: 1601 MHz 4: 1602 MHz&#xA;Drives:    HDD Total Size: 1060.2GB (55.2% used)&#xA;           ID-1: /dev/sda model: ST31000524AS size: 1000.2GB&#xA;           ID-2: /dev/sdb model: Corsair_Force_GT size: 60.0GB&#xA;Partition: ID-1: / size: 366G used: 282G (82%) fs: ext4 dev: /dev/sda1&#xA;           ID-2: swap-1 size: 0.70GB used: 0.00GB (0%) fs: swap dev: /dev/sda5&#xA;Info:      Processes: 313 Uptime: 16:37 Memory: 3421.4/15906.9MB Client: Shell (bash) inxi: 2.3.56&#xA;

    &#xA;
    &#xA;

    UPDATE :

    &#xA;

    Following Charles' advice, I used performance sampling :

    &#xA;

    # perf record -a -g sleep 180&#xA;

    &#xA;

    ...and here's the report :

    &#xA;

    Samples: 74K of event &#x27;cycles&#x27;, Event count (approx.): 1043554519767&#xA;  Children      Self  Command          Shared Object&#xA;-   50.56%    45.86%  ffmpeg           libavcodec.so.57.107.100                                                                                &#xA;   - 3.10% 0x4489480000002825                                                                                                                  &#xA;       0.64% 0x7ffaf24b92f0                                                                                                                   &#xA;   - 2.12% 0x5f7369007265646f                                                                                                                  &#xA;       av_default_item_name                                                                                                                   &#xA;     1.39% 0                                                                                                                                   &#xA;-   44.48%    40.59%  ffmpeg           libx264.so.152                                                                                          &#xA;     5.78% x264_add8x8_idct_avx2.skip_prologue                                                                                                 &#xA;     3.13% x264_add8x8_idct_avx2.skip_prologue                                                                                                 &#xA;     2.91% x264_add8x8_idct_avx2.skip_prologue                                                                                                 &#xA;     2.31% x264_add8x8_idct_avx.skip_prologue                                                                                                  &#xA;     2.03% 0                                                                                                                                   &#xA;     1.78% 0x1                                                                                                                                 &#xA;     1.26% x264_add8x8_idct_avx2.skip_prologue                                                                                                 &#xA;     1.09% x264_add8x8_idct_avx.skip_prologue                                                                                                  &#xA;     1.06% x264_me_search_ref                                                                                                                  &#xA;     0.97% x264_add8x8_idct_avx.skip_prologue                                                                                                  &#xA;     0.60% x264_me_search_ref                                                                                                                  &#xA;-   38.01%     0.00%  ffmpeg           [unknown]                                                                                               &#xA;     4.10% 0                                                                                                                                   &#xA;   - 3.49% 0x4489480000002825                                                                                                                  &#xA;        0.70% 0x7ffaf24b92f0                                                                                                                   &#xA;        0.56% 0x7f273ae822f0                                                                                                                   &#xA;        0.50% 0x7f0c4768b2f0                                                                                                                   &#xA;   - 2.29% 0x5f7369007265646f                                                                                                                  &#xA;        av_default_item_name                                                                                                                   &#xA;     1.99% 0x1                                                                                                                                 &#xA;    10.13%    10.12%  ffmpeg           [kernel.kallsyms]                                                                                       &#xA;-    3.14%     0.73%  ffmpeg           libavutil.so.55.78.100                                                                                  &#xA;     2.34% av_default_item_name                                                                                                                &#xA;-    1.73%     0.21%  ffmpeg           libpthread-2.27.so                                                                                      &#xA;   - 0.70% pthread_cond_wait@@GLIBC_2.3.2                                                                                                      &#xA;      - 0.62% entry_SYSCALL_64_after_hwframe                                                                                                   &#xA;         - 0.62% do_syscall_64                                                                                                                 &#xA;            - 0.57% __x64_sys_futex                                                                                                            &#xA;                 0.52% do_futex                                                                                                                &#xA;     0.93%     0.89%  ffmpeg           libc-2.27.so                                                                                            &#xA;-    0.64%     0.64%  swapper          [kernel.kallsyms]                                                                                       &#xA;     0.63% secondary_startup_64                                                                                                                &#xA;     0.21%     0.18%  ffmpeg           libavfilter.so.6.107.100                                                                                &#xA;     0.20%     0.11%  ffmpeg           libavformat.so.57.83.100                                                                                &#xA;     0.12%     0.11%  ffmpeg           ffmpeg                                                                                                  &#xA;     0.11%     0.00%  gnome-terminal-  [unknown]                                                                                               &#xA;     0.09%     0.07%  ffmpeg           libm-2.27.so                                                                                            &#xA;     0.08%     0.07%  ffmpeg           ld-2.27.so                                                                                              &#xA;     0.04%     0.04%  gnome-terminal-  libglib-2.0.so.0.5600.4&#xA;

    &#xA;

    &#xA;