From a24b575929b0ccdb706093802f4245eb7659dc16 Mon Sep 17 00:00:00 2001 From: Medinar Date: Sun, 19 Jan 2020 22:36:36 +0100 Subject: [PATCH 1/6] The SIDE_DATA section inside a stream section are ignored --- ffprobe/ffprobe.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ffprobe/ffprobe.py b/ffprobe/ffprobe.py index abc4ad9..04f84e7 100644 --- a/ffprobe/ffprobe.py +++ b/ffprobe/ffprobe.py @@ -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 = [] @@ -47,13 +48,20 @@ def __init__(self, path_to_video): 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 From 646ca3e8a289da93396202f4333b750cbf64b0b3 Mon Sep 17 00:00:00 2001 From: Medinar Date: Sun, 19 Jan 2020 22:58:17 +0100 Subject: [PATCH 2/6] Fix test file to run with pytest -Filename changed to be detected by pytest -Function added to be detected as a test by pytest -Remove link to removed data (50mb) --- tests/ffprobe-test.py | 33 --------------------------------- tests/ffprobe_test.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 33 deletions(-) delete mode 100644 tests/ffprobe-test.py create mode 100644 tests/ffprobe_test.py 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..2d09444 --- /dev/null +++ b/tests/ffprobe_test.py @@ -0,0 +1,32 @@ +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'), +] + +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) From 4881bffe6d96fce8d1f7d21b9a68fa9b02ee20c5 Mon Sep 17 00:00:00 2001 From: Dongwon Kim Date: Mon, 27 Jul 2020 11:40:04 +0900 Subject: [PATCH 3/6] Fixed parsing-error when probing audio files - added checking valid object --- ffprobe/ffprobe.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ffprobe/ffprobe.py b/ffprobe/ffprobe.py index 04f84e7..61caaca 100644 --- a/ffprobe/ffprobe.py +++ b/ffprobe/ffprobe.py @@ -79,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 From 9b40baebf1c12c938f46824db9dae03089d6f687 Mon Sep 17 00:00:00 2001 From: Ruslan Valiyev Date: Sun, 11 Oct 2020 14:42:01 +0200 Subject: [PATCH 4/6] Allow specifying streams (e.g. IPTV) as input --- README.md | 8 ++++++-- ffprobe/ffprobe.py | 16 ++++++++++------ tests/ffprobe_test.py | 26 ++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 8 deletions(-) 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 61caaca..3668b23 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: @@ -105,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)) @@ -204,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 index 2d09444..9078f76 100644 --- a/tests/ffprobe_test.py +++ b/tests/ffprobe_test.py @@ -11,6 +11,12 @@ 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) @@ -30,3 +36,23 @@ def test_video (): 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) From 967d8388fea6694eada56bed090ea45b37fae69d Mon Sep 17 00:00:00 2001 From: XavierTolza Date: Tue, 2 Mar 2021 18:47:44 +0100 Subject: [PATCH 5/6] Update ffprobe.py I sometimes get the following error on my files: `UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 63: invalid start byte` This small change fixes it --- ffprobe/ffprobe.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ffprobe/ffprobe.py b/ffprobe/ffprobe.py index 3668b23..aef1ff6 100644 --- a/ffprobe/ffprobe.py +++ b/ffprobe/ffprobe.py @@ -44,7 +44,7 @@ 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 From 78ed6646ad0bccb7a2a186c6ed3b29a3f24b107d Mon Sep 17 00:00:00 2001 From: Xavier TOLZA Date: Tue, 2 Mar 2021 18:55:11 +0100 Subject: [PATCH 6/6] added one missing ignore --- ffprobe/ffprobe.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ffprobe/ffprobe.py b/ffprobe/ffprobe.py index aef1ff6..f1eb3dc 100644 --- a/ffprobe/ffprobe.py +++ b/ffprobe/ffprobe.py @@ -68,7 +68,7 @@ def __init__(self, path_to_video): 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