Пример #1
0
    def load_infos(self, print_infos=False):
        """ reads the FFMPEG info on the file and sets self.size
            and self.fps """
        # open the file in a pipe, provoke an error, read output
        proc = sp.Popen([FFMPEG_BINARY,"-i",self.filename, "-"],
                stdin=sp.PIPE,
                stdout=sp.PIPE,
                stderr=sp.PIPE)
        proc.stdout.readline()
        proc.terminate()
        infos = proc.stderr.read().decode('utf8')

        if print_infos:
            # print the whole info text returned by FFMPEG
            print( infos )
            
        lines = infos.splitlines()
        
        if "No such file or directory" in lines[-1]:
            raise IOError("%s not found ! Wrong path ?"%self.filename)
            
        # get duration (in seconds)
        line = [l for l in lines if 'Duration: ' in l][0]
        match = re.search(" [0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9]",line)
        hms = map(float,line[match.start()+1:match.end()].split(':'))
        self.duration = cvsecs(*hms)
        self.nframes = int(self.duration*self.fps)
Пример #2
0
def show(clip, t=0, with_mask=True):
    """
    Splashes the frame of clip corresponding to time ``t``.
    
    Parameters
    ------------
    
    t
      Time in seconds of the frame to display.
    
    with_mask
      ``False`` if the clip has a mask but you want to see the clip
      without the mask.
    
    """

    if isinstance(t, tuple):
        t = cvsecs(*t)

    if clip.ismask:
        clip = clip.to_RGB()
    if with_mask and (clip.mask != None):
        import moviepy.video.compositing.CompositeVideoClip as cvc
        clip = cvc.CompositeVideoClip([clip.set_pos((0,0))])
    imdisplay(clip.get_frame(t))
Пример #3
0
    def load_infos(self, print_infos=False):
        """ reads the FFMPEG info on the file and sets self.size
            and self.fps """
        # open the file in a pipe, provoke an error, read output
        proc = sp.Popen([FFMPEG_BINARY, "-i", self.filename, "-"], stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.PIPE)
        proc.stdout.readline()
        proc.terminate()
        infos = proc.stderr.read().decode("utf8")
        if print_infos:
            # print the whole info text returned by FFMPEG
            print(infos)

        lines = infos.splitlines()
        if "No such file or directory" in lines[-1]:
            raise IOError("%s not found ! Wrong path ?" % self.filename)

        # get the output line that speaks about video
        line = [l for l in lines if " Video: " in l][0]

        # get the size, of the form 460x320 (w x h)
        match = re.search(" [0-9]*x[0-9]*(,| )", line)
        self.size = list(map(int, line[match.start() : match.end() - 1].split("x")))

        # get the frame rate
        match = re.search("( [0-9]*.| )[0-9]* (tbr|fps)", line)
        self.fps = float(line[match.start() : match.end()].split(" ")[1])

        # get duration (in seconds)
        line = [l for l in lines if "Duration: " in l][0]
        match = re.search(" [0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9]", line)
        hms = map(float, line[match.start() + 1 : match.end()].split(":"))
        self.duration = cvsecs(*hms)
        self.nframes = int(self.duration * self.fps)
Пример #4
0
    def load_infos(self, print_infos=False):
        """ reads the FFMPEG info on the file and sets self.size
            and self.fps """
        # open the file in a pipe, provoke an error, read output
        proc = sp.Popen([FFMPEG_BINARY, "-i", self.filename, "-"],
                        stdin=sp.PIPE,
                        stdout=sp.PIPE,
                        stderr=sp.PIPE)
        proc.stdout.readline()
        proc.terminate()
        infos = proc.stderr.read()
        if print_infos:
            # print the whole info text returned by FFMPEG
            print infos

        lines = infos.splitlines()

        if "No such file or directory" in lines[-1]:
            raise IOError("%s not found ! Wrong path ?" % self.filename)

        # get duration (in seconds)
        line = [l for l in lines if 'Duration: ' in l][0]
        match = re.search(" [0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9]", line)
        hms = map(float, line[match.start() + 1:match.end()].split(':'))
        self.duration = cvsecs(*hms)
        self.nframes = int(self.duration * self.fps)
Пример #5
0
def time_can_be_tuple(f, clip, *a, **k):
    """
    All tuples in the arguments of f will be considered as time and
    converted to seconds.
    """
    
    fun = lambda e: e if (not isinstance(e,tuple)) else cvsecs(*e)
    a = map(fun,a)
    k = dict( [(m, fun(n)) for m,n in k.items()])
    return f(clip, *a, **k)
Пример #6
0
def time_can_be_tuple(f, clip, *a, **k):
    """
    All tuples in the arguments of f will be considered as time and
    converted to seconds.
    """
    
    fun = lambda e: e if (not isinstance(e,tuple)) else cvsecs(*e)
    a = map(fun,a)
    k = dict( [(m, fun(n)) for m,n in k.items()])
    return f(clip, *a, **k)
Пример #7
0
def time_can_be_tuple(f, clip, *a, **k):
    """
    This decorator tells that the function f (audioclip -> audioclip)
    can be also used on a video clip, at which case it returns a
    videoclip with modified audio.
    """
    fun = lambda e: e if (not isinstance(e,tuple)) else cvsecs(*e)
    a = map(fun,a)
    k = dict( [(m, fun(n)) for m,n in k.items()])
    return f(clip, *a, **k)
Пример #8
0
def test_3():
    """Test the cvsecs funtion outputs correct times as per the docstring."""
    lefts = [15.4, (1,21.5), (1,1,2), '01:01:33.5', '01:01:33.045' ]
    rights = [15.4, 81.5, 3662, 3693.5, 3693.045]
    for i in range(len(lefts)):
        left = tools.cvsecs(lefts[i])
        right = rights[i]
        message = "{0} resulted in {1}, but {2} was expected"\
            .format(lefts[i],left, right)
        assert left == right, message
Пример #9
0
def time_can_be_tuple(f, clip, *a, **k):
    """
    This decorator tells that the function f (audioclip -> audioclip)
    can be also used on a video clip, at which case it returns a
    videoclip with modified audio.
    """
    fun = lambda e: e if (not isinstance(e, tuple)) else cvsecs(*e)
    a = map(fun, a)
    k = dict([(m, fun(n)) for m, n in k.items()])
    return f(clip, *a, **k)
