diff --git a/ffprobe/ffprobe.py b/ffprobe/ffprobe.py index 9ed80d7..750e429 100644 --- a/ffprobe/ffprobe.py +++ b/ffprobe/ffprobe.py @@ -5,209 +5,248 @@ """ +version = '0.1' -version='0.1' - -import subprocess import re +import subprocess import sys import os import pipes +import platform + class FFProbe: - """ - FFProbe wraps the ffprobe command and pulls the data into an object form:: - metadata=FFProbe('multimedia-file.mov') - """ - def __init__(self,video_file): - self.video_file=video_file - try: - with open(os.devnull, 'w') as tempf: - subprocess.check_call(["ffprobe","-h"],stdout=tempf,stderr=tempf) - except: - raise IOError('ffprobe not found.') - if os.path.isfile(video_file): - if str(platform.system())=='Windows': - cmd=["ffprobe","-show_streams",self.video_file] - else: - cmd=["ffprobe -show_streams "+pipes.quote(self.video_file)] - - p = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True) - self.format=None - self.created=None - self.duration=None - self.start=None - self.bitrate=None - self.streams=[] - self.video=[] - self.audio=[] - datalines=[] - for a in iter(p.stdout.readline, b''): - if re.match('\[STREAM\]',a): - datalines=[] - elif re.match('\[\/STREAM\]',a): - self.streams.append(FFStream(datalines)) - datalines=[] - else: - datalines.append(a) - for a in iter(p.stderr.readline, b''): - if re.match('\[STREAM\]',a): - datalines=[] - elif re.match('\[\/STREAM\]',a): - self.streams.append(FFStream(datalines)) - datalines=[] - else: - datalines.append(a) - p.stdout.close() - p.stderr.close() - for a in self.streams: - if a.isAudio(): - self.audio.append(a) - if a.isVideo(): - self.video.append(a) - else: - raise IOError('No such media file '+video_file) + """ + FFProbe wraps the ffprobe command and pulls the data into an object form:: + metadata=FFProbe('multimedia-file.mov') + """ + + def __init__(self, video_file): + self.video_file = video_file + try: + with open(os.devnull, 'w') as tempf: + subprocess.check_call( + ["ffprobe", "-h"], stdout=tempf, stderr=tempf) + except: + raise IOError('ffprobe not found.') + if os.path.isfile(video_file): + if str(platform.system()) == 'Windows': + cmd = ["ffprobe", "-show_streams", self.video_file] + else: + cmd = ["ffprobe -show_streams " + pipes.quote(self.video_file)] + + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, + stderr=subprocess.PIPE, shell=True) + self.format = None + self.created = None + self.duration = None + self.start = None + self.bitrate = None + self.streams = [] + self.video = [] + self.audio = [] + datalines = [] + for a in iter(p.stdout.readline, b''): + if re.match('\[STREAM\]', a): + datalines = [] + elif re.match('\[\/STREAM\]', a): + self.streams.append(FFStream(datalines)) + datalines = [] + else: + datalines.append(a) + for a in iter(p.stderr.readline, b''): + if re.match('\[STREAM\]', a): + datalines = [] + elif re.match('\[\/STREAM\]', a): + self.streams.append(FFStream(datalines)) + datalines = [] + else: + datalines.append(a) + p.stdout.close() + p.stderr.close() + for a in self.streams: + if a.isAudio(): + self.audio.append(a) + if a.isVideo(): + self.video.append(a) + else: + raise IOError('No such media file ' + video_file) class FFStream: - """ - An object representation of an individual stream in a multimedia file. - """ - def __init__(self,datalines): - for a in datalines: - (key,val)=a.strip().split('=') - self.__dict__[key]=val - - def isAudio(self): - """ - Is this stream labelled as an audio stream? - """ - val=False - if self.__dict__['codec_type']: - if str(self.__dict__['codec_type']) == 'audio': - val=True - return val - - def isVideo(self): - """ - Is the stream labelled as a video stream. - """ - val=False - if self.__dict__['codec_type']: - if self.codec_type == 'video': - val=True - return val - - def isSubtitle(self): - """ - Is the stream labelled as a subtitle stream. - """ - val=False - if self.__dict__['codec_type']: - if str(self.codec_type)=='subtitle': - val=True - return val - - def frameSize(self): - """ - Returns the pixel frame size as an integer tuple (width,height) if the stream is a video stream. - Returns None if it is not a video stream. - """ - size=None - if self.isVideo(): - if self.__dict__['width'] and self.__dict__['height']: - try: - size=(int(self.__dict__['width']),int(self.__dict__['height'])) - except Exception as e: - print "None integer size %s:%s" %(str(self.__dict__['width']),str(+self.__dict__['height'])) - size=(0,0) - return size - - def pixelFormat(self): - """ - Returns a string representing the pixel format of the video stream. e.g. yuv420p. - Returns none is it is not a video stream. - """ - f=None - if self.isVideo(): - if self.__dict__['pix_fmt']: - f=self.__dict__['pix_fmt'] - return f - - def frames(self): - """ - Returns the length of a video stream in frames. Returns 0 if not a video stream. - """ - f=0 - if self.isVideo() or self.isAudio(): - if self.__dict__['nb_frames']: - try: - f=int(self.__dict__['nb_frames']) - except Exception as e: - print "None integer frame count" - return f - - def durationSeconds(self): - """ - Returns the runtime duration of the video stream as a floating point number of seconds. - Returns 0.0 if not a video stream. - """ - f=0.0 - if self.isVideo() or self.isAudio(): - if self.__dict__['duration']: - try: - f=float(self.__dict__['duration']) - except Exception as e: - print "None numeric duration" - return f - - def language(self): - """ - Returns language tag of stream. e.g. eng - """ - lang=None - if self.__dict__['TAG:language']: - lang=self.__dict__['TAG:language'] - return lang - - def codec(self): - """ - Returns a string representation of the stream codec. - """ - codec_name=None - if self.__dict__['codec_name']: - codec_name=self.__dict__['codec_name'] - return codec_name - - def codecDescription(self): - """ - Returns a long representation of the stream codec. - """ - codec_d=None - if self.__dict__['codec_long_name']: - codec_d=self.__dict__['codec_long_name'] - return codec_d - - def codecTag(self): - """ - Returns a short representative tag of the stream codec. - """ - codec_t=None - if self.__dict__['codec_tag_string']: - codec_t=self.__dict__['codec_tag_string'] - return codec_t - - def bitrate(self): - """ - Returns bitrate as an integer in bps - """ - b=0 - if self.__dict__['bit_rate']: - try: - b=int(self.__dict__['bit_rate']) - except Exception as e: - print "None integer bitrate" - return b - + """ + An object representation of an individual stream in a multimedia file. + """ + + def __init__(self, datalines): + self.side_data = [] + reading_side_data = False + for a in datalines: + if re.match('\[SIDE_DATA\]', a): + datalines = [] + reading_side_data = True + elif re.match('\[\/SIDE_DATA\]', a): + self.side_data.append(FFStreamSideData(datalines)) + datalines = [] + reading_side_data = False + else: + if reading_side_data: + datalines.append(a) + else: + (key, val) = a.strip().split('=') + self.__dict__[key] = val + + def isAudio(self): + """ + Is this stream labelled as an audio stream? + """ + val = False + if self.__dict__['codec_type']: + if str(self.__dict__['codec_type']) == 'audio': + val = True + return val + + def isVideo(self): + """ + Is the stream labelled as a video stream. + """ + val = False + if self.__dict__['codec_type']: + if self.codec_type == 'video': + val = True + return val + + def isSubtitle(self): + """ + Is the stream labelled as a subtitle stream. + """ + val = False + if self.__dict__['codec_type']: + if str(self.codec_type) == 'subtitle': + val = True + return val + + def frameSize(self): + """ + Returns the pixel frame size as an integer tuple (width,height) if the stream is a video stream. + Returns None if it is not a video stream. + """ + size = None + if self.isVideo(): + if self.__dict__['width'] and self.__dict__['height']: + try: + size = (int(self.__dict__['width']), int( + self.__dict__['height'])) + except Exception as e: + print "None integer size %s:%s" % (str(self.__dict__['width']), str(+self.__dict__['height'])) + size = (0, 0) + return size + + def pixelFormat(self): + """ + Returns a string representing the pixel format of the video stream. e.g. yuv420p. + Returns none is it is not a video stream. + """ + f = None + if self.isVideo(): + if self.__dict__['pix_fmt']: + f = self.__dict__['pix_fmt'] + return f + + def frames(self): + """ + Returns the length of a video stream in frames. Returns 0 if not a video stream. + """ + f = 0 + if self.isVideo() or self.isAudio(): + if self.__dict__['nb_frames']: + try: + f = int(self.__dict__['nb_frames']) + except Exception as e: + print "None integer frame count" + return f + + def durationSeconds(self): + """ + Returns the runtime duration of the video stream as a floating point number of seconds. + Returns 0.0 if not a video stream. + """ + f = 0.0 + if self.isVideo() or self.isAudio(): + if self.__dict__['duration']: + try: + f = float(self.__dict__['duration']) + except Exception as e: + print "None numeric duration" + return f + + def language(self): + """ + Returns language tag of stream. e.g. eng + """ + lang = None + if self.__dict__['TAG:language']: + lang = self.__dict__['TAG:language'] + return lang + + def codec(self): + """ + Returns a string representation of the stream codec. + """ + codec_name = None + if self.__dict__['codec_name']: + codec_name = self.__dict__['codec_name'] + return codec_name + + def codecDescription(self): + """ + Returns a long representation of the stream codec. + """ + codec_d = None + if self.__dict__['codec_long_name']: + codec_d = self.__dict__['codec_long_name'] + return codec_d + + def codecTag(self): + """ + Returns a short representative tag of the stream codec. + """ + codec_t = None + if self.__dict__['codec_tag_string']: + codec_t = self.__dict__['codec_tag_string'] + return codec_t + + def bitrate(self): + """ + Returns bitrate as an integer in bps + """ + b = 0 + if self.__dict__['bit_rate']: + try: + b = int(self.__dict__['bit_rate']) + except Exception as e: + print "None integer bitrate" + return b + + +class FFStreamSideData(object): + """ + An object representation of a stream's side data. + """ + + def __init__(self, datalines): + reading_displaymatrix = False + datalines = filter(lambda s: s != '\n', datalines) + for a in datalines: + if reading_displaymatrix and re.match('[0-9]+: ', a): + self.displaymatrix.append(map(int, a.split(':')[1].split())) + elif re.match('displaymatrix=', a): + reading_displaymatrix = True + self.displaymatrix = [] + else: + (key, val) = a.strip().split('=') + self.__dict__[key] = val + + if __name__ == '__main__': - print "Module ffprobe" + print "Module ffprobe"