在 Python 3.10 中使用 ffprobe 有困难

Difficulty with ffprobe in Python 3.10

我很新

所以这个 getLength 函数 运行 在 python 2.7 中可以正常工作,但我无法在 3.10 中使用它。想知道是否有人可以建议可能需要更改的内容,因为我不知所措。当我尝试打印 return 时,那里什么也没有。我 95% 确定问题出在 result = subprocess.Popen() 行,但为了完整起见,我包含了整个函数

#function...returns 视频文件的时长HH:MM:SS

def getLength(filename):

   #uses ffprobe to get info about the video file

   result = subprocess.Popen(["ffprobe", filename],

   stdout = subprocess.PIPE, stderr = subprocess.STDOUT)


   #finds the info that has the word "Duration"

   y = [x for x in result.stdout.readlines() if "Duration: " in x]

   #get the location of the "Duration: " phrase

   loc = y[0].find("Duration: ")

   #assuming we find the location of that phrase..

   if loc != -1:

   #cut out everything before and everything more than 10 characters later

   print ( y[0][loc+10:loc+18] )

   return y[0][loc+10:loc+18]

   else:

   #if we don't find anything then set it to be 2 seconds of nothing...

   print ( y[0][loc+10:loc+18] )

   return '00:00:02' 

我很确定 python3 中的输出是字节流而不是字符串。
试试这个:

import subprocess
media = "/home/rolf/BBB.ogv"
try:
    comm = subprocess.Popen(['ffprobe', '-hide_banner', '-show_entries', 'format=size, duration',\
                       '-i', media], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True)
except Exception as e:
    pass
try:
    with comm.stdout:
        for i in iter(comm.stdout.readline, b''):
            if i != '':
                print(i)
            else:
                break
except Exception as e:
    print("Error: ", str(e))

输出:

python probe.py
Input #0, ogg, from '/home/rolf/BBB.ogv':

  Duration: 00:01:00.14, start: 0.000000, bitrate: 264 kb/s

  Stream #0:0(eng): Video: theora, yuv420p, 640x360 [SAR 1:1 DAR 16:9], 24 fps, 24.04 tbr, 24.04 tbn

    Metadata:

      creation_time   : 2011-03-16 10:41:52

      handler_name    : Apple Video Media Handler

      encoder         : Lavc56.60.100 libtheora

      major_brand     : mp42

      minor_version   : 1

      compatible_brands: mp42avc1

  Stream #0:1(eng): Audio: vorbis, 44100 Hz, mono, fltp, 80 kb/s

    Metadata:

      creation_time   : 2011-03-16 10:41:53

      handler_name    : Apple Sound Media Handler

      encoder         : Lavc56.60.100 libvorbis

      major_brand     : mp42

      minor_version   : 1

      compatible_brands: mp42avc1

[FORMAT]

duration=60.139683

size=1992112

[/FORMAT]
    

如果您同意以秒为单位的持续时间(不是 HH:MM:SS 表示法),我更喜欢使用 -of json 选项,这样我就可以使用 json 包来解析ffprobe 输出:

import subprocess as sp
import json
from pprint import pprint

out = sp.run(['ffprobe','-hide_banner','-of','json',
                        '-show_entries','format:stream', f'"{filename}"'], 
             stdout=sp.PIPE, universal_newlines=True)
results = json.loads(out.stdout)

pprint(results) # to see the full details

format_duration = float(results['formats']['duration']) # in seconds
stream_durations = [float(st['duration']) for st in results['streams']] # in seconds

注意:您必须指定 -show_entries 选项,否则它将 return 为空 JSON

只是为了插入我的图书馆(pip install fmpegio-core),你可以交替运行:

import ffmpegio

file_duration = ffmpegio.probe.format_basic(filename)['duration']

在Python中3个字符串在Unicode format中,stdout输出是字节数组。

我们可以使用 x.decode("utf-8"):

将字节数组转换为字符串

解析列表可能如下所示:

y = [x.decode("utf-8") for x in result.stdout.readlines() if "Duration: " in x.decode("utf-8")]

完整代码示例(使用 stderr 而不是 stdout):

import subprocess

def get_length(filename):
    # Uses FFprobe to get info about the video file
    result = subprocess.Popen(["ffprobe", filename], stderr=subprocess.PIPE)

    # Finds the info that has the word "Duration"
    # Convert bytes array to strings using decode("utf-8")
    y = [x.decode("utf-8") for x in result.stderr.readlines() if "Duration: " in x.decode("utf-8")]

    # Get the location of the "Duration: " phrase
    loc = y[0].find("Duration: ")

    # Assuming we find the location of that phrase..
    if loc != -1:
        # Cut out everything before and everything more than 10 characters later
        print(y[0][loc+10:loc+18])
        return y[0][loc+10:loc+18]
    else:
        # If we don't find anything then set it to be 2 seconds of nothing...
        print(y[0][loc+10:loc+18])
        return '00:00:02' 


res = get_length('BBB.ogv')
print(res)

为了获取 OVG(或 MP4)文件的视频持续时间,我们可以 select JSON 格式:

import subprocess as sp
import json

# https://superuser.com/questions/650291/how-to-get-video-duration-in-seconds
data = sp.run(["ffprobe", '-v', 'error', '-select_streams', 'v', '-of', 'default=noprint_wrappers=1:nokey=1', '-show_entries', 'stream=duration', '-of', 'json', 'BBB.ogv'], stdout=sp.PIPE).stdout

dict = json.loads(data)

print(dict['streams'][0]['duration'])