Пример #10
0
def test_3():
    """Test the cvsecs funtion outputs correct times as per the docstring."""
    lefts = [15.4, (1,21.5), (1,1,2), '01:01:33.5', '01:01:33.045' ]
    rights = [15.4, 81.5, 3662, 3693.5, 3693.045]
    for i in range(len(lefts)):
        left = tools.cvsecs(lefts[i])
        right = rights[i]
        message = "{0} resulted in {1}, but {2} was expected"\
            .format(lefts[i],left, right)
        assert left == right, message
Пример #11
0
    def get_chapter_duration(self, chapters, full_duration=None, idx=None):
        """

        :param chapters:
        :param full_duration:
        :param idx:
        :return:
        """
        start = cvsecs(chapters[idx].start)
        if idx is 0:
            start = 0
        try:
            chapter_end_time = chapters[idx + 1].start
        except IndexError:
            chapter_end_time = full_duration

        chapter_end_time = cvsecs(chapter_end_time)
        duration = chapter_end_time - start

        return duration
Пример #12
0
 def warper(f, *a, **kw):
     if hasattr(f, "func_code"):
         func_code = f.func_code # Python 2
     else:
         func_code = f.__code__ # Python 3
         
     names = func_code.co_varnames
     new_a = [cvsecs(arg) if (name in varnames) else arg
              for (arg, name) in zip(a, names)]
     new_kw = {k: fun(v) if k in varnames else v
              for (k,v) in kw.items()}
     return f(*new_a, **new_kw)
Пример #13
0
    def warper(f, *a, **kw):
        if hasattr(f, "func_code"):
            func_code = f.func_code  # Python 2
        else:
            func_code = f.__code__  # Python 3

        names = func_code.co_varnames
        new_a = [
            cvsecs(arg) if (name in varnames) else arg
            for (arg, name) in zip(a, names)
        ]
        new_kw = {k: fun(v) if k in varnames else v for (k, v) in kw.items()}
        return f(*new_a, **new_kw)
Пример #14
0
	def time(self, value):
		""" Sets the time of the clock. Useful for seeking. 
		
		Parameters
		----------
		value : str or int
			The time to seek to. Can be any of the following formats:

		    >>> 15.4 -> 15.4 # seconds
		    >>> (1,21.5) -> 81.5 # (min,sec)
		    >>> (1,1,2) -> 3662 # (hr, min, sec)
		    >>> '01:01:33.5' -> 3693.5  #(hr,min,sec)
		    >>> '01:01:33.045' -> 3693.045
		    >>> '01:01:33,5' #comma works too
		"""
		seconds = cvsecs(value)
		self.reset()
		self.previous_intervals.append(seconds)
Пример #15
0
    def time(self, value):
        """ Sets the time of the clock. Useful for seeking. 
		
		Parameters
		----------
		value : str or int
			The time to seek to. Can be any of the following formats:

		    >>> 15.4 -> 15.4 # seconds
		    >>> (1,21.5) -> 81.5 # (min,sec)
		    >>> (1,1,2) -> 3662 # (hr, min, sec)
		    >>> '01:01:33.5' -> 3693.5  #(hr,min,sec)
		    >>> '01:01:33.045' -> 3693.045
		    >>> '01:01:33,5' #comma works too
		"""
        seconds = cvsecs(value)
        self.reset()
        self.previous_intervals.append(seconds)
Пример #16
0
def show(clip, t=0, with_mask=True, interactive=False):
    """
    Splashes the frame of clip corresponding to time ``t``.
    
    Parameters
    ------------
    
    t
      Time in seconds of the frame to display.
    
    with_mask
      ``False`` if the clip has a mask but you want to see the clip
      without the mask.
    
    """

    if isinstance(t, tuple):
        t = cvsecs(*t)

    if clip.ismask:
        clip = clip.to_RGB()
    if with_mask and (clip.mask != None):
        import moviepy.video.compositing.CompositeVideoClip as cvc
        clip = cvc.CompositeVideoClip([clip.set_pos((0, 0))])
    img = clip.get_frame(t)
    imdisplay(img)

    if interactive:
        result = []
        while True:
            for event in pg.event.get():
                if event.type == pg.KEYDOWN:
                    if (event.key == pg.K_ESCAPE):
                        print("Keyboard interrupt")
                        return result
                elif event.type == pg.MOUSEBUTTONDOWN:
                    x, y = pg.mouse.get_pos()
                    rgb = img[y, x]
                    result.append({'position': (x, y), 'color': rgb})
                    print("position, color : ", "%s, %s" % (str(
                        (x, y)), str(rgb)))
            time.sleep(.03)
Пример #17
0
def show(clip, t=0, with_mask=True, interactive=False):
    """
    Splashes the frame of clip corresponding to time ``t``.
    
    Parameters
    ------------
    
    t
      Time in seconds of the frame to display.
    
    with_mask
      ``False`` if the clip has a mask but you want to see the clip
      without the mask.
    
    """

    if isinstance(t, tuple):
        t = cvsecs(*t)

    if clip.ismask:
        clip = clip.to_RGB()
    if with_mask and (clip.mask != None):
        import moviepy.video.compositing.CompositeVideoClip as cvc
        clip = cvc.CompositeVideoClip([clip.set_pos((0,0))])
    img = clip.get_frame(t)
    imdisplay(img)

    if interactive:
        result=[]
        while True:
            for event in pg.event.get():
                if event.type == pg.KEYDOWN:
                    if (event.key == pg.K_ESCAPE):
                        print( "Keyboard interrupt" )
                        return result
                elif event.type == pg.MOUSEBUTTONDOWN:
                     x,y = pg.mouse.get_pos()
                     rgb = img[y,x]
                     result.append({'position':(x,y), 'color':rgb})
                     print( "position, color : ", "%s, %s"%(
                             str((x,y)),str(rgb)))
            time.sleep(.03)
