diff --git a/README.md b/README.md index 4519225..5578ba6 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,21 @@ ffprobe-python module ===================== -A wrapper around the ffprobe command to extract metadata from media files. +A wrapper around the ffprobe command to extract metadata from media files or streams. -Usage:: +Usage: ```python #!/usr/bin/env python from ffprobe import FFProbe +# Local file metadata=FFProbe('test-media-file.mov') +# Video stream +# metadata=FFProbe('http://some-streaming-url.com:8080/stream') + for stream in metadata.streams: if stream.is_video(): print('Stream contains {} frames.'.format(stream.frames())) diff --git a/ffprobe/ffprobe.py b/ffprobe/ffprobe.py index abc4ad9..f1eb3dc 100644 --- a/ffprobe/ffprobe.py +++ b/ffprobe/ffprobe.py @@ -27,7 +27,7 @@ def __init__(self, path_to_video): except FileNotFoundError: raise IOError('ffprobe not found.') - if os.path.isfile(self.path_to_video): + if os.path.isfile(self.path_to_video) or self.path_to_video.startswith('http'): if platform.system() == 'Windows': cmd = ["ffprobe", "-show_streams", self.path_to_video] else: @@ -36,6 +36,7 @@ def __init__(self, path_to_video): p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) stream = False + ignoreLine = False self.streams = [] self.video = [] self.audio = [] @@ -43,24 +44,31 @@ def __init__(self, path_to_video): self.attachment = [] for line in iter(p.stdout.readline, b''): - line = line.decode('UTF-8') + line = line.decode('UTF-8', 'ignore') if '[STREAM]' in line: stream = True + ignoreLine = False data_lines = [] elif '[/STREAM]' in line and stream: stream = False + ignoreLine = False # noinspection PyUnboundLocalVariable self.streams.append(FFStream(data_lines)) elif stream: - data_lines.append(line) + if '[SIDE_DATA]' in line: + ignoreLine = True + elif '[/SIDE_DATA]' in line: + ignoreLine = False + elif ignoreLine == False: + data_lines.append(line) self.metadata = {} is_metadata = False stream_metadata_met = False for line in iter(p.stderr.readline, b''): - line = line.decode('UTF-8') + line = line.decode('UTF-8', 'ignore') if 'Metadata:' in line and not stream_metadata_met: is_metadata = True @@ -71,8 +79,9 @@ def __init__(self, path_to_video): splits = line.split(',') for s in splits: m = re.search(r'(\w+)\s*:\s*(.*)$', s) - # print(m.groups()) - self.metadata[m.groups()[0]] = m.groups()[1].strip() + if m is not None: + # print(m.groups()) + self.metadata[m.groups()[0]] = m.groups()[1].strip() if '[STREAM]' in line: stream = True @@ -96,7 +105,7 @@ def __init__(self, path_to_video): elif stream.is_attachment(): self.attachment.append(stream) else: - raise IOError('No such media file ' + self.path_to_video) + raise IOError('No such media file or stream is not responding: ' + self.path_to_video) def __repr__(self): return "".format(**vars(self)) @@ -195,10 +204,14 @@ def frames(self): Returns the length of a video stream in frames. Returns 0 if not a video stream. """ if self.is_video() or self.is_audio(): - try: - frame_count = int(self.__dict__.get('nb_frames', '')) - except ValueError: - raise FFProbeError('None integer frame count') + if self.__dict__.get('nb_frames', '') != 'N/A': + try: + frame_count = int(self.__dict__.get('nb_frames', '')) + except ValueError: + raise FFProbeError('None integer frame count') + else: + # When N/A is returned, set frame_count to 0 too + frame_count = 0 else: frame_count = 0 diff --git a/tests/ffprobe-test.py b/tests/ffprobe-test.py deleted file mode 100644 index 4e20ef9..0000000 --- a/tests/ffprobe-test.py +++ /dev/null @@ -1,33 +0,0 @@ -from __future__ import print_function - -import os -from ffprobe3 import FFProbe -from ffprobe3.exceptions import FFProbeError - -test_dir = os.path.dirname(os.path.abspath(__file__)) - -test_videos = [ - os.path.join(test_dir, './data/SampleVideo_720x480_5mb.mp4'), - os.path.join(test_dir, './data/SampleVideo_1280x720_1mb.mp4'), - os.path.join(test_dir, './data/SampleVideo_360x240_50mb.mp4'), - os.path.join(test_dir, './data/SampleVideo_1280x720_50mb.mp4'), -] - -for test_video in test_videos: - media = FFProbe(test_video) - print('File:', test_video) - print('\tStreams:', len(media.streams)) - for index, stream in enumerate(media.streams, 1): - print('\tStream: ', index) - try: - if stream.is_video(): - frame_rate = stream.frames() / stream.duration_seconds() - print('\t\tFrame Rate:', frame_rate) - print('\t\tFrame Size:', stream.frame_size()) - print('\t\tDuration:', stream.duration_seconds()) - print('\t\tFrames:', stream.frames()) - print('\t\tIs video:', stream.is_video()) - except FFProbeError as e: - print(e) - except Exception as e: - print(e) diff --git a/tests/ffprobe_test.py b/tests/ffprobe_test.py new file mode 100644 index 0000000..9078f76 --- /dev/null +++ b/tests/ffprobe_test.py @@ -0,0 +1,58 @@ +from __future__ import print_function + +import os +from ffprobe import FFProbe +from ffprobe.exceptions import FFProbeError + +test_dir = os.path.dirname(os.path.abspath(__file__)) + +test_videos = [ + os.path.join(test_dir, './data/SampleVideo_720x480_5mb.mp4'), + os.path.join(test_dir, './data/SampleVideo_1280x720_1mb.mp4'), +] + +# Taken from https://bitmovin.com/mpeg-dash-hls-examples-sample-streams +test_streams = [ + 'https://bitdash-a.akamaihd.net/content/MI201109210084_1/m3u8s/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.m3u8', + 'https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8' +] + +def test_video (): + for test_video in test_videos: + media = FFProbe(test_video) + print('File:', test_video) + print('\tStreams:', len(media.streams)) + for index, stream in enumerate(media.streams, 1): + print('\tStream: ', index) + try: + if stream.is_video(): + frame_rate = stream.frames() / stream.duration_seconds() + print('\t\tFrame Rate:', frame_rate) + print('\t\tFrame Size:', stream.frame_size()) + print('\t\tDuration:', stream.duration_seconds()) + print('\t\tFrames:', stream.frames()) + print('\t\tIs video:', stream.is_video()) + except FFProbeError as e: + print(e) + except Exception as e: + print(e) + +def test_stream (): + for test_stream in test_streams: + media = FFProbe(test_stream) + print('File:', test_stream) + print('\tStreams:', len(media.streams)) + for index, stream in enumerate(media.streams, 1): + print('\tStream: ', index) + try: + if stream.is_video(): + frame_rate = stream.frames() / stream.duration_seconds() + print('\t\tFrame Rate:', frame_rate) + print('\t\tFrame Size:', stream.frame_size()) + print('\t\tDuration:', stream.duration_seconds()) + print('\t\tFrames:', stream.frames()) + print('\t\tIs video:', stream.is_video()) + except FFProbeError as e: + print(e) + except Exception as e: + print(e)