Пример #18
0
    def load_infos(self, print_infos=False):
        """Get file infos using ffmpeg.
        
        Grabs the FFMPEG info on the file and use them to set the
        attributes ``self.size`` and ``self.fps`` """

        # open the file in a pipe, provoke an error, read output
        proc = sp.Popen([FFMPEG_BINARY, "-i", self.filename, "-"],
                        bufsize=10**6,
                        stdin=sp.PIPE,
                        stdout=sp.PIPE,
                        stderr=sp.PIPE)
        proc.stdout.readline()
        proc.terminate()
        infos = proc.stderr.read().decode('utf8')
        if print_infos:
            # print the whole info text returned by FFMPEG
            print(infos)

        lines = infos.splitlines()
        if "No such file or directory" in lines[-1]:
            raise IOError("%s not found ! Wrong path ?" % self.filename)

        # get the output line that speaks about video
        line = [l for l in lines if ' Video: ' in l][0]

        # get the size, of the form 460x320 (w x h)
        match = re.search(" [0-9]*x[0-9]*(,| )", line)
        self.size = list(
            map(int, line[match.start():match.end() - 1].split('x')))

        # get the frame rate
        match = re.search("( [0-9]*.| )[0-9]* (tbr|fps)", line)
        self.fps = float(line[match.start():match.end()].split(' ')[1])

        # get duration (in seconds)
        line = [l for l in lines if 'Duration: ' in l][0]
        match = re.search(" [0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9]", line)
        hms = map(float, line[match.start() + 1:match.end()].split(':'))
        self.duration = cvsecs(*hms)
        self.nframes = int(self.duration * self.fps)
Пример #19
0
def file_to_subtitles(filename):
    """ Converts a srt file into subtitles.

    The returned list is of the form ``[((ta,tb),'some text'),...]``
    and can be fed to SubtitlesClip.

    Only works for '.srt' format for the moment.
    """
    times_texts = []
    current_times = None
    current_text = ""
    with open(filename, "r") as f:
        for line in f:
            times = re.findall("([0-9]*:[0-9]*:[0-9]*,[0-9]*)", line)
            if times:
                current_times = [cvsecs(t) for t in times]
            elif line.strip() == "":
                times_texts.append((current_times, current_text.strip("\n")))
                current_times, current_text = None, ""
            elif current_times:
                current_text += line
    return times_texts
Пример #20
0
 def to_srt(sub_element):
     (ta, tb), txt = sub_element
     fta = cvsecs(ta)
     ftb = cvsecs(tb)
     return "%s - %s\n%s" % (fta, ftb, txt)
def ffmpeg_parse_infos(filename,
                       print_infos=False,
                       check_duration=True,
                       fps_source='tbr'):
    """Get file infos using ffmpeg.

    Returns a dictionnary with the fields:
    "video_found", "video_fps", "duration", "video_nframes",
    "video_duration", "audio_found", "audio_fps"

    "video_duration" is slightly smaller than "duration" to avoid
    fetching the uncomplete frames at the end, which raises an error.

    """

    # open the file in a pipe, provoke an error, read output
    is_GIF = filename.endswith('.gif')
    cmd = [get_setting("FFMPEG_BINARY"), "-i", filename]
    if is_GIF:
        cmd += ["-f", "null", "/dev/null"]

    popen_params = {
        "bufsize": 10**5,
        "stdout": sp.PIPE,
        "stderr": sp.PIPE,
        "stdin": DEVNULL
    }

    if os.name == "nt":
        popen_params["creationflags"] = 0x08000000

    proc = sp.Popen(cmd, **popen_params)

    out, err = proc.communicate()
    proc.terminate()
    infos = err.decode('utf8')

    del proc

    if print_infos:
        # print the whole info text returned by FFMPEG
        print(infos)

    lines = infos.splitlines()
    if "No such file or directory" in lines[-1]:
        raise IOError(("MoviePy error: the file %s could not be found!\n"
                       "Please check that you entered the correct "
                       "path.") % filename)

    result = dict()

    # get duration (in seconds)
    result['duration'] = None

    if check_duration:
        try:
            keyword = ('frame=' if is_GIF else 'Duration: ')
            # for large GIFS the "full" duration is presented as the last element in the list.
            index = -1 if is_GIF else 0
            line = [l for l in lines if keyword in l][index]
            match = re.findall("([0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9])",
                               line)[0]
            result['duration'] = cvsecs(match)
        except:
            raise IOError(
                ("MoviePy error: failed to read the duration of file %s.\n"
                 "Here are the file infos returned by ffmpeg:\n\n%s") %
                (filename, infos))

    # get the output line that speaks about video
    lines_video = [
        l for l in lines if ' Video: ' in l and re.search('\d+x\d+', l)
    ]

    result['video_found'] = (lines_video != [])

    if result['video_found']:
        try:
            line = lines_video[0]

            # get the size, of the form 460x320 (w x h)
            match = re.search(" [0-9]*x[0-9]*(,| )", line)
            s = list(map(int, line[match.start():match.end() - 1].split('x')))
            result['video_size'] = s
        except:
            raise IOError(
                ("MoviePy error: failed to read video dimensions in file %s.\n"
                 "Here are the file infos returned by ffmpeg:\n\n%s") %
                (filename, infos))

        # Get the frame rate. Sometimes it's 'tbr', sometimes 'fps', sometimes
        # tbc, and sometimes tbc/2...
        # Current policy: Trust tbr first, then fps unless fps_source is
        # specified as 'fps' in which case try fps then tbr

        # If result is near from x*1000/1001 where x is 23,24,25,50,
        # replace by x*1000/1001 (very common case for the fps).

        def get_tbr():
            match = re.search("( [0-9]*.| )[0-9]* tbr", line)

            # Sometimes comes as e.g. 12k. We need to replace that with 12000.
            s_tbr = line[match.start():match.end()].split(' ')[1]
            if "k" in s_tbr:
                tbr = float(s_tbr.replace("k", "")) * 1000
            else:
                tbr = float(s_tbr)
            return tbr

        def get_fps():
            match = re.search("( [0-9]*.| )[0-9]* fps", line)
            fps = float(line[match.start():match.end()].split(' ')[1])
            return fps

        if fps_source == 'tbr':
            try:
                result['video_fps'] = get_tbr()
            except:
                result['video_fps'] = get_fps()

        elif fps_source == 'fps':
            try:
                result['video_fps'] = get_fps()
            except:
                result['video_fps'] = get_tbr()

        # It is known that a fps of 24 is often written as 24000/1001
        # but then ffmpeg nicely rounds it to 23.98, which we hate.
        coef = 1000.0 / 1001.0
        fps = result['video_fps']
        for x in [23, 24, 25, 30, 50]:
            if (fps != x) and abs(fps - x * coef) < .01:
                result['video_fps'] = x * coef

        if check_duration:
            result['video_nframes'] = int(
                result['duration'] * result['video_fps']) + 1
            result['video_duration'] = result['duration']
        else:
            result['video_nframes'] = 1
            result['video_duration'] = None
        # We could have also recomputed the duration from the number
        # of frames, as follows:
        # >>> result['video_duration'] = result['video_nframes'] / result['video_fps']

        # get the video rotation info.
        try:
            rotation_lines = [
                l for l in lines
                if 'rotate          :' in l and re.search('\d+$', l)
            ]
            if len(rotation_lines):
                rotation_line = rotation_lines[0]
                match = re.search('\d+$', rotation_line)
                result['video_rotation'] = int(
                    rotation_line[match.start():match.end()])
            else:
                result['video_rotation'] = 0
        except:
            raise IOError(
                ("MoviePy error: failed to read video rotation in file %s.\n"
                 "Here are the file infos returned by ffmpeg:\n\n%s") %
                (filename, infos))

    lines_audio = [l for l in lines if ' Audio: ' in l]

    result['audio_found'] = lines_audio != []

    if result['audio_found']:
        line = lines_audio[0]
        try:
            match = re.search(" [0-9]* Hz", line)
            hz_string = line[match.start() + 1:match.end() -
                             3]  # Removes the 'hz' from the end
            result['audio_fps'] = int(hz_string)
        except:
            result['audio_fps'] = 'unknown'

    return result
Пример #22
0
def ffmpeg_parse_infos(filename, print_infos=False, check_duration=True):
    """Get file infos using ffmpeg.

    Returns a dictionnary with the fields:
    "video_found", "video_fps", "duration", "video_nframes",
    "video_duration", "audio_found", "audio_fps"

    "video_duration" is slightly smaller than "duration" to avoid
    fetching the uncomplete frames at the end, which raises an error.

    """

    # open the file in a pipe, provoke an error, read output
    cmd = [get_setting("FFMPEG_BINARY"), "-i", filename]

    popen_params = {
        "bufsize": 10**5,
        "stdout": sp.PIPE,
        "stderr": sp.PIPE,
        "stdin": DEVNULL
    }

    if os.name == "nt":
        popen_params["creationflags"] = 0x08000000

    proc = sp.Popen(cmd, **popen_params)

    proc.stdout.readline()
    proc.terminate()
    infos = proc.stderr.read().decode('utf8')
    del proc

    if print_infos:
        # print the whole info text returned by FFMPEG
        print(infos)

    lines = infos.splitlines()
    if "No such file or directory" in lines[-1]:
        raise IOError(("MoviePy error: the file %s could not be found !\n"
                       "Please check that you entered the correct "
                       "path.") % filename)

    result = dict()

    # get duration (in seconds)
    result['duration'] = None

    if check_duration:
        try:
            keyword = 'Duration: '
            line = [l for l in lines if keyword in l][0]
            match = re.findall("([0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9])",
                               line)[0]
            result['duration'] = cvsecs(match)
        except:
            raise IOError(
                ("MoviePy error: failed to read the duration of file %s.\n"
                 "Here are the file infos returned by ffmpeg:\n\n%s") %
                (filename, infos))

    # get the output line that speaks about video
    lines_video = [l for l in lines if ' Video: ' in l]

    result['video_found'] = (lines_video != [])

    if result['video_found']:

        try:
            line = lines_video[0]

            # get the size, of the form 460x320 (w x h)
            match = re.search(" [0-9]*x[0-9]*(,| )", line)
            s = list(map(int, line[match.start():match.end() - 1].split('x')))
            result['video_size'] = s
        except:
            raise (
                ("MoviePy error: failed to read video dimensions in file %s.\n"
                 "Here are the file infos returned by ffmpeg:\n\n%s") %
                (filename, infos))

        # get the frame rate. Sometimes it's 'tbr', sometimes 'fps', sometimes
        # tbc, and sometimes tbc/2...
        # Current policy: Trust tbr first, then fps. If result is near from x*1000/1001
        # where x is 23,24,25,50, replace by x*1000/1001 (very common case for the fps).

        try:
            match = re.search("( [0-9]*.| )[0-9]* tbr", line)
            tbr = float(line[match.start():match.end()].split(' ')[1])
            result['video_fps'] = tbr

        except:
            match = re.search("( [0-9]*.| )[0-9]* fps", line)
            result['video_fps'] = float(
                line[match.start():match.end()].split(' ')[1])

        # It is known that a fps of 24 is often written as 24000/1001
        # but then ffmpeg nicely rounds it to 23.98, which we hate.
        coef = 1000.0 / 1001.0
        fps = result['video_fps']
        for x in [23, 24, 25, 30, 50]:
            if (fps != x) and abs(fps - x * coef) < .01:
                result['video_fps'] = x * coef

        if check_duration:
            result['video_nframes'] = int(
                result['duration'] * result['video_fps']) + 1
            result['video_duration'] = result['duration']
        else:
            result['video_nframes'] = 1
            result['video_duration'] = None
            # We could have also recomputed the duration from the number
            # of frames, as follows:
            # >>> result['video_duration'] = result['video_nframes'] / result['video_fps']

    lines_audio = [l for l in lines if ' Audio: ' in l]

    result['audio_found'] = lines_audio != []

    if result['audio_found']:
        line = lines_audio[0]
        try:
            match = re.search(" [0-9]* Hz", line)
            result['audio_fps'] = int(line[match.start() + 1:match.end()])
        except:
            result['audio_fps'] = 'unknown'

    return result
Пример #23
0
def ffmpeg_parse_infos(
    filename,
    decode_file=False,
    print_infos=False,
    check_duration=True,
    fps_source="fps",
):
    """Get file infos using ffmpeg.

    Returns a dictionnary with the fields:
    "video_found", "video_fps", "duration", "video_nframes",
    "video_duration", "video_bitrate","audio_found", "audio_fps", "audio_bitrate"

    "video_duration" is slightly smaller than "duration" to avoid
    fetching the uncomplete frames at the end, which raises an error.

    """
    # Open the file in a pipe, read output
    cmd = [FFMPEG_BINARY, "-i", filename]
    if decode_file:
        cmd.extend(["-f", "null", "-"])

    popen_params = {
        "bufsize": 10**5,
        "stdout": sp.PIPE,
        "stderr": sp.PIPE,
        "stdin": sp.DEVNULL,
    }

    if os.name == "nt":
        popen_params["creationflags"] = 0x08000000

    proc = sp.Popen(cmd, **popen_params)
    (output, error) = proc.communicate()
    infos = error.decode("utf8", errors="ignore")

    proc.terminate()
    del proc

    if print_infos:
        # print the whole info text returned by FFMPEG
        print(infos)

    lines = infos.splitlines()
    if "No such file or directory" in lines[-1]:
        raise IOError(("MoviePy error: the file %s could not be found!\n"
                       "Please check that you entered the correct "
                       "path.") % filename)

    result = dict()

    # get duration (in seconds)
    result["duration"] = None

    if check_duration:
        try:
            if decode_file:
                line = [l for l in lines if "time=" in l][-1]
            else:
                line = [l for l in lines if "Duration:" in l][-1]
            match = re.findall("([0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9])",
                               line)[0]
            result["duration"] = cvsecs(match)
        except Exception:
            raise IOError(
                f"MoviePy error: failed to read the duration of file {filename}.\nHere are the file infos returned by ffmpeg:\n\n{infos}"
            )

    # get the output line that speaks about video
    lines_video = [
        l for l in lines if " Video: " in l and re.search(r"\d+x\d+", l)
    ]

    result["video_found"] = lines_video != []

    if result["video_found"]:
        try:
            line = lines_video[0]

            # get the size, of the form 460x320 (w x h)
            match = re.search(" [0-9]*x[0-9]*(,| )", line)
            s = list(map(int, line[match.start():match.end() - 1].split("x")))
            result["video_size"] = s

        except Exception:
            raise IOError(
                ("MoviePy error: failed to read video dimensions in file %s.\n"
                 "Here are the file infos returned by ffmpeg:\n\n%s") %
                (filename, infos))
        match_bit = re.search(r"(\d+) kb/s", line)
        result["video_bitrate"] = int(
            match_bit.group(1)) if match_bit else None

        # Get the frame rate. Sometimes it's 'tbr', sometimes 'fps', sometimes
        # tbc, and sometimes tbc/2...
        # Current policy: Trust fps first, then tbr unless fps_source is
        # specified as 'tbr' in which case try tbr then fps

        # If result is near from x*1000/1001 where x is 23,24,25,50,
        # replace by x*1000/1001 (very common case for the fps).

        def get_tbr():
            match = re.search("( [0-9]*.| )[0-9]* tbr", line)

            # Sometimes comes as e.g. 12k. We need to replace that with 12000.
            s_tbr = line[match.start():match.end()].split(" ")[1]
            if "k" in s_tbr:
                tbr = float(s_tbr.replace("k", "")) * 1000
            else:
                tbr = float(s_tbr)
            return tbr

        def get_fps():
            match = re.search("( [0-9]*.| )[0-9]* fps", line)
            fps = float(line[match.start():match.end()].split(" ")[1])
            return fps

        if fps_source == "tbr":
            try:
                result["video_fps"] = get_tbr()
            except Exception:
                result["video_fps"] = get_fps()

        elif fps_source == "fps":
            try:
                result["video_fps"] = get_fps()
            except Exception:
                result["video_fps"] = get_tbr()

        # It is known that a fps of 24 is often written as 24000/1001
        # but then ffmpeg nicely rounds it to 23.98, which we hate.
        coef = 1000.0 / 1001.0
        fps = result["video_fps"]
        for x in [23, 24, 25, 30, 50]:
            if (fps != x) and abs(fps - x * coef) < 0.01:
                result["video_fps"] = x * coef

        if check_duration:
            result["video_nframes"] = int(result["duration"] *
                                          result["video_fps"])
            result["video_duration"] = result["duration"]
        else:
            result["video_nframes"] = 1
            result["video_duration"] = None
        # We could have also recomputed the duration from the number
        # of frames, as follows:
        # >>> result['video_duration'] = result['video_nframes'] / result['video_fps']

        # get the video rotation info.
        try:
            rotation_lines = [
                l for l in lines
                if "rotate          :" in l and re.search(r"\d+$", l)
            ]
            if len(rotation_lines):
                rotation_line = rotation_lines[0]
                match = re.search(r"\d+$", rotation_line)
                result["video_rotation"] = int(
                    rotation_line[match.start():match.end()])
            else:
                result["video_rotation"] = 0
        except Exception:
            raise IOError(
                ("MoviePy error: failed to read video rotation in file %s.\n"
                 "Here are the file infos returned by ffmpeg:\n\n%s") %
                (filename, infos))

    lines_audio = [l for l in lines if " Audio: " in l]

    result["audio_found"] = lines_audio != []

    if result["audio_found"]:
        line = lines_audio[0]
        try:
            match = re.search(" [0-9]* Hz", line)
            hz_string = line[match.start() + 1:match.end() -
                             3]  # Removes the 'hz' from the end
            result["audio_fps"] = int(hz_string)
        except Exception:
            result["audio_fps"] = "unknown"
        match_bit = re.search(r"(\d+) kb/s", line)
        result["audio_bitrate"] = int(
            match_bit.group(1)) if match_bit else None

    return result
Пример #24
0
def ffmpeg_parse_infos(filename, print_infos=False, check_duration=True):
    """Get file infos using ffmpeg.

    Returns a dictionnary with the fields:
    "video_found", "video_fps", "duration", "video_nframes",
    "video_duration", "audio_found", "audio_fps"

    "video_duration" is slightly smaller than "duration" to avoid
    fetching the uncomplete frames at the end, which raises an error.

    """


    # open the file in a pipe, provoke an error, read output
    is_GIF = filename.endswith('.gif')
    cmd = [get_setting("FFMPEG_BINARY"), "-i", filename]
    if is_GIF:
        cmd += ["-f", "null", "/dev/null"]

    popen_params = {"bufsize": 10**5,
                    "stdout": sp.PIPE,
                    "stderr": sp.PIPE,
                    "stdin": DEVNULL}

    if os.name == "nt":
        popen_params["creationflags"] = 0x08000000

    proc = sp.Popen(cmd, **popen_params)

    proc.stdout.readline()
    proc.terminate()
    infos = proc.stderr.read().decode('utf8')
    del proc

    if print_infos:
        # print the whole info text returned by FFMPEG
        print( infos )


    lines = infos.splitlines()
    if "No such file or directory" in lines[-1]:
        raise IOError(("MoviePy error: the file %s could not be found !\n"
                      "Please check that you entered the correct "
                      "path.")%filename)

    result = dict()


    # get duration (in seconds)
    result['duration'] = None

    if check_duration:
        try:
            keyword = ('frame=' if is_GIF else 'Duration: ')
            line = [l for l in lines if keyword in l][0]
            match = re.findall("([0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9])", line)[0]
            result['duration'] = cvsecs(match)
        except:
            raise IOError(("MoviePy error: failed to read the duration of file %s.\n"
                           "Here are the file infos returned by ffmpeg:\n\n%s")%(
                              filename, infos))

    # get the output line that speaks about video
    lines_video = [l for l in lines if ' Video: ' in l]

    result['video_found'] = ( lines_video != [] )

    if result['video_found']:


        try:
            line = lines_video[0]

            # get the size, of the form 460x320 (w x h)
            match = re.search(" [0-9]*x[0-9]*(,| )", line)
            s = list(map(int, line[match.start():match.end()-1].split('x')))
            result['video_size'] = s
        except:
            raise (("MoviePy error: failed to read video dimensions in file %s.\n"
                           "Here are the file infos returned by ffmpeg:\n\n%s")%(
                              filename, infos))


        # get the frame rate. Sometimes it's 'tbr', sometimes 'fps', sometimes
        # tbc, and sometimes tbc/2...
        # Current policy: Trust tbr first, then fps. If result is near from x*1000/1001
        # where x is 23,24,25,50, replace by x*1000/1001 (very common case for the fps).

        try:
            match = re.search("( [0-9]*.| )[0-9]* tbr", line)
            tbr = float(line[match.start():match.end()].split(' ')[1])
            result['video_fps'] = tbr

        except:
            match = re.search("( [0-9]*.| )[0-9]* fps", line)
            result['video_fps'] = float(line[match.start():match.end()].split(' ')[1])


        # It is known that a fps of 24 is often written as 24000/1001
        # but then ffmpeg nicely rounds it to 23.98, which we hate.
        coef = 1000.0/1001.0
        fps = result['video_fps']
        for x in [23,24,25,30,50]:
            if (fps!=x) and abs(fps - x*coef) < .01:
                result['video_fps'] = x*coef

        if check_duration:
            result['video_nframes'] = int(result['duration']*result['video_fps'])+1
            result['video_duration'] = result['duration']
        else:
            result['video_nframes'] = 1
            result['video_duration'] = None
        # We could have also recomputed the duration from the number
        # of frames, as follows:
        # >>> result['video_duration'] = result['video_nframes'] / result['video_fps']


    lines_audio = [l for l in lines if ' Audio: ' in l]

    result['audio_found'] = lines_audio != []

    if result['audio_found']:
        line = lines_audio[0]
        try:
            match = re.search(" [0-9]* Hz", line)
            result['audio_fps'] = int(line[match.start()+1:match.end()])
        except:
            result['audio_fps'] = 'unknown'

    return result
Пример #25
0
def test_cvsecs(given, expected):
    """Test the cvsecs funtion outputs correct times as per the docstring."""
    assert tools.cvsecs(given) == expected
Пример #26
0
def ffmpeg_parse_infos(filename, print_infos=False):
    """Get file infos using ffmpeg.

    Returns a dictionnary with the fields:
    "video_found", "video_fps", "duration", "video_nframes",
    "video_duration"
    "audio_found", "audio_fps"

    "video_duration" is slightly smaller than "duration" to avoid
    fetching the uncomplete frames at the end, which raises an error.

    """
    

    # open the file in a pipe, provoke an error, read output
    proc = sp.Popen([FFMPEG_BINARY, "-i", filename, "-"],
            bufsize=10**6,
            stdout=sp.PIPE,
            stderr=sp.PIPE)

    proc.stdout.readline()
    proc.terminate()
    infos = proc.stderr.read().decode('utf8')
    if print_infos:
        # print the whole info text returned by FFMPEG
        print( infos )


    lines = infos.splitlines()
    if "No such file or directory" in lines[-1]:
        raise IOError("%s not found ! Wrong path ?"%filename)
    
    result = dict()
    

    # get duration (in seconds)
    line = [l for l in lines if 'Duration: ' in l][0]
    match = re.search(" [0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9]", line)
    hms = map(float, line[match.start()+1:match.end()].split(':'))
    result['duration'] = cvsecs(*hms)

    # get the output line that speaks about video
    lines_video = [l for l in lines if ' Video: ' in l]
    
    result['video_found'] = lines_video != []
    
    if result['video_found']:
        
        line = lines_video[0]

        # get the size, of the form 460x320 (w x h)
        match = re.search(" [0-9]*x[0-9]*(,| )", line)
        s = list(map(int, line[match.start():match.end()-1].split('x')))
        result['video_size'] = s


        # get the frame rate
        try:
            match = re.search("( [0-9]*.| )[0-9]* tbr", line)
            result['video_fps'] = float(line[match.start():match.end()].split(' ')[1])
        except:
            match = re.search("( [0-9]*.| )[0-9]* fps", line)
            result['video_fps'] = float(line[match.start():match.end()].split(' ')[1])

        result['video_nframes'] = int(result['duration']*result['video_fps'])
        result['video_duration'] = result['video_nframes'] / result['video_fps']
    
    lines_audio = [l for l in lines if ' Audio: ' in l]
    
    result['audio_found'] = lines_audio != []
    
    if result['audio_found']:
        line = lines_audio[0]
        try:
            match = re.search(" [0-9]* Hz", line)
            result['audio_fps'] = int(line[match.start()+1:match.end()])
        except:
            result['audio_fps'] = 'unknown'

    return result
Пример #27
0
def ffmpeg_parse_infos(filename, print_infos=False):
    """Get file infos using ffmpeg.

    Returns a dictionnary with the fields:
    "video_found", "video_fps", "duration", "video_nframes",
    "video_duration"
    "audio_found", "audio_fps"

    "video_duration" is slightly smaller than "duration" to avoid
    fetching the uncomplete frames at the end, which raises an error.

    """

    # open the file in a pipe, provoke an error, read output
    proc = sp.Popen([FFMPEG_BINARY, "-i", filename, "-"],
                    bufsize=10**6,
                    stdout=sp.PIPE,
                    stderr=sp.PIPE)

    proc.stdout.readline()
    proc.terminate()
    infos = proc.stderr.read().decode('utf8')
    if print_infos:
        # print the whole info text returned by FFMPEG
        print(infos)

    lines = infos.splitlines()
    if "No such file or directory" in lines[-1]:
        raise IOError("%s not found ! Wrong path ?" % filename)

    result = dict()

    # get duration (in seconds)
    line = [l for l in lines if 'Duration: ' in l][0]
    match = re.search(" [0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9]", line)
    hms = map(float, line[match.start() + 1:match.end()].split(':'))
    result['duration'] = cvsecs(*hms)

    # get the output line that speaks about video
    lines_video = [l for l in lines if ' Video: ' in l]

    result['video_found'] = lines_video != []

    if result['video_found']:

        line = lines_video[0]

        # get the size, of the form 460x320 (w x h)
        match = re.search(" [0-9]*x[0-9]*(,| )", line)
        s = list(map(int, line[match.start():match.end() - 1].split('x')))
        result['video_size'] = s

        # get the frame rate
        try:
            match = re.search("( [0-9]*.| )[0-9]* tbr", line)
            result['video_fps'] = float(
                line[match.start():match.end()].split(' ')[1])
        except:
            match = re.search("( [0-9]*.| )[0-9]* fps", line)
            result['video_fps'] = float(
                line[match.start():match.end()].split(' ')[1])

        result['video_nframes'] = int(result['duration'] * result['video_fps'])
        result[
            'video_duration'] = result['video_nframes'] / result['video_fps']

    lines_audio = [l for l in lines if ' Audio: ' in l]

    result['audio_found'] = lines_audio != []

    if result['audio_found']:
        line = lines_audio[0]
        try:
            match = re.search(" [0-9]* Hz", line)
            result['audio_fps'] = int(line[match.start() + 1:match.end()])
        except:
            result['audio_fps'] = 'unknown'

    return result
Пример #28
0
def ffmpeg_parse_infos(filename, print_infos=False):
    """Get file infos using ffmpeg.

    Returns a dictionnary with the fields:
    "video_found", "video_fps", "duration", "video_nframes",
    "video_duration"
    "audio_found", "audio_fps"

    "video_duration" is slightly smaller than "duration" to avoid
    fetching the uncomplete frames at the end, which raises an error.

    """
    

    # open the file in a pipe, provoke an error, read output
    is_GIF = filename.endswith('.gif')
    cmd = [FFMPEG_BINARY, "-i", filename]
    if is_GIF:
        cmd += ["-f", "null", "/dev/null"]
    proc = sp.Popen(cmd,
            bufsize=10**5,
            stdout=sp.PIPE,
            stderr=sp.PIPE)

    proc.stdout.readline()
    proc.terminate()
    infos = proc.stderr.read().decode('utf8')
    del proc

    if print_infos:
        # print the whole info text returned by FFMPEG
        print( infos )


    lines = infos.splitlines()
    if "No such file or directory" in lines[-1]:
        raise IOError(("MoviePy error: the file %s could not be found !\n"
                      "Please check that you entered the correct "
                      "path.")%filename)
    
    result = dict()
    

    # get duration (in seconds)
    try:
        keyword = ('frame=' if is_GIF else 'Duration: ')
        line = [l for l in lines if keyword in l][0]
        match = re.search("[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9]", line)
        hms = map(float, line[match.start()+1:match.end()].split(':'))
        result['duration'] = cvsecs(*hms)
    except:
        raise IOError(("MoviePy error: failed to read the duration of file %s.\n"
                       "Here are the file infos returned by ffmpeg:\n\n%s")%(
                          filename, infos))

    # get the output line that speaks about video
    lines_video = [l for l in lines if ' Video: ' in l]
    
    result['video_found'] = ( lines_video != [] )
    
    if result['video_found']:
        
        line = lines_video[0]

        # get the size, of the form 460x320 (w x h)
        match = re.search(" [0-9]*x[0-9]*(,| )", line)
        s = list(map(int, line[match.start():match.end()-1].split('x')))
        result['video_size'] = s


        # get the frame rate. Sometimes it's 'tbr', sometimes 'fps', sometimes
        # tbc, and sometimes tbc/2... Trust tbc first, then tbr, then fps.
        try:
            match = re.search("( [0-9]*.| )[0-9]* tbr", line)
            tbr = float(line[match.start():match.end()].split(' ')[1])

            try:
                match = re.search("( [0-9]*.| )[0-9]* tbc", line)
                tbc = float(line[match.start():match.end()].split(' ')[1])
                if abs(tbr - tbc/2) < abs(tbr-tbc):
                    result['video_fps'] = 1.0*tbc /2
                else:
                    result['video_fps'] = tbc
            except:
                result['video_fps'] = tbr


        except:
            match = re.search("( [0-9]*.| )[0-9]* fps", line)
            result['video_fps'] = float(line[match.start():match.end()].split(' ')[1])


        # It is known that a fps of 24 is often written as 24000/1001
        # but then ffmpeg nicely rounds it to 23.98, which we hate.
        coef = 1000.0/1001.0
        fps = result['video_fps']
        for x in [23,24,25]:
            if (fps!=x) and abs(fps - x*coef) < .01:
                result['video_fps'] = x*coef

        result['video_nframes'] = int(result['duration']*result['video_fps'])+1

        result['video_duration'] = result['duration']
        # We could have also recomputed the duration from the number
        # of frames, as follows:
        # >>> result['video_duration'] = result['video_nframes'] / result['video_fps']


    lines_audio = [l for l in lines if ' Audio: ' in l]
    
    result['audio_found'] = lines_audio != []
    
    if result['audio_found']:
        line = lines_audio[0]
        try:
            match = re.search(" [0-9]* Hz", line)
            result['audio_fps'] = int(line[match.start()+1:match.end()])
        except:
            result['audio_fps'] = 'unknown'

    return result
Пример #29
0
def ffmpeg_parse_infos(filename, print_infos=False):
    """Get file infos using ffmpeg.

    Returns a dictionnary with the fields:
    "video_found", "video_fps", "duration", "video_nframes",
    "video_duration"
    "audio_found", "audio_fps"

    "video_duration" is slightly smaller than "duration" to avoid
    fetching the uncomplete frames at the end, which raises an error.

    """
    

    # open the file in a pipe, provoke an error, read output
    is_GIF = filename.endswith('.gif')
    cmd = [FFMPEG_BINARY, "-i", filename]
    if is_GIF:
        cmd += ["-f", "null", "/dev/null"]
    proc = sp.Popen(cmd,
            bufsize=10**5,
            stdout=sp.PIPE,
            stderr=sp.PIPE)

    proc.stdout.readline()
    proc.terminate()
    infos = proc.stderr.read().decode('utf8')
    del proc

    if print_infos:
        # print the whole info text returned by FFMPEG
        print( infos )


    lines = infos.splitlines()
    if "No such file or directory" in lines[-1]:
        raise IOError("%s not found ! Wrong path ?"%filename)
    
    result = dict()
    

    # get duration (in seconds)
    try:
        keyword = ('frame=' if is_GIF else 'Duration: ')
        line = [l for l in lines if keyword in l][0]
        match = re.search("[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9]", line)
        hms = map(float, line[match.start()+1:match.end()].split(':'))
        result['duration'] = cvsecs(*hms)
    except:
        raise IOError("Error reading duration in file %s,"%(filename)+
                      "Text parsed: %s"%infos)

    # get the output line that speaks about video
    lines_video = [l for l in lines if ' Video: ' in l]
    
    result['video_found'] = ( lines_video != [] )
    
    if result['video_found']:
        
        line = lines_video[0]

        # get the size, of the form 460x320 (w x h)
        match = re.search(" [0-9]*x[0-9]*(,| )", line)
        s = list(map(int, line[match.start():match.end()-1].split('x')))
        result['video_size'] = s


        # get the frame rate
        try:
            match = re.search("( [0-9]*.| )[0-9]* tbr", line)
            result['video_fps'] = float(line[match.start():match.end()].split(' ')[1])
        except:
            match = re.search("( [0-9]*.| )[0-9]* fps", line)
            result['video_fps'] = float(line[match.start():match.end()].split(' ')[1])

        result['video_nframes'] = int(result['duration']*result['video_fps'])+1

        result['video_duration'] = result['duration']
        # We could have also recomputed the duration from the number
        # of frames, as follows:
        # >>> result['video_duration'] = result['video_nframes'] / result['video_fps']


    lines_audio = [l for l in lines if ' Audio: ' in l]
    
    result['audio_found'] = lines_audio != []
    
    if result['audio_found']:
        line = lines_audio[0]
        try:
            match = re.search(" [0-9]* Hz", line)
            result['audio_fps'] = int(line[match.start()+1:match.end()])
        except:
            result['audio_fps'] = 'unknown'

    return result
Пример #30
0
def ffmpeg_parse_infos(filename, print_infos=False):
    """Get file infos using ffmpeg.

    Returns a dictionnary with the fields:
    "video_found", "video_fps", "duration", "video_nframes",
    "video_duration"
    "audio_found", "audio_fps"

    "video_duration" is slightly smaller than "duration" to avoid
    fetching the uncomplete frames at the end, which raises an error.

    """

    # open the file in a pipe, provoke an error, read output
    is_GIF = filename.endswith('.gif')
    cmd = [FFMPEG_BINARY, "-i", filename]
    if is_GIF:
        cmd += ["-f", "null", "/dev/null"]
    proc = sp.Popen(cmd, bufsize=10**5, stdout=sp.PIPE, stderr=sp.PIPE)

    proc.stdout.readline()
    proc.terminate()
    infos = proc.stderr.read().decode('utf8')
    del proc

    if print_infos:
        # print the whole info text returned by FFMPEG
        print(infos)

    lines = infos.splitlines()
    if "No such file or directory" in lines[-1]:
        raise IOError("%s not found ! Wrong path ?" % filename)

    result = dict()

    # get duration (in seconds)
    try:
        keyword = ('frame=' if is_GIF else 'Duration: ')
        line = [l for l in lines if keyword in l][0]
        match = re.search("[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9]", line)
        hms = map(float, line[match.start() + 1:match.end()].split(':'))
        result['duration'] = cvsecs(*hms)
    except:
        raise IOError("Error reading duration in file %s," % (filename) +
                      "Text parsed: %s" % infos)

    # get the output line that speaks about video
    lines_video = [l for l in lines if ' Video: ' in l]

    result['video_found'] = (lines_video != [])

    if result['video_found']:

        line = lines_video[0]

        # get the size, of the form 460x320 (w x h)
        match = re.search(" [0-9]*x[0-9]*(,| )", line)
        s = list(map(int, line[match.start():match.end() - 1].split('x')))
        result['video_size'] = s

        # get the frame rate
        try:
            match = re.search("( [0-9]*.| )[0-9]* tbr", line)
            result['video_fps'] = float(
                line[match.start():match.end()].split(' ')[1])
        except:
            match = re.search("( [0-9]*.| )[0-9]* fps", line)
            result['video_fps'] = float(
                line[match.start():match.end()].split(' ')[1])

        result['video_nframes'] = int(
            result['duration'] * result['video_fps']) + 1

        result['video_duration'] = result['duration']
        # We could have also recomputed the duration from the number
        # of frames, as follows:
        # >>> result['video_duration'] = result['video_nframes'] / result['video_fps']

    lines_audio = [l for l in lines if ' Audio: ' in l]

    result['audio_found'] = lines_audio != []

    if result['audio_found']:
        line = lines_audio[0]
        try:
            match = re.search(" [0-9]* Hz", line)
            result['audio_fps'] = int(line[match.start() + 1:match.end()])
        except:
            result['audio_fps'] = 'unknown'

    return result