From e5211a44c0e93aad1d2527ed75cd77b6aedfed7f Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Thu, 11 Oct 2018 09:02:38 +0100 Subject: [PATCH 001/277] Issue #16: added a Python script stub for checking multi-threading reliability --- .../multithreading_reliability_check.py | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100755 src/tests/pipeline/multithreading_reliability_check.py diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py new file mode 100755 index 00000000..c6729066 --- /dev/null +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from pygiftgrab import (VideoSourceFactory, + ColourSpace, + IObservableObserver) + +""" +This script provides a multi-threading reliability check. +The background is issue #16. It looks like in applications +where multiple Python threads are involved, occasionally +the acquisition of the Global Interpreter Lock leads to a +deadlocks, which crashes the whole application with a +non-specific segmentation fault. + +In this script we run a number of multi-threaded GIFT-Grab +pipelines, which should serve as a validation that this +problem is fixed. +""" + +if __name__ == '__main__': + print('multithreading reliability check script') From 30d63ee4b3a5c05966aea868784450269f886cc7 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Thu, 11 Oct 2018 09:03:41 +0100 Subject: [PATCH 002/277] Issue #16: added a Bash script for building GIFT-Grab and subsequently running the multi-threading reliability check script --- .gitignore | 1 + .../check_multithreading_reliability.sh | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100755 src/tests/pipeline/check_multithreading_reliability.sh diff --git a/.gitignore b/.gitignore index 08b31459..d7eb0905 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ src/build src/dist src/*.egg-info *.swp +src/tests/pipeline/mtr-build diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh new file mode 100755 index 00000000..b974bfa8 --- /dev/null +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +# -*- coding: utf-8 -*- + +# Build a basic GIFT-Grab capable of reading a video file, +# and encoding to a video file in real time, with Python +# and NumPy support. Subsequently run the multi-threading +# reliability check script. + +CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" +BUILD_DIR=$CURRENT_DIR/mtr-build +SOURCE_DIR="$( cd "$CURRENT_DIR/../.." >/dev/null && pwd )" +CMAKE_OPTS="-D USE_FILES=ON" +CMAKE_OPTS="$CMAKE_OPTS -D USE_HEVC=ON" +CMAKE_OPTS="$CMAKE_OPTS -D ENABLE_NONFREE=ON -D USE_NVENC=ON" +CMAKE_OPTS="$CMAKE_OPTS -D BUILD_PYTHON=ON -D USE_NUMPY=ON" +MTR_SCRIPT=$CURRENT_DIR/multithreading_reliability_check.py + +mkdir -p $BUILD_DIR +rm -rf $BUILD_DIR/* +cd $BUILD_DIR +cmake $CMAKE_OPTS $SOURCE_DIR +make -j4 +PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT From d40566a6eb418212720c041dc09763e1dff6c020 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 08:06:21 +0100 Subject: [PATCH 003/277] Issue #16: added a 'Dyer' processing node to multi-threading reliability checker --- .../pipeline/multithreading_reliability_check.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index c6729066..7aa1fc0d 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -18,5 +18,20 @@ problem is fixed. """ + +class Dyer(IObservableObserver): + + def __init__(self, channel, value): + super(Dyer, self).__init__() + assert 0 <= channel < 3 + assert 0 <= value < 256 + self.channel = channel + self.value = value + + def update(self, frame): + data = frame.data(True) + data[:, :, self.channel] = self.value + + if __name__ == '__main__': print('multithreading reliability check script') From 974a5f81ff2cd7b64db08b428c82cb7e44ec7860 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 08:28:08 +0100 Subject: [PATCH 004/277] Issue #16: Python script now uses CLI argument for input file --- .../pipeline/check_multithreading_reliability.sh | 2 +- .../pipeline/multithreading_reliability_check.py | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index b974bfa8..efae4d95 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -20,4 +20,4 @@ rm -rf $BUILD_DIR/* cd $BUILD_DIR cmake $CMAKE_OPTS $SOURCE_DIR make -j4 -PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT +PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT --input $1 diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 7aa1fc0d..02982cf7 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -1,6 +1,8 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +import argparse +import os.path from pygiftgrab import (VideoSourceFactory, ColourSpace, IObservableObserver) @@ -34,4 +36,14 @@ def update(self, frame): if __name__ == '__main__': - print('multithreading reliability check script') + parser = argparse.ArgumentParser() + parser.add_argument('-i', '--input', type=str, required=True, + metavar='VIDEO_FILE', + help='Input video file (HEVC-encoded MP4)') + args = parser.parse_args() + in_file = args.input + + filename = os.path.basename(in_file) + filename, ext = os.path.splitext(filename) + assert filename + assert ext == '.mp4' From 88f76a12839c100a138597b54801237b3ff367a3 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 08:32:30 +0100 Subject: [PATCH 005/277] Issue #16: added multi-node pipeline producing red- and yellow-dyed output --- .../multithreading_reliability_check.py | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 02982cf7..01c4ead3 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -1,11 +1,12 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +from time import sleep import argparse import os.path from pygiftgrab import (VideoSourceFactory, - ColourSpace, - IObservableObserver) + ColourSpace, IObservableObserver, + VideoTargetFactory, Codec) """ This script provides a multi-threading reliability check. @@ -47,3 +48,29 @@ def update(self, frame): filename, ext = os.path.splitext(filename) assert filename assert ext == '.mp4' + + sfac = VideoSourceFactory.get_instance() + reader = sfac.create_file_reader(in_file, ColourSpace.BGRA) + + tfac = VideoTargetFactory.get_instance() + frame_rate = reader.get_frame_rate() + + red = Dyer(2, 127) + green = Dyer(1, 191) + + red_file = os.path.join('.', ''.join([filename, '-red', ext])) + red_writer = tfac.create_file_writer(Codec.HEVC, red_file, frame_rate) + yellow_file = os.path.join('.', ''.join([filename, '-yellow', ext])) + yellow_writer = tfac.create_file_writer(Codec.HEVC, yellow_file, frame_rate) + + reader.attach(red) + red.attach(red_writer) + red.attach(green) + green.attach(yellow_writer) + + sleep(20) # operate pipeline for 20 sec + + reader.detach(red) + red.detach(red_writer) + red.detach(green) + green.detach(yellow_writer) From bc4eda524d42853c967b87457b8c96337e30d859 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 09:09:08 +0100 Subject: [PATCH 006/277] Issue #16: added a threaded Histogrammer class stub --- .../multithreading_reliability_check.py | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 01c4ead3..c1ba3b48 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -4,6 +4,7 @@ from time import sleep import argparse import os.path +import threading from pygiftgrab import (VideoSourceFactory, ColourSpace, IObservableObserver, VideoTargetFactory, Codec) @@ -22,6 +23,30 @@ """ +buffer = None +lock = threading.Lock() + + +class Histogrammer(threading.Thread, IObservableObserver): + + def __init__(self, channel): + super(Histogrammer, self).__init__() + assert 0 <= channel < 3 + self.channel = channel + self.running = False + + def run(self): + if self.running: + return + + pass + + def stop(self): + self.running = False + + def update(self, frame): + pass + class Dyer(IObservableObserver): def __init__(self, channel, value): @@ -57,6 +82,8 @@ def update(self, frame): red = Dyer(2, 127) green = Dyer(1, 191) + hist = Histogrammer(0) + hist.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) red_writer = tfac.create_file_writer(Codec.HEVC, red_file, frame_rate) @@ -69,6 +96,7 @@ def update(self, frame): green.attach(yellow_writer) sleep(20) # operate pipeline for 20 sec + hist.stop() reader.detach(red) red.detach(red_writer) From 178bfbdcd116b84e0e61e218e2e6c9efc040eff2 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 09:12:38 +0100 Subject: [PATCH 007/277] Issue #16: added dummy print statement to see Histogrammer is alive --- src/tests/pipeline/multithreading_reliability_check.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index c1ba3b48..4dd459a1 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -40,6 +40,10 @@ def run(self): return pass + self.running = True + while self.running: + print('Running') + sleep(0.100) def stop(self): self.running = False From b1f5865d0419eca5302c7cd1ae7e0e93a71ec21b Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 09:57:57 +0100 Subject: [PATCH 008/277] Issue #16: factored Histogrammer stub out to HistogrammerRed and BuffererRed --- .../multithreading_reliability_check.py | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 4dd459a1..12a467bb 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -23,33 +23,40 @@ """ -buffer = None +buffer_red = None lock = threading.Lock() -class Histogrammer(threading.Thread, IObservableObserver): +class BuffererRed(IObservableObserver): - def __init__(self, channel): - super(Histogrammer, self).__init__() - assert 0 <= channel < 3 - self.channel = channel + def __init__(self): + super(BuffererRed, self).__init__() + + def update(self, frame): + global buffer_red + # TODO + + +class HistogrammerRed(threading.Thread): + + def __init__(self): + super(HistogrammerRed, self).__init__() self.running = False def run(self): if self.running: return - pass + # TODO self.running = True while self.running: print('Running') + # TODO sleep(0.100) def stop(self): self.running = False - def update(self, frame): - pass class Dyer(IObservableObserver): @@ -86,7 +93,7 @@ def update(self, frame): red = Dyer(2, 127) green = Dyer(1, 191) - hist = Histogrammer(0) + hist = HistogrammerRed() hist.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) From efcff6293bca733d5609f4d7ce1eda1da407fedd Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 09:59:41 +0100 Subject: [PATCH 009/277] Issue #16: implemented update of BuffererRed --- src/tests/pipeline/multithreading_reliability_check.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 12a467bb..aa8eb0dd 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -5,6 +5,7 @@ import argparse import os.path import threading +import numpy as np from pygiftgrab import (VideoSourceFactory, ColourSpace, IObservableObserver, VideoTargetFactory, Codec) @@ -34,7 +35,12 @@ def __init__(self): def update(self, frame): global buffer_red - # TODO + with lock: + data = frame.data(True) + if buffer_red is None: + buffer_red = np.copy(data) + else: + buffer_red[:, :, :] = data[:, :, :] class HistogrammerRed(threading.Thread): From 6e639edaa3bb7fd380376c0fb076a7c3ce91dc08 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 10:06:55 +0100 Subject: [PATCH 010/277] Issue #16: implemented run of HistogrammerRed --- src/tests/pipeline/multithreading_reliability_check.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index aa8eb0dd..54ceb230 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -53,11 +53,15 @@ def run(self): if self.running: return - # TODO + global buffer_red + histogram = None self.running = True while self.running: - print('Running') - # TODO + with lock: + if buffer_red is not None: + histogram = np.histogram(buffer_red[:, :, 2], + bins=8, range=(0, 256)) + print(histogram) sleep(0.100) def stop(self): From 963bfc0b3fed82d858d37686f514cdd1e8d556c3 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 10:11:05 +0100 Subject: [PATCH 011/277] Issue #16: renamed Dyer vars for clarity --- .../multithreading_reliability_check.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 54ceb230..ff1fda67 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -101,8 +101,8 @@ def update(self, frame): tfac = VideoTargetFactory.get_instance() frame_rate = reader.get_frame_rate() - red = Dyer(2, 127) - green = Dyer(1, 191) + red_dyer = Dyer(2, 127) + green_dyer = Dyer(1, 191) hist = HistogrammerRed() hist.start() @@ -111,15 +111,15 @@ def update(self, frame): yellow_file = os.path.join('.', ''.join([filename, '-yellow', ext])) yellow_writer = tfac.create_file_writer(Codec.HEVC, yellow_file, frame_rate) - reader.attach(red) - red.attach(red_writer) - red.attach(green) - green.attach(yellow_writer) + reader.attach(red_dyer) + red_dyer.attach(red_writer) + red_dyer.attach(green_dyer) + green_dyer.attach(yellow_writer) sleep(20) # operate pipeline for 20 sec hist.stop() - reader.detach(red) - red.detach(red_writer) - red.detach(green) - green.detach(yellow_writer) + reader.detach(red_dyer) + red_dyer.detach(red_writer) + red_dyer.detach(green_dyer) + green_dyer.detach(yellow_writer) From f7988744d96ef17b1d290dbdf49ce4079790ac7d Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 10:19:12 +0100 Subject: [PATCH 012/277] Issue #16: Dyer.update uses lock --- src/tests/pipeline/multithreading_reliability_check.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index ff1fda67..ee40fea7 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -78,8 +78,9 @@ def __init__(self, channel, value): self.value = value def update(self, frame): - data = frame.data(True) - data[:, :, self.channel] = self.value + with lock: + data = frame.data(True) + data[:, :, self.channel] = self.value if __name__ == '__main__': From 87660df5a1e43f6272f678357bee12d57225e076 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 10:20:32 +0100 Subject: [PATCH 013/277] Issue #16: inserted a red bufferer into the pipeline --- src/tests/pipeline/multithreading_reliability_check.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index ee40fea7..dd0f0dcf 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -104,6 +104,9 @@ def update(self, frame): red_dyer = Dyer(2, 127) green_dyer = Dyer(1, 191) + + bufferer_red = BuffererRed() + hist = HistogrammerRed() hist.start() @@ -114,6 +117,7 @@ def update(self, frame): reader.attach(red_dyer) red_dyer.attach(red_writer) + red_dyer.attach(bufferer_red) red_dyer.attach(green_dyer) green_dyer.attach(yellow_writer) @@ -122,5 +126,6 @@ def update(self, frame): reader.detach(red_dyer) red_dyer.detach(red_writer) + red_dyer.detach(bufferer_red) red_dyer.detach(green_dyer) green_dyer.detach(yellow_writer) From 0512cc2963a64b6422d730b315a1a8b3699c35d2 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 10:22:03 +0100 Subject: [PATCH 014/277] Issue #16: fixed call to histogram function --- src/tests/pipeline/multithreading_reliability_check.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index dd0f0dcf..0987129b 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -59,8 +59,9 @@ def run(self): while self.running: with lock: if buffer_red is not None: - histogram = np.histogram(buffer_red[:, :, 2], - bins=8, range=(0, 256)) + histogram, _ = np.histogram( + buffer_red[:, :, 2], bins=8, range=(0, 256) + ) print(histogram) sleep(0.100) From 5de7d2ccce9fd3fa56d825de305710b2f9aa41f6 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 10:32:24 +0100 Subject: [PATCH 015/277] Issue #16: Dyer now really dyes instead of fixing color to a value --- src/tests/pipeline/multithreading_reliability_check.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 0987129b..54802904 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -71,17 +71,18 @@ def stop(self): class Dyer(IObservableObserver): - def __init__(self, channel, value): + def __init__(self, channel, increment): super(Dyer, self).__init__() assert 0 <= channel < 3 - assert 0 <= value < 256 + assert 0 <= increment < 256 self.channel = channel - self.value = value + self.increment = increment def update(self, frame): with lock: data = frame.data(True) - data[:, :, self.channel] = self.value + channel_data = data[:, :, self.channel] + channel_data[channel_data < 255 - self.increment] += self.increment if __name__ == '__main__': From 9416804cd28a21b523c7544d04a90a8f5bef950c Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 10:53:49 +0100 Subject: [PATCH 016/277] Issue #16: histogrammer now displays a redness score instead of histogram --- .../pipeline/multithreading_reliability_check.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 54802904..d8bf97ed 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -54,15 +54,21 @@ def run(self): return global buffer_red - histogram = None + histogram, num_bins = None, 10 + redness_scale = np.array([i for i in range(1, num_bins + 1)], np.float) self.running = True while self.running: with lock: if buffer_red is not None: histogram, _ = np.histogram( - buffer_red[:, :, 2], bins=8, range=(0, 256) + buffer_red[:, :, 2], bins=num_bins, range=(0, 256) ) - print(histogram) + if histogram is not None: + redness = np.sum(histogram * redness_scale) + redness /= np.sum(histogram) + redness /= num_bins + redness *= 100 + print('Redness: {} %'.format(int(round(redness)))) sleep(0.100) def stop(self): From 81929f74abc49ab4197037a11cf91d604716658d Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 10:54:11 +0100 Subject: [PATCH 017/277] Issue #16: using more sensible values for dyeing --- src/tests/pipeline/multithreading_reliability_check.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index d8bf97ed..a024030b 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -110,8 +110,8 @@ def update(self, frame): tfac = VideoTargetFactory.get_instance() frame_rate = reader.get_frame_rate() - red_dyer = Dyer(2, 127) - green_dyer = Dyer(1, 191) + red_dyer = Dyer(2, 64) + green_dyer = Dyer(1, 64) bufferer_red = BuffererRed() From 053f499ae6554460df9a755067e1ff5ec817a247 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 10:59:42 +0100 Subject: [PATCH 018/277] Issue #16: added a BuffererOrig class, a virtual replica of BuffererRed --- .../multithreading_reliability_check.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index a024030b..7b497725 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -24,7 +24,7 @@ """ -buffer_red = None +buffer_red, buffer_orig = None, None lock = threading.Lock() @@ -43,6 +43,21 @@ def update(self, frame): buffer_red[:, :, :] = data[:, :, :] +class BuffererOrig(IObservableObserver): + + def __init__(self): + super(BuffererOrig, self).__init__() + + def update(self, frame): + global buffer_orig + with lock: + data = frame.data(True) + if buffer_orig is None: + buffer_orig = np.copy(data) + else: + buffer_red[:, :, :] = data[:, :, :] + + class HistogrammerRed(threading.Thread): def __init__(self): From 90de48b6c4bc3f06750598427aed8e00c9184bf1 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:03:50 +0100 Subject: [PATCH 019/277] Issue #16: BuffererRed now takes buffer as parameter to constructor instead of using global var --- .../multithreading_reliability_check.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 7b497725..0ca024bc 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -6,7 +6,7 @@ import os.path import threading import numpy as np -from pygiftgrab import (VideoSourceFactory, +from pygiftgrab import (VideoSourceFactory, VideoFrame, ColourSpace, IObservableObserver, VideoTargetFactory, Codec) @@ -30,17 +30,14 @@ class BuffererRed(IObservableObserver): - def __init__(self): + def __init__(self, buffer): super(BuffererRed, self).__init__() + self.buffer = buffer def update(self, frame): - global buffer_red with lock: data = frame.data(True) - if buffer_red is None: - buffer_red = np.copy(data) - else: - buffer_red[:, :, :] = data[:, :, :] + self.buffer[:, :, :] = data[:, :, :] class BuffererOrig(IObservableObserver): @@ -121,6 +118,9 @@ def update(self, frame): sfac = VideoSourceFactory.get_instance() reader = sfac.create_file_reader(in_file, ColourSpace.BGRA) + frame = VideoFrame(ColourSpace.BGRA, False) + reader.get_frame(frame) + frame_shape = (frame.rows(), frame.cols(), 4) tfac = VideoTargetFactory.get_instance() frame_rate = reader.get_frame_rate() @@ -128,7 +128,8 @@ def update(self, frame): red_dyer = Dyer(2, 64) green_dyer = Dyer(1, 64) - bufferer_red = BuffererRed() + buffer_red = np.zeros(frame_shape, np.uint8) + bufferer_red = BuffererRed(buffer_red) hist = HistogrammerRed() hist.start() From 97f8d27931fac817888405fdbad6c6d96f97fb3c Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:10:43 +0100 Subject: [PATCH 020/277] Revert "Issue #16: added a BuffererOrig class, a virtual replica of BuffererRed" This reverts commit 053f499ae6554460df9a755067e1ff5ec817a247. --- .../multithreading_reliability_check.py | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 0ca024bc..8aed9c85 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -24,7 +24,7 @@ """ -buffer_red, buffer_orig = None, None +buffer_red = None lock = threading.Lock() @@ -40,21 +40,6 @@ def update(self, frame): self.buffer[:, :, :] = data[:, :, :] -class BuffererOrig(IObservableObserver): - - def __init__(self): - super(BuffererOrig, self).__init__() - - def update(self, frame): - global buffer_orig - with lock: - data = frame.data(True) - if buffer_orig is None: - buffer_orig = np.copy(data) - else: - buffer_red[:, :, :] = data[:, :, :] - - class HistogrammerRed(threading.Thread): def __init__(self): From 97e9e65ff42958005dd069c4db9ecbf84cd755a1 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:12:15 +0100 Subject: [PATCH 021/277] Issue #16: renamed BuffererRed => Bufferer --- src/tests/pipeline/multithreading_reliability_check.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 8aed9c85..a345dfd6 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -28,10 +28,10 @@ lock = threading.Lock() -class BuffererRed(IObservableObserver): +class Bufferer(IObservableObserver): def __init__(self, buffer): - super(BuffererRed, self).__init__() + super(Bufferer, self).__init__() self.buffer = buffer def update(self, frame): @@ -114,7 +114,7 @@ def update(self, frame): green_dyer = Dyer(1, 64) buffer_red = np.zeros(frame_shape, np.uint8) - bufferer_red = BuffererRed(buffer_red) + bufferer_red = Bufferer(buffer_red) hist = HistogrammerRed() hist.start() From 7dacc271d3d662ed794cb90b3d0847b52bf1add9 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:15:02 +0100 Subject: [PATCH 022/277] Issue #16: HistogrammerRed now takes buffer as a constructor argument rather than using global var --- .../pipeline/multithreading_reliability_check.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index a345dfd6..4a58d7bb 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -42,24 +42,23 @@ def update(self, frame): class HistogrammerRed(threading.Thread): - def __init__(self): + def __init__(self, buffer): super(HistogrammerRed, self).__init__() + self.buffer = buffer self.running = False def run(self): if self.running: return - global buffer_red histogram, num_bins = None, 10 redness_scale = np.array([i for i in range(1, num_bins + 1)], np.float) self.running = True while self.running: with lock: - if buffer_red is not None: - histogram, _ = np.histogram( - buffer_red[:, :, 2], bins=num_bins, range=(0, 256) - ) + histogram, _ = np.histogram( + self.buffer[:, :, 2], bins=num_bins, range=(0, 256) + ) if histogram is not None: redness = np.sum(histogram * redness_scale) redness /= np.sum(histogram) @@ -116,7 +115,7 @@ def update(self, frame): buffer_red = np.zeros(frame_shape, np.uint8) bufferer_red = Bufferer(buffer_red) - hist = HistogrammerRed() + hist = HistogrammerRed(buffer_red) hist.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) From 051e36c55386d570a09e8af6bf05b053fa770d31 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:22:12 +0100 Subject: [PATCH 023/277] Issue #16: HistogrammerRed is now generic Histogrammer --- .../multithreading_reliability_check.py | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 4a58d7bb..0de913ed 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -40,10 +40,14 @@ def update(self, frame): self.buffer[:, :, :] = data[:, :, :] -class HistogrammerRed(threading.Thread): +class Histogrammer(threading.Thread): - def __init__(self, buffer): - super(HistogrammerRed, self).__init__() + channels = ('Blue', 'Green', 'Red', 'Alpha') + + def __init__(self, buffer, channel): + super(Histogrammer, self).__init__() + assert channel in range(3) + self.channel = channel self.buffer = buffer self.running = False @@ -52,7 +56,7 @@ def run(self): return histogram, num_bins = None, 10 - redness_scale = np.array([i for i in range(1, num_bins + 1)], np.float) + scale = np.array([i for i in range(1, num_bins + 1)], np.float) self.running = True while self.running: with lock: @@ -60,11 +64,13 @@ def run(self): self.buffer[:, :, 2], bins=num_bins, range=(0, 256) ) if histogram is not None: - redness = np.sum(histogram * redness_scale) - redness /= np.sum(histogram) - redness /= num_bins - redness *= 100 - print('Redness: {} %'.format(int(round(redness)))) + coloredness = np.sum(histogram * scale) + coloredness /= np.sum(histogram) + coloredness /= num_bins + coloredness *= 100 + print('{}ness of dyed image: {} %'.format( + Histogrammer.channels[self.channel], int(round(coloredness)) + )) sleep(0.100) def stop(self): @@ -115,7 +121,7 @@ def update(self, frame): buffer_red = np.zeros(frame_shape, np.uint8) bufferer_red = Bufferer(buffer_red) - hist = HistogrammerRed(buffer_red) + hist = Histogrammer(buffer_red, 2) hist.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) From 6d1c02b253e6d480d2344ae16eae310c1d166c24 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:27:00 +0100 Subject: [PATCH 024/277] Issue #16: Histogrammer now accepts a tag for generically printing what the image is --- src/tests/pipeline/multithreading_reliability_check.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 0de913ed..168b6b9f 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -44,11 +44,12 @@ class Histogrammer(threading.Thread): channels = ('Blue', 'Green', 'Red', 'Alpha') - def __init__(self, buffer, channel): + def __init__(self, buffer, channel, tag): super(Histogrammer, self).__init__() assert channel in range(3) self.channel = channel self.buffer = buffer + self.tag = tag self.running = False def run(self): @@ -68,8 +69,8 @@ def run(self): coloredness /= np.sum(histogram) coloredness /= num_bins coloredness *= 100 - print('{}ness of dyed image: {} %'.format( - Histogrammer.channels[self.channel], int(round(coloredness)) + print('{}ness of {} image: {} %'.format( + Histogrammer.channels[self.channel], self.tag, int(round(coloredness)) )) sleep(0.100) @@ -121,7 +122,7 @@ def update(self, frame): buffer_red = np.zeros(frame_shape, np.uint8) bufferer_red = Bufferer(buffer_red) - hist = Histogrammer(buffer_red, 2) + hist = Histogrammer(buffer_red, 2, 'red-dyed') hist.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) From 712da535ef3165f93fc9a8ed4134903a9041ff4f Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:34:30 +0100 Subject: [PATCH 025/277] Issue #16: inserted an original image histogrammer into the pipeline --- .../multithreading_reliability_check.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 168b6b9f..971e94b2 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -24,7 +24,7 @@ """ -buffer_red = None +buffer_red, buffer_orig = None, None lock = threading.Lock() @@ -121,25 +121,32 @@ def update(self, frame): buffer_red = np.zeros(frame_shape, np.uint8) bufferer_red = Bufferer(buffer_red) + buffer_orig = np.zeros_like(buffer_red) + bufferer_orig = Bufferer(buffer_orig) - hist = Histogrammer(buffer_red, 2, 'red-dyed') - hist.start() + hist_red = Histogrammer(buffer_red, 2, 'red-dyed') + hist_red.start() + hist_orig = Histogrammer(buffer_orig, 2, 'original') + hist_orig.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) red_writer = tfac.create_file_writer(Codec.HEVC, red_file, frame_rate) yellow_file = os.path.join('.', ''.join([filename, '-yellow', ext])) yellow_writer = tfac.create_file_writer(Codec.HEVC, yellow_file, frame_rate) - reader.attach(red_dyer) + reader.attach(bufferer_orig) + bufferer_orig.attach(red_dyer) red_dyer.attach(red_writer) red_dyer.attach(bufferer_red) red_dyer.attach(green_dyer) green_dyer.attach(yellow_writer) sleep(20) # operate pipeline for 20 sec - hist.stop() + hist_red.stop() + hist_orig.stop() - reader.detach(red_dyer) + reader.detach(bufferer_orig) + bufferer_orig.detach(red_dyer) red_dyer.detach(red_writer) red_dyer.detach(bufferer_red) red_dyer.detach(green_dyer) From 7707bb26bc9b16cc38a27d9fcb925b5ff8d1a6e2 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:39:33 +0100 Subject: [PATCH 026/277] Issue #16: Histogrammer now accepts a frame rate and flag for displaying coloredness --- .../multithreading_reliability_check.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 971e94b2..df093c13 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -44,12 +44,15 @@ class Histogrammer(threading.Thread): channels = ('Blue', 'Green', 'Red', 'Alpha') - def __init__(self, buffer, channel, tag): + def __init__(self, buffer, channel, tag, frame_rate, show=True): super(Histogrammer, self).__init__() assert channel in range(3) + assert 0 < frame_rate <= 60 self.channel = channel self.buffer = buffer self.tag = tag + self.show = show + self.sleep_interval = 1.0 / frame_rate self.running = False def run(self): @@ -69,10 +72,12 @@ def run(self): coloredness /= np.sum(histogram) coloredness /= num_bins coloredness *= 100 - print('{}ness of {} image: {} %'.format( - Histogrammer.channels[self.channel], self.tag, int(round(coloredness)) - )) - sleep(0.100) + if self.show: + print('{}ness of {} image: {} %'.format( + Histogrammer.channels[self.channel], + self.tag, int(round(coloredness)) + )) + sleep(self.sleep_interval) def stop(self): self.running = False @@ -124,9 +129,9 @@ def update(self, frame): buffer_orig = np.zeros_like(buffer_red) bufferer_orig = Bufferer(buffer_orig) - hist_red = Histogrammer(buffer_red, 2, 'red-dyed') + hist_red = Histogrammer(buffer_red, 2, 'red-dyed', 30, False) hist_red.start() - hist_orig = Histogrammer(buffer_orig, 2, 'original') + hist_orig = Histogrammer(buffer_orig, 2, 'original', 30, False) hist_orig.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) From 63f2fcd47eb6e6cad73614c6dae072d0fe1f05d9 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:45:12 +0100 Subject: [PATCH 027/277] Issue #16: now can specify the frequency of coloredness prints --- .../pipeline/multithreading_reliability_check.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index df093c13..43e82a19 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -44,14 +44,16 @@ class Histogrammer(threading.Thread): channels = ('Blue', 'Green', 'Red', 'Alpha') - def __init__(self, buffer, channel, tag, frame_rate, show=True): + def __init__(self, buffer, channel, tag, frame_rate, display_freq): super(Histogrammer, self).__init__() assert channel in range(3) assert 0 < frame_rate <= 60 + assert 0 <= display_freq self.channel = channel self.buffer = buffer self.tag = tag - self.show = show + self.display_freq = display_freq + self.num_skipped = 0 self.sleep_interval = 1.0 / frame_rate self.running = False @@ -72,11 +74,14 @@ def run(self): coloredness /= np.sum(histogram) coloredness /= num_bins coloredness *= 100 - if self.show: + if self.num_skipped >= self.display_freq: print('{}ness of {} image: {} %'.format( Histogrammer.channels[self.channel], self.tag, int(round(coloredness)) )) + self.num_skipped = 0 + else: + self.num_skipped += 1 sleep(self.sleep_interval) def stop(self): @@ -129,9 +134,9 @@ def update(self, frame): buffer_orig = np.zeros_like(buffer_red) bufferer_orig = Bufferer(buffer_orig) - hist_red = Histogrammer(buffer_red, 2, 'red-dyed', 30, False) + hist_red = Histogrammer(buffer_red, 2, 'red-dyed', 30.0, 10) hist_red.start() - hist_orig = Histogrammer(buffer_orig, 2, 'original', 30, False) + hist_orig = Histogrammer(buffer_orig, 2, 'original', 30.0, 10) hist_orig.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) From c8c22be3dc83e00833485d867e596acc5aa16190 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:47:38 +0100 Subject: [PATCH 028/277] Issue #16: dyeing red more prominently --- src/tests/pipeline/multithreading_reliability_check.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 43e82a19..72ab94d2 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -126,7 +126,7 @@ def update(self, frame): tfac = VideoTargetFactory.get_instance() frame_rate = reader.get_frame_rate() - red_dyer = Dyer(2, 64) + red_dyer = Dyer(2, 128) green_dyer = Dyer(1, 64) buffer_red = np.zeros(frame_shape, np.uint8) From e0076d9a2b9c5062d33bb010de6735fe37bbc734 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:53:47 +0100 Subject: [PATCH 029/277] Issue #16: frame rate values that reproduced the problem --- src/tests/pipeline/multithreading_reliability_check.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 72ab94d2..42cc36e3 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -134,9 +134,9 @@ def update(self, frame): buffer_orig = np.zeros_like(buffer_red) bufferer_orig = Bufferer(buffer_orig) - hist_red = Histogrammer(buffer_red, 2, 'red-dyed', 30.0, 10) + hist_red = Histogrammer(buffer_red, 2, 'red-dyed', 60.0, 10) hist_red.start() - hist_orig = Histogrammer(buffer_orig, 2, 'original', 30.0, 10) + hist_orig = Histogrammer(buffer_orig, 2, 'original', 50.0, 10) hist_orig.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) From 125b11eec9d3c4a8838f9b39f3f98b02a797afdb Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:54:25 +0100 Subject: [PATCH 030/277] Issue #16: using Debug CMake type in build script --- src/tests/pipeline/check_multithreading_reliability.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index efae4d95..7ea874b2 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -13,6 +13,7 @@ CMAKE_OPTS="-D USE_FILES=ON" CMAKE_OPTS="$CMAKE_OPTS -D USE_HEVC=ON" CMAKE_OPTS="$CMAKE_OPTS -D ENABLE_NONFREE=ON -D USE_NVENC=ON" CMAKE_OPTS="$CMAKE_OPTS -D BUILD_PYTHON=ON -D USE_NUMPY=ON" +CMAKE_OPTS="$CMAKE_OPTS -D CMAKE_BUILD_TYPE=Debug" MTR_SCRIPT=$CURRENT_DIR/multithreading_reliability_check.py mkdir -p $BUILD_DIR From 20fb19e7601806e790797f1d037051ec0e5fc72b Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 08:28:50 +0100 Subject: [PATCH 031/277] Issue #16: renamed variable for clarity in run script --- src/tests/pipeline/check_multithreading_reliability.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 7ea874b2..2be8fea2 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -6,15 +6,15 @@ # and NumPy support. Subsequently run the multi-threading # reliability check script. -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" -BUILD_DIR=$CURRENT_DIR/mtr-build -SOURCE_DIR="$( cd "$CURRENT_DIR/../.." >/dev/null && pwd )" +ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" +BUILD_DIR=$ROOT_DIR/mtr-build +SOURCE_DIR="$( cd "$ROOT_DIR/../.." >/dev/null && pwd )" CMAKE_OPTS="-D USE_FILES=ON" CMAKE_OPTS="$CMAKE_OPTS -D USE_HEVC=ON" CMAKE_OPTS="$CMAKE_OPTS -D ENABLE_NONFREE=ON -D USE_NVENC=ON" CMAKE_OPTS="$CMAKE_OPTS -D BUILD_PYTHON=ON -D USE_NUMPY=ON" CMAKE_OPTS="$CMAKE_OPTS -D CMAKE_BUILD_TYPE=Debug" -MTR_SCRIPT=$CURRENT_DIR/multithreading_reliability_check.py +MTR_SCRIPT=$ROOT_DIR/multithreading_reliability_check.py mkdir -p $BUILD_DIR rm -rf $BUILD_DIR/* From 7dac7e6e36afbb2028073edc6af37b6d10619836 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 09:00:44 +0100 Subject: [PATCH 032/277] Issue #16: setting ulimit to dump cores when running check --- src/tests/pipeline/check_multithreading_reliability.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 2be8fea2..4519cb84 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -15,6 +15,7 @@ CMAKE_OPTS="$CMAKE_OPTS -D ENABLE_NONFREE=ON -D USE_NVENC=ON" CMAKE_OPTS="$CMAKE_OPTS -D BUILD_PYTHON=ON -D USE_NUMPY=ON" CMAKE_OPTS="$CMAKE_OPTS -D CMAKE_BUILD_TYPE=Debug" MTR_SCRIPT=$ROOT_DIR/multithreading_reliability_check.py +ulimit -c unlimited mkdir -p $BUILD_DIR rm -rf $BUILD_DIR/* @@ -22,3 +23,5 @@ cd $BUILD_DIR cmake $CMAKE_OPTS $SOURCE_DIR make -j4 PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT --input $1 + +ulimit -c 0 From 470cfc842c43de888f3c85e810940ce78ad13ea2 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 09:02:44 +0100 Subject: [PATCH 033/277] Issue #16: saving all output in a hierarchical session directory --- .../pipeline/check_multithreading_reliability.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 4519cb84..f3cc6910 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -15,13 +15,26 @@ CMAKE_OPTS="$CMAKE_OPTS -D ENABLE_NONFREE=ON -D USE_NVENC=ON" CMAKE_OPTS="$CMAKE_OPTS -D BUILD_PYTHON=ON -D USE_NUMPY=ON" CMAKE_OPTS="$CMAKE_OPTS -D CMAKE_BUILD_TYPE=Debug" MTR_SCRIPT=$ROOT_DIR/multithreading_reliability_check.py +SESSION_DIR=$ROOT_DIR/$(date +"%Y-%m-%d-%H-%M-%S") +mkdir $SESSION_DIR ulimit -c unlimited +BUILD_LOG=$SESSION_DIR/build.log +{ mkdir -p $BUILD_DIR rm -rf $BUILD_DIR/* cd $BUILD_DIR cmake $CMAKE_OPTS $SOURCE_DIR make -j4 +} > $BUILD_LOG 2>&1 + +run_no=1 +WORKING_DIR=$SESSION_DIR/$run_no +mkdir $WORKING_DIR +cd $WORKING_DIR +RUN_LOG=$WORKING_DIR/run.log +{ PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT --input $1 +} > $RUN_LOG 2>&1 ulimit -c 0 From 5e89c911da13ee50ac533200436e0bacefb46f38 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 09:05:12 +0100 Subject: [PATCH 034/277] Issue #16: added indentation for readability --- .../pipeline/check_multithreading_reliability.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index f3cc6910..71e9efc0 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -21,11 +21,11 @@ ulimit -c unlimited BUILD_LOG=$SESSION_DIR/build.log { -mkdir -p $BUILD_DIR -rm -rf $BUILD_DIR/* -cd $BUILD_DIR -cmake $CMAKE_OPTS $SOURCE_DIR -make -j4 + mkdir -p $BUILD_DIR + rm -rf $BUILD_DIR/* + cd $BUILD_DIR + cmake $CMAKE_OPTS $SOURCE_DIR + make -j4 } > $BUILD_LOG 2>&1 run_no=1 @@ -34,7 +34,7 @@ mkdir $WORKING_DIR cd $WORKING_DIR RUN_LOG=$WORKING_DIR/run.log { -PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT --input $1 + PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT --input $1 } > $RUN_LOG 2>&1 ulimit -c 0 From bc2a2d935666bc5abc478541f485ff6fb654571f Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 09:14:47 +0100 Subject: [PATCH 035/277] Issue #16: can now specify number of reps in check script --- .../check_multithreading_reliability.sh | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 71e9efc0..52eed368 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -28,13 +28,20 @@ BUILD_LOG=$SESSION_DIR/build.log make -j4 } > $BUILD_LOG 2>&1 -run_no=1 -WORKING_DIR=$SESSION_DIR/$run_no -mkdir $WORKING_DIR -cd $WORKING_DIR -RUN_LOG=$WORKING_DIR/run.log -{ - PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT --input $1 -} > $RUN_LOG 2>&1 +num_reps=1 +if [ $# -ge 2 ]; +then + num_reps=$2 +fi +for run_no in `seq 1 $num_reps`; +do + WORKING_DIR=$SESSION_DIR/$(printf "%03d" $run_no) + mkdir $WORKING_DIR + cd $WORKING_DIR + RUN_LOG=$WORKING_DIR/run.log + { + PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT --input $1 + } > $RUN_LOG 2>&1 +done ulimit -c 0 From 435b302d28e8312efe9b86ea2e0d944adcf6f7f5 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 10:38:52 +0100 Subject: [PATCH 036/277] Issue #16: can now optionally specify root output dir (e.g. not to fill up disk space) --- .../pipeline/check_multithreading_reliability.sh | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 52eed368..1a90362e 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -6,15 +6,22 @@ # and NumPy support. Subsequently run the multi-threading # reliability check script. -ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" +CALL_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" +SOURCE_DIR="$( cd "$CALL_DIR/../.." >/dev/null && pwd )" +MTR_SCRIPT=$SOURCE_DIR/tests/pipeline/multithreading_reliability_check.py +if [ $# -ge 3 ]; +then + ROOT_DIR=$3 +else + ROOT_DIR=$CALL_DIR +fi + BUILD_DIR=$ROOT_DIR/mtr-build -SOURCE_DIR="$( cd "$ROOT_DIR/../.." >/dev/null && pwd )" CMAKE_OPTS="-D USE_FILES=ON" CMAKE_OPTS="$CMAKE_OPTS -D USE_HEVC=ON" CMAKE_OPTS="$CMAKE_OPTS -D ENABLE_NONFREE=ON -D USE_NVENC=ON" CMAKE_OPTS="$CMAKE_OPTS -D BUILD_PYTHON=ON -D USE_NUMPY=ON" CMAKE_OPTS="$CMAKE_OPTS -D CMAKE_BUILD_TYPE=Debug" -MTR_SCRIPT=$ROOT_DIR/multithreading_reliability_check.py SESSION_DIR=$ROOT_DIR/$(date +"%Y-%m-%d-%H-%M-%S") mkdir $SESSION_DIR ulimit -c unlimited From d69aee7b3ce66917e3c41c42cb089cccd931c993 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 10:48:37 +0100 Subject: [PATCH 037/277] Issue #16: logging frequency of exit codes as well --- .../pipeline/check_multithreading_reliability.sh | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 1a90362e..f7fbb5fe 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -40,6 +40,8 @@ if [ $# -ge 2 ]; then num_reps=$2 fi + +declare -a exit_code_freqs for run_no in `seq 1 $num_reps`; do WORKING_DIR=$SESSION_DIR/$(printf "%03d" $run_no) @@ -48,7 +50,21 @@ do RUN_LOG=$WORKING_DIR/run.log { PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT --input $1 + + exit_code=$? + echo "Exit code was: $exit_code" + freq=${exit_code_freqs[$exit_code]} + let freq=$freq+1 + exit_code_freqs[$exit_code]=$freq } > $RUN_LOG 2>&1 + + sleep 5 +done + +EXIT_CODES_LOG=$SESSION_DIR/exit-codes.csv +for exit_code in "${!exit_code_freqs[@]}"; +do + echo "$exit_code ${exit_code_freqs[$exit_code]}" >> $EXIT_CODES_LOG done ulimit -c 0 From dfab9e4050c937ba2bc654a64c77ff05aa809c65 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 10:59:58 +0100 Subject: [PATCH 038/277] Issue #16: nicer formatting of exit code frequencies log --- src/tests/pipeline/check_multithreading_reliability.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index f7fbb5fe..419b7c08 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -62,9 +62,14 @@ do done EXIT_CODES_LOG=$SESSION_DIR/exit-codes.csv +printf "%10s" "exit-code" >> $EXIT_CODES_LOG +printf "%10s" "frequency" >> $EXIT_CODES_LOG +printf "\n" >> $EXIT_CODES_LOG for exit_code in "${!exit_code_freqs[@]}"; do - echo "$exit_code ${exit_code_freqs[$exit_code]}" >> $EXIT_CODES_LOG + printf "%10d" $exit_code >> $EXIT_CODES_LOG + printf "%10d" ${exit_code_freqs[$exit_code]} >> $EXIT_CODES_LOG + printf "\n" >> $EXIT_CODES_LOG done ulimit -c 0 From b74aeb5552c78401d7a2e9d91c307cbca389a3f3 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 11:02:37 +0100 Subject: [PATCH 039/277] Issue #16: ignoring output folder to avoid an accidental commit of big files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d7eb0905..35b7a77b 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ src/dist src/*.egg-info *.swp src/tests/pipeline/mtr-build +gg-iss-16 From 099903ae87d26e8d6cbeff2467cf5ab73d5d0ddf Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 11:06:29 +0100 Subject: [PATCH 040/277] Issue #16: using absolute path expansion if root-dir passed as a CLI param --- src/tests/pipeline/check_multithreading_reliability.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 419b7c08..18b9133e 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -11,7 +11,7 @@ SOURCE_DIR="$( cd "$CALL_DIR/../.." >/dev/null && pwd )" MTR_SCRIPT=$SOURCE_DIR/tests/pipeline/multithreading_reliability_check.py if [ $# -ge 3 ]; then - ROOT_DIR=$3 + ROOT_DIR="$( cd "$3" >/dev/null && pwd )" else ROOT_DIR=$CALL_DIR fi From a0cc695e749fe2372c7364923c832b0744c354e1 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 11:56:45 +0100 Subject: [PATCH 041/277] Issue #16: intermediately writing exit codes every 10 iterations --- .../check_multithreading_reliability.sh | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 18b9133e..64b58250 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -58,18 +58,21 @@ do exit_code_freqs[$exit_code]=$freq } > $RUN_LOG 2>&1 - sleep 5 -done + if [ $(($run_no % 10)) -eq 0 ] || [ $run_no -eq $num_reps ]; + then + EXIT_CODES_LOG=$SESSION_DIR/exit-codes-$run_no.csv + printf "%10s" "exit-code" >> $EXIT_CODES_LOG + printf "%10s" "frequency" >> $EXIT_CODES_LOG + printf "\n" >> $EXIT_CODES_LOG + for exit_code in "${!exit_code_freqs[@]}"; + do + printf "%10d" $exit_code >> $EXIT_CODES_LOG + printf "%10d" ${exit_code_freqs[$exit_code]} >> $EXIT_CODES_LOG + printf "\n" >> $EXIT_CODES_LOG + done + fi -EXIT_CODES_LOG=$SESSION_DIR/exit-codes.csv -printf "%10s" "exit-code" >> $EXIT_CODES_LOG -printf "%10s" "frequency" >> $EXIT_CODES_LOG -printf "\n" >> $EXIT_CODES_LOG -for exit_code in "${!exit_code_freqs[@]}"; -do - printf "%10d" $exit_code >> $EXIT_CODES_LOG - printf "%10d" ${exit_code_freqs[$exit_code]} >> $EXIT_CODES_LOG - printf "\n" >> $EXIT_CODES_LOG + sleep 5 done ulimit -c 0 From 2ee8a52b8806fb9c76f351aff6b1a16f5aad2797 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 12:19:39 +0100 Subject: [PATCH 042/277] Issue #16: using git-describe to tag the output with the version used --- src/tests/pipeline/check_multithreading_reliability.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 64b58250..71e2bb62 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -28,6 +28,7 @@ ulimit -c unlimited BUILD_LOG=$SESSION_DIR/build.log { + git describe --dirty mkdir -p $BUILD_DIR rm -rf $BUILD_DIR/* cd $BUILD_DIR From e319205c580a484bf665b00cd50f513e8bd79495 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 12:47:45 +0100 Subject: [PATCH 043/277] Issue #16: querying for update override after the acquisition of GIL --- src/python/wrapper.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/python/wrapper.cpp b/src/python/wrapper.cpp index ba34c646..a82018bc 100644 --- a/src/python/wrapper.cpp +++ b/src/python/wrapper.cpp @@ -332,11 +332,13 @@ class IObservableObserverWrapper : public gg::IObservable void update(gg::VideoFrame & frame) { - if (override f = this->get_override("update")) { - VideoFrameNumPyWrapper wrapped_frame(&frame); gg::ScopedPythonGILLock gil_lock; - f(boost::ref(wrapped_frame)); + if (override f = this->get_override("update")) + { + VideoFrameNumPyWrapper wrapped_frame(&frame); + f(boost::ref(wrapped_frame)); + } } notify(frame); } From 40777b605d5dd4caa599543d70b5ce6281346218 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 13:35:54 +0100 Subject: [PATCH 044/277] Issue #16: checking update method overridden in Python before actually calling it from within IObserverWrapper --- src/python/wrapper.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/python/wrapper.cpp b/src/python/wrapper.cpp index a82018bc..83c4f11a 100644 --- a/src/python/wrapper.cpp +++ b/src/python/wrapper.cpp @@ -268,7 +268,8 @@ class IObserverWrapper : public gg::IObserver, public wrapper { gg::ScopedPythonGILLock gil_lock; VideoFrameNumPyWrapper wrapped_frame(&frame); - this->get_override("update")(boost::ref(wrapped_frame)); + if (override f = this->get_override("update")) + f(boost::ref(wrapped_frame)); } }; From f47b76ed396d64b4720bc2b3128ad0ae91a3453e Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 09:06:14 +0100 Subject: [PATCH 045/277] Issue #16: using Pythonic percentage formatting --- src/tests/pipeline/multithreading_reliability_check.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 42cc36e3..e1c50e30 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -73,11 +73,10 @@ def run(self): coloredness = np.sum(histogram * scale) coloredness /= np.sum(histogram) coloredness /= num_bins - coloredness *= 100 if self.num_skipped >= self.display_freq: - print('{}ness of {} image: {} %'.format( + print('{}ness of {} image: {:.0%}'.format( Histogrammer.channels[self.channel], - self.tag, int(round(coloredness)) + self.tag, coloredness )) self.num_skipped = 0 else: From ed3a02ade578786a4fe13a2a2de1d11a2cf22780 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 09:24:39 +0100 Subject: [PATCH 046/277] Issue #16: added a SnapshotSaver class that implements IObserver directly --- .../multithreading_reliability_check.py | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index e1c50e30..a880b355 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -6,9 +6,10 @@ import os.path import threading import numpy as np +import scipy.misc from pygiftgrab import (VideoSourceFactory, VideoFrame, ColourSpace, IObservableObserver, - VideoTargetFactory, Codec) + VideoTargetFactory, Codec, IObserver) """ This script provides a multi-threading reliability check. @@ -28,6 +29,32 @@ lock = threading.Lock() +class SnapshotSaver(IObserver): + """A snapshot saver for saving incoming frames to PNG files.""" + + def __init__(self, root_dir, frame_rate=0.2): + """ + Initialise a snapshot saver with a saving frequency. + + :param root_dir: the folder where to save the snapshots + :param frame_rate: saving frequency. The default value tells + the saver to save a frame every 5 sec. + """ + super(SnapshotSaver, self).__init__() + assert 0 < frame_rate <= 1 # to avoid flooding disk with images + self.save_freq = 1.0 / frame_rate + self.root_dir = root_dir + self.num_called = 0 + + def update(self, frame): + """Implement ``IObserver.update``.""" + self.num_called += 1 + if self.num_called % self.save_freq == 1: + out_file = os.path.join(self.root_dir, + 'frame-{:010d}.png'.format(self.num_called)) + scipy.misc.imsave(out_file, frame.data(True)) + + class Bufferer(IObservableObserver): def __init__(self, buffer): From f87c8ff63dafe2a3f50df67cb90b0f630c906126 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 09:25:08 +0100 Subject: [PATCH 047/277] Issue #16: inserted snapshot saver into the pipeline --- src/tests/pipeline/multithreading_reliability_check.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index a880b355..f1a1697f 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -170,12 +170,15 @@ def update(self, frame): yellow_file = os.path.join('.', ''.join([filename, '-yellow', ext])) yellow_writer = tfac.create_file_writer(Codec.HEVC, yellow_file, frame_rate) + yellow_snapshots = SnapshotSaver('.') + reader.attach(bufferer_orig) bufferer_orig.attach(red_dyer) red_dyer.attach(red_writer) red_dyer.attach(bufferer_red) red_dyer.attach(green_dyer) green_dyer.attach(yellow_writer) + green_dyer.attach(yellow_snapshots) sleep(20) # operate pipeline for 20 sec hist_red.stop() @@ -187,3 +190,4 @@ def update(self, frame): red_dyer.detach(bufferer_red) red_dyer.detach(green_dyer) green_dyer.detach(yellow_writer) + green_dyer.detach(yellow_snapshots) From 9be73e9e497502e8f033498b16d31962a2fdbea0 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 09:47:20 +0100 Subject: [PATCH 048/277] Issue #16: fixed timed saving of snapshots --- .../multithreading_reliability_check.py | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index f1a1697f..7eca3382 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -from time import sleep +from time import (sleep, time) import argparse import os.path import threading @@ -32,27 +32,29 @@ class SnapshotSaver(IObserver): """A snapshot saver for saving incoming frames to PNG files.""" - def __init__(self, root_dir, frame_rate=0.2): + def __init__(self, root_dir, save_freq=5): """ Initialise a snapshot saver with a saving frequency. :param root_dir: the folder where to save the snapshots - :param frame_rate: saving frequency. The default value tells - the saver to save a frame every 5 sec. + :param save_freq: saving frequency. The default value tells + the saver to save every 5 seconds. """ super(SnapshotSaver, self).__init__() - assert 0 < frame_rate <= 1 # to avoid flooding disk with images - self.save_freq = 1.0 / frame_rate + assert 5 <= save_freq # to avoid flooding disk with images + self.save_freq = save_freq self.root_dir = root_dir - self.num_called = 0 + self.last_saved = time() + self.num_saved = 0 def update(self, frame): """Implement ``IObserver.update``.""" - self.num_called += 1 - if self.num_called % self.save_freq == 1: + if time() - self.last_saved >= self.save_freq: + self.num_saved += 1 out_file = os.path.join(self.root_dir, - 'frame-{:010d}.png'.format(self.num_called)) + 'frame-{:010d}.png'.format(self.num_saved)) scipy.misc.imsave(out_file, frame.data(True)) + self.last_saved = time() class Bufferer(IObservableObserver): From e4c17d0bae912678e40f9cb55c50036409d47ed5 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 10:10:24 +0100 Subject: [PATCH 049/277] Issue #16: renamed buffer => np_buffer as buffer is built-in type --- src/tests/pipeline/multithreading_reliability_check.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 7eca3382..0091b993 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -59,9 +59,9 @@ def update(self, frame): class Bufferer(IObservableObserver): - def __init__(self, buffer): + def __init__(self, np_buffer): super(Bufferer, self).__init__() - self.buffer = buffer + self.buffer = np_buffer def update(self, frame): with lock: @@ -73,13 +73,13 @@ class Histogrammer(threading.Thread): channels = ('Blue', 'Green', 'Red', 'Alpha') - def __init__(self, buffer, channel, tag, frame_rate, display_freq): + def __init__(self, np_buffer, channel, tag, frame_rate, display_freq): super(Histogrammer, self).__init__() assert channel in range(3) assert 0 < frame_rate <= 60 assert 0 <= display_freq self.channel = channel - self.buffer = buffer + self.buffer = np_buffer self.tag = tag self.display_freq = display_freq self.num_skipped = 0 From 93a6cc7dd22c8fb933cdffbabc5875dc8097f408 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 10:17:51 +0100 Subject: [PATCH 050/277] Issue #16: renamed global buffers for clarity --- .../pipeline/multithreading_reliability_check.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 0091b993..8d3d4b89 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -25,7 +25,7 @@ """ -buffer_red, buffer_orig = None, None +np_buffer_red, np_buffer_orig = None, None lock = threading.Lock() @@ -157,14 +157,14 @@ def update(self, frame): red_dyer = Dyer(2, 128) green_dyer = Dyer(1, 64) - buffer_red = np.zeros(frame_shape, np.uint8) - bufferer_red = Bufferer(buffer_red) - buffer_orig = np.zeros_like(buffer_red) - bufferer_orig = Bufferer(buffer_orig) + np_buffer_red = np.zeros(frame_shape, np.uint8) + bufferer_red = Bufferer(np_buffer_red) + np_buffer_orig = np.zeros_like(np_buffer_red) + bufferer_orig = Bufferer(np_buffer_orig) - hist_red = Histogrammer(buffer_red, 2, 'red-dyed', 60.0, 10) + hist_red = Histogrammer(np_buffer_red, 2, 'red-dyed', 60.0, 10) hist_red.start() - hist_orig = Histogrammer(buffer_orig, 2, 'original', 50.0, 10) + hist_orig = Histogrammer(np_buffer_orig, 2, 'original', 50.0, 10) hist_orig.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) From 782c8a17e04a1b9c230106ad6012cfcc769c880a Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 10:20:01 +0100 Subject: [PATCH 051/277] Issue #16: commented checker script --- .../multithreading_reliability_check.py | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 8d3d4b89..b4d21c9c 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -25,7 +25,11 @@ """ +# global NumPy buffers np_buffer_red, np_buffer_orig = None, None + +# mutex protecting frame data passed from node to node +# in the GIFT-Grab processing pipeline lock = threading.Lock() @@ -58,22 +62,41 @@ def update(self, frame): class Bufferer(IObservableObserver): + """GIFT-Grab processing node that updates a frame buffer.""" def __init__(self, np_buffer): + """Initialise a bufferer that will update given buffer.""" super(Bufferer, self).__init__() self.buffer = np_buffer def update(self, frame): + """Implement ``IObservableObserver.update``.""" with lock: data = frame.data(True) self.buffer[:, :, :] = data[:, :, :] class Histogrammer(threading.Thread): + """ + GIFT-Grab processing node that computes the histogram of + an image channel and prints how "colored" that channel is. + """ channels = ('Blue', 'Green', 'Red', 'Alpha') def __init__(self, np_buffer, channel, tag, frame_rate, display_freq): + """ + :param np_buffer: image buffer to use + :param channel: image channel to compute coloredness for + :param tag: a tag describing what this image is, e.g. + how it's been processed within a GIFT-Grab pipeline + :param frame_rate: the rate at which to compute the + coloredness (unit: frames-per-second) + :param display_freq: how many times to skip the display + of computed coloredness, e.g. if 5 is provided, the + coloredness of every 5th frame will be printed to the + console + """ super(Histogrammer, self).__init__() assert channel in range(3) assert 0 < frame_rate <= 60 @@ -87,6 +110,7 @@ def __init__(self, np_buffer, channel, tag, frame_rate, display_freq): self.running = False def run(self): + """Override ``Thread.run``.""" if self.running: return @@ -113,12 +137,18 @@ def run(self): sleep(self.sleep_interval) def stop(self): + """Stop the thread.""" self.running = False class Dyer(IObservableObserver): + """Dyes specified channel of an incoming video frame.""" def __init__(self, channel, increment): + """ + :param channel: image channel to dye + :param increment: how much to dye the image channel + """ super(Dyer, self).__init__() assert 0 <= channel < 3 assert 0 <= increment < 256 @@ -126,6 +156,7 @@ def __init__(self, channel, increment): self.increment = increment def update(self, frame): + """Implement ``IObservableObserver.update``.""" with lock: data = frame.data(True) channel_data = data[:, :, self.channel] @@ -145,35 +176,46 @@ def update(self, frame): assert filename assert ext == '.mp4' + # initialise reading of passed file sfac = VideoSourceFactory.get_instance() reader = sfac.create_file_reader(in_file, ColourSpace.BGRA) frame = VideoFrame(ColourSpace.BGRA, False) reader.get_frame(frame) frame_shape = (frame.rows(), frame.cols(), 4) + # prepare for creating encoders (writers) tfac = VideoTargetFactory.get_instance() frame_rate = reader.get_frame_rate() + # create a red and green Dyer red_dyer = Dyer(2, 128) green_dyer = Dyer(1, 64) + # create the bufferer for the red and green Dyers np_buffer_red = np.zeros(frame_shape, np.uint8) bufferer_red = Bufferer(np_buffer_red) np_buffer_orig = np.zeros_like(np_buffer_red) bufferer_orig = Bufferer(np_buffer_orig) + # create the histogrammers for the red-dyed and + # the original video frames, and start them hist_red = Histogrammer(np_buffer_red, 2, 'red-dyed', 60.0, 10) hist_red.start() hist_orig = Histogrammer(np_buffer_orig, 2, 'original', 50.0, 10) hist_orig.start() + # create encoders for the red-dyed and yellow-dyed (as green + # is applied on top of red) video streams red_file = os.path.join('.', ''.join([filename, '-red', ext])) red_writer = tfac.create_file_writer(Codec.HEVC, red_file, frame_rate) yellow_file = os.path.join('.', ''.join([filename, '-yellow', ext])) yellow_writer = tfac.create_file_writer(Codec.HEVC, yellow_file, frame_rate) + # create a SnapshotSavers for saving a number of yellow-dyed + # video frames yellow_snapshots = SnapshotSaver('.') + # assemble the GIFT-Grab pipeline reader.attach(bufferer_orig) bufferer_orig.attach(red_dyer) red_dyer.attach(red_writer) @@ -183,9 +225,12 @@ def update(self, frame): green_dyer.attach(yellow_snapshots) sleep(20) # operate pipeline for 20 sec + + # stop the histogrammers hist_red.stop() hist_orig.stop() + # disassemble the GIFT-Grab pipeline reader.detach(bufferer_orig) bufferer_orig.detach(red_dyer) red_dyer.detach(red_writer) From b6261c57d99e2cb25ba46f897cb09fa633e0d4e7 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 10:54:24 +0100 Subject: [PATCH 052/277] Issue #16: moved issue-specific comments to shell script --- .../check_multithreading_reliability.sh | 17 +++++++++++++---- .../multithreading_reliability_check.py | 18 +++++------------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 71e2bb62..ceafc345 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -1,10 +1,19 @@ #!/usr/bin/env bash # -*- coding: utf-8 -*- -# Build a basic GIFT-Grab capable of reading a video file, -# and encoding to a video file in real time, with Python -# and NumPy support. Subsequently run the multi-threading -# reliability check script. +# This script provides a multi-threading reliability check. +# The background is issue #16. It looks like in applications +# where multiple Python threads are involved, occasionally +# the acquisition of the Global Interpreter Lock leads to a +# deadlocks, which crashes the whole application with a +# non-specific segmentation fault. +# +# It builds a basic GIFT-Grab capable of reading a video file, +# and encoding to a video file in real time, with Python and +# NumPy support. It subsequently runs a multi-threaded +# GIFT-Grab pipeline a number of times, recording the exit +# status each time. This is essentially a stress-test that +# should serve as a validation that issue #16 is fixed. CALL_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" SOURCE_DIR="$( cd "$CALL_DIR/../.." >/dev/null && pwd )" diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index b4d21c9c..3fdad38b 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -1,6 +1,11 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +""" +Example showing a complex GIFT-Grab pipeline with +multiple intermediate processing nodes. +""" + from time import (sleep, time) import argparse import os.path @@ -11,19 +16,6 @@ ColourSpace, IObservableObserver, VideoTargetFactory, Codec, IObserver) -""" -This script provides a multi-threading reliability check. -The background is issue #16. It looks like in applications -where multiple Python threads are involved, occasionally -the acquisition of the Global Interpreter Lock leads to a -deadlocks, which crashes the whole application with a -non-specific segmentation fault. - -In this script we run a number of multi-threaded GIFT-Grab -pipelines, which should serve as a validation that this -problem is fixed. -""" - # global NumPy buffers np_buffer_red, np_buffer_orig = None, None From fdfbde5942972c6845e1a8542ebd3f9a95bc9cd2 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 10:54:45 +0100 Subject: [PATCH 053/277] Issue #16: added synopsis display to shell script --- .../pipeline/check_multithreading_reliability.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index ceafc345..c6419403 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -15,6 +15,18 @@ # status each time. This is essentially a stress-test that # should serve as a validation that issue #16 is fixed. +if [ $# -lt 1 ] || [ $# -gt 3 ]; +then + THIS_SCRIPT="$(basename "$(test -L "${BASH_SOURCE[0]}" && readlink "$0" || echo "$0")")" + printf "Usage: $THIS_SCRIPT video_file [ num_reps [ output_dir ] ]\n" + printf "\tvideo_file: path to an HEVC-encoded MP4 file\n" + printf "\tnum_reps: how many times to run the Python script " + printf "(default: once)\n" + printf "\toutput_dir: where to save all the generated output " + printf "(default: current directory)\n" + exit 1 +fi + CALL_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" SOURCE_DIR="$( cd "$CALL_DIR/../.." >/dev/null && pwd )" MTR_SCRIPT=$SOURCE_DIR/tests/pipeline/multithreading_reliability_check.py From 9108bdd280f1c21a5995424f64ef9988a144b827 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 10:57:52 +0100 Subject: [PATCH 054/277] Issue #16: shell script now shows the current session directory before starting --- src/tests/pipeline/check_multithreading_reliability.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index c6419403..39df9537 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -45,6 +45,7 @@ CMAKE_OPTS="$CMAKE_OPTS -D BUILD_PYTHON=ON -D USE_NUMPY=ON" CMAKE_OPTS="$CMAKE_OPTS -D CMAKE_BUILD_TYPE=Debug" SESSION_DIR=$ROOT_DIR/$(date +"%Y-%m-%d-%H-%M-%S") mkdir $SESSION_DIR +echo "Session directory: $SESSION_DIR" ulimit -c unlimited BUILD_LOG=$SESSION_DIR/build.log From 345aa97c3092eccf95ee25a88d716def8b8eae3d Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 11:01:37 +0100 Subject: [PATCH 055/277] Issue #16: shorter name for Python script --- .../{multithreading_reliability_check.py => complex_pipeline.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/tests/pipeline/{multithreading_reliability_check.py => complex_pipeline.py} (100%) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/complex_pipeline.py similarity index 100% rename from src/tests/pipeline/multithreading_reliability_check.py rename to src/tests/pipeline/complex_pipeline.py From 1a88e0b6db4c8802b10a2e14b4f504ee7c25edf9 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 11:02:26 +0100 Subject: [PATCH 056/277] Issue #16: shorter name for Bash script --- ...heck_multithreading_reliability.sh => run-complex-pipeline.sh} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/tests/pipeline/{check_multithreading_reliability.sh => run-complex-pipeline.sh} (100%) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/run-complex-pipeline.sh similarity index 100% rename from src/tests/pipeline/check_multithreading_reliability.sh rename to src/tests/pipeline/run-complex-pipeline.sh From 5db2dcc64da2ba52367f95718a5279bf56c97327 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 11:04:37 +0100 Subject: [PATCH 057/277] Issue #16: fixed typos --- src/tests/pipeline/complex_pipeline.py | 2 +- src/tests/pipeline/run-complex-pipeline.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/pipeline/complex_pipeline.py b/src/tests/pipeline/complex_pipeline.py index 3fdad38b..1d9d7346 100755 --- a/src/tests/pipeline/complex_pipeline.py +++ b/src/tests/pipeline/complex_pipeline.py @@ -203,7 +203,7 @@ def update(self, frame): yellow_file = os.path.join('.', ''.join([filename, '-yellow', ext])) yellow_writer = tfac.create_file_writer(Codec.HEVC, yellow_file, frame_rate) - # create a SnapshotSavers for saving a number of yellow-dyed + # create a SnapshotSaver for saving a number of yellow-dyed # video frames yellow_snapshots = SnapshotSaver('.') diff --git a/src/tests/pipeline/run-complex-pipeline.sh b/src/tests/pipeline/run-complex-pipeline.sh index 39df9537..5166507b 100755 --- a/src/tests/pipeline/run-complex-pipeline.sh +++ b/src/tests/pipeline/run-complex-pipeline.sh @@ -5,7 +5,7 @@ # The background is issue #16. It looks like in applications # where multiple Python threads are involved, occasionally # the acquisition of the Global Interpreter Lock leads to a -# deadlocks, which crashes the whole application with a +# deadlock, which crashes the whole application with a # non-specific segmentation fault. # # It builds a basic GIFT-Grab capable of reading a video file, From 37ff47d70ea5a1f3a59086ff769963642d488448 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 11:04:55 +0100 Subject: [PATCH 058/277] Issue #16: reduced snapshot output --- src/tests/pipeline/complex_pipeline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/pipeline/complex_pipeline.py b/src/tests/pipeline/complex_pipeline.py index 1d9d7346..66686f1e 100755 --- a/src/tests/pipeline/complex_pipeline.py +++ b/src/tests/pipeline/complex_pipeline.py @@ -205,7 +205,7 @@ def update(self, frame): # create a SnapshotSaver for saving a number of yellow-dyed # video frames - yellow_snapshots = SnapshotSaver('.') + yellow_snapshots = SnapshotSaver('.', 9) # assemble the GIFT-Grab pipeline reader.attach(bufferer_orig) From 67ee662300a3f795933d9747b7f73a39126a0dae Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 11:09:55 +0100 Subject: [PATCH 059/277] Issue #16: fixed calling of Python script from Bash script --- src/tests/pipeline/run-complex-pipeline.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/pipeline/run-complex-pipeline.sh b/src/tests/pipeline/run-complex-pipeline.sh index 5166507b..3ed9e038 100755 --- a/src/tests/pipeline/run-complex-pipeline.sh +++ b/src/tests/pipeline/run-complex-pipeline.sh @@ -29,7 +29,7 @@ fi CALL_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" SOURCE_DIR="$( cd "$CALL_DIR/../.." >/dev/null && pwd )" -MTR_SCRIPT=$SOURCE_DIR/tests/pipeline/multithreading_reliability_check.py +MTR_SCRIPT=$SOURCE_DIR/tests/pipeline/complex_pipeline.py if [ $# -ge 3 ]; then ROOT_DIR="$( cd "$3" >/dev/null && pwd )" From 4f5a726f0b31f1546d03f55846fa99eb41cb4676 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 11:41:33 +0100 Subject: [PATCH 060/277] Issue #16: added an RTD page linking to the complex pipeline example --- doc/source/complex.rst | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 doc/source/complex.rst diff --git a/doc/source/complex.rst b/doc/source/complex.rst new file mode 100644 index 00000000..3982fb7f --- /dev/null +++ b/doc/source/complex.rst @@ -0,0 +1,20 @@ +.. _Complex: + +Multi-threaded processing pipelines +=================================== + +This example shows how GIFT-Grab can be used for running complex pipelines with multiple intermediate +processing nodes and threads. +The intermediate processing nodes are built on the same principles as in the SciPy_ example. +Running the example requires an `HEVC-encoded MP4 file`_, an `NVENC-capable GPU`_, and `NumPy support`_. + +.. _`HEVC-encoded MP4 file`: https://github.com/gift-surg/GIFT-Grab/blob/master/doc/build.md#reading-video-files +.. _`NVENC-capable GPU`: https://github.com/gift-surg/GIFT-Grab/blob/master/doc/build.md#hevc +.. _`NumPy support`: https://github.com/gift-surg/GIFT-Grab/blob/master/doc/build.md#python-api + +Below is the commented full source code: + +.. literalinclude:: ../../src/tests/pipeline/complex_pipeline.py + :language: python + :linenos: + From aae78a2e148bf1892bb15cd178b26ea5d3403afc Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 11:41:59 +0100 Subject: [PATCH 061/277] Issue #16: added the new RTD page to the index --- doc/source/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/index.rst b/doc/source/index.rst index 2c8fddc2..8e9af514 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -51,6 +51,7 @@ Examples network scipy encoding + complex Citing GIFT-Grab ^^^^^^^^^^^^^^^^ From 291fc3fdbc1a196cb3da74090b20242a1b09a5f3 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 11:59:27 +0100 Subject: [PATCH 062/277] Issue #16: fixed cross-reference to NumPy example from new RTD page --- doc/source/complex.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/complex.rst b/doc/source/complex.rst index 3982fb7f..6e0c8a60 100644 --- a/doc/source/complex.rst +++ b/doc/source/complex.rst @@ -5,7 +5,7 @@ Multi-threaded processing pipelines This example shows how GIFT-Grab can be used for running complex pipelines with multiple intermediate processing nodes and threads. -The intermediate processing nodes are built on the same principles as in the SciPy_ example. +The intermediate processing nodes are built on the same principles as in the :ref:`SciPy` example. Running the example requires an `HEVC-encoded MP4 file`_, an `NVENC-capable GPU`_, and `NumPy support`_. .. _`HEVC-encoded MP4 file`: https://github.com/gift-surg/GIFT-Grab/blob/master/doc/build.md#reading-video-files From 153175848d7881f7295780aef2f9d95afb0aaee7 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 12:00:34 +0100 Subject: [PATCH 063/277] Issue #16: added link from new RTD page to example source code on GitHub --- doc/source/complex.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/source/complex.rst b/doc/source/complex.rst index 6e0c8a60..060bce72 100644 --- a/doc/source/complex.rst +++ b/doc/source/complex.rst @@ -12,9 +12,11 @@ Running the example requires an `HEVC-encoded MP4 file`_, an `NVENC-capable GPU` .. _`NVENC-capable GPU`: https://github.com/gift-surg/GIFT-Grab/blob/master/doc/build.md#hevc .. _`NumPy support`: https://github.com/gift-surg/GIFT-Grab/blob/master/doc/build.md#python-api -Below is the commented full source code: +Below is the commented full source code, which is also available on GitHub_: .. literalinclude:: ../../src/tests/pipeline/complex_pipeline.py :language: python :linenos: +.. _GitHub: https://github.com/gift-surg/GIFT-Grab/blob/master/src/tests/pipeline/complex_pipeline.py + From a7c65355514be06a3c02e8ca33d5ed3475164974 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 18:47:20 +0100 Subject: [PATCH 064/277] Issue #16: made the title of the new RTD page more descriptive --- doc/source/complex.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/source/complex.rst b/doc/source/complex.rst index 060bce72..98fc12ce 100644 --- a/doc/source/complex.rst +++ b/doc/source/complex.rst @@ -1,7 +1,7 @@ .. _Complex: -Multi-threaded processing pipelines -=================================== +Multi-threaded complex processing pipelines +=========================================== This example shows how GIFT-Grab can be used for running complex pipelines with multiple intermediate processing nodes and threads. From e78af6fb6f192be5d81c462e0a24bc8cebd0b092 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 18:51:26 +0100 Subject: [PATCH 065/277] Issue #16: revised the RTD page wording for clarity --- doc/source/complex.rst | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/doc/source/complex.rst b/doc/source/complex.rst index 98fc12ce..0d231ccb 100644 --- a/doc/source/complex.rst +++ b/doc/source/complex.rst @@ -3,16 +3,19 @@ Multi-threaded complex processing pipelines =========================================== -This example shows how GIFT-Grab can be used for running complex pipelines with multiple intermediate -processing nodes and threads. -The intermediate processing nodes are built on the same principles as in the :ref:`SciPy` example. +The example below shows how GIFT-Grab can be used for running complex pipelines with multiple +intermediate processing nodes and threads. +The intermediate processing nodes in this example are built on the same principles as in the +:ref:`SciPy` example. Running the example requires an `HEVC-encoded MP4 file`_, an `NVENC-capable GPU`_, and `NumPy support`_. .. _`HEVC-encoded MP4 file`: https://github.com/gift-surg/GIFT-Grab/blob/master/doc/build.md#reading-video-files .. _`NVENC-capable GPU`: https://github.com/gift-surg/GIFT-Grab/blob/master/doc/build.md#hevc .. _`NumPy support`: https://github.com/gift-surg/GIFT-Grab/blob/master/doc/build.md#python-api -Below is the commented full source code, which is also available on GitHub_: +The full source code of the example is below. +Please follow the comments and the flow of code. +This example is also available on GitHub_: .. literalinclude:: ../../src/tests/pipeline/complex_pipeline.py :language: python From 2e07b9af9477f884e24c04c9f861168793761f0a Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 18:53:21 +0100 Subject: [PATCH 066/277] Issue #16: removed line numbers from example on new RTD page --- doc/source/complex.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/source/complex.rst b/doc/source/complex.rst index 0d231ccb..eba60359 100644 --- a/doc/source/complex.rst +++ b/doc/source/complex.rst @@ -19,7 +19,6 @@ This example is also available on GitHub_: .. literalinclude:: ../../src/tests/pipeline/complex_pipeline.py :language: python - :linenos: .. _GitHub: https://github.com/gift-surg/GIFT-Grab/blob/master/src/tests/pipeline/complex_pipeline.py From 3657e010bbc2ca054ceed1e7730398618ca8ffff Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Thu, 11 Oct 2018 09:02:38 +0100 Subject: [PATCH 067/277] Issue #16: added a Python script stub for checking multi-threading reliability --- .../multithreading_reliability_check.py | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100755 src/tests/pipeline/multithreading_reliability_check.py diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py new file mode 100755 index 00000000..c6729066 --- /dev/null +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from pygiftgrab import (VideoSourceFactory, + ColourSpace, + IObservableObserver) + +""" +This script provides a multi-threading reliability check. +The background is issue #16. It looks like in applications +where multiple Python threads are involved, occasionally +the acquisition of the Global Interpreter Lock leads to a +deadlocks, which crashes the whole application with a +non-specific segmentation fault. + +In this script we run a number of multi-threaded GIFT-Grab +pipelines, which should serve as a validation that this +problem is fixed. +""" + +if __name__ == '__main__': + print('multithreading reliability check script') From 559b95508d017daac15445daa24443cfed5dbb79 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Thu, 11 Oct 2018 09:03:41 +0100 Subject: [PATCH 068/277] Issue #16: added a Bash script for building GIFT-Grab and subsequently running the multi-threading reliability check script --- .gitignore | 1 + .../check_multithreading_reliability.sh | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100755 src/tests/pipeline/check_multithreading_reliability.sh diff --git a/.gitignore b/.gitignore index 08b31459..d7eb0905 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ src/build src/dist src/*.egg-info *.swp +src/tests/pipeline/mtr-build diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh new file mode 100755 index 00000000..b974bfa8 --- /dev/null +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +# -*- coding: utf-8 -*- + +# Build a basic GIFT-Grab capable of reading a video file, +# and encoding to a video file in real time, with Python +# and NumPy support. Subsequently run the multi-threading +# reliability check script. + +CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" +BUILD_DIR=$CURRENT_DIR/mtr-build +SOURCE_DIR="$( cd "$CURRENT_DIR/../.." >/dev/null && pwd )" +CMAKE_OPTS="-D USE_FILES=ON" +CMAKE_OPTS="$CMAKE_OPTS -D USE_HEVC=ON" +CMAKE_OPTS="$CMAKE_OPTS -D ENABLE_NONFREE=ON -D USE_NVENC=ON" +CMAKE_OPTS="$CMAKE_OPTS -D BUILD_PYTHON=ON -D USE_NUMPY=ON" +MTR_SCRIPT=$CURRENT_DIR/multithreading_reliability_check.py + +mkdir -p $BUILD_DIR +rm -rf $BUILD_DIR/* +cd $BUILD_DIR +cmake $CMAKE_OPTS $SOURCE_DIR +make -j4 +PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT From 21bd7c0f1b4f0f49e5e4222d3b22ccb734aac746 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 08:06:21 +0100 Subject: [PATCH 069/277] Issue #16: added a 'Dyer' processing node to multi-threading reliability checker --- .../pipeline/multithreading_reliability_check.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index c6729066..7aa1fc0d 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -18,5 +18,20 @@ problem is fixed. """ + +class Dyer(IObservableObserver): + + def __init__(self, channel, value): + super(Dyer, self).__init__() + assert 0 <= channel < 3 + assert 0 <= value < 256 + self.channel = channel + self.value = value + + def update(self, frame): + data = frame.data(True) + data[:, :, self.channel] = self.value + + if __name__ == '__main__': print('multithreading reliability check script') From 7b7e8ced9678d5933d1efac9902c8fdfa5c41c31 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 08:28:08 +0100 Subject: [PATCH 070/277] Issue #16: Python script now uses CLI argument for input file --- .../pipeline/check_multithreading_reliability.sh | 2 +- .../pipeline/multithreading_reliability_check.py | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index b974bfa8..efae4d95 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -20,4 +20,4 @@ rm -rf $BUILD_DIR/* cd $BUILD_DIR cmake $CMAKE_OPTS $SOURCE_DIR make -j4 -PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT +PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT --input $1 diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 7aa1fc0d..02982cf7 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -1,6 +1,8 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +import argparse +import os.path from pygiftgrab import (VideoSourceFactory, ColourSpace, IObservableObserver) @@ -34,4 +36,14 @@ def update(self, frame): if __name__ == '__main__': - print('multithreading reliability check script') + parser = argparse.ArgumentParser() + parser.add_argument('-i', '--input', type=str, required=True, + metavar='VIDEO_FILE', + help='Input video file (HEVC-encoded MP4)') + args = parser.parse_args() + in_file = args.input + + filename = os.path.basename(in_file) + filename, ext = os.path.splitext(filename) + assert filename + assert ext == '.mp4' From da1a82d98eaaed478f9f084df91a09a5edc33d1a Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 08:32:30 +0100 Subject: [PATCH 071/277] Issue #16: added multi-node pipeline producing red- and yellow-dyed output --- .../multithreading_reliability_check.py | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 02982cf7..01c4ead3 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -1,11 +1,12 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +from time import sleep import argparse import os.path from pygiftgrab import (VideoSourceFactory, - ColourSpace, - IObservableObserver) + ColourSpace, IObservableObserver, + VideoTargetFactory, Codec) """ This script provides a multi-threading reliability check. @@ -47,3 +48,29 @@ def update(self, frame): filename, ext = os.path.splitext(filename) assert filename assert ext == '.mp4' + + sfac = VideoSourceFactory.get_instance() + reader = sfac.create_file_reader(in_file, ColourSpace.BGRA) + + tfac = VideoTargetFactory.get_instance() + frame_rate = reader.get_frame_rate() + + red = Dyer(2, 127) + green = Dyer(1, 191) + + red_file = os.path.join('.', ''.join([filename, '-red', ext])) + red_writer = tfac.create_file_writer(Codec.HEVC, red_file, frame_rate) + yellow_file = os.path.join('.', ''.join([filename, '-yellow', ext])) + yellow_writer = tfac.create_file_writer(Codec.HEVC, yellow_file, frame_rate) + + reader.attach(red) + red.attach(red_writer) + red.attach(green) + green.attach(yellow_writer) + + sleep(20) # operate pipeline for 20 sec + + reader.detach(red) + red.detach(red_writer) + red.detach(green) + green.detach(yellow_writer) From e63d5e3f7b4efaa7fd977954fefc376a5f7a583a Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 09:09:08 +0100 Subject: [PATCH 072/277] Issue #16: added a threaded Histogrammer class stub --- .../multithreading_reliability_check.py | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 01c4ead3..c1ba3b48 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -4,6 +4,7 @@ from time import sleep import argparse import os.path +import threading from pygiftgrab import (VideoSourceFactory, ColourSpace, IObservableObserver, VideoTargetFactory, Codec) @@ -22,6 +23,30 @@ """ +buffer = None +lock = threading.Lock() + + +class Histogrammer(threading.Thread, IObservableObserver): + + def __init__(self, channel): + super(Histogrammer, self).__init__() + assert 0 <= channel < 3 + self.channel = channel + self.running = False + + def run(self): + if self.running: + return + + pass + + def stop(self): + self.running = False + + def update(self, frame): + pass + class Dyer(IObservableObserver): def __init__(self, channel, value): @@ -57,6 +82,8 @@ def update(self, frame): red = Dyer(2, 127) green = Dyer(1, 191) + hist = Histogrammer(0) + hist.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) red_writer = tfac.create_file_writer(Codec.HEVC, red_file, frame_rate) @@ -69,6 +96,7 @@ def update(self, frame): green.attach(yellow_writer) sleep(20) # operate pipeline for 20 sec + hist.stop() reader.detach(red) red.detach(red_writer) From e9bebfc5b1a08ea3b61da395fefe830c48bf4937 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 09:12:38 +0100 Subject: [PATCH 073/277] Issue #16: added dummy print statement to see Histogrammer is alive --- src/tests/pipeline/multithreading_reliability_check.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index c1ba3b48..4dd459a1 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -40,6 +40,10 @@ def run(self): return pass + self.running = True + while self.running: + print('Running') + sleep(0.100) def stop(self): self.running = False From 7395cbd13722c582f195bc7b34124eef29ebc1f9 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 09:57:57 +0100 Subject: [PATCH 074/277] Issue #16: factored Histogrammer stub out to HistogrammerRed and BuffererRed --- .../multithreading_reliability_check.py | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 4dd459a1..12a467bb 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -23,33 +23,40 @@ """ -buffer = None +buffer_red = None lock = threading.Lock() -class Histogrammer(threading.Thread, IObservableObserver): +class BuffererRed(IObservableObserver): - def __init__(self, channel): - super(Histogrammer, self).__init__() - assert 0 <= channel < 3 - self.channel = channel + def __init__(self): + super(BuffererRed, self).__init__() + + def update(self, frame): + global buffer_red + # TODO + + +class HistogrammerRed(threading.Thread): + + def __init__(self): + super(HistogrammerRed, self).__init__() self.running = False def run(self): if self.running: return - pass + # TODO self.running = True while self.running: print('Running') + # TODO sleep(0.100) def stop(self): self.running = False - def update(self, frame): - pass class Dyer(IObservableObserver): @@ -86,7 +93,7 @@ def update(self, frame): red = Dyer(2, 127) green = Dyer(1, 191) - hist = Histogrammer(0) + hist = HistogrammerRed() hist.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) From e54ed8906f01e61d6b6f25763b186bdc6e747fe1 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 09:59:41 +0100 Subject: [PATCH 075/277] Issue #16: implemented update of BuffererRed --- src/tests/pipeline/multithreading_reliability_check.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 12a467bb..aa8eb0dd 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -5,6 +5,7 @@ import argparse import os.path import threading +import numpy as np from pygiftgrab import (VideoSourceFactory, ColourSpace, IObservableObserver, VideoTargetFactory, Codec) @@ -34,7 +35,12 @@ def __init__(self): def update(self, frame): global buffer_red - # TODO + with lock: + data = frame.data(True) + if buffer_red is None: + buffer_red = np.copy(data) + else: + buffer_red[:, :, :] = data[:, :, :] class HistogrammerRed(threading.Thread): From 0851be6d1cdbc52a599c6c06b32b342e31f5afe2 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 10:06:55 +0100 Subject: [PATCH 076/277] Issue #16: implemented run of HistogrammerRed --- src/tests/pipeline/multithreading_reliability_check.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index aa8eb0dd..54ceb230 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -53,11 +53,15 @@ def run(self): if self.running: return - # TODO + global buffer_red + histogram = None self.running = True while self.running: - print('Running') - # TODO + with lock: + if buffer_red is not None: + histogram = np.histogram(buffer_red[:, :, 2], + bins=8, range=(0, 256)) + print(histogram) sleep(0.100) def stop(self): From 3b40ef0808d1d4777420488e949f981e2e417019 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 10:11:05 +0100 Subject: [PATCH 077/277] Issue #16: renamed Dyer vars for clarity --- .../multithreading_reliability_check.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 54ceb230..ff1fda67 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -101,8 +101,8 @@ def update(self, frame): tfac = VideoTargetFactory.get_instance() frame_rate = reader.get_frame_rate() - red = Dyer(2, 127) - green = Dyer(1, 191) + red_dyer = Dyer(2, 127) + green_dyer = Dyer(1, 191) hist = HistogrammerRed() hist.start() @@ -111,15 +111,15 @@ def update(self, frame): yellow_file = os.path.join('.', ''.join([filename, '-yellow', ext])) yellow_writer = tfac.create_file_writer(Codec.HEVC, yellow_file, frame_rate) - reader.attach(red) - red.attach(red_writer) - red.attach(green) - green.attach(yellow_writer) + reader.attach(red_dyer) + red_dyer.attach(red_writer) + red_dyer.attach(green_dyer) + green_dyer.attach(yellow_writer) sleep(20) # operate pipeline for 20 sec hist.stop() - reader.detach(red) - red.detach(red_writer) - red.detach(green) - green.detach(yellow_writer) + reader.detach(red_dyer) + red_dyer.detach(red_writer) + red_dyer.detach(green_dyer) + green_dyer.detach(yellow_writer) From a05de379b64dfd03b80a1da11fb77f1bdd141b1a Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 10:19:12 +0100 Subject: [PATCH 078/277] Issue #16: Dyer.update uses lock --- src/tests/pipeline/multithreading_reliability_check.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index ff1fda67..ee40fea7 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -78,8 +78,9 @@ def __init__(self, channel, value): self.value = value def update(self, frame): - data = frame.data(True) - data[:, :, self.channel] = self.value + with lock: + data = frame.data(True) + data[:, :, self.channel] = self.value if __name__ == '__main__': From 41bb484d3ebcc4f9d0f8dcb4c247735de3c705e2 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 10:20:32 +0100 Subject: [PATCH 079/277] Issue #16: inserted a red bufferer into the pipeline --- src/tests/pipeline/multithreading_reliability_check.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index ee40fea7..dd0f0dcf 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -104,6 +104,9 @@ def update(self, frame): red_dyer = Dyer(2, 127) green_dyer = Dyer(1, 191) + + bufferer_red = BuffererRed() + hist = HistogrammerRed() hist.start() @@ -114,6 +117,7 @@ def update(self, frame): reader.attach(red_dyer) red_dyer.attach(red_writer) + red_dyer.attach(bufferer_red) red_dyer.attach(green_dyer) green_dyer.attach(yellow_writer) @@ -122,5 +126,6 @@ def update(self, frame): reader.detach(red_dyer) red_dyer.detach(red_writer) + red_dyer.detach(bufferer_red) red_dyer.detach(green_dyer) green_dyer.detach(yellow_writer) From 1855e357912539e5f81db019940cafc8fdf6384c Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 10:22:03 +0100 Subject: [PATCH 080/277] Issue #16: fixed call to histogram function --- src/tests/pipeline/multithreading_reliability_check.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index dd0f0dcf..0987129b 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -59,8 +59,9 @@ def run(self): while self.running: with lock: if buffer_red is not None: - histogram = np.histogram(buffer_red[:, :, 2], - bins=8, range=(0, 256)) + histogram, _ = np.histogram( + buffer_red[:, :, 2], bins=8, range=(0, 256) + ) print(histogram) sleep(0.100) From 6c468c9b064e72ac0b8327ef47e14d51bf5150e2 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 10:32:24 +0100 Subject: [PATCH 081/277] Issue #16: Dyer now really dyes instead of fixing color to a value --- src/tests/pipeline/multithreading_reliability_check.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 0987129b..54802904 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -71,17 +71,18 @@ def stop(self): class Dyer(IObservableObserver): - def __init__(self, channel, value): + def __init__(self, channel, increment): super(Dyer, self).__init__() assert 0 <= channel < 3 - assert 0 <= value < 256 + assert 0 <= increment < 256 self.channel = channel - self.value = value + self.increment = increment def update(self, frame): with lock: data = frame.data(True) - data[:, :, self.channel] = self.value + channel_data = data[:, :, self.channel] + channel_data[channel_data < 255 - self.increment] += self.increment if __name__ == '__main__': From ae82811e40d7d89a459fb938312fa30b2adefbcf Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 10:53:49 +0100 Subject: [PATCH 082/277] Issue #16: histogrammer now displays a redness score instead of histogram --- .../pipeline/multithreading_reliability_check.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 54802904..d8bf97ed 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -54,15 +54,21 @@ def run(self): return global buffer_red - histogram = None + histogram, num_bins = None, 10 + redness_scale = np.array([i for i in range(1, num_bins + 1)], np.float) self.running = True while self.running: with lock: if buffer_red is not None: histogram, _ = np.histogram( - buffer_red[:, :, 2], bins=8, range=(0, 256) + buffer_red[:, :, 2], bins=num_bins, range=(0, 256) ) - print(histogram) + if histogram is not None: + redness = np.sum(histogram * redness_scale) + redness /= np.sum(histogram) + redness /= num_bins + redness *= 100 + print('Redness: {} %'.format(int(round(redness)))) sleep(0.100) def stop(self): From a571512e53c8d29ead300c3364f8305ce2776028 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 10:54:11 +0100 Subject: [PATCH 083/277] Issue #16: using more sensible values for dyeing --- src/tests/pipeline/multithreading_reliability_check.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index d8bf97ed..a024030b 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -110,8 +110,8 @@ def update(self, frame): tfac = VideoTargetFactory.get_instance() frame_rate = reader.get_frame_rate() - red_dyer = Dyer(2, 127) - green_dyer = Dyer(1, 191) + red_dyer = Dyer(2, 64) + green_dyer = Dyer(1, 64) bufferer_red = BuffererRed() From 42544f9809936b41838406947bcc8e39f22dc81e Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 10:59:42 +0100 Subject: [PATCH 084/277] Issue #16: added a BuffererOrig class, a virtual replica of BuffererRed --- .../multithreading_reliability_check.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index a024030b..7b497725 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -24,7 +24,7 @@ """ -buffer_red = None +buffer_red, buffer_orig = None, None lock = threading.Lock() @@ -43,6 +43,21 @@ def update(self, frame): buffer_red[:, :, :] = data[:, :, :] +class BuffererOrig(IObservableObserver): + + def __init__(self): + super(BuffererOrig, self).__init__() + + def update(self, frame): + global buffer_orig + with lock: + data = frame.data(True) + if buffer_orig is None: + buffer_orig = np.copy(data) + else: + buffer_red[:, :, :] = data[:, :, :] + + class HistogrammerRed(threading.Thread): def __init__(self): From 59bf5b2eeb9e9635bca79e444989f795d0b73c38 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:03:50 +0100 Subject: [PATCH 085/277] Issue #16: BuffererRed now takes buffer as parameter to constructor instead of using global var --- .../multithreading_reliability_check.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 7b497725..0ca024bc 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -6,7 +6,7 @@ import os.path import threading import numpy as np -from pygiftgrab import (VideoSourceFactory, +from pygiftgrab import (VideoSourceFactory, VideoFrame, ColourSpace, IObservableObserver, VideoTargetFactory, Codec) @@ -30,17 +30,14 @@ class BuffererRed(IObservableObserver): - def __init__(self): + def __init__(self, buffer): super(BuffererRed, self).__init__() + self.buffer = buffer def update(self, frame): - global buffer_red with lock: data = frame.data(True) - if buffer_red is None: - buffer_red = np.copy(data) - else: - buffer_red[:, :, :] = data[:, :, :] + self.buffer[:, :, :] = data[:, :, :] class BuffererOrig(IObservableObserver): @@ -121,6 +118,9 @@ def update(self, frame): sfac = VideoSourceFactory.get_instance() reader = sfac.create_file_reader(in_file, ColourSpace.BGRA) + frame = VideoFrame(ColourSpace.BGRA, False) + reader.get_frame(frame) + frame_shape = (frame.rows(), frame.cols(), 4) tfac = VideoTargetFactory.get_instance() frame_rate = reader.get_frame_rate() @@ -128,7 +128,8 @@ def update(self, frame): red_dyer = Dyer(2, 64) green_dyer = Dyer(1, 64) - bufferer_red = BuffererRed() + buffer_red = np.zeros(frame_shape, np.uint8) + bufferer_red = BuffererRed(buffer_red) hist = HistogrammerRed() hist.start() From f436ed71a9c94735ffae8a3fa21f015d4e7cb80a Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:10:43 +0100 Subject: [PATCH 086/277] Revert "Issue #16: added a BuffererOrig class, a virtual replica of BuffererRed" This reverts commit 053f499ae6554460df9a755067e1ff5ec817a247. --- .../multithreading_reliability_check.py | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 0ca024bc..8aed9c85 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -24,7 +24,7 @@ """ -buffer_red, buffer_orig = None, None +buffer_red = None lock = threading.Lock() @@ -40,21 +40,6 @@ def update(self, frame): self.buffer[:, :, :] = data[:, :, :] -class BuffererOrig(IObservableObserver): - - def __init__(self): - super(BuffererOrig, self).__init__() - - def update(self, frame): - global buffer_orig - with lock: - data = frame.data(True) - if buffer_orig is None: - buffer_orig = np.copy(data) - else: - buffer_red[:, :, :] = data[:, :, :] - - class HistogrammerRed(threading.Thread): def __init__(self): From db0527fa773b561176ea4ee634915ed81396d2ed Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:12:15 +0100 Subject: [PATCH 087/277] Issue #16: renamed BuffererRed => Bufferer --- src/tests/pipeline/multithreading_reliability_check.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 8aed9c85..a345dfd6 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -28,10 +28,10 @@ lock = threading.Lock() -class BuffererRed(IObservableObserver): +class Bufferer(IObservableObserver): def __init__(self, buffer): - super(BuffererRed, self).__init__() + super(Bufferer, self).__init__() self.buffer = buffer def update(self, frame): @@ -114,7 +114,7 @@ def update(self, frame): green_dyer = Dyer(1, 64) buffer_red = np.zeros(frame_shape, np.uint8) - bufferer_red = BuffererRed(buffer_red) + bufferer_red = Bufferer(buffer_red) hist = HistogrammerRed() hist.start() From 85db3b3a91520b8ecbb21289149828b054e1ea4c Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:15:02 +0100 Subject: [PATCH 088/277] Issue #16: HistogrammerRed now takes buffer as a constructor argument rather than using global var --- .../pipeline/multithreading_reliability_check.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index a345dfd6..4a58d7bb 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -42,24 +42,23 @@ def update(self, frame): class HistogrammerRed(threading.Thread): - def __init__(self): + def __init__(self, buffer): super(HistogrammerRed, self).__init__() + self.buffer = buffer self.running = False def run(self): if self.running: return - global buffer_red histogram, num_bins = None, 10 redness_scale = np.array([i for i in range(1, num_bins + 1)], np.float) self.running = True while self.running: with lock: - if buffer_red is not None: - histogram, _ = np.histogram( - buffer_red[:, :, 2], bins=num_bins, range=(0, 256) - ) + histogram, _ = np.histogram( + self.buffer[:, :, 2], bins=num_bins, range=(0, 256) + ) if histogram is not None: redness = np.sum(histogram * redness_scale) redness /= np.sum(histogram) @@ -116,7 +115,7 @@ def update(self, frame): buffer_red = np.zeros(frame_shape, np.uint8) bufferer_red = Bufferer(buffer_red) - hist = HistogrammerRed() + hist = HistogrammerRed(buffer_red) hist.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) From 1105daacf93b3564840845a527ebcb76a7f58cad Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:22:12 +0100 Subject: [PATCH 089/277] Issue #16: HistogrammerRed is now generic Histogrammer --- .../multithreading_reliability_check.py | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 4a58d7bb..0de913ed 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -40,10 +40,14 @@ def update(self, frame): self.buffer[:, :, :] = data[:, :, :] -class HistogrammerRed(threading.Thread): +class Histogrammer(threading.Thread): - def __init__(self, buffer): - super(HistogrammerRed, self).__init__() + channels = ('Blue', 'Green', 'Red', 'Alpha') + + def __init__(self, buffer, channel): + super(Histogrammer, self).__init__() + assert channel in range(3) + self.channel = channel self.buffer = buffer self.running = False @@ -52,7 +56,7 @@ def run(self): return histogram, num_bins = None, 10 - redness_scale = np.array([i for i in range(1, num_bins + 1)], np.float) + scale = np.array([i for i in range(1, num_bins + 1)], np.float) self.running = True while self.running: with lock: @@ -60,11 +64,13 @@ def run(self): self.buffer[:, :, 2], bins=num_bins, range=(0, 256) ) if histogram is not None: - redness = np.sum(histogram * redness_scale) - redness /= np.sum(histogram) - redness /= num_bins - redness *= 100 - print('Redness: {} %'.format(int(round(redness)))) + coloredness = np.sum(histogram * scale) + coloredness /= np.sum(histogram) + coloredness /= num_bins + coloredness *= 100 + print('{}ness of dyed image: {} %'.format( + Histogrammer.channels[self.channel], int(round(coloredness)) + )) sleep(0.100) def stop(self): @@ -115,7 +121,7 @@ def update(self, frame): buffer_red = np.zeros(frame_shape, np.uint8) bufferer_red = Bufferer(buffer_red) - hist = HistogrammerRed(buffer_red) + hist = Histogrammer(buffer_red, 2) hist.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) From 0b9296a1f449017f3bce1a41c4a222799f7c5e63 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:27:00 +0100 Subject: [PATCH 090/277] Issue #16: Histogrammer now accepts a tag for generically printing what the image is --- src/tests/pipeline/multithreading_reliability_check.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 0de913ed..168b6b9f 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -44,11 +44,12 @@ class Histogrammer(threading.Thread): channels = ('Blue', 'Green', 'Red', 'Alpha') - def __init__(self, buffer, channel): + def __init__(self, buffer, channel, tag): super(Histogrammer, self).__init__() assert channel in range(3) self.channel = channel self.buffer = buffer + self.tag = tag self.running = False def run(self): @@ -68,8 +69,8 @@ def run(self): coloredness /= np.sum(histogram) coloredness /= num_bins coloredness *= 100 - print('{}ness of dyed image: {} %'.format( - Histogrammer.channels[self.channel], int(round(coloredness)) + print('{}ness of {} image: {} %'.format( + Histogrammer.channels[self.channel], self.tag, int(round(coloredness)) )) sleep(0.100) @@ -121,7 +122,7 @@ def update(self, frame): buffer_red = np.zeros(frame_shape, np.uint8) bufferer_red = Bufferer(buffer_red) - hist = Histogrammer(buffer_red, 2) + hist = Histogrammer(buffer_red, 2, 'red-dyed') hist.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) From 5b0e52117dca89d46a99b8adeae450c2e4f52881 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:34:30 +0100 Subject: [PATCH 091/277] Issue #16: inserted an original image histogrammer into the pipeline --- .../multithreading_reliability_check.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 168b6b9f..971e94b2 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -24,7 +24,7 @@ """ -buffer_red = None +buffer_red, buffer_orig = None, None lock = threading.Lock() @@ -121,25 +121,32 @@ def update(self, frame): buffer_red = np.zeros(frame_shape, np.uint8) bufferer_red = Bufferer(buffer_red) + buffer_orig = np.zeros_like(buffer_red) + bufferer_orig = Bufferer(buffer_orig) - hist = Histogrammer(buffer_red, 2, 'red-dyed') - hist.start() + hist_red = Histogrammer(buffer_red, 2, 'red-dyed') + hist_red.start() + hist_orig = Histogrammer(buffer_orig, 2, 'original') + hist_orig.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) red_writer = tfac.create_file_writer(Codec.HEVC, red_file, frame_rate) yellow_file = os.path.join('.', ''.join([filename, '-yellow', ext])) yellow_writer = tfac.create_file_writer(Codec.HEVC, yellow_file, frame_rate) - reader.attach(red_dyer) + reader.attach(bufferer_orig) + bufferer_orig.attach(red_dyer) red_dyer.attach(red_writer) red_dyer.attach(bufferer_red) red_dyer.attach(green_dyer) green_dyer.attach(yellow_writer) sleep(20) # operate pipeline for 20 sec - hist.stop() + hist_red.stop() + hist_orig.stop() - reader.detach(red_dyer) + reader.detach(bufferer_orig) + bufferer_orig.detach(red_dyer) red_dyer.detach(red_writer) red_dyer.detach(bufferer_red) red_dyer.detach(green_dyer) From 682dae16daafce89efce95e62569bed75d462529 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:39:33 +0100 Subject: [PATCH 092/277] Issue #16: Histogrammer now accepts a frame rate and flag for displaying coloredness --- .../multithreading_reliability_check.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 971e94b2..df093c13 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -44,12 +44,15 @@ class Histogrammer(threading.Thread): channels = ('Blue', 'Green', 'Red', 'Alpha') - def __init__(self, buffer, channel, tag): + def __init__(self, buffer, channel, tag, frame_rate, show=True): super(Histogrammer, self).__init__() assert channel in range(3) + assert 0 < frame_rate <= 60 self.channel = channel self.buffer = buffer self.tag = tag + self.show = show + self.sleep_interval = 1.0 / frame_rate self.running = False def run(self): @@ -69,10 +72,12 @@ def run(self): coloredness /= np.sum(histogram) coloredness /= num_bins coloredness *= 100 - print('{}ness of {} image: {} %'.format( - Histogrammer.channels[self.channel], self.tag, int(round(coloredness)) - )) - sleep(0.100) + if self.show: + print('{}ness of {} image: {} %'.format( + Histogrammer.channels[self.channel], + self.tag, int(round(coloredness)) + )) + sleep(self.sleep_interval) def stop(self): self.running = False @@ -124,9 +129,9 @@ def update(self, frame): buffer_orig = np.zeros_like(buffer_red) bufferer_orig = Bufferer(buffer_orig) - hist_red = Histogrammer(buffer_red, 2, 'red-dyed') + hist_red = Histogrammer(buffer_red, 2, 'red-dyed', 30, False) hist_red.start() - hist_orig = Histogrammer(buffer_orig, 2, 'original') + hist_orig = Histogrammer(buffer_orig, 2, 'original', 30, False) hist_orig.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) From decbde60935fa97c079bf77912c3136448465f3d Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:45:12 +0100 Subject: [PATCH 093/277] Issue #16: now can specify the frequency of coloredness prints --- .../pipeline/multithreading_reliability_check.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index df093c13..43e82a19 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -44,14 +44,16 @@ class Histogrammer(threading.Thread): channels = ('Blue', 'Green', 'Red', 'Alpha') - def __init__(self, buffer, channel, tag, frame_rate, show=True): + def __init__(self, buffer, channel, tag, frame_rate, display_freq): super(Histogrammer, self).__init__() assert channel in range(3) assert 0 < frame_rate <= 60 + assert 0 <= display_freq self.channel = channel self.buffer = buffer self.tag = tag - self.show = show + self.display_freq = display_freq + self.num_skipped = 0 self.sleep_interval = 1.0 / frame_rate self.running = False @@ -72,11 +74,14 @@ def run(self): coloredness /= np.sum(histogram) coloredness /= num_bins coloredness *= 100 - if self.show: + if self.num_skipped >= self.display_freq: print('{}ness of {} image: {} %'.format( Histogrammer.channels[self.channel], self.tag, int(round(coloredness)) )) + self.num_skipped = 0 + else: + self.num_skipped += 1 sleep(self.sleep_interval) def stop(self): @@ -129,9 +134,9 @@ def update(self, frame): buffer_orig = np.zeros_like(buffer_red) bufferer_orig = Bufferer(buffer_orig) - hist_red = Histogrammer(buffer_red, 2, 'red-dyed', 30, False) + hist_red = Histogrammer(buffer_red, 2, 'red-dyed', 30.0, 10) hist_red.start() - hist_orig = Histogrammer(buffer_orig, 2, 'original', 30, False) + hist_orig = Histogrammer(buffer_orig, 2, 'original', 30.0, 10) hist_orig.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) From a6e4c34bd3ea95cfeae3eddd853e93dc9d4db96b Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:47:38 +0100 Subject: [PATCH 094/277] Issue #16: dyeing red more prominently --- src/tests/pipeline/multithreading_reliability_check.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 43e82a19..72ab94d2 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -126,7 +126,7 @@ def update(self, frame): tfac = VideoTargetFactory.get_instance() frame_rate = reader.get_frame_rate() - red_dyer = Dyer(2, 64) + red_dyer = Dyer(2, 128) green_dyer = Dyer(1, 64) buffer_red = np.zeros(frame_shape, np.uint8) From e544b48f9ff4d26be36430439a88e7fa71728931 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:53:47 +0100 Subject: [PATCH 095/277] Issue #16: frame rate values that reproduced the problem --- src/tests/pipeline/multithreading_reliability_check.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 72ab94d2..42cc36e3 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -134,9 +134,9 @@ def update(self, frame): buffer_orig = np.zeros_like(buffer_red) bufferer_orig = Bufferer(buffer_orig) - hist_red = Histogrammer(buffer_red, 2, 'red-dyed', 30.0, 10) + hist_red = Histogrammer(buffer_red, 2, 'red-dyed', 60.0, 10) hist_red.start() - hist_orig = Histogrammer(buffer_orig, 2, 'original', 30.0, 10) + hist_orig = Histogrammer(buffer_orig, 2, 'original', 50.0, 10) hist_orig.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) From 1446b97a43296c4899fff458a067ee22881e4957 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:54:25 +0100 Subject: [PATCH 096/277] Issue #16: using Debug CMake type in build script --- src/tests/pipeline/check_multithreading_reliability.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index efae4d95..7ea874b2 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -13,6 +13,7 @@ CMAKE_OPTS="-D USE_FILES=ON" CMAKE_OPTS="$CMAKE_OPTS -D USE_HEVC=ON" CMAKE_OPTS="$CMAKE_OPTS -D ENABLE_NONFREE=ON -D USE_NVENC=ON" CMAKE_OPTS="$CMAKE_OPTS -D BUILD_PYTHON=ON -D USE_NUMPY=ON" +CMAKE_OPTS="$CMAKE_OPTS -D CMAKE_BUILD_TYPE=Debug" MTR_SCRIPT=$CURRENT_DIR/multithreading_reliability_check.py mkdir -p $BUILD_DIR From 0b0398b5d517b5b922f43eb8c664cfb9924f9b48 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 08:28:50 +0100 Subject: [PATCH 097/277] Issue #16: renamed variable for clarity in run script --- src/tests/pipeline/check_multithreading_reliability.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 7ea874b2..2be8fea2 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -6,15 +6,15 @@ # and NumPy support. Subsequently run the multi-threading # reliability check script. -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" -BUILD_DIR=$CURRENT_DIR/mtr-build -SOURCE_DIR="$( cd "$CURRENT_DIR/../.." >/dev/null && pwd )" +ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" +BUILD_DIR=$ROOT_DIR/mtr-build +SOURCE_DIR="$( cd "$ROOT_DIR/../.." >/dev/null && pwd )" CMAKE_OPTS="-D USE_FILES=ON" CMAKE_OPTS="$CMAKE_OPTS -D USE_HEVC=ON" CMAKE_OPTS="$CMAKE_OPTS -D ENABLE_NONFREE=ON -D USE_NVENC=ON" CMAKE_OPTS="$CMAKE_OPTS -D BUILD_PYTHON=ON -D USE_NUMPY=ON" CMAKE_OPTS="$CMAKE_OPTS -D CMAKE_BUILD_TYPE=Debug" -MTR_SCRIPT=$CURRENT_DIR/multithreading_reliability_check.py +MTR_SCRIPT=$ROOT_DIR/multithreading_reliability_check.py mkdir -p $BUILD_DIR rm -rf $BUILD_DIR/* From 171ed86de698e1a84babe41b0f443047de0853a5 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 09:00:44 +0100 Subject: [PATCH 098/277] Issue #16: setting ulimit to dump cores when running check --- src/tests/pipeline/check_multithreading_reliability.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 2be8fea2..4519cb84 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -15,6 +15,7 @@ CMAKE_OPTS="$CMAKE_OPTS -D ENABLE_NONFREE=ON -D USE_NVENC=ON" CMAKE_OPTS="$CMAKE_OPTS -D BUILD_PYTHON=ON -D USE_NUMPY=ON" CMAKE_OPTS="$CMAKE_OPTS -D CMAKE_BUILD_TYPE=Debug" MTR_SCRIPT=$ROOT_DIR/multithreading_reliability_check.py +ulimit -c unlimited mkdir -p $BUILD_DIR rm -rf $BUILD_DIR/* @@ -22,3 +23,5 @@ cd $BUILD_DIR cmake $CMAKE_OPTS $SOURCE_DIR make -j4 PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT --input $1 + +ulimit -c 0 From 382c77a257b1084b31da4a7423c1d1759fe2044f Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 09:02:44 +0100 Subject: [PATCH 099/277] Issue #16: saving all output in a hierarchical session directory --- .../pipeline/check_multithreading_reliability.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 4519cb84..f3cc6910 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -15,13 +15,26 @@ CMAKE_OPTS="$CMAKE_OPTS -D ENABLE_NONFREE=ON -D USE_NVENC=ON" CMAKE_OPTS="$CMAKE_OPTS -D BUILD_PYTHON=ON -D USE_NUMPY=ON" CMAKE_OPTS="$CMAKE_OPTS -D CMAKE_BUILD_TYPE=Debug" MTR_SCRIPT=$ROOT_DIR/multithreading_reliability_check.py +SESSION_DIR=$ROOT_DIR/$(date +"%Y-%m-%d-%H-%M-%S") +mkdir $SESSION_DIR ulimit -c unlimited +BUILD_LOG=$SESSION_DIR/build.log +{ mkdir -p $BUILD_DIR rm -rf $BUILD_DIR/* cd $BUILD_DIR cmake $CMAKE_OPTS $SOURCE_DIR make -j4 +} > $BUILD_LOG 2>&1 + +run_no=1 +WORKING_DIR=$SESSION_DIR/$run_no +mkdir $WORKING_DIR +cd $WORKING_DIR +RUN_LOG=$WORKING_DIR/run.log +{ PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT --input $1 +} > $RUN_LOG 2>&1 ulimit -c 0 From 84b4757129ebf3aa38fcab1d3eb52d847e7c01a9 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 09:05:12 +0100 Subject: [PATCH 100/277] Issue #16: added indentation for readability --- .../pipeline/check_multithreading_reliability.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index f3cc6910..71e9efc0 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -21,11 +21,11 @@ ulimit -c unlimited BUILD_LOG=$SESSION_DIR/build.log { -mkdir -p $BUILD_DIR -rm -rf $BUILD_DIR/* -cd $BUILD_DIR -cmake $CMAKE_OPTS $SOURCE_DIR -make -j4 + mkdir -p $BUILD_DIR + rm -rf $BUILD_DIR/* + cd $BUILD_DIR + cmake $CMAKE_OPTS $SOURCE_DIR + make -j4 } > $BUILD_LOG 2>&1 run_no=1 @@ -34,7 +34,7 @@ mkdir $WORKING_DIR cd $WORKING_DIR RUN_LOG=$WORKING_DIR/run.log { -PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT --input $1 + PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT --input $1 } > $RUN_LOG 2>&1 ulimit -c 0 From 6736a2412736d391a3738edbebd7a8cefe50cb8c Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 09:14:47 +0100 Subject: [PATCH 101/277] Issue #16: can now specify number of reps in check script --- .../check_multithreading_reliability.sh | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 71e9efc0..52eed368 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -28,13 +28,20 @@ BUILD_LOG=$SESSION_DIR/build.log make -j4 } > $BUILD_LOG 2>&1 -run_no=1 -WORKING_DIR=$SESSION_DIR/$run_no -mkdir $WORKING_DIR -cd $WORKING_DIR -RUN_LOG=$WORKING_DIR/run.log -{ - PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT --input $1 -} > $RUN_LOG 2>&1 +num_reps=1 +if [ $# -ge 2 ]; +then + num_reps=$2 +fi +for run_no in `seq 1 $num_reps`; +do + WORKING_DIR=$SESSION_DIR/$(printf "%03d" $run_no) + mkdir $WORKING_DIR + cd $WORKING_DIR + RUN_LOG=$WORKING_DIR/run.log + { + PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT --input $1 + } > $RUN_LOG 2>&1 +done ulimit -c 0 From f1c5d657ecb6a8afb91b16a12ff7dea358cd4fd7 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 10:38:52 +0100 Subject: [PATCH 102/277] Issue #16: can now optionally specify root output dir (e.g. not to fill up disk space) --- .../pipeline/check_multithreading_reliability.sh | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 52eed368..1a90362e 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -6,15 +6,22 @@ # and NumPy support. Subsequently run the multi-threading # reliability check script. -ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" +CALL_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" +SOURCE_DIR="$( cd "$CALL_DIR/../.." >/dev/null && pwd )" +MTR_SCRIPT=$SOURCE_DIR/tests/pipeline/multithreading_reliability_check.py +if [ $# -ge 3 ]; +then + ROOT_DIR=$3 +else + ROOT_DIR=$CALL_DIR +fi + BUILD_DIR=$ROOT_DIR/mtr-build -SOURCE_DIR="$( cd "$ROOT_DIR/../.." >/dev/null && pwd )" CMAKE_OPTS="-D USE_FILES=ON" CMAKE_OPTS="$CMAKE_OPTS -D USE_HEVC=ON" CMAKE_OPTS="$CMAKE_OPTS -D ENABLE_NONFREE=ON -D USE_NVENC=ON" CMAKE_OPTS="$CMAKE_OPTS -D BUILD_PYTHON=ON -D USE_NUMPY=ON" CMAKE_OPTS="$CMAKE_OPTS -D CMAKE_BUILD_TYPE=Debug" -MTR_SCRIPT=$ROOT_DIR/multithreading_reliability_check.py SESSION_DIR=$ROOT_DIR/$(date +"%Y-%m-%d-%H-%M-%S") mkdir $SESSION_DIR ulimit -c unlimited From bdd466b7955990ef3639dd73b7f95508a89ff8e1 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 10:48:37 +0100 Subject: [PATCH 103/277] Issue #16: logging frequency of exit codes as well --- .../pipeline/check_multithreading_reliability.sh | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 1a90362e..f7fbb5fe 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -40,6 +40,8 @@ if [ $# -ge 2 ]; then num_reps=$2 fi + +declare -a exit_code_freqs for run_no in `seq 1 $num_reps`; do WORKING_DIR=$SESSION_DIR/$(printf "%03d" $run_no) @@ -48,7 +50,21 @@ do RUN_LOG=$WORKING_DIR/run.log { PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT --input $1 + + exit_code=$? + echo "Exit code was: $exit_code" + freq=${exit_code_freqs[$exit_code]} + let freq=$freq+1 + exit_code_freqs[$exit_code]=$freq } > $RUN_LOG 2>&1 + + sleep 5 +done + +EXIT_CODES_LOG=$SESSION_DIR/exit-codes.csv +for exit_code in "${!exit_code_freqs[@]}"; +do + echo "$exit_code ${exit_code_freqs[$exit_code]}" >> $EXIT_CODES_LOG done ulimit -c 0 From 4f06fa905474b795a9a92627301aa5a275b30404 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 10:59:58 +0100 Subject: [PATCH 104/277] Issue #16: nicer formatting of exit code frequencies log --- src/tests/pipeline/check_multithreading_reliability.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index f7fbb5fe..419b7c08 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -62,9 +62,14 @@ do done EXIT_CODES_LOG=$SESSION_DIR/exit-codes.csv +printf "%10s" "exit-code" >> $EXIT_CODES_LOG +printf "%10s" "frequency" >> $EXIT_CODES_LOG +printf "\n" >> $EXIT_CODES_LOG for exit_code in "${!exit_code_freqs[@]}"; do - echo "$exit_code ${exit_code_freqs[$exit_code]}" >> $EXIT_CODES_LOG + printf "%10d" $exit_code >> $EXIT_CODES_LOG + printf "%10d" ${exit_code_freqs[$exit_code]} >> $EXIT_CODES_LOG + printf "\n" >> $EXIT_CODES_LOG done ulimit -c 0 From 90d10ac9df2cfb64db6ba39abbb9dd6566764bb5 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 11:02:37 +0100 Subject: [PATCH 105/277] Issue #16: ignoring output folder to avoid an accidental commit of big files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d7eb0905..35b7a77b 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ src/dist src/*.egg-info *.swp src/tests/pipeline/mtr-build +gg-iss-16 From ba7731be46a6dd976ef73deb64875e48d0051aae Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 11:06:29 +0100 Subject: [PATCH 106/277] Issue #16: using absolute path expansion if root-dir passed as a CLI param --- src/tests/pipeline/check_multithreading_reliability.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 419b7c08..18b9133e 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -11,7 +11,7 @@ SOURCE_DIR="$( cd "$CALL_DIR/../.." >/dev/null && pwd )" MTR_SCRIPT=$SOURCE_DIR/tests/pipeline/multithreading_reliability_check.py if [ $# -ge 3 ]; then - ROOT_DIR=$3 + ROOT_DIR="$( cd "$3" >/dev/null && pwd )" else ROOT_DIR=$CALL_DIR fi From 4f5dec2b908b89911b682ba83f8388cd724def1c Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 11:56:45 +0100 Subject: [PATCH 107/277] Issue #16: intermediately writing exit codes every 10 iterations --- .../check_multithreading_reliability.sh | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 18b9133e..64b58250 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -58,18 +58,21 @@ do exit_code_freqs[$exit_code]=$freq } > $RUN_LOG 2>&1 - sleep 5 -done + if [ $(($run_no % 10)) -eq 0 ] || [ $run_no -eq $num_reps ]; + then + EXIT_CODES_LOG=$SESSION_DIR/exit-codes-$run_no.csv + printf "%10s" "exit-code" >> $EXIT_CODES_LOG + printf "%10s" "frequency" >> $EXIT_CODES_LOG + printf "\n" >> $EXIT_CODES_LOG + for exit_code in "${!exit_code_freqs[@]}"; + do + printf "%10d" $exit_code >> $EXIT_CODES_LOG + printf "%10d" ${exit_code_freqs[$exit_code]} >> $EXIT_CODES_LOG + printf "\n" >> $EXIT_CODES_LOG + done + fi -EXIT_CODES_LOG=$SESSION_DIR/exit-codes.csv -printf "%10s" "exit-code" >> $EXIT_CODES_LOG -printf "%10s" "frequency" >> $EXIT_CODES_LOG -printf "\n" >> $EXIT_CODES_LOG -for exit_code in "${!exit_code_freqs[@]}"; -do - printf "%10d" $exit_code >> $EXIT_CODES_LOG - printf "%10d" ${exit_code_freqs[$exit_code]} >> $EXIT_CODES_LOG - printf "\n" >> $EXIT_CODES_LOG + sleep 5 done ulimit -c 0 From 46f2e79b496f13dda960dc5657b82206413d12e2 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 12:19:39 +0100 Subject: [PATCH 108/277] Issue #16: using git-describe to tag the output with the version used --- src/tests/pipeline/check_multithreading_reliability.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 64b58250..71e2bb62 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -28,6 +28,7 @@ ulimit -c unlimited BUILD_LOG=$SESSION_DIR/build.log { + git describe --dirty mkdir -p $BUILD_DIR rm -rf $BUILD_DIR/* cd $BUILD_DIR From 8096d0ae921c62feeed76bc446a55710e8076ce1 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 12:47:45 +0100 Subject: [PATCH 109/277] Issue #16: querying for update override after the acquisition of GIL --- src/python/wrapper.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/python/wrapper.cpp b/src/python/wrapper.cpp index ae1125de..f6651d9a 100644 --- a/src/python/wrapper.cpp +++ b/src/python/wrapper.cpp @@ -332,11 +332,13 @@ class IObservableObserverWrapper : public gg::IObservable void update(gg::VideoFrame & frame) { - if (override f = this->get_override("update")) { - VideoFrameNumPyWrapper wrapped_frame(&frame); gg::ScopedPythonGILLock gil_lock; - f(boost::ref(wrapped_frame)); + if (override f = this->get_override("update")) + { + VideoFrameNumPyWrapper wrapped_frame(&frame); + f(boost::ref(wrapped_frame)); + } } notify(frame); } From bddf3a9e0a741b11568c784ca37ef5df9dd58508 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 13:35:54 +0100 Subject: [PATCH 110/277] Issue #16: checking update method overridden in Python before actually calling it from within IObserverWrapper --- src/python/wrapper.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/python/wrapper.cpp b/src/python/wrapper.cpp index f6651d9a..11f7e72f 100644 --- a/src/python/wrapper.cpp +++ b/src/python/wrapper.cpp @@ -268,7 +268,8 @@ class IObserverWrapper : public gg::IObserver, public wrapper { gg::ScopedPythonGILLock gil_lock; VideoFrameNumPyWrapper wrapped_frame(&frame); - this->get_override("update")(boost::ref(wrapped_frame)); + if (override f = this->get_override("update")) + f(boost::ref(wrapped_frame)); } }; From 27c2dc169e57656b1d64175f0d4007296b575205 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 09:06:14 +0100 Subject: [PATCH 111/277] Issue #16: using Pythonic percentage formatting --- src/tests/pipeline/multithreading_reliability_check.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 42cc36e3..e1c50e30 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -73,11 +73,10 @@ def run(self): coloredness = np.sum(histogram * scale) coloredness /= np.sum(histogram) coloredness /= num_bins - coloredness *= 100 if self.num_skipped >= self.display_freq: - print('{}ness of {} image: {} %'.format( + print('{}ness of {} image: {:.0%}'.format( Histogrammer.channels[self.channel], - self.tag, int(round(coloredness)) + self.tag, coloredness )) self.num_skipped = 0 else: From ab70a44e944a15936b4a45a7ab2eb024217c1192 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 09:24:39 +0100 Subject: [PATCH 112/277] Issue #16: added a SnapshotSaver class that implements IObserver directly --- .../multithreading_reliability_check.py | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index e1c50e30..a880b355 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -6,9 +6,10 @@ import os.path import threading import numpy as np +import scipy.misc from pygiftgrab import (VideoSourceFactory, VideoFrame, ColourSpace, IObservableObserver, - VideoTargetFactory, Codec) + VideoTargetFactory, Codec, IObserver) """ This script provides a multi-threading reliability check. @@ -28,6 +29,32 @@ lock = threading.Lock() +class SnapshotSaver(IObserver): + """A snapshot saver for saving incoming frames to PNG files.""" + + def __init__(self, root_dir, frame_rate=0.2): + """ + Initialise a snapshot saver with a saving frequency. + + :param root_dir: the folder where to save the snapshots + :param frame_rate: saving frequency. The default value tells + the saver to save a frame every 5 sec. + """ + super(SnapshotSaver, self).__init__() + assert 0 < frame_rate <= 1 # to avoid flooding disk with images + self.save_freq = 1.0 / frame_rate + self.root_dir = root_dir + self.num_called = 0 + + def update(self, frame): + """Implement ``IObserver.update``.""" + self.num_called += 1 + if self.num_called % self.save_freq == 1: + out_file = os.path.join(self.root_dir, + 'frame-{:010d}.png'.format(self.num_called)) + scipy.misc.imsave(out_file, frame.data(True)) + + class Bufferer(IObservableObserver): def __init__(self, buffer): From 4009f1518e0780487ab8e0a383d44ecbf700247b Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 09:25:08 +0100 Subject: [PATCH 113/277] Issue #16: inserted snapshot saver into the pipeline --- src/tests/pipeline/multithreading_reliability_check.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index a880b355..f1a1697f 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -170,12 +170,15 @@ def update(self, frame): yellow_file = os.path.join('.', ''.join([filename, '-yellow', ext])) yellow_writer = tfac.create_file_writer(Codec.HEVC, yellow_file, frame_rate) + yellow_snapshots = SnapshotSaver('.') + reader.attach(bufferer_orig) bufferer_orig.attach(red_dyer) red_dyer.attach(red_writer) red_dyer.attach(bufferer_red) red_dyer.attach(green_dyer) green_dyer.attach(yellow_writer) + green_dyer.attach(yellow_snapshots) sleep(20) # operate pipeline for 20 sec hist_red.stop() @@ -187,3 +190,4 @@ def update(self, frame): red_dyer.detach(bufferer_red) red_dyer.detach(green_dyer) green_dyer.detach(yellow_writer) + green_dyer.detach(yellow_snapshots) From d318f78e9ca2c6c217f065bc6143a5816588cc43 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 09:47:20 +0100 Subject: [PATCH 114/277] Issue #16: fixed timed saving of snapshots --- .../multithreading_reliability_check.py | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index f1a1697f..7eca3382 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -from time import sleep +from time import (sleep, time) import argparse import os.path import threading @@ -32,27 +32,29 @@ class SnapshotSaver(IObserver): """A snapshot saver for saving incoming frames to PNG files.""" - def __init__(self, root_dir, frame_rate=0.2): + def __init__(self, root_dir, save_freq=5): """ Initialise a snapshot saver with a saving frequency. :param root_dir: the folder where to save the snapshots - :param frame_rate: saving frequency. The default value tells - the saver to save a frame every 5 sec. + :param save_freq: saving frequency. The default value tells + the saver to save every 5 seconds. """ super(SnapshotSaver, self).__init__() - assert 0 < frame_rate <= 1 # to avoid flooding disk with images - self.save_freq = 1.0 / frame_rate + assert 5 <= save_freq # to avoid flooding disk with images + self.save_freq = save_freq self.root_dir = root_dir - self.num_called = 0 + self.last_saved = time() + self.num_saved = 0 def update(self, frame): """Implement ``IObserver.update``.""" - self.num_called += 1 - if self.num_called % self.save_freq == 1: + if time() - self.last_saved >= self.save_freq: + self.num_saved += 1 out_file = os.path.join(self.root_dir, - 'frame-{:010d}.png'.format(self.num_called)) + 'frame-{:010d}.png'.format(self.num_saved)) scipy.misc.imsave(out_file, frame.data(True)) + self.last_saved = time() class Bufferer(IObservableObserver): From 9b57f8881ea497ffaa7eb81d005a128b32e54d65 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 10:10:24 +0100 Subject: [PATCH 115/277] Issue #16: renamed buffer => np_buffer as buffer is built-in type --- src/tests/pipeline/multithreading_reliability_check.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 7eca3382..0091b993 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -59,9 +59,9 @@ def update(self, frame): class Bufferer(IObservableObserver): - def __init__(self, buffer): + def __init__(self, np_buffer): super(Bufferer, self).__init__() - self.buffer = buffer + self.buffer = np_buffer def update(self, frame): with lock: @@ -73,13 +73,13 @@ class Histogrammer(threading.Thread): channels = ('Blue', 'Green', 'Red', 'Alpha') - def __init__(self, buffer, channel, tag, frame_rate, display_freq): + def __init__(self, np_buffer, channel, tag, frame_rate, display_freq): super(Histogrammer, self).__init__() assert channel in range(3) assert 0 < frame_rate <= 60 assert 0 <= display_freq self.channel = channel - self.buffer = buffer + self.buffer = np_buffer self.tag = tag self.display_freq = display_freq self.num_skipped = 0 From 1b119b048f01ef82094d5f8d6ed532b06ad1873c Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 10:17:51 +0100 Subject: [PATCH 116/277] Issue #16: renamed global buffers for clarity --- .../pipeline/multithreading_reliability_check.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 0091b993..8d3d4b89 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -25,7 +25,7 @@ """ -buffer_red, buffer_orig = None, None +np_buffer_red, np_buffer_orig = None, None lock = threading.Lock() @@ -157,14 +157,14 @@ def update(self, frame): red_dyer = Dyer(2, 128) green_dyer = Dyer(1, 64) - buffer_red = np.zeros(frame_shape, np.uint8) - bufferer_red = Bufferer(buffer_red) - buffer_orig = np.zeros_like(buffer_red) - bufferer_orig = Bufferer(buffer_orig) + np_buffer_red = np.zeros(frame_shape, np.uint8) + bufferer_red = Bufferer(np_buffer_red) + np_buffer_orig = np.zeros_like(np_buffer_red) + bufferer_orig = Bufferer(np_buffer_orig) - hist_red = Histogrammer(buffer_red, 2, 'red-dyed', 60.0, 10) + hist_red = Histogrammer(np_buffer_red, 2, 'red-dyed', 60.0, 10) hist_red.start() - hist_orig = Histogrammer(buffer_orig, 2, 'original', 50.0, 10) + hist_orig = Histogrammer(np_buffer_orig, 2, 'original', 50.0, 10) hist_orig.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) From d1b7ece3d84597afd51688a13e8ae90674604484 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 10:20:01 +0100 Subject: [PATCH 117/277] Issue #16: commented checker script --- .../multithreading_reliability_check.py | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 8d3d4b89..b4d21c9c 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -25,7 +25,11 @@ """ +# global NumPy buffers np_buffer_red, np_buffer_orig = None, None + +# mutex protecting frame data passed from node to node +# in the GIFT-Grab processing pipeline lock = threading.Lock() @@ -58,22 +62,41 @@ def update(self, frame): class Bufferer(IObservableObserver): + """GIFT-Grab processing node that updates a frame buffer.""" def __init__(self, np_buffer): + """Initialise a bufferer that will update given buffer.""" super(Bufferer, self).__init__() self.buffer = np_buffer def update(self, frame): + """Implement ``IObservableObserver.update``.""" with lock: data = frame.data(True) self.buffer[:, :, :] = data[:, :, :] class Histogrammer(threading.Thread): + """ + GIFT-Grab processing node that computes the histogram of + an image channel and prints how "colored" that channel is. + """ channels = ('Blue', 'Green', 'Red', 'Alpha') def __init__(self, np_buffer, channel, tag, frame_rate, display_freq): + """ + :param np_buffer: image buffer to use + :param channel: image channel to compute coloredness for + :param tag: a tag describing what this image is, e.g. + how it's been processed within a GIFT-Grab pipeline + :param frame_rate: the rate at which to compute the + coloredness (unit: frames-per-second) + :param display_freq: how many times to skip the display + of computed coloredness, e.g. if 5 is provided, the + coloredness of every 5th frame will be printed to the + console + """ super(Histogrammer, self).__init__() assert channel in range(3) assert 0 < frame_rate <= 60 @@ -87,6 +110,7 @@ def __init__(self, np_buffer, channel, tag, frame_rate, display_freq): self.running = False def run(self): + """Override ``Thread.run``.""" if self.running: return @@ -113,12 +137,18 @@ def run(self): sleep(self.sleep_interval) def stop(self): + """Stop the thread.""" self.running = False class Dyer(IObservableObserver): + """Dyes specified channel of an incoming video frame.""" def __init__(self, channel, increment): + """ + :param channel: image channel to dye + :param increment: how much to dye the image channel + """ super(Dyer, self).__init__() assert 0 <= channel < 3 assert 0 <= increment < 256 @@ -126,6 +156,7 @@ def __init__(self, channel, increment): self.increment = increment def update(self, frame): + """Implement ``IObservableObserver.update``.""" with lock: data = frame.data(True) channel_data = data[:, :, self.channel] @@ -145,35 +176,46 @@ def update(self, frame): assert filename assert ext == '.mp4' + # initialise reading of passed file sfac = VideoSourceFactory.get_instance() reader = sfac.create_file_reader(in_file, ColourSpace.BGRA) frame = VideoFrame(ColourSpace.BGRA, False) reader.get_frame(frame) frame_shape = (frame.rows(), frame.cols(), 4) + # prepare for creating encoders (writers) tfac = VideoTargetFactory.get_instance() frame_rate = reader.get_frame_rate() + # create a red and green Dyer red_dyer = Dyer(2, 128) green_dyer = Dyer(1, 64) + # create the bufferer for the red and green Dyers np_buffer_red = np.zeros(frame_shape, np.uint8) bufferer_red = Bufferer(np_buffer_red) np_buffer_orig = np.zeros_like(np_buffer_red) bufferer_orig = Bufferer(np_buffer_orig) + # create the histogrammers for the red-dyed and + # the original video frames, and start them hist_red = Histogrammer(np_buffer_red, 2, 'red-dyed', 60.0, 10) hist_red.start() hist_orig = Histogrammer(np_buffer_orig, 2, 'original', 50.0, 10) hist_orig.start() + # create encoders for the red-dyed and yellow-dyed (as green + # is applied on top of red) video streams red_file = os.path.join('.', ''.join([filename, '-red', ext])) red_writer = tfac.create_file_writer(Codec.HEVC, red_file, frame_rate) yellow_file = os.path.join('.', ''.join([filename, '-yellow', ext])) yellow_writer = tfac.create_file_writer(Codec.HEVC, yellow_file, frame_rate) + # create a SnapshotSavers for saving a number of yellow-dyed + # video frames yellow_snapshots = SnapshotSaver('.') + # assemble the GIFT-Grab pipeline reader.attach(bufferer_orig) bufferer_orig.attach(red_dyer) red_dyer.attach(red_writer) @@ -183,9 +225,12 @@ def update(self, frame): green_dyer.attach(yellow_snapshots) sleep(20) # operate pipeline for 20 sec + + # stop the histogrammers hist_red.stop() hist_orig.stop() + # disassemble the GIFT-Grab pipeline reader.detach(bufferer_orig) bufferer_orig.detach(red_dyer) red_dyer.detach(red_writer) From e3368a19864d307a878d195be26f5dbd996cb39e Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 10:54:24 +0100 Subject: [PATCH 118/277] Issue #16: moved issue-specific comments to shell script --- .../check_multithreading_reliability.sh | 17 +++++++++++++---- .../multithreading_reliability_check.py | 18 +++++------------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 71e2bb62..ceafc345 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -1,10 +1,19 @@ #!/usr/bin/env bash # -*- coding: utf-8 -*- -# Build a basic GIFT-Grab capable of reading a video file, -# and encoding to a video file in real time, with Python -# and NumPy support. Subsequently run the multi-threading -# reliability check script. +# This script provides a multi-threading reliability check. +# The background is issue #16. It looks like in applications +# where multiple Python threads are involved, occasionally +# the acquisition of the Global Interpreter Lock leads to a +# deadlocks, which crashes the whole application with a +# non-specific segmentation fault. +# +# It builds a basic GIFT-Grab capable of reading a video file, +# and encoding to a video file in real time, with Python and +# NumPy support. It subsequently runs a multi-threaded +# GIFT-Grab pipeline a number of times, recording the exit +# status each time. This is essentially a stress-test that +# should serve as a validation that issue #16 is fixed. CALL_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" SOURCE_DIR="$( cd "$CALL_DIR/../.." >/dev/null && pwd )" diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index b4d21c9c..3fdad38b 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -1,6 +1,11 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +""" +Example showing a complex GIFT-Grab pipeline with +multiple intermediate processing nodes. +""" + from time import (sleep, time) import argparse import os.path @@ -11,19 +16,6 @@ ColourSpace, IObservableObserver, VideoTargetFactory, Codec, IObserver) -""" -This script provides a multi-threading reliability check. -The background is issue #16. It looks like in applications -where multiple Python threads are involved, occasionally -the acquisition of the Global Interpreter Lock leads to a -deadlocks, which crashes the whole application with a -non-specific segmentation fault. - -In this script we run a number of multi-threaded GIFT-Grab -pipelines, which should serve as a validation that this -problem is fixed. -""" - # global NumPy buffers np_buffer_red, np_buffer_orig = None, None From 5298af2919ec179d0e441b398a634935179aea9d Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 10:54:45 +0100 Subject: [PATCH 119/277] Issue #16: added synopsis display to shell script --- .../pipeline/check_multithreading_reliability.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index ceafc345..c6419403 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -15,6 +15,18 @@ # status each time. This is essentially a stress-test that # should serve as a validation that issue #16 is fixed. +if [ $# -lt 1 ] || [ $# -gt 3 ]; +then + THIS_SCRIPT="$(basename "$(test -L "${BASH_SOURCE[0]}" && readlink "$0" || echo "$0")")" + printf "Usage: $THIS_SCRIPT video_file [ num_reps [ output_dir ] ]\n" + printf "\tvideo_file: path to an HEVC-encoded MP4 file\n" + printf "\tnum_reps: how many times to run the Python script " + printf "(default: once)\n" + printf "\toutput_dir: where to save all the generated output " + printf "(default: current directory)\n" + exit 1 +fi + CALL_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" SOURCE_DIR="$( cd "$CALL_DIR/../.." >/dev/null && pwd )" MTR_SCRIPT=$SOURCE_DIR/tests/pipeline/multithreading_reliability_check.py From 075eeacdd0386365593c0dcc72b10f00d5143422 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 10:57:52 +0100 Subject: [PATCH 120/277] Issue #16: shell script now shows the current session directory before starting --- src/tests/pipeline/check_multithreading_reliability.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index c6419403..39df9537 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -45,6 +45,7 @@ CMAKE_OPTS="$CMAKE_OPTS -D BUILD_PYTHON=ON -D USE_NUMPY=ON" CMAKE_OPTS="$CMAKE_OPTS -D CMAKE_BUILD_TYPE=Debug" SESSION_DIR=$ROOT_DIR/$(date +"%Y-%m-%d-%H-%M-%S") mkdir $SESSION_DIR +echo "Session directory: $SESSION_DIR" ulimit -c unlimited BUILD_LOG=$SESSION_DIR/build.log From 70e8fde6e24fe142a26392b8b547c75521a04ff3 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 11:01:37 +0100 Subject: [PATCH 121/277] Issue #16: shorter name for Python script --- .../{multithreading_reliability_check.py => complex_pipeline.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/tests/pipeline/{multithreading_reliability_check.py => complex_pipeline.py} (100%) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/complex_pipeline.py similarity index 100% rename from src/tests/pipeline/multithreading_reliability_check.py rename to src/tests/pipeline/complex_pipeline.py From 18ef69b7810261e8158791aa321cdb2a942aa843 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 11:02:26 +0100 Subject: [PATCH 122/277] Issue #16: shorter name for Bash script --- ...heck_multithreading_reliability.sh => run-complex-pipeline.sh} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/tests/pipeline/{check_multithreading_reliability.sh => run-complex-pipeline.sh} (100%) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/run-complex-pipeline.sh similarity index 100% rename from src/tests/pipeline/check_multithreading_reliability.sh rename to src/tests/pipeline/run-complex-pipeline.sh From cf3c85ed23f8b81d5768786b19faa447ea1d2966 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 11:04:37 +0100 Subject: [PATCH 123/277] Issue #16: fixed typos --- src/tests/pipeline/complex_pipeline.py | 2 +- src/tests/pipeline/run-complex-pipeline.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/pipeline/complex_pipeline.py b/src/tests/pipeline/complex_pipeline.py index 3fdad38b..1d9d7346 100755 --- a/src/tests/pipeline/complex_pipeline.py +++ b/src/tests/pipeline/complex_pipeline.py @@ -203,7 +203,7 @@ def update(self, frame): yellow_file = os.path.join('.', ''.join([filename, '-yellow', ext])) yellow_writer = tfac.create_file_writer(Codec.HEVC, yellow_file, frame_rate) - # create a SnapshotSavers for saving a number of yellow-dyed + # create a SnapshotSaver for saving a number of yellow-dyed # video frames yellow_snapshots = SnapshotSaver('.') diff --git a/src/tests/pipeline/run-complex-pipeline.sh b/src/tests/pipeline/run-complex-pipeline.sh index 39df9537..5166507b 100755 --- a/src/tests/pipeline/run-complex-pipeline.sh +++ b/src/tests/pipeline/run-complex-pipeline.sh @@ -5,7 +5,7 @@ # The background is issue #16. It looks like in applications # where multiple Python threads are involved, occasionally # the acquisition of the Global Interpreter Lock leads to a -# deadlocks, which crashes the whole application with a +# deadlock, which crashes the whole application with a # non-specific segmentation fault. # # It builds a basic GIFT-Grab capable of reading a video file, From 38e62cef86fada9719ac18b748a11428760cddbc Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 11:04:55 +0100 Subject: [PATCH 124/277] Issue #16: reduced snapshot output --- src/tests/pipeline/complex_pipeline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/pipeline/complex_pipeline.py b/src/tests/pipeline/complex_pipeline.py index 1d9d7346..66686f1e 100755 --- a/src/tests/pipeline/complex_pipeline.py +++ b/src/tests/pipeline/complex_pipeline.py @@ -205,7 +205,7 @@ def update(self, frame): # create a SnapshotSaver for saving a number of yellow-dyed # video frames - yellow_snapshots = SnapshotSaver('.') + yellow_snapshots = SnapshotSaver('.', 9) # assemble the GIFT-Grab pipeline reader.attach(bufferer_orig) From 124e100908450a0f4b47216ac54dcbdb53aa9af5 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 11:09:55 +0100 Subject: [PATCH 125/277] Issue #16: fixed calling of Python script from Bash script --- src/tests/pipeline/run-complex-pipeline.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/pipeline/run-complex-pipeline.sh b/src/tests/pipeline/run-complex-pipeline.sh index 5166507b..3ed9e038 100755 --- a/src/tests/pipeline/run-complex-pipeline.sh +++ b/src/tests/pipeline/run-complex-pipeline.sh @@ -29,7 +29,7 @@ fi CALL_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" SOURCE_DIR="$( cd "$CALL_DIR/../.." >/dev/null && pwd )" -MTR_SCRIPT=$SOURCE_DIR/tests/pipeline/multithreading_reliability_check.py +MTR_SCRIPT=$SOURCE_DIR/tests/pipeline/complex_pipeline.py if [ $# -ge 3 ]; then ROOT_DIR="$( cd "$3" >/dev/null && pwd )" From b194ba8076f98da010f05fb2c8fcec6915e03257 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 11:41:33 +0100 Subject: [PATCH 126/277] Issue #16: added an RTD page linking to the complex pipeline example --- doc/source/complex.rst | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 doc/source/complex.rst diff --git a/doc/source/complex.rst b/doc/source/complex.rst new file mode 100644 index 00000000..3982fb7f --- /dev/null +++ b/doc/source/complex.rst @@ -0,0 +1,20 @@ +.. _Complex: + +Multi-threaded processing pipelines +=================================== + +This example shows how GIFT-Grab can be used for running complex pipelines with multiple intermediate +processing nodes and threads. +The intermediate processing nodes are built on the same principles as in the SciPy_ example. +Running the example requires an `HEVC-encoded MP4 file`_, an `NVENC-capable GPU`_, and `NumPy support`_. + +.. _`HEVC-encoded MP4 file`: https://github.com/gift-surg/GIFT-Grab/blob/master/doc/build.md#reading-video-files +.. _`NVENC-capable GPU`: https://github.com/gift-surg/GIFT-Grab/blob/master/doc/build.md#hevc +.. _`NumPy support`: https://github.com/gift-surg/GIFT-Grab/blob/master/doc/build.md#python-api + +Below is the commented full source code: + +.. literalinclude:: ../../src/tests/pipeline/complex_pipeline.py + :language: python + :linenos: + From 791a83c98d07bfe7148287d92b269602d1954493 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 11:41:59 +0100 Subject: [PATCH 127/277] Issue #16: added the new RTD page to the index --- doc/source/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/index.rst b/doc/source/index.rst index 2c8fddc2..8e9af514 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -51,6 +51,7 @@ Examples network scipy encoding + complex Citing GIFT-Grab ^^^^^^^^^^^^^^^^ From 7ea7c47fe8c2d93cb876c1c105241269d7d9e6b5 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 11:59:27 +0100 Subject: [PATCH 128/277] Issue #16: fixed cross-reference to NumPy example from new RTD page --- doc/source/complex.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/complex.rst b/doc/source/complex.rst index 3982fb7f..6e0c8a60 100644 --- a/doc/source/complex.rst +++ b/doc/source/complex.rst @@ -5,7 +5,7 @@ Multi-threaded processing pipelines This example shows how GIFT-Grab can be used for running complex pipelines with multiple intermediate processing nodes and threads. -The intermediate processing nodes are built on the same principles as in the SciPy_ example. +The intermediate processing nodes are built on the same principles as in the :ref:`SciPy` example. Running the example requires an `HEVC-encoded MP4 file`_, an `NVENC-capable GPU`_, and `NumPy support`_. .. _`HEVC-encoded MP4 file`: https://github.com/gift-surg/GIFT-Grab/blob/master/doc/build.md#reading-video-files From 75fb5bd839100f4f77ff22501cef44cb70ac78dd Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 12:00:34 +0100 Subject: [PATCH 129/277] Issue #16: added link from new RTD page to example source code on GitHub --- doc/source/complex.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/source/complex.rst b/doc/source/complex.rst index 6e0c8a60..060bce72 100644 --- a/doc/source/complex.rst +++ b/doc/source/complex.rst @@ -12,9 +12,11 @@ Running the example requires an `HEVC-encoded MP4 file`_, an `NVENC-capable GPU` .. _`NVENC-capable GPU`: https://github.com/gift-surg/GIFT-Grab/blob/master/doc/build.md#hevc .. _`NumPy support`: https://github.com/gift-surg/GIFT-Grab/blob/master/doc/build.md#python-api -Below is the commented full source code: +Below is the commented full source code, which is also available on GitHub_: .. literalinclude:: ../../src/tests/pipeline/complex_pipeline.py :language: python :linenos: +.. _GitHub: https://github.com/gift-surg/GIFT-Grab/blob/master/src/tests/pipeline/complex_pipeline.py + From 2ec3b25364f9f83a2da61223446297d2dab074e1 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 18:47:20 +0100 Subject: [PATCH 130/277] Issue #16: made the title of the new RTD page more descriptive --- doc/source/complex.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/source/complex.rst b/doc/source/complex.rst index 060bce72..98fc12ce 100644 --- a/doc/source/complex.rst +++ b/doc/source/complex.rst @@ -1,7 +1,7 @@ .. _Complex: -Multi-threaded processing pipelines -=================================== +Multi-threaded complex processing pipelines +=========================================== This example shows how GIFT-Grab can be used for running complex pipelines with multiple intermediate processing nodes and threads. From 8ca5d2021cfc6545216d369cd22368a1087b9c0a Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 18:51:26 +0100 Subject: [PATCH 131/277] Issue #16: revised the RTD page wording for clarity --- doc/source/complex.rst | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/doc/source/complex.rst b/doc/source/complex.rst index 98fc12ce..0d231ccb 100644 --- a/doc/source/complex.rst +++ b/doc/source/complex.rst @@ -3,16 +3,19 @@ Multi-threaded complex processing pipelines =========================================== -This example shows how GIFT-Grab can be used for running complex pipelines with multiple intermediate -processing nodes and threads. -The intermediate processing nodes are built on the same principles as in the :ref:`SciPy` example. +The example below shows how GIFT-Grab can be used for running complex pipelines with multiple +intermediate processing nodes and threads. +The intermediate processing nodes in this example are built on the same principles as in the +:ref:`SciPy` example. Running the example requires an `HEVC-encoded MP4 file`_, an `NVENC-capable GPU`_, and `NumPy support`_. .. _`HEVC-encoded MP4 file`: https://github.com/gift-surg/GIFT-Grab/blob/master/doc/build.md#reading-video-files .. _`NVENC-capable GPU`: https://github.com/gift-surg/GIFT-Grab/blob/master/doc/build.md#hevc .. _`NumPy support`: https://github.com/gift-surg/GIFT-Grab/blob/master/doc/build.md#python-api -Below is the commented full source code, which is also available on GitHub_: +The full source code of the example is below. +Please follow the comments and the flow of code. +This example is also available on GitHub_: .. literalinclude:: ../../src/tests/pipeline/complex_pipeline.py :language: python From b7cd7b92ee72a76a5473692a675121f04750c957 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 18:53:21 +0100 Subject: [PATCH 132/277] Issue #16: removed line numbers from example on new RTD page --- doc/source/complex.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/source/complex.rst b/doc/source/complex.rst index 0d231ccb..eba60359 100644 --- a/doc/source/complex.rst +++ b/doc/source/complex.rst @@ -19,7 +19,6 @@ This example is also available on GitHub_: .. literalinclude:: ../../src/tests/pipeline/complex_pipeline.py :language: python - :linenos: .. _GitHub: https://github.com/gift-surg/GIFT-Grab/blob/master/src/tests/pipeline/complex_pipeline.py From be5620a685af687b70232b46167b82ebb72e2d8e Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 19 Oct 2018 14:57:13 +0100 Subject: [PATCH 133/277] Issue #16: checker script now supports Blackmagic DeckLink 4K Extreme 12G --- src/tests/pipeline/complex_pipeline.py | 27 ++++++++++++++-------- src/tests/pipeline/run-complex-pipeline.sh | 10 +++++++- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/tests/pipeline/complex_pipeline.py b/src/tests/pipeline/complex_pipeline.py index 66686f1e..e3738d9b 100755 --- a/src/tests/pipeline/complex_pipeline.py +++ b/src/tests/pipeline/complex_pipeline.py @@ -12,7 +12,7 @@ import threading import numpy as np import scipy.misc -from pygiftgrab import (VideoSourceFactory, VideoFrame, +from pygiftgrab import (VideoSourceFactory, VideoFrame, Device, ColourSpace, IObservableObserver, VideoTargetFactory, Codec, IObserver) @@ -158,19 +158,26 @@ def update(self, frame): if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('-i', '--input', type=str, required=True, - metavar='VIDEO_FILE', - help='Input video file (HEVC-encoded MP4)') + metavar='VIDEO_INPUT', + help='"decklink" (for grabbing frames from a Blackmagic DeckLink 4K Extreme 12G)' + ' or a video file (HEVC-encoded MP4)') args = parser.parse_args() in_file = args.input - filename = os.path.basename(in_file) - filename, ext = os.path.splitext(filename) - assert filename - assert ext == '.mp4' - - # initialise reading of passed file sfac = VideoSourceFactory.get_instance() - reader = sfac.create_file_reader(in_file, ColourSpace.BGRA) + + if in_file == 'decklink': + reader = sfac.get_device(Device.DeckLink4KExtreme12G, ColourSpace.BGRA) + reader.set_sub_frame(640, 300, 640, 480) + else: + filename = os.path.basename(in_file) + filename, ext = os.path.splitext(filename) + assert filename + assert ext == '.mp4' + + # initialise reading of passed file + reader = sfac.create_file_reader(in_file, ColourSpace.BGRA) + frame = VideoFrame(ColourSpace.BGRA, False) reader.get_frame(frame) frame_shape = (frame.rows(), frame.cols(), 4) diff --git a/src/tests/pipeline/run-complex-pipeline.sh b/src/tests/pipeline/run-complex-pipeline.sh index 3ed9e038..5dfb083a 100755 --- a/src/tests/pipeline/run-complex-pipeline.sh +++ b/src/tests/pipeline/run-complex-pipeline.sh @@ -18,8 +18,9 @@ if [ $# -lt 1 ] || [ $# -gt 3 ]; then THIS_SCRIPT="$(basename "$(test -L "${BASH_SOURCE[0]}" && readlink "$0" || echo "$0")")" - printf "Usage: $THIS_SCRIPT video_file [ num_reps [ output_dir ] ]\n" + printf "Usage: $THIS_SCRIPT video_file|decklink [ num_reps [ output_dir ] ]\n" printf "\tvideo_file: path to an HEVC-encoded MP4 file\n" + printf "\tdecklink: Blackmagic DeckLink 4K Extreme 12G frame grabber\n" printf "\tnum_reps: how many times to run the Python script " printf "(default: once)\n" printf "\toutput_dir: where to save all the generated output " @@ -42,6 +43,13 @@ CMAKE_OPTS="-D USE_FILES=ON" CMAKE_OPTS="$CMAKE_OPTS -D USE_HEVC=ON" CMAKE_OPTS="$CMAKE_OPTS -D ENABLE_NONFREE=ON -D USE_NVENC=ON" CMAKE_OPTS="$CMAKE_OPTS -D BUILD_PYTHON=ON -D USE_NUMPY=ON" +if [ "$1" = "decklink" ]; then + if [[ -z "${BlackmagicSDK_DIR}" ]]; then + echo "Please set BlackmagicSDK_DIR to the path of the Blackmagic SDK" + exit 1 + fi + CMAKE_OPTS="$CMAKE_OPTS -D USE_BLACKMAGIC_DECKLINK_4K_EXTREME_12G=ON -D ENABLE_NONFREE=ON" +fi CMAKE_OPTS="$CMAKE_OPTS -D CMAKE_BUILD_TYPE=Debug" SESSION_DIR=$ROOT_DIR/$(date +"%Y-%m-%d-%H-%M-%S") mkdir $SESSION_DIR From 32921fc439c0175a06f1fa83aae5845b0a43590f Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 19 Oct 2018 14:59:14 +0100 Subject: [PATCH 134/277] Issue #16: revised checker script for more generic variable names --- src/tests/pipeline/complex_pipeline.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/tests/pipeline/complex_pipeline.py b/src/tests/pipeline/complex_pipeline.py index e3738d9b..1968c33a 100755 --- a/src/tests/pipeline/complex_pipeline.py +++ b/src/tests/pipeline/complex_pipeline.py @@ -159,32 +159,33 @@ def update(self, frame): parser = argparse.ArgumentParser() parser.add_argument('-i', '--input', type=str, required=True, metavar='VIDEO_INPUT', - help='"decklink" (for grabbing frames from a Blackmagic DeckLink 4K Extreme 12G)' + help='decklink (for grabbing frames from a Blackmagic DeckLink 4K Extreme 12G)' ' or a video file (HEVC-encoded MP4)') args = parser.parse_args() - in_file = args.input + video_input = args.input sfac = VideoSourceFactory.get_instance() - if in_file == 'decklink': - reader = sfac.get_device(Device.DeckLink4KExtreme12G, ColourSpace.BGRA) - reader.set_sub_frame(640, 300, 640, 480) + if video_input == 'decklink': + # start acquiring frames from a DeckLink 4K Extreme 12G + source = sfac.get_device(Device.DeckLink4KExtreme12G, ColourSpace.BGRA) + source.set_sub_frame(640, 300, 640, 480) else: - filename = os.path.basename(in_file) + filename = os.path.basename(video_input) filename, ext = os.path.splitext(filename) assert filename assert ext == '.mp4' # initialise reading of passed file - reader = sfac.create_file_reader(in_file, ColourSpace.BGRA) + source = sfac.create_file_reader(video_input, ColourSpace.BGRA) frame = VideoFrame(ColourSpace.BGRA, False) - reader.get_frame(frame) + source.get_frame(frame) frame_shape = (frame.rows(), frame.cols(), 4) # prepare for creating encoders (writers) tfac = VideoTargetFactory.get_instance() - frame_rate = reader.get_frame_rate() + frame_rate = source.get_frame_rate() # create a red and green Dyer red_dyer = Dyer(2, 128) @@ -215,7 +216,7 @@ def update(self, frame): yellow_snapshots = SnapshotSaver('.', 9) # assemble the GIFT-Grab pipeline - reader.attach(bufferer_orig) + source.attach(bufferer_orig) bufferer_orig.attach(red_dyer) red_dyer.attach(red_writer) red_dyer.attach(bufferer_red) @@ -230,7 +231,7 @@ def update(self, frame): hist_orig.stop() # disassemble the GIFT-Grab pipeline - reader.detach(bufferer_orig) + source.detach(bufferer_orig) bufferer_orig.detach(red_dyer) red_dyer.detach(red_writer) red_dyer.detach(bufferer_red) From 3f003c90991ea2553314ad5c43ef4e7fa41d034f Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 19 Oct 2018 15:21:23 +0100 Subject: [PATCH 135/277] Issue #16: added missing variable and removed cropping in checker script BM part --- src/tests/pipeline/complex_pipeline.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tests/pipeline/complex_pipeline.py b/src/tests/pipeline/complex_pipeline.py index 1968c33a..fbdf3196 100755 --- a/src/tests/pipeline/complex_pipeline.py +++ b/src/tests/pipeline/complex_pipeline.py @@ -167,9 +167,10 @@ def update(self, frame): sfac = VideoSourceFactory.get_instance() if video_input == 'decklink': + filename = 'decklink' + # start acquiring frames from a DeckLink 4K Extreme 12G source = sfac.get_device(Device.DeckLink4KExtreme12G, ColourSpace.BGRA) - source.set_sub_frame(640, 300, 640, 480) else: filename = os.path.basename(video_input) filename, ext = os.path.splitext(filename) From af2157c01933191b07e71b653dc8466c098f1b57 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 19 Oct 2018 15:44:04 +0100 Subject: [PATCH 136/277] Issue #16: added missing file extension specification when using DeckLink device --- src/tests/pipeline/complex_pipeline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/pipeline/complex_pipeline.py b/src/tests/pipeline/complex_pipeline.py index fbdf3196..b61e8f1c 100755 --- a/src/tests/pipeline/complex_pipeline.py +++ b/src/tests/pipeline/complex_pipeline.py @@ -167,7 +167,7 @@ def update(self, frame): sfac = VideoSourceFactory.get_instance() if video_input == 'decklink': - filename = 'decklink' + filename, ext = 'decklink', '.mp4' # start acquiring frames from a DeckLink 4K Extreme 12G source = sfac.get_device(Device.DeckLink4KExtreme12G, ColourSpace.BGRA) From a327c37a95351c56fcb73725b818ba799adba9ab Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 21 Oct 2018 11:48:02 +0100 Subject: [PATCH 137/277] Issue #16: multi-threading reliability checker now supports Epiphan DVI2PCIe Duo DVI port --- src/tests/pipeline/complex_pipeline.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/tests/pipeline/complex_pipeline.py b/src/tests/pipeline/complex_pipeline.py index b61e8f1c..9383db13 100755 --- a/src/tests/pipeline/complex_pipeline.py +++ b/src/tests/pipeline/complex_pipeline.py @@ -159,7 +159,8 @@ def update(self, frame): parser = argparse.ArgumentParser() parser.add_argument('-i', '--input', type=str, required=True, metavar='VIDEO_INPUT', - help='decklink (for grabbing frames from a Blackmagic DeckLink 4K Extreme 12G)' + help='decklink (for grabbing frames from a Blackmagic DeckLink 4K Extreme 12G),\n' + 'dvi2pcie (for grabbing frames from an Epiphan DVI2PCIe Duo DVI port\n' ' or a video file (HEVC-encoded MP4)') args = parser.parse_args() video_input = args.input @@ -171,6 +172,11 @@ def update(self, frame): # start acquiring frames from a DeckLink 4K Extreme 12G source = sfac.get_device(Device.DeckLink4KExtreme12G, ColourSpace.BGRA) + elif video_input == 'dvi2pcie': + filename, ext = 'dvi2pcie', '.mp4' + + # start acquirigin frames from an Epiphan DVI2PCIe Duo DVI port + source = sfac.get_device(Device.DVI2PCIeDuo_DVI, ColourSpace.BGRA) else: filename = os.path.basename(video_input) filename, ext = os.path.splitext(filename) From f1179d0d1d85723b6b54bd96ecef5e6439cfa6dd Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 21 Oct 2018 11:48:42 +0100 Subject: [PATCH 138/277] Issue #16: multi-threading reliability launch script now supports Epiphan DVI2PCIe Duo as well --- src/tests/pipeline/run-complex-pipeline.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tests/pipeline/run-complex-pipeline.sh b/src/tests/pipeline/run-complex-pipeline.sh index 5dfb083a..8a016785 100755 --- a/src/tests/pipeline/run-complex-pipeline.sh +++ b/src/tests/pipeline/run-complex-pipeline.sh @@ -18,9 +18,10 @@ if [ $# -lt 1 ] || [ $# -gt 3 ]; then THIS_SCRIPT="$(basename "$(test -L "${BASH_SOURCE[0]}" && readlink "$0" || echo "$0")")" - printf "Usage: $THIS_SCRIPT video_file|decklink [ num_reps [ output_dir ] ]\n" + printf "Usage: $THIS_SCRIPT video_file|decklink|dvi2pcie [ num_reps [ output_dir ] ]\n" printf "\tvideo_file: path to an HEVC-encoded MP4 file\n" printf "\tdecklink: Blackmagic DeckLink 4K Extreme 12G frame grabber\n" + printf "\tdvi2pcie: Epiphan DVI2PCIe Duo frame grabber\n" printf "\tnum_reps: how many times to run the Python script " printf "(default: once)\n" printf "\toutput_dir: where to save all the generated output " @@ -49,6 +50,8 @@ if [ "$1" = "decklink" ]; then exit 1 fi CMAKE_OPTS="$CMAKE_OPTS -D USE_BLACKMAGIC_DECKLINK_4K_EXTREME_12G=ON -D ENABLE_NONFREE=ON" +elif [ "$1" = "dvi2pcie" ]; then + CMAKE_OPTS="$CMAKE_OPTS -D USE_EPIPHAN_DVI2PCIE_DUO=ON -D USE_I420=OFF" fi CMAKE_OPTS="$CMAKE_OPTS -D CMAKE_BUILD_TYPE=Debug" SESSION_DIR=$ROOT_DIR/$(date +"%Y-%m-%d-%H-%M-%S") From 5cdd60a32b674544f7ee0bf71d3cb112723268c1 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Thu, 11 Oct 2018 09:02:38 +0100 Subject: [PATCH 139/277] Issue #16: added a Python script stub for checking multi-threading reliability --- .../multithreading_reliability_check.py | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100755 src/tests/pipeline/multithreading_reliability_check.py diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py new file mode 100755 index 00000000..c6729066 --- /dev/null +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from pygiftgrab import (VideoSourceFactory, + ColourSpace, + IObservableObserver) + +""" +This script provides a multi-threading reliability check. +The background is issue #16. It looks like in applications +where multiple Python threads are involved, occasionally +the acquisition of the Global Interpreter Lock leads to a +deadlocks, which crashes the whole application with a +non-specific segmentation fault. + +In this script we run a number of multi-threaded GIFT-Grab +pipelines, which should serve as a validation that this +problem is fixed. +""" + +if __name__ == '__main__': + print('multithreading reliability check script') From 28a40bf8739c12c8a3f01fedbe0636fccc0a2279 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Thu, 11 Oct 2018 09:03:41 +0100 Subject: [PATCH 140/277] Issue #16: added a Bash script for building GIFT-Grab and subsequently running the multi-threading reliability check script --- .gitignore | 1 + .../check_multithreading_reliability.sh | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100755 src/tests/pipeline/check_multithreading_reliability.sh diff --git a/.gitignore b/.gitignore index 08b31459..d7eb0905 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ src/build src/dist src/*.egg-info *.swp +src/tests/pipeline/mtr-build diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh new file mode 100755 index 00000000..b974bfa8 --- /dev/null +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +# -*- coding: utf-8 -*- + +# Build a basic GIFT-Grab capable of reading a video file, +# and encoding to a video file in real time, with Python +# and NumPy support. Subsequently run the multi-threading +# reliability check script. + +CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" +BUILD_DIR=$CURRENT_DIR/mtr-build +SOURCE_DIR="$( cd "$CURRENT_DIR/../.." >/dev/null && pwd )" +CMAKE_OPTS="-D USE_FILES=ON" +CMAKE_OPTS="$CMAKE_OPTS -D USE_HEVC=ON" +CMAKE_OPTS="$CMAKE_OPTS -D ENABLE_NONFREE=ON -D USE_NVENC=ON" +CMAKE_OPTS="$CMAKE_OPTS -D BUILD_PYTHON=ON -D USE_NUMPY=ON" +MTR_SCRIPT=$CURRENT_DIR/multithreading_reliability_check.py + +mkdir -p $BUILD_DIR +rm -rf $BUILD_DIR/* +cd $BUILD_DIR +cmake $CMAKE_OPTS $SOURCE_DIR +make -j4 +PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT From b4ab05be343a6aa84746d3e28fb9697ddb4e57df Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 08:06:21 +0100 Subject: [PATCH 141/277] Issue #16: added a 'Dyer' processing node to multi-threading reliability checker --- .../pipeline/multithreading_reliability_check.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index c6729066..7aa1fc0d 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -18,5 +18,20 @@ problem is fixed. """ + +class Dyer(IObservableObserver): + + def __init__(self, channel, value): + super(Dyer, self).__init__() + assert 0 <= channel < 3 + assert 0 <= value < 256 + self.channel = channel + self.value = value + + def update(self, frame): + data = frame.data(True) + data[:, :, self.channel] = self.value + + if __name__ == '__main__': print('multithreading reliability check script') From 5a59a172553d975d4671441a4e4d3c4ee6c95b45 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 08:28:08 +0100 Subject: [PATCH 142/277] Issue #16: Python script now uses CLI argument for input file --- .../pipeline/check_multithreading_reliability.sh | 2 +- .../pipeline/multithreading_reliability_check.py | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index b974bfa8..efae4d95 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -20,4 +20,4 @@ rm -rf $BUILD_DIR/* cd $BUILD_DIR cmake $CMAKE_OPTS $SOURCE_DIR make -j4 -PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT +PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT --input $1 diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 7aa1fc0d..02982cf7 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -1,6 +1,8 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +import argparse +import os.path from pygiftgrab import (VideoSourceFactory, ColourSpace, IObservableObserver) @@ -34,4 +36,14 @@ def update(self, frame): if __name__ == '__main__': - print('multithreading reliability check script') + parser = argparse.ArgumentParser() + parser.add_argument('-i', '--input', type=str, required=True, + metavar='VIDEO_FILE', + help='Input video file (HEVC-encoded MP4)') + args = parser.parse_args() + in_file = args.input + + filename = os.path.basename(in_file) + filename, ext = os.path.splitext(filename) + assert filename + assert ext == '.mp4' From 10c748f8179323cb0620bf4462a68bd9970d7f1a Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 08:32:30 +0100 Subject: [PATCH 143/277] Issue #16: added multi-node pipeline producing red- and yellow-dyed output --- .../multithreading_reliability_check.py | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 02982cf7..01c4ead3 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -1,11 +1,12 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +from time import sleep import argparse import os.path from pygiftgrab import (VideoSourceFactory, - ColourSpace, - IObservableObserver) + ColourSpace, IObservableObserver, + VideoTargetFactory, Codec) """ This script provides a multi-threading reliability check. @@ -47,3 +48,29 @@ def update(self, frame): filename, ext = os.path.splitext(filename) assert filename assert ext == '.mp4' + + sfac = VideoSourceFactory.get_instance() + reader = sfac.create_file_reader(in_file, ColourSpace.BGRA) + + tfac = VideoTargetFactory.get_instance() + frame_rate = reader.get_frame_rate() + + red = Dyer(2, 127) + green = Dyer(1, 191) + + red_file = os.path.join('.', ''.join([filename, '-red', ext])) + red_writer = tfac.create_file_writer(Codec.HEVC, red_file, frame_rate) + yellow_file = os.path.join('.', ''.join([filename, '-yellow', ext])) + yellow_writer = tfac.create_file_writer(Codec.HEVC, yellow_file, frame_rate) + + reader.attach(red) + red.attach(red_writer) + red.attach(green) + green.attach(yellow_writer) + + sleep(20) # operate pipeline for 20 sec + + reader.detach(red) + red.detach(red_writer) + red.detach(green) + green.detach(yellow_writer) From b7078b33b634e369a54fe7b462f42cc8202c7536 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 09:09:08 +0100 Subject: [PATCH 144/277] Issue #16: added a threaded Histogrammer class stub --- .../multithreading_reliability_check.py | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 01c4ead3..c1ba3b48 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -4,6 +4,7 @@ from time import sleep import argparse import os.path +import threading from pygiftgrab import (VideoSourceFactory, ColourSpace, IObservableObserver, VideoTargetFactory, Codec) @@ -22,6 +23,30 @@ """ +buffer = None +lock = threading.Lock() + + +class Histogrammer(threading.Thread, IObservableObserver): + + def __init__(self, channel): + super(Histogrammer, self).__init__() + assert 0 <= channel < 3 + self.channel = channel + self.running = False + + def run(self): + if self.running: + return + + pass + + def stop(self): + self.running = False + + def update(self, frame): + pass + class Dyer(IObservableObserver): def __init__(self, channel, value): @@ -57,6 +82,8 @@ def update(self, frame): red = Dyer(2, 127) green = Dyer(1, 191) + hist = Histogrammer(0) + hist.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) red_writer = tfac.create_file_writer(Codec.HEVC, red_file, frame_rate) @@ -69,6 +96,7 @@ def update(self, frame): green.attach(yellow_writer) sleep(20) # operate pipeline for 20 sec + hist.stop() reader.detach(red) red.detach(red_writer) From 836abb05370e071ab75268f73551e99b3b4ad9f2 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 09:12:38 +0100 Subject: [PATCH 145/277] Issue #16: added dummy print statement to see Histogrammer is alive --- src/tests/pipeline/multithreading_reliability_check.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index c1ba3b48..4dd459a1 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -40,6 +40,10 @@ def run(self): return pass + self.running = True + while self.running: + print('Running') + sleep(0.100) def stop(self): self.running = False From 79ae44518aa6275c51cece824d37207abc2529d3 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 09:57:57 +0100 Subject: [PATCH 146/277] Issue #16: factored Histogrammer stub out to HistogrammerRed and BuffererRed --- .../multithreading_reliability_check.py | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 4dd459a1..12a467bb 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -23,33 +23,40 @@ """ -buffer = None +buffer_red = None lock = threading.Lock() -class Histogrammer(threading.Thread, IObservableObserver): +class BuffererRed(IObservableObserver): - def __init__(self, channel): - super(Histogrammer, self).__init__() - assert 0 <= channel < 3 - self.channel = channel + def __init__(self): + super(BuffererRed, self).__init__() + + def update(self, frame): + global buffer_red + # TODO + + +class HistogrammerRed(threading.Thread): + + def __init__(self): + super(HistogrammerRed, self).__init__() self.running = False def run(self): if self.running: return - pass + # TODO self.running = True while self.running: print('Running') + # TODO sleep(0.100) def stop(self): self.running = False - def update(self, frame): - pass class Dyer(IObservableObserver): @@ -86,7 +93,7 @@ def update(self, frame): red = Dyer(2, 127) green = Dyer(1, 191) - hist = Histogrammer(0) + hist = HistogrammerRed() hist.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) From f6b9a61fd57a100c9be193f7ceb24ccaa139649e Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 09:59:41 +0100 Subject: [PATCH 147/277] Issue #16: implemented update of BuffererRed --- src/tests/pipeline/multithreading_reliability_check.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 12a467bb..aa8eb0dd 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -5,6 +5,7 @@ import argparse import os.path import threading +import numpy as np from pygiftgrab import (VideoSourceFactory, ColourSpace, IObservableObserver, VideoTargetFactory, Codec) @@ -34,7 +35,12 @@ def __init__(self): def update(self, frame): global buffer_red - # TODO + with lock: + data = frame.data(True) + if buffer_red is None: + buffer_red = np.copy(data) + else: + buffer_red[:, :, :] = data[:, :, :] class HistogrammerRed(threading.Thread): From 57e85b004f37dd3614b90c70942b3ad5c1e34dcd Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 10:06:55 +0100 Subject: [PATCH 148/277] Issue #16: implemented run of HistogrammerRed --- src/tests/pipeline/multithreading_reliability_check.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index aa8eb0dd..54ceb230 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -53,11 +53,15 @@ def run(self): if self.running: return - # TODO + global buffer_red + histogram = None self.running = True while self.running: - print('Running') - # TODO + with lock: + if buffer_red is not None: + histogram = np.histogram(buffer_red[:, :, 2], + bins=8, range=(0, 256)) + print(histogram) sleep(0.100) def stop(self): From ea8e80921e740a014e9f7a03269a71b613bc2553 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 10:11:05 +0100 Subject: [PATCH 149/277] Issue #16: renamed Dyer vars for clarity --- .../multithreading_reliability_check.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 54ceb230..ff1fda67 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -101,8 +101,8 @@ def update(self, frame): tfac = VideoTargetFactory.get_instance() frame_rate = reader.get_frame_rate() - red = Dyer(2, 127) - green = Dyer(1, 191) + red_dyer = Dyer(2, 127) + green_dyer = Dyer(1, 191) hist = HistogrammerRed() hist.start() @@ -111,15 +111,15 @@ def update(self, frame): yellow_file = os.path.join('.', ''.join([filename, '-yellow', ext])) yellow_writer = tfac.create_file_writer(Codec.HEVC, yellow_file, frame_rate) - reader.attach(red) - red.attach(red_writer) - red.attach(green) - green.attach(yellow_writer) + reader.attach(red_dyer) + red_dyer.attach(red_writer) + red_dyer.attach(green_dyer) + green_dyer.attach(yellow_writer) sleep(20) # operate pipeline for 20 sec hist.stop() - reader.detach(red) - red.detach(red_writer) - red.detach(green) - green.detach(yellow_writer) + reader.detach(red_dyer) + red_dyer.detach(red_writer) + red_dyer.detach(green_dyer) + green_dyer.detach(yellow_writer) From 1a8d91ca86853dc430db532492da19fd25210b79 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 10:19:12 +0100 Subject: [PATCH 150/277] Issue #16: Dyer.update uses lock --- src/tests/pipeline/multithreading_reliability_check.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index ff1fda67..ee40fea7 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -78,8 +78,9 @@ def __init__(self, channel, value): self.value = value def update(self, frame): - data = frame.data(True) - data[:, :, self.channel] = self.value + with lock: + data = frame.data(True) + data[:, :, self.channel] = self.value if __name__ == '__main__': From 6d1ede03d4843925ef3e25251e9951275bb611dd Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 10:20:32 +0100 Subject: [PATCH 151/277] Issue #16: inserted a red bufferer into the pipeline --- src/tests/pipeline/multithreading_reliability_check.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index ee40fea7..dd0f0dcf 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -104,6 +104,9 @@ def update(self, frame): red_dyer = Dyer(2, 127) green_dyer = Dyer(1, 191) + + bufferer_red = BuffererRed() + hist = HistogrammerRed() hist.start() @@ -114,6 +117,7 @@ def update(self, frame): reader.attach(red_dyer) red_dyer.attach(red_writer) + red_dyer.attach(bufferer_red) red_dyer.attach(green_dyer) green_dyer.attach(yellow_writer) @@ -122,5 +126,6 @@ def update(self, frame): reader.detach(red_dyer) red_dyer.detach(red_writer) + red_dyer.detach(bufferer_red) red_dyer.detach(green_dyer) green_dyer.detach(yellow_writer) From b1b52468075342e84cdff7279aa08357361e085f Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 10:22:03 +0100 Subject: [PATCH 152/277] Issue #16: fixed call to histogram function --- src/tests/pipeline/multithreading_reliability_check.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index dd0f0dcf..0987129b 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -59,8 +59,9 @@ def run(self): while self.running: with lock: if buffer_red is not None: - histogram = np.histogram(buffer_red[:, :, 2], - bins=8, range=(0, 256)) + histogram, _ = np.histogram( + buffer_red[:, :, 2], bins=8, range=(0, 256) + ) print(histogram) sleep(0.100) From 4cc919c0af2906e1452189b1fd51061472cf8d8a Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 10:32:24 +0100 Subject: [PATCH 153/277] Issue #16: Dyer now really dyes instead of fixing color to a value --- src/tests/pipeline/multithreading_reliability_check.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 0987129b..54802904 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -71,17 +71,18 @@ def stop(self): class Dyer(IObservableObserver): - def __init__(self, channel, value): + def __init__(self, channel, increment): super(Dyer, self).__init__() assert 0 <= channel < 3 - assert 0 <= value < 256 + assert 0 <= increment < 256 self.channel = channel - self.value = value + self.increment = increment def update(self, frame): with lock: data = frame.data(True) - data[:, :, self.channel] = self.value + channel_data = data[:, :, self.channel] + channel_data[channel_data < 255 - self.increment] += self.increment if __name__ == '__main__': From 36ba5c443f9760ca6bd5293a0f1484ef52d7a309 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 10:53:49 +0100 Subject: [PATCH 154/277] Issue #16: histogrammer now displays a redness score instead of histogram --- .../pipeline/multithreading_reliability_check.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 54802904..d8bf97ed 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -54,15 +54,21 @@ def run(self): return global buffer_red - histogram = None + histogram, num_bins = None, 10 + redness_scale = np.array([i for i in range(1, num_bins + 1)], np.float) self.running = True while self.running: with lock: if buffer_red is not None: histogram, _ = np.histogram( - buffer_red[:, :, 2], bins=8, range=(0, 256) + buffer_red[:, :, 2], bins=num_bins, range=(0, 256) ) - print(histogram) + if histogram is not None: + redness = np.sum(histogram * redness_scale) + redness /= np.sum(histogram) + redness /= num_bins + redness *= 100 + print('Redness: {} %'.format(int(round(redness)))) sleep(0.100) def stop(self): From 1c247f2b87c4139bd127c96e4a33e862b170bca8 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 10:54:11 +0100 Subject: [PATCH 155/277] Issue #16: using more sensible values for dyeing --- src/tests/pipeline/multithreading_reliability_check.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index d8bf97ed..a024030b 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -110,8 +110,8 @@ def update(self, frame): tfac = VideoTargetFactory.get_instance() frame_rate = reader.get_frame_rate() - red_dyer = Dyer(2, 127) - green_dyer = Dyer(1, 191) + red_dyer = Dyer(2, 64) + green_dyer = Dyer(1, 64) bufferer_red = BuffererRed() From d001d8f9d5ccaa103bb229859067bc2a660ede89 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 10:59:42 +0100 Subject: [PATCH 156/277] Issue #16: added a BuffererOrig class, a virtual replica of BuffererRed --- .../multithreading_reliability_check.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index a024030b..7b497725 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -24,7 +24,7 @@ """ -buffer_red = None +buffer_red, buffer_orig = None, None lock = threading.Lock() @@ -43,6 +43,21 @@ def update(self, frame): buffer_red[:, :, :] = data[:, :, :] +class BuffererOrig(IObservableObserver): + + def __init__(self): + super(BuffererOrig, self).__init__() + + def update(self, frame): + global buffer_orig + with lock: + data = frame.data(True) + if buffer_orig is None: + buffer_orig = np.copy(data) + else: + buffer_red[:, :, :] = data[:, :, :] + + class HistogrammerRed(threading.Thread): def __init__(self): From b1d83109864e527ec940497c849b3856ba102dfb Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:03:50 +0100 Subject: [PATCH 157/277] Issue #16: BuffererRed now takes buffer as parameter to constructor instead of using global var --- .../multithreading_reliability_check.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 7b497725..0ca024bc 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -6,7 +6,7 @@ import os.path import threading import numpy as np -from pygiftgrab import (VideoSourceFactory, +from pygiftgrab import (VideoSourceFactory, VideoFrame, ColourSpace, IObservableObserver, VideoTargetFactory, Codec) @@ -30,17 +30,14 @@ class BuffererRed(IObservableObserver): - def __init__(self): + def __init__(self, buffer): super(BuffererRed, self).__init__() + self.buffer = buffer def update(self, frame): - global buffer_red with lock: data = frame.data(True) - if buffer_red is None: - buffer_red = np.copy(data) - else: - buffer_red[:, :, :] = data[:, :, :] + self.buffer[:, :, :] = data[:, :, :] class BuffererOrig(IObservableObserver): @@ -121,6 +118,9 @@ def update(self, frame): sfac = VideoSourceFactory.get_instance() reader = sfac.create_file_reader(in_file, ColourSpace.BGRA) + frame = VideoFrame(ColourSpace.BGRA, False) + reader.get_frame(frame) + frame_shape = (frame.rows(), frame.cols(), 4) tfac = VideoTargetFactory.get_instance() frame_rate = reader.get_frame_rate() @@ -128,7 +128,8 @@ def update(self, frame): red_dyer = Dyer(2, 64) green_dyer = Dyer(1, 64) - bufferer_red = BuffererRed() + buffer_red = np.zeros(frame_shape, np.uint8) + bufferer_red = BuffererRed(buffer_red) hist = HistogrammerRed() hist.start() From 1290fad47f8e953ec290fa5979466ff301c05e9c Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:10:43 +0100 Subject: [PATCH 158/277] Revert "Issue #16: added a BuffererOrig class, a virtual replica of BuffererRed" This reverts commit 053f499ae6554460df9a755067e1ff5ec817a247. --- .../multithreading_reliability_check.py | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 0ca024bc..8aed9c85 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -24,7 +24,7 @@ """ -buffer_red, buffer_orig = None, None +buffer_red = None lock = threading.Lock() @@ -40,21 +40,6 @@ def update(self, frame): self.buffer[:, :, :] = data[:, :, :] -class BuffererOrig(IObservableObserver): - - def __init__(self): - super(BuffererOrig, self).__init__() - - def update(self, frame): - global buffer_orig - with lock: - data = frame.data(True) - if buffer_orig is None: - buffer_orig = np.copy(data) - else: - buffer_red[:, :, :] = data[:, :, :] - - class HistogrammerRed(threading.Thread): def __init__(self): From 6fcf20a134ba3c453460d868a3fef0067cdc1f56 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:12:15 +0100 Subject: [PATCH 159/277] Issue #16: renamed BuffererRed => Bufferer --- src/tests/pipeline/multithreading_reliability_check.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 8aed9c85..a345dfd6 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -28,10 +28,10 @@ lock = threading.Lock() -class BuffererRed(IObservableObserver): +class Bufferer(IObservableObserver): def __init__(self, buffer): - super(BuffererRed, self).__init__() + super(Bufferer, self).__init__() self.buffer = buffer def update(self, frame): @@ -114,7 +114,7 @@ def update(self, frame): green_dyer = Dyer(1, 64) buffer_red = np.zeros(frame_shape, np.uint8) - bufferer_red = BuffererRed(buffer_red) + bufferer_red = Bufferer(buffer_red) hist = HistogrammerRed() hist.start() From 66dd339f02970fe13cd16df3f0243948a08072dd Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:15:02 +0100 Subject: [PATCH 160/277] Issue #16: HistogrammerRed now takes buffer as a constructor argument rather than using global var --- .../pipeline/multithreading_reliability_check.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index a345dfd6..4a58d7bb 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -42,24 +42,23 @@ def update(self, frame): class HistogrammerRed(threading.Thread): - def __init__(self): + def __init__(self, buffer): super(HistogrammerRed, self).__init__() + self.buffer = buffer self.running = False def run(self): if self.running: return - global buffer_red histogram, num_bins = None, 10 redness_scale = np.array([i for i in range(1, num_bins + 1)], np.float) self.running = True while self.running: with lock: - if buffer_red is not None: - histogram, _ = np.histogram( - buffer_red[:, :, 2], bins=num_bins, range=(0, 256) - ) + histogram, _ = np.histogram( + self.buffer[:, :, 2], bins=num_bins, range=(0, 256) + ) if histogram is not None: redness = np.sum(histogram * redness_scale) redness /= np.sum(histogram) @@ -116,7 +115,7 @@ def update(self, frame): buffer_red = np.zeros(frame_shape, np.uint8) bufferer_red = Bufferer(buffer_red) - hist = HistogrammerRed() + hist = HistogrammerRed(buffer_red) hist.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) From 60d44a59863738b28a1996772d82baddee0cfb7c Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:22:12 +0100 Subject: [PATCH 161/277] Issue #16: HistogrammerRed is now generic Histogrammer --- .../multithreading_reliability_check.py | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 4a58d7bb..0de913ed 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -40,10 +40,14 @@ def update(self, frame): self.buffer[:, :, :] = data[:, :, :] -class HistogrammerRed(threading.Thread): +class Histogrammer(threading.Thread): - def __init__(self, buffer): - super(HistogrammerRed, self).__init__() + channels = ('Blue', 'Green', 'Red', 'Alpha') + + def __init__(self, buffer, channel): + super(Histogrammer, self).__init__() + assert channel in range(3) + self.channel = channel self.buffer = buffer self.running = False @@ -52,7 +56,7 @@ def run(self): return histogram, num_bins = None, 10 - redness_scale = np.array([i for i in range(1, num_bins + 1)], np.float) + scale = np.array([i for i in range(1, num_bins + 1)], np.float) self.running = True while self.running: with lock: @@ -60,11 +64,13 @@ def run(self): self.buffer[:, :, 2], bins=num_bins, range=(0, 256) ) if histogram is not None: - redness = np.sum(histogram * redness_scale) - redness /= np.sum(histogram) - redness /= num_bins - redness *= 100 - print('Redness: {} %'.format(int(round(redness)))) + coloredness = np.sum(histogram * scale) + coloredness /= np.sum(histogram) + coloredness /= num_bins + coloredness *= 100 + print('{}ness of dyed image: {} %'.format( + Histogrammer.channels[self.channel], int(round(coloredness)) + )) sleep(0.100) def stop(self): @@ -115,7 +121,7 @@ def update(self, frame): buffer_red = np.zeros(frame_shape, np.uint8) bufferer_red = Bufferer(buffer_red) - hist = HistogrammerRed(buffer_red) + hist = Histogrammer(buffer_red, 2) hist.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) From 07d9ca9c1c1dfca3c61d75238e2a539dad5bc312 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:27:00 +0100 Subject: [PATCH 162/277] Issue #16: Histogrammer now accepts a tag for generically printing what the image is --- src/tests/pipeline/multithreading_reliability_check.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 0de913ed..168b6b9f 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -44,11 +44,12 @@ class Histogrammer(threading.Thread): channels = ('Blue', 'Green', 'Red', 'Alpha') - def __init__(self, buffer, channel): + def __init__(self, buffer, channel, tag): super(Histogrammer, self).__init__() assert channel in range(3) self.channel = channel self.buffer = buffer + self.tag = tag self.running = False def run(self): @@ -68,8 +69,8 @@ def run(self): coloredness /= np.sum(histogram) coloredness /= num_bins coloredness *= 100 - print('{}ness of dyed image: {} %'.format( - Histogrammer.channels[self.channel], int(round(coloredness)) + print('{}ness of {} image: {} %'.format( + Histogrammer.channels[self.channel], self.tag, int(round(coloredness)) )) sleep(0.100) @@ -121,7 +122,7 @@ def update(self, frame): buffer_red = np.zeros(frame_shape, np.uint8) bufferer_red = Bufferer(buffer_red) - hist = Histogrammer(buffer_red, 2) + hist = Histogrammer(buffer_red, 2, 'red-dyed') hist.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) From 2347e43170d54276224abe67359e022e0a7afd22 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:34:30 +0100 Subject: [PATCH 163/277] Issue #16: inserted an original image histogrammer into the pipeline --- .../multithreading_reliability_check.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 168b6b9f..971e94b2 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -24,7 +24,7 @@ """ -buffer_red = None +buffer_red, buffer_orig = None, None lock = threading.Lock() @@ -121,25 +121,32 @@ def update(self, frame): buffer_red = np.zeros(frame_shape, np.uint8) bufferer_red = Bufferer(buffer_red) + buffer_orig = np.zeros_like(buffer_red) + bufferer_orig = Bufferer(buffer_orig) - hist = Histogrammer(buffer_red, 2, 'red-dyed') - hist.start() + hist_red = Histogrammer(buffer_red, 2, 'red-dyed') + hist_red.start() + hist_orig = Histogrammer(buffer_orig, 2, 'original') + hist_orig.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) red_writer = tfac.create_file_writer(Codec.HEVC, red_file, frame_rate) yellow_file = os.path.join('.', ''.join([filename, '-yellow', ext])) yellow_writer = tfac.create_file_writer(Codec.HEVC, yellow_file, frame_rate) - reader.attach(red_dyer) + reader.attach(bufferer_orig) + bufferer_orig.attach(red_dyer) red_dyer.attach(red_writer) red_dyer.attach(bufferer_red) red_dyer.attach(green_dyer) green_dyer.attach(yellow_writer) sleep(20) # operate pipeline for 20 sec - hist.stop() + hist_red.stop() + hist_orig.stop() - reader.detach(red_dyer) + reader.detach(bufferer_orig) + bufferer_orig.detach(red_dyer) red_dyer.detach(red_writer) red_dyer.detach(bufferer_red) red_dyer.detach(green_dyer) From a947f5bcfe8d015191a066842a5076e7e648d292 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:39:33 +0100 Subject: [PATCH 164/277] Issue #16: Histogrammer now accepts a frame rate and flag for displaying coloredness --- .../multithreading_reliability_check.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 971e94b2..df093c13 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -44,12 +44,15 @@ class Histogrammer(threading.Thread): channels = ('Blue', 'Green', 'Red', 'Alpha') - def __init__(self, buffer, channel, tag): + def __init__(self, buffer, channel, tag, frame_rate, show=True): super(Histogrammer, self).__init__() assert channel in range(3) + assert 0 < frame_rate <= 60 self.channel = channel self.buffer = buffer self.tag = tag + self.show = show + self.sleep_interval = 1.0 / frame_rate self.running = False def run(self): @@ -69,10 +72,12 @@ def run(self): coloredness /= np.sum(histogram) coloredness /= num_bins coloredness *= 100 - print('{}ness of {} image: {} %'.format( - Histogrammer.channels[self.channel], self.tag, int(round(coloredness)) - )) - sleep(0.100) + if self.show: + print('{}ness of {} image: {} %'.format( + Histogrammer.channels[self.channel], + self.tag, int(round(coloredness)) + )) + sleep(self.sleep_interval) def stop(self): self.running = False @@ -124,9 +129,9 @@ def update(self, frame): buffer_orig = np.zeros_like(buffer_red) bufferer_orig = Bufferer(buffer_orig) - hist_red = Histogrammer(buffer_red, 2, 'red-dyed') + hist_red = Histogrammer(buffer_red, 2, 'red-dyed', 30, False) hist_red.start() - hist_orig = Histogrammer(buffer_orig, 2, 'original') + hist_orig = Histogrammer(buffer_orig, 2, 'original', 30, False) hist_orig.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) From 7e4bfe4145c9b0570a206b05a9edeb997e1b33f7 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:45:12 +0100 Subject: [PATCH 165/277] Issue #16: now can specify the frequency of coloredness prints --- .../pipeline/multithreading_reliability_check.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index df093c13..43e82a19 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -44,14 +44,16 @@ class Histogrammer(threading.Thread): channels = ('Blue', 'Green', 'Red', 'Alpha') - def __init__(self, buffer, channel, tag, frame_rate, show=True): + def __init__(self, buffer, channel, tag, frame_rate, display_freq): super(Histogrammer, self).__init__() assert channel in range(3) assert 0 < frame_rate <= 60 + assert 0 <= display_freq self.channel = channel self.buffer = buffer self.tag = tag - self.show = show + self.display_freq = display_freq + self.num_skipped = 0 self.sleep_interval = 1.0 / frame_rate self.running = False @@ -72,11 +74,14 @@ def run(self): coloredness /= np.sum(histogram) coloredness /= num_bins coloredness *= 100 - if self.show: + if self.num_skipped >= self.display_freq: print('{}ness of {} image: {} %'.format( Histogrammer.channels[self.channel], self.tag, int(round(coloredness)) )) + self.num_skipped = 0 + else: + self.num_skipped += 1 sleep(self.sleep_interval) def stop(self): @@ -129,9 +134,9 @@ def update(self, frame): buffer_orig = np.zeros_like(buffer_red) bufferer_orig = Bufferer(buffer_orig) - hist_red = Histogrammer(buffer_red, 2, 'red-dyed', 30, False) + hist_red = Histogrammer(buffer_red, 2, 'red-dyed', 30.0, 10) hist_red.start() - hist_orig = Histogrammer(buffer_orig, 2, 'original', 30, False) + hist_orig = Histogrammer(buffer_orig, 2, 'original', 30.0, 10) hist_orig.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) From 805e6592dfc54b73aa6152a36eae5387c6e3a079 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:47:38 +0100 Subject: [PATCH 166/277] Issue #16: dyeing red more prominently --- src/tests/pipeline/multithreading_reliability_check.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 43e82a19..72ab94d2 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -126,7 +126,7 @@ def update(self, frame): tfac = VideoTargetFactory.get_instance() frame_rate = reader.get_frame_rate() - red_dyer = Dyer(2, 64) + red_dyer = Dyer(2, 128) green_dyer = Dyer(1, 64) buffer_red = np.zeros(frame_shape, np.uint8) From faf96f7d82ecbd1bb1638319e28813d276c4af59 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:53:47 +0100 Subject: [PATCH 167/277] Issue #16: frame rate values that reproduced the problem --- src/tests/pipeline/multithreading_reliability_check.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 72ab94d2..42cc36e3 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -134,9 +134,9 @@ def update(self, frame): buffer_orig = np.zeros_like(buffer_red) bufferer_orig = Bufferer(buffer_orig) - hist_red = Histogrammer(buffer_red, 2, 'red-dyed', 30.0, 10) + hist_red = Histogrammer(buffer_red, 2, 'red-dyed', 60.0, 10) hist_red.start() - hist_orig = Histogrammer(buffer_orig, 2, 'original', 30.0, 10) + hist_orig = Histogrammer(buffer_orig, 2, 'original', 50.0, 10) hist_orig.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) From 36746d2217db89d30cc7d52c95530d4ee402f278 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:54:25 +0100 Subject: [PATCH 168/277] Issue #16: using Debug CMake type in build script --- src/tests/pipeline/check_multithreading_reliability.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index efae4d95..7ea874b2 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -13,6 +13,7 @@ CMAKE_OPTS="-D USE_FILES=ON" CMAKE_OPTS="$CMAKE_OPTS -D USE_HEVC=ON" CMAKE_OPTS="$CMAKE_OPTS -D ENABLE_NONFREE=ON -D USE_NVENC=ON" CMAKE_OPTS="$CMAKE_OPTS -D BUILD_PYTHON=ON -D USE_NUMPY=ON" +CMAKE_OPTS="$CMAKE_OPTS -D CMAKE_BUILD_TYPE=Debug" MTR_SCRIPT=$CURRENT_DIR/multithreading_reliability_check.py mkdir -p $BUILD_DIR From 1ef3c353aa9a5c2812c40c4e6fa7549471048d65 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 08:28:50 +0100 Subject: [PATCH 169/277] Issue #16: renamed variable for clarity in run script --- src/tests/pipeline/check_multithreading_reliability.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 7ea874b2..2be8fea2 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -6,15 +6,15 @@ # and NumPy support. Subsequently run the multi-threading # reliability check script. -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" -BUILD_DIR=$CURRENT_DIR/mtr-build -SOURCE_DIR="$( cd "$CURRENT_DIR/../.." >/dev/null && pwd )" +ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" +BUILD_DIR=$ROOT_DIR/mtr-build +SOURCE_DIR="$( cd "$ROOT_DIR/../.." >/dev/null && pwd )" CMAKE_OPTS="-D USE_FILES=ON" CMAKE_OPTS="$CMAKE_OPTS -D USE_HEVC=ON" CMAKE_OPTS="$CMAKE_OPTS -D ENABLE_NONFREE=ON -D USE_NVENC=ON" CMAKE_OPTS="$CMAKE_OPTS -D BUILD_PYTHON=ON -D USE_NUMPY=ON" CMAKE_OPTS="$CMAKE_OPTS -D CMAKE_BUILD_TYPE=Debug" -MTR_SCRIPT=$CURRENT_DIR/multithreading_reliability_check.py +MTR_SCRIPT=$ROOT_DIR/multithreading_reliability_check.py mkdir -p $BUILD_DIR rm -rf $BUILD_DIR/* From 5483be9c7188c6b5bce94dc06f50492b493892fb Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 09:00:44 +0100 Subject: [PATCH 170/277] Issue #16: setting ulimit to dump cores when running check --- src/tests/pipeline/check_multithreading_reliability.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 2be8fea2..4519cb84 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -15,6 +15,7 @@ CMAKE_OPTS="$CMAKE_OPTS -D ENABLE_NONFREE=ON -D USE_NVENC=ON" CMAKE_OPTS="$CMAKE_OPTS -D BUILD_PYTHON=ON -D USE_NUMPY=ON" CMAKE_OPTS="$CMAKE_OPTS -D CMAKE_BUILD_TYPE=Debug" MTR_SCRIPT=$ROOT_DIR/multithreading_reliability_check.py +ulimit -c unlimited mkdir -p $BUILD_DIR rm -rf $BUILD_DIR/* @@ -22,3 +23,5 @@ cd $BUILD_DIR cmake $CMAKE_OPTS $SOURCE_DIR make -j4 PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT --input $1 + +ulimit -c 0 From fe2930011eafdb962fca98486078767d4d27589b Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 09:02:44 +0100 Subject: [PATCH 171/277] Issue #16: saving all output in a hierarchical session directory --- .../pipeline/check_multithreading_reliability.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 4519cb84..f3cc6910 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -15,13 +15,26 @@ CMAKE_OPTS="$CMAKE_OPTS -D ENABLE_NONFREE=ON -D USE_NVENC=ON" CMAKE_OPTS="$CMAKE_OPTS -D BUILD_PYTHON=ON -D USE_NUMPY=ON" CMAKE_OPTS="$CMAKE_OPTS -D CMAKE_BUILD_TYPE=Debug" MTR_SCRIPT=$ROOT_DIR/multithreading_reliability_check.py +SESSION_DIR=$ROOT_DIR/$(date +"%Y-%m-%d-%H-%M-%S") +mkdir $SESSION_DIR ulimit -c unlimited +BUILD_LOG=$SESSION_DIR/build.log +{ mkdir -p $BUILD_DIR rm -rf $BUILD_DIR/* cd $BUILD_DIR cmake $CMAKE_OPTS $SOURCE_DIR make -j4 +} > $BUILD_LOG 2>&1 + +run_no=1 +WORKING_DIR=$SESSION_DIR/$run_no +mkdir $WORKING_DIR +cd $WORKING_DIR +RUN_LOG=$WORKING_DIR/run.log +{ PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT --input $1 +} > $RUN_LOG 2>&1 ulimit -c 0 From 620f0f4b97147755ed580aec000ac8fc72c6dd69 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 09:05:12 +0100 Subject: [PATCH 172/277] Issue #16: added indentation for readability --- .../pipeline/check_multithreading_reliability.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index f3cc6910..71e9efc0 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -21,11 +21,11 @@ ulimit -c unlimited BUILD_LOG=$SESSION_DIR/build.log { -mkdir -p $BUILD_DIR -rm -rf $BUILD_DIR/* -cd $BUILD_DIR -cmake $CMAKE_OPTS $SOURCE_DIR -make -j4 + mkdir -p $BUILD_DIR + rm -rf $BUILD_DIR/* + cd $BUILD_DIR + cmake $CMAKE_OPTS $SOURCE_DIR + make -j4 } > $BUILD_LOG 2>&1 run_no=1 @@ -34,7 +34,7 @@ mkdir $WORKING_DIR cd $WORKING_DIR RUN_LOG=$WORKING_DIR/run.log { -PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT --input $1 + PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT --input $1 } > $RUN_LOG 2>&1 ulimit -c 0 From ee7aa5fdeaced44d5ed64eb4efc790ed10376bbb Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 09:14:47 +0100 Subject: [PATCH 173/277] Issue #16: can now specify number of reps in check script --- .../check_multithreading_reliability.sh | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 71e9efc0..52eed368 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -28,13 +28,20 @@ BUILD_LOG=$SESSION_DIR/build.log make -j4 } > $BUILD_LOG 2>&1 -run_no=1 -WORKING_DIR=$SESSION_DIR/$run_no -mkdir $WORKING_DIR -cd $WORKING_DIR -RUN_LOG=$WORKING_DIR/run.log -{ - PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT --input $1 -} > $RUN_LOG 2>&1 +num_reps=1 +if [ $# -ge 2 ]; +then + num_reps=$2 +fi +for run_no in `seq 1 $num_reps`; +do + WORKING_DIR=$SESSION_DIR/$(printf "%03d" $run_no) + mkdir $WORKING_DIR + cd $WORKING_DIR + RUN_LOG=$WORKING_DIR/run.log + { + PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT --input $1 + } > $RUN_LOG 2>&1 +done ulimit -c 0 From 94ffd82f97b25afe4030608be8493234e953cef2 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 10:38:52 +0100 Subject: [PATCH 174/277] Issue #16: can now optionally specify root output dir (e.g. not to fill up disk space) --- .../pipeline/check_multithreading_reliability.sh | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 52eed368..1a90362e 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -6,15 +6,22 @@ # and NumPy support. Subsequently run the multi-threading # reliability check script. -ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" +CALL_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" +SOURCE_DIR="$( cd "$CALL_DIR/../.." >/dev/null && pwd )" +MTR_SCRIPT=$SOURCE_DIR/tests/pipeline/multithreading_reliability_check.py +if [ $# -ge 3 ]; +then + ROOT_DIR=$3 +else + ROOT_DIR=$CALL_DIR +fi + BUILD_DIR=$ROOT_DIR/mtr-build -SOURCE_DIR="$( cd "$ROOT_DIR/../.." >/dev/null && pwd )" CMAKE_OPTS="-D USE_FILES=ON" CMAKE_OPTS="$CMAKE_OPTS -D USE_HEVC=ON" CMAKE_OPTS="$CMAKE_OPTS -D ENABLE_NONFREE=ON -D USE_NVENC=ON" CMAKE_OPTS="$CMAKE_OPTS -D BUILD_PYTHON=ON -D USE_NUMPY=ON" CMAKE_OPTS="$CMAKE_OPTS -D CMAKE_BUILD_TYPE=Debug" -MTR_SCRIPT=$ROOT_DIR/multithreading_reliability_check.py SESSION_DIR=$ROOT_DIR/$(date +"%Y-%m-%d-%H-%M-%S") mkdir $SESSION_DIR ulimit -c unlimited From f77c463803bac067cee347b1fdbb990248520a4a Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 10:48:37 +0100 Subject: [PATCH 175/277] Issue #16: logging frequency of exit codes as well --- .../pipeline/check_multithreading_reliability.sh | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 1a90362e..f7fbb5fe 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -40,6 +40,8 @@ if [ $# -ge 2 ]; then num_reps=$2 fi + +declare -a exit_code_freqs for run_no in `seq 1 $num_reps`; do WORKING_DIR=$SESSION_DIR/$(printf "%03d" $run_no) @@ -48,7 +50,21 @@ do RUN_LOG=$WORKING_DIR/run.log { PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT --input $1 + + exit_code=$? + echo "Exit code was: $exit_code" + freq=${exit_code_freqs[$exit_code]} + let freq=$freq+1 + exit_code_freqs[$exit_code]=$freq } > $RUN_LOG 2>&1 + + sleep 5 +done + +EXIT_CODES_LOG=$SESSION_DIR/exit-codes.csv +for exit_code in "${!exit_code_freqs[@]}"; +do + echo "$exit_code ${exit_code_freqs[$exit_code]}" >> $EXIT_CODES_LOG done ulimit -c 0 From c3ce578fd59b56842e30c1224556787da1d126f4 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 10:59:58 +0100 Subject: [PATCH 176/277] Issue #16: nicer formatting of exit code frequencies log --- src/tests/pipeline/check_multithreading_reliability.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index f7fbb5fe..419b7c08 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -62,9 +62,14 @@ do done EXIT_CODES_LOG=$SESSION_DIR/exit-codes.csv +printf "%10s" "exit-code" >> $EXIT_CODES_LOG +printf "%10s" "frequency" >> $EXIT_CODES_LOG +printf "\n" >> $EXIT_CODES_LOG for exit_code in "${!exit_code_freqs[@]}"; do - echo "$exit_code ${exit_code_freqs[$exit_code]}" >> $EXIT_CODES_LOG + printf "%10d" $exit_code >> $EXIT_CODES_LOG + printf "%10d" ${exit_code_freqs[$exit_code]} >> $EXIT_CODES_LOG + printf "\n" >> $EXIT_CODES_LOG done ulimit -c 0 From 5072e59398690250201454064882b997ddb83cac Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 11:02:37 +0100 Subject: [PATCH 177/277] Issue #16: ignoring output folder to avoid an accidental commit of big files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d7eb0905..35b7a77b 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ src/dist src/*.egg-info *.swp src/tests/pipeline/mtr-build +gg-iss-16 From 8d884351255cfb3946c6f1a769d4266866860de8 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 11:06:29 +0100 Subject: [PATCH 178/277] Issue #16: using absolute path expansion if root-dir passed as a CLI param --- src/tests/pipeline/check_multithreading_reliability.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 419b7c08..18b9133e 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -11,7 +11,7 @@ SOURCE_DIR="$( cd "$CALL_DIR/../.." >/dev/null && pwd )" MTR_SCRIPT=$SOURCE_DIR/tests/pipeline/multithreading_reliability_check.py if [ $# -ge 3 ]; then - ROOT_DIR=$3 + ROOT_DIR="$( cd "$3" >/dev/null && pwd )" else ROOT_DIR=$CALL_DIR fi From 43e9512f10c3f530f98253505a8cc0ccc43ce08a Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 11:56:45 +0100 Subject: [PATCH 179/277] Issue #16: intermediately writing exit codes every 10 iterations --- .../check_multithreading_reliability.sh | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 18b9133e..64b58250 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -58,18 +58,21 @@ do exit_code_freqs[$exit_code]=$freq } > $RUN_LOG 2>&1 - sleep 5 -done + if [ $(($run_no % 10)) -eq 0 ] || [ $run_no -eq $num_reps ]; + then + EXIT_CODES_LOG=$SESSION_DIR/exit-codes-$run_no.csv + printf "%10s" "exit-code" >> $EXIT_CODES_LOG + printf "%10s" "frequency" >> $EXIT_CODES_LOG + printf "\n" >> $EXIT_CODES_LOG + for exit_code in "${!exit_code_freqs[@]}"; + do + printf "%10d" $exit_code >> $EXIT_CODES_LOG + printf "%10d" ${exit_code_freqs[$exit_code]} >> $EXIT_CODES_LOG + printf "\n" >> $EXIT_CODES_LOG + done + fi -EXIT_CODES_LOG=$SESSION_DIR/exit-codes.csv -printf "%10s" "exit-code" >> $EXIT_CODES_LOG -printf "%10s" "frequency" >> $EXIT_CODES_LOG -printf "\n" >> $EXIT_CODES_LOG -for exit_code in "${!exit_code_freqs[@]}"; -do - printf "%10d" $exit_code >> $EXIT_CODES_LOG - printf "%10d" ${exit_code_freqs[$exit_code]} >> $EXIT_CODES_LOG - printf "\n" >> $EXIT_CODES_LOG + sleep 5 done ulimit -c 0 From 8e0704296e7e685574edc46e311c4557cb90dc12 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 12:19:39 +0100 Subject: [PATCH 180/277] Issue #16: using git-describe to tag the output with the version used --- src/tests/pipeline/check_multithreading_reliability.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 64b58250..71e2bb62 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -28,6 +28,7 @@ ulimit -c unlimited BUILD_LOG=$SESSION_DIR/build.log { + git describe --dirty mkdir -p $BUILD_DIR rm -rf $BUILD_DIR/* cd $BUILD_DIR From f0f7bb533b4cf600e245789c78454958f248024d Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 12:47:45 +0100 Subject: [PATCH 181/277] Issue #16: querying for update override after the acquisition of GIL --- src/python/wrapper.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/python/wrapper.cpp b/src/python/wrapper.cpp index ae1125de..f6651d9a 100644 --- a/src/python/wrapper.cpp +++ b/src/python/wrapper.cpp @@ -332,11 +332,13 @@ class IObservableObserverWrapper : public gg::IObservable void update(gg::VideoFrame & frame) { - if (override f = this->get_override("update")) { - VideoFrameNumPyWrapper wrapped_frame(&frame); gg::ScopedPythonGILLock gil_lock; - f(boost::ref(wrapped_frame)); + if (override f = this->get_override("update")) + { + VideoFrameNumPyWrapper wrapped_frame(&frame); + f(boost::ref(wrapped_frame)); + } } notify(frame); } From 3b96e7219b79e84a3cb5816823602b57f2cd6a59 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 13:35:54 +0100 Subject: [PATCH 182/277] Issue #16: checking update method overridden in Python before actually calling it from within IObserverWrapper --- src/python/wrapper.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/python/wrapper.cpp b/src/python/wrapper.cpp index f6651d9a..11f7e72f 100644 --- a/src/python/wrapper.cpp +++ b/src/python/wrapper.cpp @@ -268,7 +268,8 @@ class IObserverWrapper : public gg::IObserver, public wrapper { gg::ScopedPythonGILLock gil_lock; VideoFrameNumPyWrapper wrapped_frame(&frame); - this->get_override("update")(boost::ref(wrapped_frame)); + if (override f = this->get_override("update")) + f(boost::ref(wrapped_frame)); } }; From 8a41daef1a61a9db3339a92f4d43c68b0c3055ad Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 09:06:14 +0100 Subject: [PATCH 183/277] Issue #16: using Pythonic percentage formatting --- src/tests/pipeline/multithreading_reliability_check.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 42cc36e3..e1c50e30 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -73,11 +73,10 @@ def run(self): coloredness = np.sum(histogram * scale) coloredness /= np.sum(histogram) coloredness /= num_bins - coloredness *= 100 if self.num_skipped >= self.display_freq: - print('{}ness of {} image: {} %'.format( + print('{}ness of {} image: {:.0%}'.format( Histogrammer.channels[self.channel], - self.tag, int(round(coloredness)) + self.tag, coloredness )) self.num_skipped = 0 else: From 3ac735d9326a15dcf0327ca78e4f72510b7d220f Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 09:24:39 +0100 Subject: [PATCH 184/277] Issue #16: added a SnapshotSaver class that implements IObserver directly --- .../multithreading_reliability_check.py | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index e1c50e30..a880b355 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -6,9 +6,10 @@ import os.path import threading import numpy as np +import scipy.misc from pygiftgrab import (VideoSourceFactory, VideoFrame, ColourSpace, IObservableObserver, - VideoTargetFactory, Codec) + VideoTargetFactory, Codec, IObserver) """ This script provides a multi-threading reliability check. @@ -28,6 +29,32 @@ lock = threading.Lock() +class SnapshotSaver(IObserver): + """A snapshot saver for saving incoming frames to PNG files.""" + + def __init__(self, root_dir, frame_rate=0.2): + """ + Initialise a snapshot saver with a saving frequency. + + :param root_dir: the folder where to save the snapshots + :param frame_rate: saving frequency. The default value tells + the saver to save a frame every 5 sec. + """ + super(SnapshotSaver, self).__init__() + assert 0 < frame_rate <= 1 # to avoid flooding disk with images + self.save_freq = 1.0 / frame_rate + self.root_dir = root_dir + self.num_called = 0 + + def update(self, frame): + """Implement ``IObserver.update``.""" + self.num_called += 1 + if self.num_called % self.save_freq == 1: + out_file = os.path.join(self.root_dir, + 'frame-{:010d}.png'.format(self.num_called)) + scipy.misc.imsave(out_file, frame.data(True)) + + class Bufferer(IObservableObserver): def __init__(self, buffer): From 74ee1c808368ee5bd6fca0e7699c7bf2c0478402 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 09:25:08 +0100 Subject: [PATCH 185/277] Issue #16: inserted snapshot saver into the pipeline --- src/tests/pipeline/multithreading_reliability_check.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index a880b355..f1a1697f 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -170,12 +170,15 @@ def update(self, frame): yellow_file = os.path.join('.', ''.join([filename, '-yellow', ext])) yellow_writer = tfac.create_file_writer(Codec.HEVC, yellow_file, frame_rate) + yellow_snapshots = SnapshotSaver('.') + reader.attach(bufferer_orig) bufferer_orig.attach(red_dyer) red_dyer.attach(red_writer) red_dyer.attach(bufferer_red) red_dyer.attach(green_dyer) green_dyer.attach(yellow_writer) + green_dyer.attach(yellow_snapshots) sleep(20) # operate pipeline for 20 sec hist_red.stop() @@ -187,3 +190,4 @@ def update(self, frame): red_dyer.detach(bufferer_red) red_dyer.detach(green_dyer) green_dyer.detach(yellow_writer) + green_dyer.detach(yellow_snapshots) From 4b10f04db7133a75ec8d8375f967ae929c8c0e80 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 09:47:20 +0100 Subject: [PATCH 186/277] Issue #16: fixed timed saving of snapshots --- .../multithreading_reliability_check.py | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index f1a1697f..7eca3382 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -from time import sleep +from time import (sleep, time) import argparse import os.path import threading @@ -32,27 +32,29 @@ class SnapshotSaver(IObserver): """A snapshot saver for saving incoming frames to PNG files.""" - def __init__(self, root_dir, frame_rate=0.2): + def __init__(self, root_dir, save_freq=5): """ Initialise a snapshot saver with a saving frequency. :param root_dir: the folder where to save the snapshots - :param frame_rate: saving frequency. The default value tells - the saver to save a frame every 5 sec. + :param save_freq: saving frequency. The default value tells + the saver to save every 5 seconds. """ super(SnapshotSaver, self).__init__() - assert 0 < frame_rate <= 1 # to avoid flooding disk with images - self.save_freq = 1.0 / frame_rate + assert 5 <= save_freq # to avoid flooding disk with images + self.save_freq = save_freq self.root_dir = root_dir - self.num_called = 0 + self.last_saved = time() + self.num_saved = 0 def update(self, frame): """Implement ``IObserver.update``.""" - self.num_called += 1 - if self.num_called % self.save_freq == 1: + if time() - self.last_saved >= self.save_freq: + self.num_saved += 1 out_file = os.path.join(self.root_dir, - 'frame-{:010d}.png'.format(self.num_called)) + 'frame-{:010d}.png'.format(self.num_saved)) scipy.misc.imsave(out_file, frame.data(True)) + self.last_saved = time() class Bufferer(IObservableObserver): From 5e03e8376d990f1ed4d2ef98002af892d7ba286c Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 10:10:24 +0100 Subject: [PATCH 187/277] Issue #16: renamed buffer => np_buffer as buffer is built-in type --- src/tests/pipeline/multithreading_reliability_check.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 7eca3382..0091b993 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -59,9 +59,9 @@ def update(self, frame): class Bufferer(IObservableObserver): - def __init__(self, buffer): + def __init__(self, np_buffer): super(Bufferer, self).__init__() - self.buffer = buffer + self.buffer = np_buffer def update(self, frame): with lock: @@ -73,13 +73,13 @@ class Histogrammer(threading.Thread): channels = ('Blue', 'Green', 'Red', 'Alpha') - def __init__(self, buffer, channel, tag, frame_rate, display_freq): + def __init__(self, np_buffer, channel, tag, frame_rate, display_freq): super(Histogrammer, self).__init__() assert channel in range(3) assert 0 < frame_rate <= 60 assert 0 <= display_freq self.channel = channel - self.buffer = buffer + self.buffer = np_buffer self.tag = tag self.display_freq = display_freq self.num_skipped = 0 From 67e384c351b5a4d182bce16f0bc1f8ec6be1f656 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 10:17:51 +0100 Subject: [PATCH 188/277] Issue #16: renamed global buffers for clarity --- .../pipeline/multithreading_reliability_check.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 0091b993..8d3d4b89 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -25,7 +25,7 @@ """ -buffer_red, buffer_orig = None, None +np_buffer_red, np_buffer_orig = None, None lock = threading.Lock() @@ -157,14 +157,14 @@ def update(self, frame): red_dyer = Dyer(2, 128) green_dyer = Dyer(1, 64) - buffer_red = np.zeros(frame_shape, np.uint8) - bufferer_red = Bufferer(buffer_red) - buffer_orig = np.zeros_like(buffer_red) - bufferer_orig = Bufferer(buffer_orig) + np_buffer_red = np.zeros(frame_shape, np.uint8) + bufferer_red = Bufferer(np_buffer_red) + np_buffer_orig = np.zeros_like(np_buffer_red) + bufferer_orig = Bufferer(np_buffer_orig) - hist_red = Histogrammer(buffer_red, 2, 'red-dyed', 60.0, 10) + hist_red = Histogrammer(np_buffer_red, 2, 'red-dyed', 60.0, 10) hist_red.start() - hist_orig = Histogrammer(buffer_orig, 2, 'original', 50.0, 10) + hist_orig = Histogrammer(np_buffer_orig, 2, 'original', 50.0, 10) hist_orig.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) From 3ed391a422af29a178200748bd9b22e866075771 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 10:20:01 +0100 Subject: [PATCH 189/277] Issue #16: commented checker script --- .../multithreading_reliability_check.py | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 8d3d4b89..b4d21c9c 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -25,7 +25,11 @@ """ +# global NumPy buffers np_buffer_red, np_buffer_orig = None, None + +# mutex protecting frame data passed from node to node +# in the GIFT-Grab processing pipeline lock = threading.Lock() @@ -58,22 +62,41 @@ def update(self, frame): class Bufferer(IObservableObserver): + """GIFT-Grab processing node that updates a frame buffer.""" def __init__(self, np_buffer): + """Initialise a bufferer that will update given buffer.""" super(Bufferer, self).__init__() self.buffer = np_buffer def update(self, frame): + """Implement ``IObservableObserver.update``.""" with lock: data = frame.data(True) self.buffer[:, :, :] = data[:, :, :] class Histogrammer(threading.Thread): + """ + GIFT-Grab processing node that computes the histogram of + an image channel and prints how "colored" that channel is. + """ channels = ('Blue', 'Green', 'Red', 'Alpha') def __init__(self, np_buffer, channel, tag, frame_rate, display_freq): + """ + :param np_buffer: image buffer to use + :param channel: image channel to compute coloredness for + :param tag: a tag describing what this image is, e.g. + how it's been processed within a GIFT-Grab pipeline + :param frame_rate: the rate at which to compute the + coloredness (unit: frames-per-second) + :param display_freq: how many times to skip the display + of computed coloredness, e.g. if 5 is provided, the + coloredness of every 5th frame will be printed to the + console + """ super(Histogrammer, self).__init__() assert channel in range(3) assert 0 < frame_rate <= 60 @@ -87,6 +110,7 @@ def __init__(self, np_buffer, channel, tag, frame_rate, display_freq): self.running = False def run(self): + """Override ``Thread.run``.""" if self.running: return @@ -113,12 +137,18 @@ def run(self): sleep(self.sleep_interval) def stop(self): + """Stop the thread.""" self.running = False class Dyer(IObservableObserver): + """Dyes specified channel of an incoming video frame.""" def __init__(self, channel, increment): + """ + :param channel: image channel to dye + :param increment: how much to dye the image channel + """ super(Dyer, self).__init__() assert 0 <= channel < 3 assert 0 <= increment < 256 @@ -126,6 +156,7 @@ def __init__(self, channel, increment): self.increment = increment def update(self, frame): + """Implement ``IObservableObserver.update``.""" with lock: data = frame.data(True) channel_data = data[:, :, self.channel] @@ -145,35 +176,46 @@ def update(self, frame): assert filename assert ext == '.mp4' + # initialise reading of passed file sfac = VideoSourceFactory.get_instance() reader = sfac.create_file_reader(in_file, ColourSpace.BGRA) frame = VideoFrame(ColourSpace.BGRA, False) reader.get_frame(frame) frame_shape = (frame.rows(), frame.cols(), 4) + # prepare for creating encoders (writers) tfac = VideoTargetFactory.get_instance() frame_rate = reader.get_frame_rate() + # create a red and green Dyer red_dyer = Dyer(2, 128) green_dyer = Dyer(1, 64) + # create the bufferer for the red and green Dyers np_buffer_red = np.zeros(frame_shape, np.uint8) bufferer_red = Bufferer(np_buffer_red) np_buffer_orig = np.zeros_like(np_buffer_red) bufferer_orig = Bufferer(np_buffer_orig) + # create the histogrammers for the red-dyed and + # the original video frames, and start them hist_red = Histogrammer(np_buffer_red, 2, 'red-dyed', 60.0, 10) hist_red.start() hist_orig = Histogrammer(np_buffer_orig, 2, 'original', 50.0, 10) hist_orig.start() + # create encoders for the red-dyed and yellow-dyed (as green + # is applied on top of red) video streams red_file = os.path.join('.', ''.join([filename, '-red', ext])) red_writer = tfac.create_file_writer(Codec.HEVC, red_file, frame_rate) yellow_file = os.path.join('.', ''.join([filename, '-yellow', ext])) yellow_writer = tfac.create_file_writer(Codec.HEVC, yellow_file, frame_rate) + # create a SnapshotSavers for saving a number of yellow-dyed + # video frames yellow_snapshots = SnapshotSaver('.') + # assemble the GIFT-Grab pipeline reader.attach(bufferer_orig) bufferer_orig.attach(red_dyer) red_dyer.attach(red_writer) @@ -183,9 +225,12 @@ def update(self, frame): green_dyer.attach(yellow_snapshots) sleep(20) # operate pipeline for 20 sec + + # stop the histogrammers hist_red.stop() hist_orig.stop() + # disassemble the GIFT-Grab pipeline reader.detach(bufferer_orig) bufferer_orig.detach(red_dyer) red_dyer.detach(red_writer) From c66665c5d984a98f4275affe2f6e5f165aebaf9a Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 10:54:24 +0100 Subject: [PATCH 190/277] Issue #16: moved issue-specific comments to shell script --- .../check_multithreading_reliability.sh | 17 +++++++++++++---- .../multithreading_reliability_check.py | 18 +++++------------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 71e2bb62..ceafc345 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -1,10 +1,19 @@ #!/usr/bin/env bash # -*- coding: utf-8 -*- -# Build a basic GIFT-Grab capable of reading a video file, -# and encoding to a video file in real time, with Python -# and NumPy support. Subsequently run the multi-threading -# reliability check script. +# This script provides a multi-threading reliability check. +# The background is issue #16. It looks like in applications +# where multiple Python threads are involved, occasionally +# the acquisition of the Global Interpreter Lock leads to a +# deadlocks, which crashes the whole application with a +# non-specific segmentation fault. +# +# It builds a basic GIFT-Grab capable of reading a video file, +# and encoding to a video file in real time, with Python and +# NumPy support. It subsequently runs a multi-threaded +# GIFT-Grab pipeline a number of times, recording the exit +# status each time. This is essentially a stress-test that +# should serve as a validation that issue #16 is fixed. CALL_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" SOURCE_DIR="$( cd "$CALL_DIR/../.." >/dev/null && pwd )" diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index b4d21c9c..3fdad38b 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -1,6 +1,11 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +""" +Example showing a complex GIFT-Grab pipeline with +multiple intermediate processing nodes. +""" + from time import (sleep, time) import argparse import os.path @@ -11,19 +16,6 @@ ColourSpace, IObservableObserver, VideoTargetFactory, Codec, IObserver) -""" -This script provides a multi-threading reliability check. -The background is issue #16. It looks like in applications -where multiple Python threads are involved, occasionally -the acquisition of the Global Interpreter Lock leads to a -deadlocks, which crashes the whole application with a -non-specific segmentation fault. - -In this script we run a number of multi-threaded GIFT-Grab -pipelines, which should serve as a validation that this -problem is fixed. -""" - # global NumPy buffers np_buffer_red, np_buffer_orig = None, None From c9eb7dd115c0be11e6d3e643b0dd93f4484b13ed Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 10:54:45 +0100 Subject: [PATCH 191/277] Issue #16: added synopsis display to shell script --- .../pipeline/check_multithreading_reliability.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index ceafc345..c6419403 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -15,6 +15,18 @@ # status each time. This is essentially a stress-test that # should serve as a validation that issue #16 is fixed. +if [ $# -lt 1 ] || [ $# -gt 3 ]; +then + THIS_SCRIPT="$(basename "$(test -L "${BASH_SOURCE[0]}" && readlink "$0" || echo "$0")")" + printf "Usage: $THIS_SCRIPT video_file [ num_reps [ output_dir ] ]\n" + printf "\tvideo_file: path to an HEVC-encoded MP4 file\n" + printf "\tnum_reps: how many times to run the Python script " + printf "(default: once)\n" + printf "\toutput_dir: where to save all the generated output " + printf "(default: current directory)\n" + exit 1 +fi + CALL_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" SOURCE_DIR="$( cd "$CALL_DIR/../.." >/dev/null && pwd )" MTR_SCRIPT=$SOURCE_DIR/tests/pipeline/multithreading_reliability_check.py From f76c706e49ebe090ed98fe95453ae8e09f4102ef Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 10:57:52 +0100 Subject: [PATCH 192/277] Issue #16: shell script now shows the current session directory before starting --- src/tests/pipeline/check_multithreading_reliability.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index c6419403..39df9537 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -45,6 +45,7 @@ CMAKE_OPTS="$CMAKE_OPTS -D BUILD_PYTHON=ON -D USE_NUMPY=ON" CMAKE_OPTS="$CMAKE_OPTS -D CMAKE_BUILD_TYPE=Debug" SESSION_DIR=$ROOT_DIR/$(date +"%Y-%m-%d-%H-%M-%S") mkdir $SESSION_DIR +echo "Session directory: $SESSION_DIR" ulimit -c unlimited BUILD_LOG=$SESSION_DIR/build.log From a1968280b4d46ecd982f7649b3aff0c170d141e9 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 11:01:37 +0100 Subject: [PATCH 193/277] Issue #16: shorter name for Python script --- .../{multithreading_reliability_check.py => complex_pipeline.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/tests/pipeline/{multithreading_reliability_check.py => complex_pipeline.py} (100%) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/complex_pipeline.py similarity index 100% rename from src/tests/pipeline/multithreading_reliability_check.py rename to src/tests/pipeline/complex_pipeline.py From 9289a48c7883b7c95811277191e926d6fd376343 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 11:02:26 +0100 Subject: [PATCH 194/277] Issue #16: shorter name for Bash script --- ...heck_multithreading_reliability.sh => run-complex-pipeline.sh} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/tests/pipeline/{check_multithreading_reliability.sh => run-complex-pipeline.sh} (100%) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/run-complex-pipeline.sh similarity index 100% rename from src/tests/pipeline/check_multithreading_reliability.sh rename to src/tests/pipeline/run-complex-pipeline.sh From 206efc2f07d11c5693c7d530fc284bdf08a84141 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 11:04:37 +0100 Subject: [PATCH 195/277] Issue #16: fixed typos --- src/tests/pipeline/complex_pipeline.py | 2 +- src/tests/pipeline/run-complex-pipeline.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/pipeline/complex_pipeline.py b/src/tests/pipeline/complex_pipeline.py index 3fdad38b..1d9d7346 100755 --- a/src/tests/pipeline/complex_pipeline.py +++ b/src/tests/pipeline/complex_pipeline.py @@ -203,7 +203,7 @@ def update(self, frame): yellow_file = os.path.join('.', ''.join([filename, '-yellow', ext])) yellow_writer = tfac.create_file_writer(Codec.HEVC, yellow_file, frame_rate) - # create a SnapshotSavers for saving a number of yellow-dyed + # create a SnapshotSaver for saving a number of yellow-dyed # video frames yellow_snapshots = SnapshotSaver('.') diff --git a/src/tests/pipeline/run-complex-pipeline.sh b/src/tests/pipeline/run-complex-pipeline.sh index 39df9537..5166507b 100755 --- a/src/tests/pipeline/run-complex-pipeline.sh +++ b/src/tests/pipeline/run-complex-pipeline.sh @@ -5,7 +5,7 @@ # The background is issue #16. It looks like in applications # where multiple Python threads are involved, occasionally # the acquisition of the Global Interpreter Lock leads to a -# deadlocks, which crashes the whole application with a +# deadlock, which crashes the whole application with a # non-specific segmentation fault. # # It builds a basic GIFT-Grab capable of reading a video file, From db276e82f7498d1a422072b754206084a31e1be1 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 11:04:55 +0100 Subject: [PATCH 196/277] Issue #16: reduced snapshot output --- src/tests/pipeline/complex_pipeline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/pipeline/complex_pipeline.py b/src/tests/pipeline/complex_pipeline.py index 1d9d7346..66686f1e 100755 --- a/src/tests/pipeline/complex_pipeline.py +++ b/src/tests/pipeline/complex_pipeline.py @@ -205,7 +205,7 @@ def update(self, frame): # create a SnapshotSaver for saving a number of yellow-dyed # video frames - yellow_snapshots = SnapshotSaver('.') + yellow_snapshots = SnapshotSaver('.', 9) # assemble the GIFT-Grab pipeline reader.attach(bufferer_orig) From b1bad2e07cd7ebcd5ac835289026eca00d37ea3e Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 11:09:55 +0100 Subject: [PATCH 197/277] Issue #16: fixed calling of Python script from Bash script --- src/tests/pipeline/run-complex-pipeline.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/pipeline/run-complex-pipeline.sh b/src/tests/pipeline/run-complex-pipeline.sh index 5166507b..3ed9e038 100755 --- a/src/tests/pipeline/run-complex-pipeline.sh +++ b/src/tests/pipeline/run-complex-pipeline.sh @@ -29,7 +29,7 @@ fi CALL_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" SOURCE_DIR="$( cd "$CALL_DIR/../.." >/dev/null && pwd )" -MTR_SCRIPT=$SOURCE_DIR/tests/pipeline/multithreading_reliability_check.py +MTR_SCRIPT=$SOURCE_DIR/tests/pipeline/complex_pipeline.py if [ $# -ge 3 ]; then ROOT_DIR="$( cd "$3" >/dev/null && pwd )" From 209e918e10cb9ebc0f2a95f5919b27845cb3089e Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 11:41:33 +0100 Subject: [PATCH 198/277] Issue #16: added an RTD page linking to the complex pipeline example --- doc/source/complex.rst | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 doc/source/complex.rst diff --git a/doc/source/complex.rst b/doc/source/complex.rst new file mode 100644 index 00000000..3982fb7f --- /dev/null +++ b/doc/source/complex.rst @@ -0,0 +1,20 @@ +.. _Complex: + +Multi-threaded processing pipelines +=================================== + +This example shows how GIFT-Grab can be used for running complex pipelines with multiple intermediate +processing nodes and threads. +The intermediate processing nodes are built on the same principles as in the SciPy_ example. +Running the example requires an `HEVC-encoded MP4 file`_, an `NVENC-capable GPU`_, and `NumPy support`_. + +.. _`HEVC-encoded MP4 file`: https://github.com/gift-surg/GIFT-Grab/blob/master/doc/build.md#reading-video-files +.. _`NVENC-capable GPU`: https://github.com/gift-surg/GIFT-Grab/blob/master/doc/build.md#hevc +.. _`NumPy support`: https://github.com/gift-surg/GIFT-Grab/blob/master/doc/build.md#python-api + +Below is the commented full source code: + +.. literalinclude:: ../../src/tests/pipeline/complex_pipeline.py + :language: python + :linenos: + From 7aa547eb59b9e64a47274d50e9ff76ffe3248ad3 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 11:41:59 +0100 Subject: [PATCH 199/277] Issue #16: added the new RTD page to the index --- doc/source/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/index.rst b/doc/source/index.rst index 2c8fddc2..8e9af514 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -51,6 +51,7 @@ Examples network scipy encoding + complex Citing GIFT-Grab ^^^^^^^^^^^^^^^^ From 3da6eea48c0072c612589d8e64a96aa95429c3b0 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 11:59:27 +0100 Subject: [PATCH 200/277] Issue #16: fixed cross-reference to NumPy example from new RTD page --- doc/source/complex.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/complex.rst b/doc/source/complex.rst index 3982fb7f..6e0c8a60 100644 --- a/doc/source/complex.rst +++ b/doc/source/complex.rst @@ -5,7 +5,7 @@ Multi-threaded processing pipelines This example shows how GIFT-Grab can be used for running complex pipelines with multiple intermediate processing nodes and threads. -The intermediate processing nodes are built on the same principles as in the SciPy_ example. +The intermediate processing nodes are built on the same principles as in the :ref:`SciPy` example. Running the example requires an `HEVC-encoded MP4 file`_, an `NVENC-capable GPU`_, and `NumPy support`_. .. _`HEVC-encoded MP4 file`: https://github.com/gift-surg/GIFT-Grab/blob/master/doc/build.md#reading-video-files From 7ead125bca62efb3d7a4b1b30c1993aa0e1159ee Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 12:00:34 +0100 Subject: [PATCH 201/277] Issue #16: added link from new RTD page to example source code on GitHub --- doc/source/complex.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/source/complex.rst b/doc/source/complex.rst index 6e0c8a60..060bce72 100644 --- a/doc/source/complex.rst +++ b/doc/source/complex.rst @@ -12,9 +12,11 @@ Running the example requires an `HEVC-encoded MP4 file`_, an `NVENC-capable GPU` .. _`NVENC-capable GPU`: https://github.com/gift-surg/GIFT-Grab/blob/master/doc/build.md#hevc .. _`NumPy support`: https://github.com/gift-surg/GIFT-Grab/blob/master/doc/build.md#python-api -Below is the commented full source code: +Below is the commented full source code, which is also available on GitHub_: .. literalinclude:: ../../src/tests/pipeline/complex_pipeline.py :language: python :linenos: +.. _GitHub: https://github.com/gift-surg/GIFT-Grab/blob/master/src/tests/pipeline/complex_pipeline.py + From 83dd35d7448f96444aa8b347482a776dd965d729 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 18:47:20 +0100 Subject: [PATCH 202/277] Issue #16: made the title of the new RTD page more descriptive --- doc/source/complex.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/source/complex.rst b/doc/source/complex.rst index 060bce72..98fc12ce 100644 --- a/doc/source/complex.rst +++ b/doc/source/complex.rst @@ -1,7 +1,7 @@ .. _Complex: -Multi-threaded processing pipelines -=================================== +Multi-threaded complex processing pipelines +=========================================== This example shows how GIFT-Grab can be used for running complex pipelines with multiple intermediate processing nodes and threads. From 1b4e3eb77dd6b37666020fb88c99f21f67d9ec00 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 18:51:26 +0100 Subject: [PATCH 203/277] Issue #16: revised the RTD page wording for clarity --- doc/source/complex.rst | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/doc/source/complex.rst b/doc/source/complex.rst index 98fc12ce..0d231ccb 100644 --- a/doc/source/complex.rst +++ b/doc/source/complex.rst @@ -3,16 +3,19 @@ Multi-threaded complex processing pipelines =========================================== -This example shows how GIFT-Grab can be used for running complex pipelines with multiple intermediate -processing nodes and threads. -The intermediate processing nodes are built on the same principles as in the :ref:`SciPy` example. +The example below shows how GIFT-Grab can be used for running complex pipelines with multiple +intermediate processing nodes and threads. +The intermediate processing nodes in this example are built on the same principles as in the +:ref:`SciPy` example. Running the example requires an `HEVC-encoded MP4 file`_, an `NVENC-capable GPU`_, and `NumPy support`_. .. _`HEVC-encoded MP4 file`: https://github.com/gift-surg/GIFT-Grab/blob/master/doc/build.md#reading-video-files .. _`NVENC-capable GPU`: https://github.com/gift-surg/GIFT-Grab/blob/master/doc/build.md#hevc .. _`NumPy support`: https://github.com/gift-surg/GIFT-Grab/blob/master/doc/build.md#python-api -Below is the commented full source code, which is also available on GitHub_: +The full source code of the example is below. +Please follow the comments and the flow of code. +This example is also available on GitHub_: .. literalinclude:: ../../src/tests/pipeline/complex_pipeline.py :language: python From 5a15bc00cffe555651dd0fc420f4e9d30851a0e8 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 18:53:21 +0100 Subject: [PATCH 204/277] Issue #16: removed line numbers from example on new RTD page --- doc/source/complex.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/source/complex.rst b/doc/source/complex.rst index 0d231ccb..eba60359 100644 --- a/doc/source/complex.rst +++ b/doc/source/complex.rst @@ -19,7 +19,6 @@ This example is also available on GitHub_: .. literalinclude:: ../../src/tests/pipeline/complex_pipeline.py :language: python - :linenos: .. _GitHub: https://github.com/gift-surg/GIFT-Grab/blob/master/src/tests/pipeline/complex_pipeline.py From eee97b95cec66288e570bff7c647475d441f083b Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Thu, 11 Oct 2018 09:02:38 +0100 Subject: [PATCH 205/277] Issue #16: added a Python script stub for checking multi-threading reliability --- .../multithreading_reliability_check.py | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100755 src/tests/pipeline/multithreading_reliability_check.py diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py new file mode 100755 index 00000000..c6729066 --- /dev/null +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from pygiftgrab import (VideoSourceFactory, + ColourSpace, + IObservableObserver) + +""" +This script provides a multi-threading reliability check. +The background is issue #16. It looks like in applications +where multiple Python threads are involved, occasionally +the acquisition of the Global Interpreter Lock leads to a +deadlocks, which crashes the whole application with a +non-specific segmentation fault. + +In this script we run a number of multi-threaded GIFT-Grab +pipelines, which should serve as a validation that this +problem is fixed. +""" + +if __name__ == '__main__': + print('multithreading reliability check script') From 170f789a7955f75ba4a2dc8ee70d61706d8d9a6d Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Thu, 11 Oct 2018 09:03:41 +0100 Subject: [PATCH 206/277] Issue #16: added a Bash script for building GIFT-Grab and subsequently running the multi-threading reliability check script --- .gitignore | 1 - .../check_multithreading_reliability.sh | 23 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100755 src/tests/pipeline/check_multithreading_reliability.sh diff --git a/.gitignore b/.gitignore index 35b7a77b..d7eb0905 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,3 @@ src/dist src/*.egg-info *.swp src/tests/pipeline/mtr-build -gg-iss-16 diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh new file mode 100755 index 00000000..b974bfa8 --- /dev/null +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +# -*- coding: utf-8 -*- + +# Build a basic GIFT-Grab capable of reading a video file, +# and encoding to a video file in real time, with Python +# and NumPy support. Subsequently run the multi-threading +# reliability check script. + +CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" +BUILD_DIR=$CURRENT_DIR/mtr-build +SOURCE_DIR="$( cd "$CURRENT_DIR/../.." >/dev/null && pwd )" +CMAKE_OPTS="-D USE_FILES=ON" +CMAKE_OPTS="$CMAKE_OPTS -D USE_HEVC=ON" +CMAKE_OPTS="$CMAKE_OPTS -D ENABLE_NONFREE=ON -D USE_NVENC=ON" +CMAKE_OPTS="$CMAKE_OPTS -D BUILD_PYTHON=ON -D USE_NUMPY=ON" +MTR_SCRIPT=$CURRENT_DIR/multithreading_reliability_check.py + +mkdir -p $BUILD_DIR +rm -rf $BUILD_DIR/* +cd $BUILD_DIR +cmake $CMAKE_OPTS $SOURCE_DIR +make -j4 +PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT From 455cc681a3dc552439bd899945b3a490cd50d06d Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 08:06:21 +0100 Subject: [PATCH 207/277] Issue #16: added a 'Dyer' processing node to multi-threading reliability checker --- .../pipeline/multithreading_reliability_check.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index c6729066..7aa1fc0d 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -18,5 +18,20 @@ problem is fixed. """ + +class Dyer(IObservableObserver): + + def __init__(self, channel, value): + super(Dyer, self).__init__() + assert 0 <= channel < 3 + assert 0 <= value < 256 + self.channel = channel + self.value = value + + def update(self, frame): + data = frame.data(True) + data[:, :, self.channel] = self.value + + if __name__ == '__main__': print('multithreading reliability check script') From 9488646b539e01557ef23e09e35d63ec082d6533 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 08:28:08 +0100 Subject: [PATCH 208/277] Issue #16: Python script now uses CLI argument for input file --- .../pipeline/check_multithreading_reliability.sh | 2 +- .../pipeline/multithreading_reliability_check.py | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index b974bfa8..efae4d95 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -20,4 +20,4 @@ rm -rf $BUILD_DIR/* cd $BUILD_DIR cmake $CMAKE_OPTS $SOURCE_DIR make -j4 -PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT +PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT --input $1 diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 7aa1fc0d..02982cf7 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -1,6 +1,8 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +import argparse +import os.path from pygiftgrab import (VideoSourceFactory, ColourSpace, IObservableObserver) @@ -34,4 +36,14 @@ def update(self, frame): if __name__ == '__main__': - print('multithreading reliability check script') + parser = argparse.ArgumentParser() + parser.add_argument('-i', '--input', type=str, required=True, + metavar='VIDEO_FILE', + help='Input video file (HEVC-encoded MP4)') + args = parser.parse_args() + in_file = args.input + + filename = os.path.basename(in_file) + filename, ext = os.path.splitext(filename) + assert filename + assert ext == '.mp4' From 20343bb1840eb7e21f9e5e935e01d3bc2be6effa Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 08:32:30 +0100 Subject: [PATCH 209/277] Issue #16: added multi-node pipeline producing red- and yellow-dyed output --- .../multithreading_reliability_check.py | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 02982cf7..01c4ead3 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -1,11 +1,12 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +from time import sleep import argparse import os.path from pygiftgrab import (VideoSourceFactory, - ColourSpace, - IObservableObserver) + ColourSpace, IObservableObserver, + VideoTargetFactory, Codec) """ This script provides a multi-threading reliability check. @@ -47,3 +48,29 @@ def update(self, frame): filename, ext = os.path.splitext(filename) assert filename assert ext == '.mp4' + + sfac = VideoSourceFactory.get_instance() + reader = sfac.create_file_reader(in_file, ColourSpace.BGRA) + + tfac = VideoTargetFactory.get_instance() + frame_rate = reader.get_frame_rate() + + red = Dyer(2, 127) + green = Dyer(1, 191) + + red_file = os.path.join('.', ''.join([filename, '-red', ext])) + red_writer = tfac.create_file_writer(Codec.HEVC, red_file, frame_rate) + yellow_file = os.path.join('.', ''.join([filename, '-yellow', ext])) + yellow_writer = tfac.create_file_writer(Codec.HEVC, yellow_file, frame_rate) + + reader.attach(red) + red.attach(red_writer) + red.attach(green) + green.attach(yellow_writer) + + sleep(20) # operate pipeline for 20 sec + + reader.detach(red) + red.detach(red_writer) + red.detach(green) + green.detach(yellow_writer) From 726bb377875dd0224bd8c6861af1bc8e6f602b5f Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 09:09:08 +0100 Subject: [PATCH 210/277] Issue #16: added a threaded Histogrammer class stub --- .../multithreading_reliability_check.py | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 01c4ead3..c1ba3b48 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -4,6 +4,7 @@ from time import sleep import argparse import os.path +import threading from pygiftgrab import (VideoSourceFactory, ColourSpace, IObservableObserver, VideoTargetFactory, Codec) @@ -22,6 +23,30 @@ """ +buffer = None +lock = threading.Lock() + + +class Histogrammer(threading.Thread, IObservableObserver): + + def __init__(self, channel): + super(Histogrammer, self).__init__() + assert 0 <= channel < 3 + self.channel = channel + self.running = False + + def run(self): + if self.running: + return + + pass + + def stop(self): + self.running = False + + def update(self, frame): + pass + class Dyer(IObservableObserver): def __init__(self, channel, value): @@ -57,6 +82,8 @@ def update(self, frame): red = Dyer(2, 127) green = Dyer(1, 191) + hist = Histogrammer(0) + hist.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) red_writer = tfac.create_file_writer(Codec.HEVC, red_file, frame_rate) @@ -69,6 +96,7 @@ def update(self, frame): green.attach(yellow_writer) sleep(20) # operate pipeline for 20 sec + hist.stop() reader.detach(red) red.detach(red_writer) From 9fda3965b01b2616e42824fbda4d9f522ad3077c Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 09:12:38 +0100 Subject: [PATCH 211/277] Issue #16: added dummy print statement to see Histogrammer is alive --- src/tests/pipeline/multithreading_reliability_check.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index c1ba3b48..4dd459a1 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -40,6 +40,10 @@ def run(self): return pass + self.running = True + while self.running: + print('Running') + sleep(0.100) def stop(self): self.running = False From 9b551611b873d83267d296e0a1a8724a216c55cd Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 09:57:57 +0100 Subject: [PATCH 212/277] Issue #16: factored Histogrammer stub out to HistogrammerRed and BuffererRed --- .../multithreading_reliability_check.py | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 4dd459a1..12a467bb 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -23,33 +23,40 @@ """ -buffer = None +buffer_red = None lock = threading.Lock() -class Histogrammer(threading.Thread, IObservableObserver): +class BuffererRed(IObservableObserver): - def __init__(self, channel): - super(Histogrammer, self).__init__() - assert 0 <= channel < 3 - self.channel = channel + def __init__(self): + super(BuffererRed, self).__init__() + + def update(self, frame): + global buffer_red + # TODO + + +class HistogrammerRed(threading.Thread): + + def __init__(self): + super(HistogrammerRed, self).__init__() self.running = False def run(self): if self.running: return - pass + # TODO self.running = True while self.running: print('Running') + # TODO sleep(0.100) def stop(self): self.running = False - def update(self, frame): - pass class Dyer(IObservableObserver): @@ -86,7 +93,7 @@ def update(self, frame): red = Dyer(2, 127) green = Dyer(1, 191) - hist = Histogrammer(0) + hist = HistogrammerRed() hist.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) From c820adbe163da9f5531a4458e5b6f650e5eb6348 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 09:59:41 +0100 Subject: [PATCH 213/277] Issue #16: implemented update of BuffererRed --- src/tests/pipeline/multithreading_reliability_check.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 12a467bb..aa8eb0dd 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -5,6 +5,7 @@ import argparse import os.path import threading +import numpy as np from pygiftgrab import (VideoSourceFactory, ColourSpace, IObservableObserver, VideoTargetFactory, Codec) @@ -34,7 +35,12 @@ def __init__(self): def update(self, frame): global buffer_red - # TODO + with lock: + data = frame.data(True) + if buffer_red is None: + buffer_red = np.copy(data) + else: + buffer_red[:, :, :] = data[:, :, :] class HistogrammerRed(threading.Thread): From 3d4dfce06d9dcd9697caed07d2e05c57e68d1af6 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 10:06:55 +0100 Subject: [PATCH 214/277] Issue #16: implemented run of HistogrammerRed --- src/tests/pipeline/multithreading_reliability_check.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index aa8eb0dd..54ceb230 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -53,11 +53,15 @@ def run(self): if self.running: return - # TODO + global buffer_red + histogram = None self.running = True while self.running: - print('Running') - # TODO + with lock: + if buffer_red is not None: + histogram = np.histogram(buffer_red[:, :, 2], + bins=8, range=(0, 256)) + print(histogram) sleep(0.100) def stop(self): From beab3d0164eb139463ad8c24191f27d84906c95b Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 10:11:05 +0100 Subject: [PATCH 215/277] Issue #16: renamed Dyer vars for clarity --- .../multithreading_reliability_check.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 54ceb230..ff1fda67 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -101,8 +101,8 @@ def update(self, frame): tfac = VideoTargetFactory.get_instance() frame_rate = reader.get_frame_rate() - red = Dyer(2, 127) - green = Dyer(1, 191) + red_dyer = Dyer(2, 127) + green_dyer = Dyer(1, 191) hist = HistogrammerRed() hist.start() @@ -111,15 +111,15 @@ def update(self, frame): yellow_file = os.path.join('.', ''.join([filename, '-yellow', ext])) yellow_writer = tfac.create_file_writer(Codec.HEVC, yellow_file, frame_rate) - reader.attach(red) - red.attach(red_writer) - red.attach(green) - green.attach(yellow_writer) + reader.attach(red_dyer) + red_dyer.attach(red_writer) + red_dyer.attach(green_dyer) + green_dyer.attach(yellow_writer) sleep(20) # operate pipeline for 20 sec hist.stop() - reader.detach(red) - red.detach(red_writer) - red.detach(green) - green.detach(yellow_writer) + reader.detach(red_dyer) + red_dyer.detach(red_writer) + red_dyer.detach(green_dyer) + green_dyer.detach(yellow_writer) From 72e48309a4e8a27eed8479d3a3f9691e503f21e8 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 10:19:12 +0100 Subject: [PATCH 216/277] Issue #16: Dyer.update uses lock --- src/tests/pipeline/multithreading_reliability_check.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index ff1fda67..ee40fea7 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -78,8 +78,9 @@ def __init__(self, channel, value): self.value = value def update(self, frame): - data = frame.data(True) - data[:, :, self.channel] = self.value + with lock: + data = frame.data(True) + data[:, :, self.channel] = self.value if __name__ == '__main__': From b8f91ad33f63fdc8d515c1b514e1788ee4c3df56 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 10:20:32 +0100 Subject: [PATCH 217/277] Issue #16: inserted a red bufferer into the pipeline --- src/tests/pipeline/multithreading_reliability_check.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index ee40fea7..dd0f0dcf 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -104,6 +104,9 @@ def update(self, frame): red_dyer = Dyer(2, 127) green_dyer = Dyer(1, 191) + + bufferer_red = BuffererRed() + hist = HistogrammerRed() hist.start() @@ -114,6 +117,7 @@ def update(self, frame): reader.attach(red_dyer) red_dyer.attach(red_writer) + red_dyer.attach(bufferer_red) red_dyer.attach(green_dyer) green_dyer.attach(yellow_writer) @@ -122,5 +126,6 @@ def update(self, frame): reader.detach(red_dyer) red_dyer.detach(red_writer) + red_dyer.detach(bufferer_red) red_dyer.detach(green_dyer) green_dyer.detach(yellow_writer) From 2c8fc12c354a3d8a203a102b36682ef8211be671 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 10:22:03 +0100 Subject: [PATCH 218/277] Issue #16: fixed call to histogram function --- src/tests/pipeline/multithreading_reliability_check.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index dd0f0dcf..0987129b 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -59,8 +59,9 @@ def run(self): while self.running: with lock: if buffer_red is not None: - histogram = np.histogram(buffer_red[:, :, 2], - bins=8, range=(0, 256)) + histogram, _ = np.histogram( + buffer_red[:, :, 2], bins=8, range=(0, 256) + ) print(histogram) sleep(0.100) From 67d370b62a2e79c6f519bfdfc5416575e53db0cb Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 10:32:24 +0100 Subject: [PATCH 219/277] Issue #16: Dyer now really dyes instead of fixing color to a value --- src/tests/pipeline/multithreading_reliability_check.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 0987129b..54802904 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -71,17 +71,18 @@ def stop(self): class Dyer(IObservableObserver): - def __init__(self, channel, value): + def __init__(self, channel, increment): super(Dyer, self).__init__() assert 0 <= channel < 3 - assert 0 <= value < 256 + assert 0 <= increment < 256 self.channel = channel - self.value = value + self.increment = increment def update(self, frame): with lock: data = frame.data(True) - data[:, :, self.channel] = self.value + channel_data = data[:, :, self.channel] + channel_data[channel_data < 255 - self.increment] += self.increment if __name__ == '__main__': From f09e3048c47a2117630ee538ad865409141a03f7 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 10:53:49 +0100 Subject: [PATCH 220/277] Issue #16: histogrammer now displays a redness score instead of histogram --- .../pipeline/multithreading_reliability_check.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 54802904..d8bf97ed 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -54,15 +54,21 @@ def run(self): return global buffer_red - histogram = None + histogram, num_bins = None, 10 + redness_scale = np.array([i for i in range(1, num_bins + 1)], np.float) self.running = True while self.running: with lock: if buffer_red is not None: histogram, _ = np.histogram( - buffer_red[:, :, 2], bins=8, range=(0, 256) + buffer_red[:, :, 2], bins=num_bins, range=(0, 256) ) - print(histogram) + if histogram is not None: + redness = np.sum(histogram * redness_scale) + redness /= np.sum(histogram) + redness /= num_bins + redness *= 100 + print('Redness: {} %'.format(int(round(redness)))) sleep(0.100) def stop(self): From 91ca884c12d961d15012e236004d5bf951911ae5 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 10:54:11 +0100 Subject: [PATCH 221/277] Issue #16: using more sensible values for dyeing --- src/tests/pipeline/multithreading_reliability_check.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index d8bf97ed..a024030b 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -110,8 +110,8 @@ def update(self, frame): tfac = VideoTargetFactory.get_instance() frame_rate = reader.get_frame_rate() - red_dyer = Dyer(2, 127) - green_dyer = Dyer(1, 191) + red_dyer = Dyer(2, 64) + green_dyer = Dyer(1, 64) bufferer_red = BuffererRed() From 97910f88b0116bf7c105e53dd14bdfda1b7a5b9b Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 10:59:42 +0100 Subject: [PATCH 222/277] Issue #16: added a BuffererOrig class, a virtual replica of BuffererRed --- .../multithreading_reliability_check.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index a024030b..7b497725 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -24,7 +24,7 @@ """ -buffer_red = None +buffer_red, buffer_orig = None, None lock = threading.Lock() @@ -43,6 +43,21 @@ def update(self, frame): buffer_red[:, :, :] = data[:, :, :] +class BuffererOrig(IObservableObserver): + + def __init__(self): + super(BuffererOrig, self).__init__() + + def update(self, frame): + global buffer_orig + with lock: + data = frame.data(True) + if buffer_orig is None: + buffer_orig = np.copy(data) + else: + buffer_red[:, :, :] = data[:, :, :] + + class HistogrammerRed(threading.Thread): def __init__(self): From b5be85c0d5451b4936aab98d31c5ea24a1852b4e Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:03:50 +0100 Subject: [PATCH 223/277] Issue #16: BuffererRed now takes buffer as parameter to constructor instead of using global var --- .../multithreading_reliability_check.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 7b497725..0ca024bc 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -6,7 +6,7 @@ import os.path import threading import numpy as np -from pygiftgrab import (VideoSourceFactory, +from pygiftgrab import (VideoSourceFactory, VideoFrame, ColourSpace, IObservableObserver, VideoTargetFactory, Codec) @@ -30,17 +30,14 @@ class BuffererRed(IObservableObserver): - def __init__(self): + def __init__(self, buffer): super(BuffererRed, self).__init__() + self.buffer = buffer def update(self, frame): - global buffer_red with lock: data = frame.data(True) - if buffer_red is None: - buffer_red = np.copy(data) - else: - buffer_red[:, :, :] = data[:, :, :] + self.buffer[:, :, :] = data[:, :, :] class BuffererOrig(IObservableObserver): @@ -121,6 +118,9 @@ def update(self, frame): sfac = VideoSourceFactory.get_instance() reader = sfac.create_file_reader(in_file, ColourSpace.BGRA) + frame = VideoFrame(ColourSpace.BGRA, False) + reader.get_frame(frame) + frame_shape = (frame.rows(), frame.cols(), 4) tfac = VideoTargetFactory.get_instance() frame_rate = reader.get_frame_rate() @@ -128,7 +128,8 @@ def update(self, frame): red_dyer = Dyer(2, 64) green_dyer = Dyer(1, 64) - bufferer_red = BuffererRed() + buffer_red = np.zeros(frame_shape, np.uint8) + bufferer_red = BuffererRed(buffer_red) hist = HistogrammerRed() hist.start() From c64f86336689ad2854a6e34c02fa7598b769f431 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:10:43 +0100 Subject: [PATCH 224/277] Revert "Issue #16: added a BuffererOrig class, a virtual replica of BuffererRed" This reverts commit 053f499ae6554460df9a755067e1ff5ec817a247. --- .../multithreading_reliability_check.py | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 0ca024bc..8aed9c85 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -24,7 +24,7 @@ """ -buffer_red, buffer_orig = None, None +buffer_red = None lock = threading.Lock() @@ -40,21 +40,6 @@ def update(self, frame): self.buffer[:, :, :] = data[:, :, :] -class BuffererOrig(IObservableObserver): - - def __init__(self): - super(BuffererOrig, self).__init__() - - def update(self, frame): - global buffer_orig - with lock: - data = frame.data(True) - if buffer_orig is None: - buffer_orig = np.copy(data) - else: - buffer_red[:, :, :] = data[:, :, :] - - class HistogrammerRed(threading.Thread): def __init__(self): From 8f7666144a0ef88a1cc843b4b71fd491c8a87e4c Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:12:15 +0100 Subject: [PATCH 225/277] Issue #16: renamed BuffererRed => Bufferer --- src/tests/pipeline/multithreading_reliability_check.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 8aed9c85..a345dfd6 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -28,10 +28,10 @@ lock = threading.Lock() -class BuffererRed(IObservableObserver): +class Bufferer(IObservableObserver): def __init__(self, buffer): - super(BuffererRed, self).__init__() + super(Bufferer, self).__init__() self.buffer = buffer def update(self, frame): @@ -114,7 +114,7 @@ def update(self, frame): green_dyer = Dyer(1, 64) buffer_red = np.zeros(frame_shape, np.uint8) - bufferer_red = BuffererRed(buffer_red) + bufferer_red = Bufferer(buffer_red) hist = HistogrammerRed() hist.start() From 66559805268794d41060e2e23b07df9cd6a8f2d1 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:15:02 +0100 Subject: [PATCH 226/277] Issue #16: HistogrammerRed now takes buffer as a constructor argument rather than using global var --- .../pipeline/multithreading_reliability_check.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index a345dfd6..4a58d7bb 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -42,24 +42,23 @@ def update(self, frame): class HistogrammerRed(threading.Thread): - def __init__(self): + def __init__(self, buffer): super(HistogrammerRed, self).__init__() + self.buffer = buffer self.running = False def run(self): if self.running: return - global buffer_red histogram, num_bins = None, 10 redness_scale = np.array([i for i in range(1, num_bins + 1)], np.float) self.running = True while self.running: with lock: - if buffer_red is not None: - histogram, _ = np.histogram( - buffer_red[:, :, 2], bins=num_bins, range=(0, 256) - ) + histogram, _ = np.histogram( + self.buffer[:, :, 2], bins=num_bins, range=(0, 256) + ) if histogram is not None: redness = np.sum(histogram * redness_scale) redness /= np.sum(histogram) @@ -116,7 +115,7 @@ def update(self, frame): buffer_red = np.zeros(frame_shape, np.uint8) bufferer_red = Bufferer(buffer_red) - hist = HistogrammerRed() + hist = HistogrammerRed(buffer_red) hist.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) From a8e95b61487034d006d48d4ef7debcd86f8e0aa7 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:22:12 +0100 Subject: [PATCH 227/277] Issue #16: HistogrammerRed is now generic Histogrammer --- .../multithreading_reliability_check.py | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 4a58d7bb..0de913ed 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -40,10 +40,14 @@ def update(self, frame): self.buffer[:, :, :] = data[:, :, :] -class HistogrammerRed(threading.Thread): +class Histogrammer(threading.Thread): - def __init__(self, buffer): - super(HistogrammerRed, self).__init__() + channels = ('Blue', 'Green', 'Red', 'Alpha') + + def __init__(self, buffer, channel): + super(Histogrammer, self).__init__() + assert channel in range(3) + self.channel = channel self.buffer = buffer self.running = False @@ -52,7 +56,7 @@ def run(self): return histogram, num_bins = None, 10 - redness_scale = np.array([i for i in range(1, num_bins + 1)], np.float) + scale = np.array([i for i in range(1, num_bins + 1)], np.float) self.running = True while self.running: with lock: @@ -60,11 +64,13 @@ def run(self): self.buffer[:, :, 2], bins=num_bins, range=(0, 256) ) if histogram is not None: - redness = np.sum(histogram * redness_scale) - redness /= np.sum(histogram) - redness /= num_bins - redness *= 100 - print('Redness: {} %'.format(int(round(redness)))) + coloredness = np.sum(histogram * scale) + coloredness /= np.sum(histogram) + coloredness /= num_bins + coloredness *= 100 + print('{}ness of dyed image: {} %'.format( + Histogrammer.channels[self.channel], int(round(coloredness)) + )) sleep(0.100) def stop(self): @@ -115,7 +121,7 @@ def update(self, frame): buffer_red = np.zeros(frame_shape, np.uint8) bufferer_red = Bufferer(buffer_red) - hist = HistogrammerRed(buffer_red) + hist = Histogrammer(buffer_red, 2) hist.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) From a409400c2eaace4ded9f62a9c285c6bfa02ed255 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:27:00 +0100 Subject: [PATCH 228/277] Issue #16: Histogrammer now accepts a tag for generically printing what the image is --- src/tests/pipeline/multithreading_reliability_check.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 0de913ed..168b6b9f 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -44,11 +44,12 @@ class Histogrammer(threading.Thread): channels = ('Blue', 'Green', 'Red', 'Alpha') - def __init__(self, buffer, channel): + def __init__(self, buffer, channel, tag): super(Histogrammer, self).__init__() assert channel in range(3) self.channel = channel self.buffer = buffer + self.tag = tag self.running = False def run(self): @@ -68,8 +69,8 @@ def run(self): coloredness /= np.sum(histogram) coloredness /= num_bins coloredness *= 100 - print('{}ness of dyed image: {} %'.format( - Histogrammer.channels[self.channel], int(round(coloredness)) + print('{}ness of {} image: {} %'.format( + Histogrammer.channels[self.channel], self.tag, int(round(coloredness)) )) sleep(0.100) @@ -121,7 +122,7 @@ def update(self, frame): buffer_red = np.zeros(frame_shape, np.uint8) bufferer_red = Bufferer(buffer_red) - hist = Histogrammer(buffer_red, 2) + hist = Histogrammer(buffer_red, 2, 'red-dyed') hist.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) From 5e4df492d32ffebbc32a1f2d80a3a18460ec9b61 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:34:30 +0100 Subject: [PATCH 229/277] Issue #16: inserted an original image histogrammer into the pipeline --- .../multithreading_reliability_check.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 168b6b9f..971e94b2 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -24,7 +24,7 @@ """ -buffer_red = None +buffer_red, buffer_orig = None, None lock = threading.Lock() @@ -121,25 +121,32 @@ def update(self, frame): buffer_red = np.zeros(frame_shape, np.uint8) bufferer_red = Bufferer(buffer_red) + buffer_orig = np.zeros_like(buffer_red) + bufferer_orig = Bufferer(buffer_orig) - hist = Histogrammer(buffer_red, 2, 'red-dyed') - hist.start() + hist_red = Histogrammer(buffer_red, 2, 'red-dyed') + hist_red.start() + hist_orig = Histogrammer(buffer_orig, 2, 'original') + hist_orig.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) red_writer = tfac.create_file_writer(Codec.HEVC, red_file, frame_rate) yellow_file = os.path.join('.', ''.join([filename, '-yellow', ext])) yellow_writer = tfac.create_file_writer(Codec.HEVC, yellow_file, frame_rate) - reader.attach(red_dyer) + reader.attach(bufferer_orig) + bufferer_orig.attach(red_dyer) red_dyer.attach(red_writer) red_dyer.attach(bufferer_red) red_dyer.attach(green_dyer) green_dyer.attach(yellow_writer) sleep(20) # operate pipeline for 20 sec - hist.stop() + hist_red.stop() + hist_orig.stop() - reader.detach(red_dyer) + reader.detach(bufferer_orig) + bufferer_orig.detach(red_dyer) red_dyer.detach(red_writer) red_dyer.detach(bufferer_red) red_dyer.detach(green_dyer) From 492cfada88590dd39d46feef28ac62f0b82df056 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:39:33 +0100 Subject: [PATCH 230/277] Issue #16: Histogrammer now accepts a frame rate and flag for displaying coloredness --- .../multithreading_reliability_check.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 971e94b2..df093c13 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -44,12 +44,15 @@ class Histogrammer(threading.Thread): channels = ('Blue', 'Green', 'Red', 'Alpha') - def __init__(self, buffer, channel, tag): + def __init__(self, buffer, channel, tag, frame_rate, show=True): super(Histogrammer, self).__init__() assert channel in range(3) + assert 0 < frame_rate <= 60 self.channel = channel self.buffer = buffer self.tag = tag + self.show = show + self.sleep_interval = 1.0 / frame_rate self.running = False def run(self): @@ -69,10 +72,12 @@ def run(self): coloredness /= np.sum(histogram) coloredness /= num_bins coloredness *= 100 - print('{}ness of {} image: {} %'.format( - Histogrammer.channels[self.channel], self.tag, int(round(coloredness)) - )) - sleep(0.100) + if self.show: + print('{}ness of {} image: {} %'.format( + Histogrammer.channels[self.channel], + self.tag, int(round(coloredness)) + )) + sleep(self.sleep_interval) def stop(self): self.running = False @@ -124,9 +129,9 @@ def update(self, frame): buffer_orig = np.zeros_like(buffer_red) bufferer_orig = Bufferer(buffer_orig) - hist_red = Histogrammer(buffer_red, 2, 'red-dyed') + hist_red = Histogrammer(buffer_red, 2, 'red-dyed', 30, False) hist_red.start() - hist_orig = Histogrammer(buffer_orig, 2, 'original') + hist_orig = Histogrammer(buffer_orig, 2, 'original', 30, False) hist_orig.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) From 59e4a9a984ede40c47417d25f8d53b387c3fc492 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:45:12 +0100 Subject: [PATCH 231/277] Issue #16: now can specify the frequency of coloredness prints --- .../pipeline/multithreading_reliability_check.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index df093c13..43e82a19 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -44,14 +44,16 @@ class Histogrammer(threading.Thread): channels = ('Blue', 'Green', 'Red', 'Alpha') - def __init__(self, buffer, channel, tag, frame_rate, show=True): + def __init__(self, buffer, channel, tag, frame_rate, display_freq): super(Histogrammer, self).__init__() assert channel in range(3) assert 0 < frame_rate <= 60 + assert 0 <= display_freq self.channel = channel self.buffer = buffer self.tag = tag - self.show = show + self.display_freq = display_freq + self.num_skipped = 0 self.sleep_interval = 1.0 / frame_rate self.running = False @@ -72,11 +74,14 @@ def run(self): coloredness /= np.sum(histogram) coloredness /= num_bins coloredness *= 100 - if self.show: + if self.num_skipped >= self.display_freq: print('{}ness of {} image: {} %'.format( Histogrammer.channels[self.channel], self.tag, int(round(coloredness)) )) + self.num_skipped = 0 + else: + self.num_skipped += 1 sleep(self.sleep_interval) def stop(self): @@ -129,9 +134,9 @@ def update(self, frame): buffer_orig = np.zeros_like(buffer_red) bufferer_orig = Bufferer(buffer_orig) - hist_red = Histogrammer(buffer_red, 2, 'red-dyed', 30, False) + hist_red = Histogrammer(buffer_red, 2, 'red-dyed', 30.0, 10) hist_red.start() - hist_orig = Histogrammer(buffer_orig, 2, 'original', 30, False) + hist_orig = Histogrammer(buffer_orig, 2, 'original', 30.0, 10) hist_orig.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) From a80a29ce71716f798fc3ee9072ebe1bec3a71182 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:47:38 +0100 Subject: [PATCH 232/277] Issue #16: dyeing red more prominently --- src/tests/pipeline/multithreading_reliability_check.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 43e82a19..72ab94d2 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -126,7 +126,7 @@ def update(self, frame): tfac = VideoTargetFactory.get_instance() frame_rate = reader.get_frame_rate() - red_dyer = Dyer(2, 64) + red_dyer = Dyer(2, 128) green_dyer = Dyer(1, 64) buffer_red = np.zeros(frame_shape, np.uint8) From c032350532b563f61e218735634b4d54fa0521f5 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:53:47 +0100 Subject: [PATCH 233/277] Issue #16: frame rate values that reproduced the problem --- src/tests/pipeline/multithreading_reliability_check.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 72ab94d2..42cc36e3 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -134,9 +134,9 @@ def update(self, frame): buffer_orig = np.zeros_like(buffer_red) bufferer_orig = Bufferer(buffer_orig) - hist_red = Histogrammer(buffer_red, 2, 'red-dyed', 30.0, 10) + hist_red = Histogrammer(buffer_red, 2, 'red-dyed', 60.0, 10) hist_red.start() - hist_orig = Histogrammer(buffer_orig, 2, 'original', 30.0, 10) + hist_orig = Histogrammer(buffer_orig, 2, 'original', 50.0, 10) hist_orig.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) From 0f3d327aa74b48181a02e831778b78011272eba1 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 12 Oct 2018 11:54:25 +0100 Subject: [PATCH 234/277] Issue #16: using Debug CMake type in build script --- src/tests/pipeline/check_multithreading_reliability.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index efae4d95..7ea874b2 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -13,6 +13,7 @@ CMAKE_OPTS="-D USE_FILES=ON" CMAKE_OPTS="$CMAKE_OPTS -D USE_HEVC=ON" CMAKE_OPTS="$CMAKE_OPTS -D ENABLE_NONFREE=ON -D USE_NVENC=ON" CMAKE_OPTS="$CMAKE_OPTS -D BUILD_PYTHON=ON -D USE_NUMPY=ON" +CMAKE_OPTS="$CMAKE_OPTS -D CMAKE_BUILD_TYPE=Debug" MTR_SCRIPT=$CURRENT_DIR/multithreading_reliability_check.py mkdir -p $BUILD_DIR From c13a24f7be4c5ccd34f8fe1ded260afffb1e6e25 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 08:28:50 +0100 Subject: [PATCH 235/277] Issue #16: renamed variable for clarity in run script --- src/tests/pipeline/check_multithreading_reliability.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 7ea874b2..2be8fea2 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -6,15 +6,15 @@ # and NumPy support. Subsequently run the multi-threading # reliability check script. -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" -BUILD_DIR=$CURRENT_DIR/mtr-build -SOURCE_DIR="$( cd "$CURRENT_DIR/../.." >/dev/null && pwd )" +ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" +BUILD_DIR=$ROOT_DIR/mtr-build +SOURCE_DIR="$( cd "$ROOT_DIR/../.." >/dev/null && pwd )" CMAKE_OPTS="-D USE_FILES=ON" CMAKE_OPTS="$CMAKE_OPTS -D USE_HEVC=ON" CMAKE_OPTS="$CMAKE_OPTS -D ENABLE_NONFREE=ON -D USE_NVENC=ON" CMAKE_OPTS="$CMAKE_OPTS -D BUILD_PYTHON=ON -D USE_NUMPY=ON" CMAKE_OPTS="$CMAKE_OPTS -D CMAKE_BUILD_TYPE=Debug" -MTR_SCRIPT=$CURRENT_DIR/multithreading_reliability_check.py +MTR_SCRIPT=$ROOT_DIR/multithreading_reliability_check.py mkdir -p $BUILD_DIR rm -rf $BUILD_DIR/* From a15424a820c19b3080ef84f1378a7d1477691b3e Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 09:00:44 +0100 Subject: [PATCH 236/277] Issue #16: setting ulimit to dump cores when running check --- src/tests/pipeline/check_multithreading_reliability.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 2be8fea2..4519cb84 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -15,6 +15,7 @@ CMAKE_OPTS="$CMAKE_OPTS -D ENABLE_NONFREE=ON -D USE_NVENC=ON" CMAKE_OPTS="$CMAKE_OPTS -D BUILD_PYTHON=ON -D USE_NUMPY=ON" CMAKE_OPTS="$CMAKE_OPTS -D CMAKE_BUILD_TYPE=Debug" MTR_SCRIPT=$ROOT_DIR/multithreading_reliability_check.py +ulimit -c unlimited mkdir -p $BUILD_DIR rm -rf $BUILD_DIR/* @@ -22,3 +23,5 @@ cd $BUILD_DIR cmake $CMAKE_OPTS $SOURCE_DIR make -j4 PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT --input $1 + +ulimit -c 0 From b864abec24d9e94c0c437b148db5da6f1b218a21 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 09:02:44 +0100 Subject: [PATCH 237/277] Issue #16: saving all output in a hierarchical session directory --- .../pipeline/check_multithreading_reliability.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 4519cb84..f3cc6910 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -15,13 +15,26 @@ CMAKE_OPTS="$CMAKE_OPTS -D ENABLE_NONFREE=ON -D USE_NVENC=ON" CMAKE_OPTS="$CMAKE_OPTS -D BUILD_PYTHON=ON -D USE_NUMPY=ON" CMAKE_OPTS="$CMAKE_OPTS -D CMAKE_BUILD_TYPE=Debug" MTR_SCRIPT=$ROOT_DIR/multithreading_reliability_check.py +SESSION_DIR=$ROOT_DIR/$(date +"%Y-%m-%d-%H-%M-%S") +mkdir $SESSION_DIR ulimit -c unlimited +BUILD_LOG=$SESSION_DIR/build.log +{ mkdir -p $BUILD_DIR rm -rf $BUILD_DIR/* cd $BUILD_DIR cmake $CMAKE_OPTS $SOURCE_DIR make -j4 +} > $BUILD_LOG 2>&1 + +run_no=1 +WORKING_DIR=$SESSION_DIR/$run_no +mkdir $WORKING_DIR +cd $WORKING_DIR +RUN_LOG=$WORKING_DIR/run.log +{ PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT --input $1 +} > $RUN_LOG 2>&1 ulimit -c 0 From 5c7bde3a6d4605262c10d0928540c1029c1304a2 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 09:05:12 +0100 Subject: [PATCH 238/277] Issue #16: added indentation for readability --- .../pipeline/check_multithreading_reliability.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index f3cc6910..71e9efc0 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -21,11 +21,11 @@ ulimit -c unlimited BUILD_LOG=$SESSION_DIR/build.log { -mkdir -p $BUILD_DIR -rm -rf $BUILD_DIR/* -cd $BUILD_DIR -cmake $CMAKE_OPTS $SOURCE_DIR -make -j4 + mkdir -p $BUILD_DIR + rm -rf $BUILD_DIR/* + cd $BUILD_DIR + cmake $CMAKE_OPTS $SOURCE_DIR + make -j4 } > $BUILD_LOG 2>&1 run_no=1 @@ -34,7 +34,7 @@ mkdir $WORKING_DIR cd $WORKING_DIR RUN_LOG=$WORKING_DIR/run.log { -PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT --input $1 + PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT --input $1 } > $RUN_LOG 2>&1 ulimit -c 0 From d3534e6a4fe0a02e9227bc2a0f20691dac4abb36 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 09:14:47 +0100 Subject: [PATCH 239/277] Issue #16: can now specify number of reps in check script --- .../check_multithreading_reliability.sh | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 71e9efc0..52eed368 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -28,13 +28,20 @@ BUILD_LOG=$SESSION_DIR/build.log make -j4 } > $BUILD_LOG 2>&1 -run_no=1 -WORKING_DIR=$SESSION_DIR/$run_no -mkdir $WORKING_DIR -cd $WORKING_DIR -RUN_LOG=$WORKING_DIR/run.log -{ - PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT --input $1 -} > $RUN_LOG 2>&1 +num_reps=1 +if [ $# -ge 2 ]; +then + num_reps=$2 +fi +for run_no in `seq 1 $num_reps`; +do + WORKING_DIR=$SESSION_DIR/$(printf "%03d" $run_no) + mkdir $WORKING_DIR + cd $WORKING_DIR + RUN_LOG=$WORKING_DIR/run.log + { + PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT --input $1 + } > $RUN_LOG 2>&1 +done ulimit -c 0 From 22c158b48424f3ff6754d47a74c4752febff7af7 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 10:38:52 +0100 Subject: [PATCH 240/277] Issue #16: can now optionally specify root output dir (e.g. not to fill up disk space) --- .../pipeline/check_multithreading_reliability.sh | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 52eed368..1a90362e 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -6,15 +6,22 @@ # and NumPy support. Subsequently run the multi-threading # reliability check script. -ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" +CALL_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" +SOURCE_DIR="$( cd "$CALL_DIR/../.." >/dev/null && pwd )" +MTR_SCRIPT=$SOURCE_DIR/tests/pipeline/multithreading_reliability_check.py +if [ $# -ge 3 ]; +then + ROOT_DIR=$3 +else + ROOT_DIR=$CALL_DIR +fi + BUILD_DIR=$ROOT_DIR/mtr-build -SOURCE_DIR="$( cd "$ROOT_DIR/../.." >/dev/null && pwd )" CMAKE_OPTS="-D USE_FILES=ON" CMAKE_OPTS="$CMAKE_OPTS -D USE_HEVC=ON" CMAKE_OPTS="$CMAKE_OPTS -D ENABLE_NONFREE=ON -D USE_NVENC=ON" CMAKE_OPTS="$CMAKE_OPTS -D BUILD_PYTHON=ON -D USE_NUMPY=ON" CMAKE_OPTS="$CMAKE_OPTS -D CMAKE_BUILD_TYPE=Debug" -MTR_SCRIPT=$ROOT_DIR/multithreading_reliability_check.py SESSION_DIR=$ROOT_DIR/$(date +"%Y-%m-%d-%H-%M-%S") mkdir $SESSION_DIR ulimit -c unlimited From 5795b393c3bda3ab8d19a7046817cffb22e01af6 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 10:48:37 +0100 Subject: [PATCH 241/277] Issue #16: logging frequency of exit codes as well --- .../pipeline/check_multithreading_reliability.sh | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 1a90362e..f7fbb5fe 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -40,6 +40,8 @@ if [ $# -ge 2 ]; then num_reps=$2 fi + +declare -a exit_code_freqs for run_no in `seq 1 $num_reps`; do WORKING_DIR=$SESSION_DIR/$(printf "%03d" $run_no) @@ -48,7 +50,21 @@ do RUN_LOG=$WORKING_DIR/run.log { PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT --input $1 + + exit_code=$? + echo "Exit code was: $exit_code" + freq=${exit_code_freqs[$exit_code]} + let freq=$freq+1 + exit_code_freqs[$exit_code]=$freq } > $RUN_LOG 2>&1 + + sleep 5 +done + +EXIT_CODES_LOG=$SESSION_DIR/exit-codes.csv +for exit_code in "${!exit_code_freqs[@]}"; +do + echo "$exit_code ${exit_code_freqs[$exit_code]}" >> $EXIT_CODES_LOG done ulimit -c 0 From 85f48387c74dad8b4590b3546349fb53f938becb Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 10:59:58 +0100 Subject: [PATCH 242/277] Issue #16: nicer formatting of exit code frequencies log --- src/tests/pipeline/check_multithreading_reliability.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index f7fbb5fe..419b7c08 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -62,9 +62,14 @@ do done EXIT_CODES_LOG=$SESSION_DIR/exit-codes.csv +printf "%10s" "exit-code" >> $EXIT_CODES_LOG +printf "%10s" "frequency" >> $EXIT_CODES_LOG +printf "\n" >> $EXIT_CODES_LOG for exit_code in "${!exit_code_freqs[@]}"; do - echo "$exit_code ${exit_code_freqs[$exit_code]}" >> $EXIT_CODES_LOG + printf "%10d" $exit_code >> $EXIT_CODES_LOG + printf "%10d" ${exit_code_freqs[$exit_code]} >> $EXIT_CODES_LOG + printf "\n" >> $EXIT_CODES_LOG done ulimit -c 0 From d0a3c050b413807445200264f70c2c083877ad30 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 11:02:37 +0100 Subject: [PATCH 243/277] Issue #16: ignoring output folder to avoid an accidental commit of big files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d7eb0905..35b7a77b 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ src/dist src/*.egg-info *.swp src/tests/pipeline/mtr-build +gg-iss-16 From 36f008692da887d70d8b976d743e613b3bc1bd80 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 11:06:29 +0100 Subject: [PATCH 244/277] Issue #16: using absolute path expansion if root-dir passed as a CLI param --- src/tests/pipeline/check_multithreading_reliability.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 419b7c08..18b9133e 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -11,7 +11,7 @@ SOURCE_DIR="$( cd "$CALL_DIR/../.." >/dev/null && pwd )" MTR_SCRIPT=$SOURCE_DIR/tests/pipeline/multithreading_reliability_check.py if [ $# -ge 3 ]; then - ROOT_DIR=$3 + ROOT_DIR="$( cd "$3" >/dev/null && pwd )" else ROOT_DIR=$CALL_DIR fi From c866810a6fda35d9f48a37add773bf1f96a86b9d Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 11:56:45 +0100 Subject: [PATCH 245/277] Issue #16: intermediately writing exit codes every 10 iterations --- .../check_multithreading_reliability.sh | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 18b9133e..64b58250 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -58,18 +58,21 @@ do exit_code_freqs[$exit_code]=$freq } > $RUN_LOG 2>&1 - sleep 5 -done + if [ $(($run_no % 10)) -eq 0 ] || [ $run_no -eq $num_reps ]; + then + EXIT_CODES_LOG=$SESSION_DIR/exit-codes-$run_no.csv + printf "%10s" "exit-code" >> $EXIT_CODES_LOG + printf "%10s" "frequency" >> $EXIT_CODES_LOG + printf "\n" >> $EXIT_CODES_LOG + for exit_code in "${!exit_code_freqs[@]}"; + do + printf "%10d" $exit_code >> $EXIT_CODES_LOG + printf "%10d" ${exit_code_freqs[$exit_code]} >> $EXIT_CODES_LOG + printf "\n" >> $EXIT_CODES_LOG + done + fi -EXIT_CODES_LOG=$SESSION_DIR/exit-codes.csv -printf "%10s" "exit-code" >> $EXIT_CODES_LOG -printf "%10s" "frequency" >> $EXIT_CODES_LOG -printf "\n" >> $EXIT_CODES_LOG -for exit_code in "${!exit_code_freqs[@]}"; -do - printf "%10d" $exit_code >> $EXIT_CODES_LOG - printf "%10d" ${exit_code_freqs[$exit_code]} >> $EXIT_CODES_LOG - printf "\n" >> $EXIT_CODES_LOG + sleep 5 done ulimit -c 0 From 5177b081c0e4af55b218798072e7bb8a5d609400 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sat, 13 Oct 2018 12:19:39 +0100 Subject: [PATCH 246/277] Issue #16: using git-describe to tag the output with the version used --- src/tests/pipeline/check_multithreading_reliability.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 64b58250..71e2bb62 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -28,6 +28,7 @@ ulimit -c unlimited BUILD_LOG=$SESSION_DIR/build.log { + git describe --dirty mkdir -p $BUILD_DIR rm -rf $BUILD_DIR/* cd $BUILD_DIR From 452b0f938bfc37bc0eee0441be138793c1c4aad6 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 09:06:14 +0100 Subject: [PATCH 247/277] Issue #16: using Pythonic percentage formatting --- src/tests/pipeline/multithreading_reliability_check.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 42cc36e3..e1c50e30 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -73,11 +73,10 @@ def run(self): coloredness = np.sum(histogram * scale) coloredness /= np.sum(histogram) coloredness /= num_bins - coloredness *= 100 if self.num_skipped >= self.display_freq: - print('{}ness of {} image: {} %'.format( + print('{}ness of {} image: {:.0%}'.format( Histogrammer.channels[self.channel], - self.tag, int(round(coloredness)) + self.tag, coloredness )) self.num_skipped = 0 else: From b2f649d1bc5f14a0fa9524577c3856ad811b34a1 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 09:24:39 +0100 Subject: [PATCH 248/277] Issue #16: added a SnapshotSaver class that implements IObserver directly --- .../multithreading_reliability_check.py | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index e1c50e30..a880b355 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -6,9 +6,10 @@ import os.path import threading import numpy as np +import scipy.misc from pygiftgrab import (VideoSourceFactory, VideoFrame, ColourSpace, IObservableObserver, - VideoTargetFactory, Codec) + VideoTargetFactory, Codec, IObserver) """ This script provides a multi-threading reliability check. @@ -28,6 +29,32 @@ lock = threading.Lock() +class SnapshotSaver(IObserver): + """A snapshot saver for saving incoming frames to PNG files.""" + + def __init__(self, root_dir, frame_rate=0.2): + """ + Initialise a snapshot saver with a saving frequency. + + :param root_dir: the folder where to save the snapshots + :param frame_rate: saving frequency. The default value tells + the saver to save a frame every 5 sec. + """ + super(SnapshotSaver, self).__init__() + assert 0 < frame_rate <= 1 # to avoid flooding disk with images + self.save_freq = 1.0 / frame_rate + self.root_dir = root_dir + self.num_called = 0 + + def update(self, frame): + """Implement ``IObserver.update``.""" + self.num_called += 1 + if self.num_called % self.save_freq == 1: + out_file = os.path.join(self.root_dir, + 'frame-{:010d}.png'.format(self.num_called)) + scipy.misc.imsave(out_file, frame.data(True)) + + class Bufferer(IObservableObserver): def __init__(self, buffer): From ecd72865e44689f61127bbfaf77e3dfa8c467bec Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 09:25:08 +0100 Subject: [PATCH 249/277] Issue #16: inserted snapshot saver into the pipeline --- src/tests/pipeline/multithreading_reliability_check.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index a880b355..f1a1697f 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -170,12 +170,15 @@ def update(self, frame): yellow_file = os.path.join('.', ''.join([filename, '-yellow', ext])) yellow_writer = tfac.create_file_writer(Codec.HEVC, yellow_file, frame_rate) + yellow_snapshots = SnapshotSaver('.') + reader.attach(bufferer_orig) bufferer_orig.attach(red_dyer) red_dyer.attach(red_writer) red_dyer.attach(bufferer_red) red_dyer.attach(green_dyer) green_dyer.attach(yellow_writer) + green_dyer.attach(yellow_snapshots) sleep(20) # operate pipeline for 20 sec hist_red.stop() @@ -187,3 +190,4 @@ def update(self, frame): red_dyer.detach(bufferer_red) red_dyer.detach(green_dyer) green_dyer.detach(yellow_writer) + green_dyer.detach(yellow_snapshots) From 0b90bd701ea36d006d792577e9479b6b7b346807 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 09:47:20 +0100 Subject: [PATCH 250/277] Issue #16: fixed timed saving of snapshots --- .../multithreading_reliability_check.py | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index f1a1697f..7eca3382 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -from time import sleep +from time import (sleep, time) import argparse import os.path import threading @@ -32,27 +32,29 @@ class SnapshotSaver(IObserver): """A snapshot saver for saving incoming frames to PNG files.""" - def __init__(self, root_dir, frame_rate=0.2): + def __init__(self, root_dir, save_freq=5): """ Initialise a snapshot saver with a saving frequency. :param root_dir: the folder where to save the snapshots - :param frame_rate: saving frequency. The default value tells - the saver to save a frame every 5 sec. + :param save_freq: saving frequency. The default value tells + the saver to save every 5 seconds. """ super(SnapshotSaver, self).__init__() - assert 0 < frame_rate <= 1 # to avoid flooding disk with images - self.save_freq = 1.0 / frame_rate + assert 5 <= save_freq # to avoid flooding disk with images + self.save_freq = save_freq self.root_dir = root_dir - self.num_called = 0 + self.last_saved = time() + self.num_saved = 0 def update(self, frame): """Implement ``IObserver.update``.""" - self.num_called += 1 - if self.num_called % self.save_freq == 1: + if time() - self.last_saved >= self.save_freq: + self.num_saved += 1 out_file = os.path.join(self.root_dir, - 'frame-{:010d}.png'.format(self.num_called)) + 'frame-{:010d}.png'.format(self.num_saved)) scipy.misc.imsave(out_file, frame.data(True)) + self.last_saved = time() class Bufferer(IObservableObserver): From 3f5e56d49b20fd0b969927ec6e17d1228d88b00d Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 10:10:24 +0100 Subject: [PATCH 251/277] Issue #16: renamed buffer => np_buffer as buffer is built-in type --- src/tests/pipeline/multithreading_reliability_check.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 7eca3382..0091b993 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -59,9 +59,9 @@ def update(self, frame): class Bufferer(IObservableObserver): - def __init__(self, buffer): + def __init__(self, np_buffer): super(Bufferer, self).__init__() - self.buffer = buffer + self.buffer = np_buffer def update(self, frame): with lock: @@ -73,13 +73,13 @@ class Histogrammer(threading.Thread): channels = ('Blue', 'Green', 'Red', 'Alpha') - def __init__(self, buffer, channel, tag, frame_rate, display_freq): + def __init__(self, np_buffer, channel, tag, frame_rate, display_freq): super(Histogrammer, self).__init__() assert channel in range(3) assert 0 < frame_rate <= 60 assert 0 <= display_freq self.channel = channel - self.buffer = buffer + self.buffer = np_buffer self.tag = tag self.display_freq = display_freq self.num_skipped = 0 From 5099c9d03d160bd794244a34f49ecaec93b0ee98 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 10:17:51 +0100 Subject: [PATCH 252/277] Issue #16: renamed global buffers for clarity --- .../pipeline/multithreading_reliability_check.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 0091b993..8d3d4b89 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -25,7 +25,7 @@ """ -buffer_red, buffer_orig = None, None +np_buffer_red, np_buffer_orig = None, None lock = threading.Lock() @@ -157,14 +157,14 @@ def update(self, frame): red_dyer = Dyer(2, 128) green_dyer = Dyer(1, 64) - buffer_red = np.zeros(frame_shape, np.uint8) - bufferer_red = Bufferer(buffer_red) - buffer_orig = np.zeros_like(buffer_red) - bufferer_orig = Bufferer(buffer_orig) + np_buffer_red = np.zeros(frame_shape, np.uint8) + bufferer_red = Bufferer(np_buffer_red) + np_buffer_orig = np.zeros_like(np_buffer_red) + bufferer_orig = Bufferer(np_buffer_orig) - hist_red = Histogrammer(buffer_red, 2, 'red-dyed', 60.0, 10) + hist_red = Histogrammer(np_buffer_red, 2, 'red-dyed', 60.0, 10) hist_red.start() - hist_orig = Histogrammer(buffer_orig, 2, 'original', 50.0, 10) + hist_orig = Histogrammer(np_buffer_orig, 2, 'original', 50.0, 10) hist_orig.start() red_file = os.path.join('.', ''.join([filename, '-red', ext])) From 58a2afef831d76f0a69b0c982681e464a81587b5 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 10:20:01 +0100 Subject: [PATCH 253/277] Issue #16: commented checker script --- .../multithreading_reliability_check.py | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index 8d3d4b89..b4d21c9c 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -25,7 +25,11 @@ """ +# global NumPy buffers np_buffer_red, np_buffer_orig = None, None + +# mutex protecting frame data passed from node to node +# in the GIFT-Grab processing pipeline lock = threading.Lock() @@ -58,22 +62,41 @@ def update(self, frame): class Bufferer(IObservableObserver): + """GIFT-Grab processing node that updates a frame buffer.""" def __init__(self, np_buffer): + """Initialise a bufferer that will update given buffer.""" super(Bufferer, self).__init__() self.buffer = np_buffer def update(self, frame): + """Implement ``IObservableObserver.update``.""" with lock: data = frame.data(True) self.buffer[:, :, :] = data[:, :, :] class Histogrammer(threading.Thread): + """ + GIFT-Grab processing node that computes the histogram of + an image channel and prints how "colored" that channel is. + """ channels = ('Blue', 'Green', 'Red', 'Alpha') def __init__(self, np_buffer, channel, tag, frame_rate, display_freq): + """ + :param np_buffer: image buffer to use + :param channel: image channel to compute coloredness for + :param tag: a tag describing what this image is, e.g. + how it's been processed within a GIFT-Grab pipeline + :param frame_rate: the rate at which to compute the + coloredness (unit: frames-per-second) + :param display_freq: how many times to skip the display + of computed coloredness, e.g. if 5 is provided, the + coloredness of every 5th frame will be printed to the + console + """ super(Histogrammer, self).__init__() assert channel in range(3) assert 0 < frame_rate <= 60 @@ -87,6 +110,7 @@ def __init__(self, np_buffer, channel, tag, frame_rate, display_freq): self.running = False def run(self): + """Override ``Thread.run``.""" if self.running: return @@ -113,12 +137,18 @@ def run(self): sleep(self.sleep_interval) def stop(self): + """Stop the thread.""" self.running = False class Dyer(IObservableObserver): + """Dyes specified channel of an incoming video frame.""" def __init__(self, channel, increment): + """ + :param channel: image channel to dye + :param increment: how much to dye the image channel + """ super(Dyer, self).__init__() assert 0 <= channel < 3 assert 0 <= increment < 256 @@ -126,6 +156,7 @@ def __init__(self, channel, increment): self.increment = increment def update(self, frame): + """Implement ``IObservableObserver.update``.""" with lock: data = frame.data(True) channel_data = data[:, :, self.channel] @@ -145,35 +176,46 @@ def update(self, frame): assert filename assert ext == '.mp4' + # initialise reading of passed file sfac = VideoSourceFactory.get_instance() reader = sfac.create_file_reader(in_file, ColourSpace.BGRA) frame = VideoFrame(ColourSpace.BGRA, False) reader.get_frame(frame) frame_shape = (frame.rows(), frame.cols(), 4) + # prepare for creating encoders (writers) tfac = VideoTargetFactory.get_instance() frame_rate = reader.get_frame_rate() + # create a red and green Dyer red_dyer = Dyer(2, 128) green_dyer = Dyer(1, 64) + # create the bufferer for the red and green Dyers np_buffer_red = np.zeros(frame_shape, np.uint8) bufferer_red = Bufferer(np_buffer_red) np_buffer_orig = np.zeros_like(np_buffer_red) bufferer_orig = Bufferer(np_buffer_orig) + # create the histogrammers for the red-dyed and + # the original video frames, and start them hist_red = Histogrammer(np_buffer_red, 2, 'red-dyed', 60.0, 10) hist_red.start() hist_orig = Histogrammer(np_buffer_orig, 2, 'original', 50.0, 10) hist_orig.start() + # create encoders for the red-dyed and yellow-dyed (as green + # is applied on top of red) video streams red_file = os.path.join('.', ''.join([filename, '-red', ext])) red_writer = tfac.create_file_writer(Codec.HEVC, red_file, frame_rate) yellow_file = os.path.join('.', ''.join([filename, '-yellow', ext])) yellow_writer = tfac.create_file_writer(Codec.HEVC, yellow_file, frame_rate) + # create a SnapshotSavers for saving a number of yellow-dyed + # video frames yellow_snapshots = SnapshotSaver('.') + # assemble the GIFT-Grab pipeline reader.attach(bufferer_orig) bufferer_orig.attach(red_dyer) red_dyer.attach(red_writer) @@ -183,9 +225,12 @@ def update(self, frame): green_dyer.attach(yellow_snapshots) sleep(20) # operate pipeline for 20 sec + + # stop the histogrammers hist_red.stop() hist_orig.stop() + # disassemble the GIFT-Grab pipeline reader.detach(bufferer_orig) bufferer_orig.detach(red_dyer) red_dyer.detach(red_writer) From a78214ce9091fcacc78a7af8d15f01fde60717ee Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 10:54:24 +0100 Subject: [PATCH 254/277] Issue #16: moved issue-specific comments to shell script --- .../check_multithreading_reliability.sh | 17 +++++++++++++---- .../multithreading_reliability_check.py | 18 +++++------------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index 71e2bb62..ceafc345 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -1,10 +1,19 @@ #!/usr/bin/env bash # -*- coding: utf-8 -*- -# Build a basic GIFT-Grab capable of reading a video file, -# and encoding to a video file in real time, with Python -# and NumPy support. Subsequently run the multi-threading -# reliability check script. +# This script provides a multi-threading reliability check. +# The background is issue #16. It looks like in applications +# where multiple Python threads are involved, occasionally +# the acquisition of the Global Interpreter Lock leads to a +# deadlocks, which crashes the whole application with a +# non-specific segmentation fault. +# +# It builds a basic GIFT-Grab capable of reading a video file, +# and encoding to a video file in real time, with Python and +# NumPy support. It subsequently runs a multi-threaded +# GIFT-Grab pipeline a number of times, recording the exit +# status each time. This is essentially a stress-test that +# should serve as a validation that issue #16 is fixed. CALL_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" SOURCE_DIR="$( cd "$CALL_DIR/../.." >/dev/null && pwd )" diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py index b4d21c9c..3fdad38b 100755 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ b/src/tests/pipeline/multithreading_reliability_check.py @@ -1,6 +1,11 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +""" +Example showing a complex GIFT-Grab pipeline with +multiple intermediate processing nodes. +""" + from time import (sleep, time) import argparse import os.path @@ -11,19 +16,6 @@ ColourSpace, IObservableObserver, VideoTargetFactory, Codec, IObserver) -""" -This script provides a multi-threading reliability check. -The background is issue #16. It looks like in applications -where multiple Python threads are involved, occasionally -the acquisition of the Global Interpreter Lock leads to a -deadlocks, which crashes the whole application with a -non-specific segmentation fault. - -In this script we run a number of multi-threaded GIFT-Grab -pipelines, which should serve as a validation that this -problem is fixed. -""" - # global NumPy buffers np_buffer_red, np_buffer_orig = None, None From 1844626b5f3657d6a290605b652a4c1284931b13 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 10:54:45 +0100 Subject: [PATCH 255/277] Issue #16: added synopsis display to shell script --- .../pipeline/check_multithreading_reliability.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index ceafc345..c6419403 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -15,6 +15,18 @@ # status each time. This is essentially a stress-test that # should serve as a validation that issue #16 is fixed. +if [ $# -lt 1 ] || [ $# -gt 3 ]; +then + THIS_SCRIPT="$(basename "$(test -L "${BASH_SOURCE[0]}" && readlink "$0" || echo "$0")")" + printf "Usage: $THIS_SCRIPT video_file [ num_reps [ output_dir ] ]\n" + printf "\tvideo_file: path to an HEVC-encoded MP4 file\n" + printf "\tnum_reps: how many times to run the Python script " + printf "(default: once)\n" + printf "\toutput_dir: where to save all the generated output " + printf "(default: current directory)\n" + exit 1 +fi + CALL_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" SOURCE_DIR="$( cd "$CALL_DIR/../.." >/dev/null && pwd )" MTR_SCRIPT=$SOURCE_DIR/tests/pipeline/multithreading_reliability_check.py From 8ef5a463a0fe819e9319d0d647c30b561733e3ed Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 10:57:52 +0100 Subject: [PATCH 256/277] Issue #16: shell script now shows the current session directory before starting --- src/tests/pipeline/check_multithreading_reliability.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh index c6419403..39df9537 100755 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ b/src/tests/pipeline/check_multithreading_reliability.sh @@ -45,6 +45,7 @@ CMAKE_OPTS="$CMAKE_OPTS -D BUILD_PYTHON=ON -D USE_NUMPY=ON" CMAKE_OPTS="$CMAKE_OPTS -D CMAKE_BUILD_TYPE=Debug" SESSION_DIR=$ROOT_DIR/$(date +"%Y-%m-%d-%H-%M-%S") mkdir $SESSION_DIR +echo "Session directory: $SESSION_DIR" ulimit -c unlimited BUILD_LOG=$SESSION_DIR/build.log From ad142620e3bbbe40fd7f22a29a1e1924b3ddef1b Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 11:01:37 +0100 Subject: [PATCH 257/277] Issue #16: shorter name for Python script --- src/tests/pipeline/complex_pipeline.py | 4 +- .../multithreading_reliability_check.py | 232 ------------------ 2 files changed, 2 insertions(+), 234 deletions(-) delete mode 100755 src/tests/pipeline/multithreading_reliability_check.py diff --git a/src/tests/pipeline/complex_pipeline.py b/src/tests/pipeline/complex_pipeline.py index 66686f1e..3fdad38b 100755 --- a/src/tests/pipeline/complex_pipeline.py +++ b/src/tests/pipeline/complex_pipeline.py @@ -203,9 +203,9 @@ def update(self, frame): yellow_file = os.path.join('.', ''.join([filename, '-yellow', ext])) yellow_writer = tfac.create_file_writer(Codec.HEVC, yellow_file, frame_rate) - # create a SnapshotSaver for saving a number of yellow-dyed + # create a SnapshotSavers for saving a number of yellow-dyed # video frames - yellow_snapshots = SnapshotSaver('.', 9) + yellow_snapshots = SnapshotSaver('.') # assemble the GIFT-Grab pipeline reader.attach(bufferer_orig) diff --git a/src/tests/pipeline/multithreading_reliability_check.py b/src/tests/pipeline/multithreading_reliability_check.py deleted file mode 100755 index 3fdad38b..00000000 --- a/src/tests/pipeline/multithreading_reliability_check.py +++ /dev/null @@ -1,232 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -Example showing a complex GIFT-Grab pipeline with -multiple intermediate processing nodes. -""" - -from time import (sleep, time) -import argparse -import os.path -import threading -import numpy as np -import scipy.misc -from pygiftgrab import (VideoSourceFactory, VideoFrame, - ColourSpace, IObservableObserver, - VideoTargetFactory, Codec, IObserver) - - -# global NumPy buffers -np_buffer_red, np_buffer_orig = None, None - -# mutex protecting frame data passed from node to node -# in the GIFT-Grab processing pipeline -lock = threading.Lock() - - -class SnapshotSaver(IObserver): - """A snapshot saver for saving incoming frames to PNG files.""" - - def __init__(self, root_dir, save_freq=5): - """ - Initialise a snapshot saver with a saving frequency. - - :param root_dir: the folder where to save the snapshots - :param save_freq: saving frequency. The default value tells - the saver to save every 5 seconds. - """ - super(SnapshotSaver, self).__init__() - assert 5 <= save_freq # to avoid flooding disk with images - self.save_freq = save_freq - self.root_dir = root_dir - self.last_saved = time() - self.num_saved = 0 - - def update(self, frame): - """Implement ``IObserver.update``.""" - if time() - self.last_saved >= self.save_freq: - self.num_saved += 1 - out_file = os.path.join(self.root_dir, - 'frame-{:010d}.png'.format(self.num_saved)) - scipy.misc.imsave(out_file, frame.data(True)) - self.last_saved = time() - - -class Bufferer(IObservableObserver): - """GIFT-Grab processing node that updates a frame buffer.""" - - def __init__(self, np_buffer): - """Initialise a bufferer that will update given buffer.""" - super(Bufferer, self).__init__() - self.buffer = np_buffer - - def update(self, frame): - """Implement ``IObservableObserver.update``.""" - with lock: - data = frame.data(True) - self.buffer[:, :, :] = data[:, :, :] - - -class Histogrammer(threading.Thread): - """ - GIFT-Grab processing node that computes the histogram of - an image channel and prints how "colored" that channel is. - """ - - channels = ('Blue', 'Green', 'Red', 'Alpha') - - def __init__(self, np_buffer, channel, tag, frame_rate, display_freq): - """ - :param np_buffer: image buffer to use - :param channel: image channel to compute coloredness for - :param tag: a tag describing what this image is, e.g. - how it's been processed within a GIFT-Grab pipeline - :param frame_rate: the rate at which to compute the - coloredness (unit: frames-per-second) - :param display_freq: how many times to skip the display - of computed coloredness, e.g. if 5 is provided, the - coloredness of every 5th frame will be printed to the - console - """ - super(Histogrammer, self).__init__() - assert channel in range(3) - assert 0 < frame_rate <= 60 - assert 0 <= display_freq - self.channel = channel - self.buffer = np_buffer - self.tag = tag - self.display_freq = display_freq - self.num_skipped = 0 - self.sleep_interval = 1.0 / frame_rate - self.running = False - - def run(self): - """Override ``Thread.run``.""" - if self.running: - return - - histogram, num_bins = None, 10 - scale = np.array([i for i in range(1, num_bins + 1)], np.float) - self.running = True - while self.running: - with lock: - histogram, _ = np.histogram( - self.buffer[:, :, 2], bins=num_bins, range=(0, 256) - ) - if histogram is not None: - coloredness = np.sum(histogram * scale) - coloredness /= np.sum(histogram) - coloredness /= num_bins - if self.num_skipped >= self.display_freq: - print('{}ness of {} image: {:.0%}'.format( - Histogrammer.channels[self.channel], - self.tag, coloredness - )) - self.num_skipped = 0 - else: - self.num_skipped += 1 - sleep(self.sleep_interval) - - def stop(self): - """Stop the thread.""" - self.running = False - - -class Dyer(IObservableObserver): - """Dyes specified channel of an incoming video frame.""" - - def __init__(self, channel, increment): - """ - :param channel: image channel to dye - :param increment: how much to dye the image channel - """ - super(Dyer, self).__init__() - assert 0 <= channel < 3 - assert 0 <= increment < 256 - self.channel = channel - self.increment = increment - - def update(self, frame): - """Implement ``IObservableObserver.update``.""" - with lock: - data = frame.data(True) - channel_data = data[:, :, self.channel] - channel_data[channel_data < 255 - self.increment] += self.increment - - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument('-i', '--input', type=str, required=True, - metavar='VIDEO_FILE', - help='Input video file (HEVC-encoded MP4)') - args = parser.parse_args() - in_file = args.input - - filename = os.path.basename(in_file) - filename, ext = os.path.splitext(filename) - assert filename - assert ext == '.mp4' - - # initialise reading of passed file - sfac = VideoSourceFactory.get_instance() - reader = sfac.create_file_reader(in_file, ColourSpace.BGRA) - frame = VideoFrame(ColourSpace.BGRA, False) - reader.get_frame(frame) - frame_shape = (frame.rows(), frame.cols(), 4) - - # prepare for creating encoders (writers) - tfac = VideoTargetFactory.get_instance() - frame_rate = reader.get_frame_rate() - - # create a red and green Dyer - red_dyer = Dyer(2, 128) - green_dyer = Dyer(1, 64) - - # create the bufferer for the red and green Dyers - np_buffer_red = np.zeros(frame_shape, np.uint8) - bufferer_red = Bufferer(np_buffer_red) - np_buffer_orig = np.zeros_like(np_buffer_red) - bufferer_orig = Bufferer(np_buffer_orig) - - # create the histogrammers for the red-dyed and - # the original video frames, and start them - hist_red = Histogrammer(np_buffer_red, 2, 'red-dyed', 60.0, 10) - hist_red.start() - hist_orig = Histogrammer(np_buffer_orig, 2, 'original', 50.0, 10) - hist_orig.start() - - # create encoders for the red-dyed and yellow-dyed (as green - # is applied on top of red) video streams - red_file = os.path.join('.', ''.join([filename, '-red', ext])) - red_writer = tfac.create_file_writer(Codec.HEVC, red_file, frame_rate) - yellow_file = os.path.join('.', ''.join([filename, '-yellow', ext])) - yellow_writer = tfac.create_file_writer(Codec.HEVC, yellow_file, frame_rate) - - # create a SnapshotSavers for saving a number of yellow-dyed - # video frames - yellow_snapshots = SnapshotSaver('.') - - # assemble the GIFT-Grab pipeline - reader.attach(bufferer_orig) - bufferer_orig.attach(red_dyer) - red_dyer.attach(red_writer) - red_dyer.attach(bufferer_red) - red_dyer.attach(green_dyer) - green_dyer.attach(yellow_writer) - green_dyer.attach(yellow_snapshots) - - sleep(20) # operate pipeline for 20 sec - - # stop the histogrammers - hist_red.stop() - hist_orig.stop() - - # disassemble the GIFT-Grab pipeline - reader.detach(bufferer_orig) - bufferer_orig.detach(red_dyer) - red_dyer.detach(red_writer) - red_dyer.detach(bufferer_red) - red_dyer.detach(green_dyer) - green_dyer.detach(yellow_writer) - green_dyer.detach(yellow_snapshots) From 4a32b61af73d6788f5d9fc8d65e1527f61c48f4b Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 11:02:26 +0100 Subject: [PATCH 258/277] Issue #16: shorter name for Bash script --- .../check_multithreading_reliability.sh | 101 ------------------ src/tests/pipeline/run-complex-pipeline.sh | 4 +- 2 files changed, 2 insertions(+), 103 deletions(-) delete mode 100755 src/tests/pipeline/check_multithreading_reliability.sh diff --git a/src/tests/pipeline/check_multithreading_reliability.sh b/src/tests/pipeline/check_multithreading_reliability.sh deleted file mode 100755 index 39df9537..00000000 --- a/src/tests/pipeline/check_multithreading_reliability.sh +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/env bash -# -*- coding: utf-8 -*- - -# This script provides a multi-threading reliability check. -# The background is issue #16. It looks like in applications -# where multiple Python threads are involved, occasionally -# the acquisition of the Global Interpreter Lock leads to a -# deadlocks, which crashes the whole application with a -# non-specific segmentation fault. -# -# It builds a basic GIFT-Grab capable of reading a video file, -# and encoding to a video file in real time, with Python and -# NumPy support. It subsequently runs a multi-threaded -# GIFT-Grab pipeline a number of times, recording the exit -# status each time. This is essentially a stress-test that -# should serve as a validation that issue #16 is fixed. - -if [ $# -lt 1 ] || [ $# -gt 3 ]; -then - THIS_SCRIPT="$(basename "$(test -L "${BASH_SOURCE[0]}" && readlink "$0" || echo "$0")")" - printf "Usage: $THIS_SCRIPT video_file [ num_reps [ output_dir ] ]\n" - printf "\tvideo_file: path to an HEVC-encoded MP4 file\n" - printf "\tnum_reps: how many times to run the Python script " - printf "(default: once)\n" - printf "\toutput_dir: where to save all the generated output " - printf "(default: current directory)\n" - exit 1 -fi - -CALL_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" -SOURCE_DIR="$( cd "$CALL_DIR/../.." >/dev/null && pwd )" -MTR_SCRIPT=$SOURCE_DIR/tests/pipeline/multithreading_reliability_check.py -if [ $# -ge 3 ]; -then - ROOT_DIR="$( cd "$3" >/dev/null && pwd )" -else - ROOT_DIR=$CALL_DIR -fi - -BUILD_DIR=$ROOT_DIR/mtr-build -CMAKE_OPTS="-D USE_FILES=ON" -CMAKE_OPTS="$CMAKE_OPTS -D USE_HEVC=ON" -CMAKE_OPTS="$CMAKE_OPTS -D ENABLE_NONFREE=ON -D USE_NVENC=ON" -CMAKE_OPTS="$CMAKE_OPTS -D BUILD_PYTHON=ON -D USE_NUMPY=ON" -CMAKE_OPTS="$CMAKE_OPTS -D CMAKE_BUILD_TYPE=Debug" -SESSION_DIR=$ROOT_DIR/$(date +"%Y-%m-%d-%H-%M-%S") -mkdir $SESSION_DIR -echo "Session directory: $SESSION_DIR" -ulimit -c unlimited - -BUILD_LOG=$SESSION_DIR/build.log -{ - git describe --dirty - mkdir -p $BUILD_DIR - rm -rf $BUILD_DIR/* - cd $BUILD_DIR - cmake $CMAKE_OPTS $SOURCE_DIR - make -j4 -} > $BUILD_LOG 2>&1 - -num_reps=1 -if [ $# -ge 2 ]; -then - num_reps=$2 -fi - -declare -a exit_code_freqs -for run_no in `seq 1 $num_reps`; -do - WORKING_DIR=$SESSION_DIR/$(printf "%03d" $run_no) - mkdir $WORKING_DIR - cd $WORKING_DIR - RUN_LOG=$WORKING_DIR/run.log - { - PYTHONPATH=$BUILD_DIR python $MTR_SCRIPT --input $1 - - exit_code=$? - echo "Exit code was: $exit_code" - freq=${exit_code_freqs[$exit_code]} - let freq=$freq+1 - exit_code_freqs[$exit_code]=$freq - } > $RUN_LOG 2>&1 - - if [ $(($run_no % 10)) -eq 0 ] || [ $run_no -eq $num_reps ]; - then - EXIT_CODES_LOG=$SESSION_DIR/exit-codes-$run_no.csv - printf "%10s" "exit-code" >> $EXIT_CODES_LOG - printf "%10s" "frequency" >> $EXIT_CODES_LOG - printf "\n" >> $EXIT_CODES_LOG - for exit_code in "${!exit_code_freqs[@]}"; - do - printf "%10d" $exit_code >> $EXIT_CODES_LOG - printf "%10d" ${exit_code_freqs[$exit_code]} >> $EXIT_CODES_LOG - printf "\n" >> $EXIT_CODES_LOG - done - fi - - sleep 5 -done - -ulimit -c 0 diff --git a/src/tests/pipeline/run-complex-pipeline.sh b/src/tests/pipeline/run-complex-pipeline.sh index 3ed9e038..39df9537 100755 --- a/src/tests/pipeline/run-complex-pipeline.sh +++ b/src/tests/pipeline/run-complex-pipeline.sh @@ -5,7 +5,7 @@ # The background is issue #16. It looks like in applications # where multiple Python threads are involved, occasionally # the acquisition of the Global Interpreter Lock leads to a -# deadlock, which crashes the whole application with a +# deadlocks, which crashes the whole application with a # non-specific segmentation fault. # # It builds a basic GIFT-Grab capable of reading a video file, @@ -29,7 +29,7 @@ fi CALL_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" SOURCE_DIR="$( cd "$CALL_DIR/../.." >/dev/null && pwd )" -MTR_SCRIPT=$SOURCE_DIR/tests/pipeline/complex_pipeline.py +MTR_SCRIPT=$SOURCE_DIR/tests/pipeline/multithreading_reliability_check.py if [ $# -ge 3 ]; then ROOT_DIR="$( cd "$3" >/dev/null && pwd )" From 0408f12662b1b5ee99d675efadb46803f7248a72 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 11:04:37 +0100 Subject: [PATCH 259/277] Issue #16: fixed typos --- src/tests/pipeline/complex_pipeline.py | 2 +- src/tests/pipeline/run-complex-pipeline.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/pipeline/complex_pipeline.py b/src/tests/pipeline/complex_pipeline.py index 3fdad38b..1d9d7346 100755 --- a/src/tests/pipeline/complex_pipeline.py +++ b/src/tests/pipeline/complex_pipeline.py @@ -203,7 +203,7 @@ def update(self, frame): yellow_file = os.path.join('.', ''.join([filename, '-yellow', ext])) yellow_writer = tfac.create_file_writer(Codec.HEVC, yellow_file, frame_rate) - # create a SnapshotSavers for saving a number of yellow-dyed + # create a SnapshotSaver for saving a number of yellow-dyed # video frames yellow_snapshots = SnapshotSaver('.') diff --git a/src/tests/pipeline/run-complex-pipeline.sh b/src/tests/pipeline/run-complex-pipeline.sh index 39df9537..5166507b 100755 --- a/src/tests/pipeline/run-complex-pipeline.sh +++ b/src/tests/pipeline/run-complex-pipeline.sh @@ -5,7 +5,7 @@ # The background is issue #16. It looks like in applications # where multiple Python threads are involved, occasionally # the acquisition of the Global Interpreter Lock leads to a -# deadlocks, which crashes the whole application with a +# deadlock, which crashes the whole application with a # non-specific segmentation fault. # # It builds a basic GIFT-Grab capable of reading a video file, From 66b0c337dcc065a517bfc1b2675e551f1a779071 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 11:04:55 +0100 Subject: [PATCH 260/277] Issue #16: reduced snapshot output --- src/tests/pipeline/complex_pipeline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/pipeline/complex_pipeline.py b/src/tests/pipeline/complex_pipeline.py index 1d9d7346..66686f1e 100755 --- a/src/tests/pipeline/complex_pipeline.py +++ b/src/tests/pipeline/complex_pipeline.py @@ -205,7 +205,7 @@ def update(self, frame): # create a SnapshotSaver for saving a number of yellow-dyed # video frames - yellow_snapshots = SnapshotSaver('.') + yellow_snapshots = SnapshotSaver('.', 9) # assemble the GIFT-Grab pipeline reader.attach(bufferer_orig) From 6f3982d7f9fcc85bda346951d5f9cde19e1796ea Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 11:09:55 +0100 Subject: [PATCH 261/277] Issue #16: fixed calling of Python script from Bash script --- src/tests/pipeline/run-complex-pipeline.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/pipeline/run-complex-pipeline.sh b/src/tests/pipeline/run-complex-pipeline.sh index 5166507b..3ed9e038 100755 --- a/src/tests/pipeline/run-complex-pipeline.sh +++ b/src/tests/pipeline/run-complex-pipeline.sh @@ -29,7 +29,7 @@ fi CALL_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" SOURCE_DIR="$( cd "$CALL_DIR/../.." >/dev/null && pwd )" -MTR_SCRIPT=$SOURCE_DIR/tests/pipeline/multithreading_reliability_check.py +MTR_SCRIPT=$SOURCE_DIR/tests/pipeline/complex_pipeline.py if [ $# -ge 3 ]; then ROOT_DIR="$( cd "$3" >/dev/null && pwd )" From f434c03423a1e8f4b3c9f64445d0b1e697c301bf Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 11:41:33 +0100 Subject: [PATCH 262/277] Issue #16: added an RTD page linking to the complex pipeline example --- doc/source/complex.rst | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/doc/source/complex.rst b/doc/source/complex.rst index eba60359..443b8182 100644 --- a/doc/source/complex.rst +++ b/doc/source/complex.rst @@ -1,24 +1,19 @@ .. _Complex: -Multi-threaded complex processing pipelines -=========================================== +Multi-threaded processing pipelines +=================================== -The example below shows how GIFT-Grab can be used for running complex pipelines with multiple -intermediate processing nodes and threads. -The intermediate processing nodes in this example are built on the same principles as in the -:ref:`SciPy` example. +This example shows how GIFT-Grab can be used for running complex pipelines with multiple intermediate +processing nodes and threads. +The intermediate processing nodes are built on the same principles as in the SciPy_ example. Running the example requires an `HEVC-encoded MP4 file`_, an `NVENC-capable GPU`_, and `NumPy support`_. .. _`HEVC-encoded MP4 file`: https://github.com/gift-surg/GIFT-Grab/blob/master/doc/build.md#reading-video-files .. _`NVENC-capable GPU`: https://github.com/gift-surg/GIFT-Grab/blob/master/doc/build.md#hevc .. _`NumPy support`: https://github.com/gift-surg/GIFT-Grab/blob/master/doc/build.md#python-api -The full source code of the example is below. -Please follow the comments and the flow of code. -This example is also available on GitHub_: +Below is the commented full source code: .. literalinclude:: ../../src/tests/pipeline/complex_pipeline.py :language: python - -.. _GitHub: https://github.com/gift-surg/GIFT-Grab/blob/master/src/tests/pipeline/complex_pipeline.py - + :linenos: From 0bd666ac2b1197445766cf59f6ccc8bd9935a30c Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 11:59:27 +0100 Subject: [PATCH 263/277] Issue #16: fixed cross-reference to NumPy example from new RTD page --- doc/source/complex.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/complex.rst b/doc/source/complex.rst index 443b8182..47104d65 100644 --- a/doc/source/complex.rst +++ b/doc/source/complex.rst @@ -5,7 +5,7 @@ Multi-threaded processing pipelines This example shows how GIFT-Grab can be used for running complex pipelines with multiple intermediate processing nodes and threads. -The intermediate processing nodes are built on the same principles as in the SciPy_ example. +The intermediate processing nodes are built on the same principles as in the :ref:`SciPy` example. Running the example requires an `HEVC-encoded MP4 file`_, an `NVENC-capable GPU`_, and `NumPy support`_. .. _`HEVC-encoded MP4 file`: https://github.com/gift-surg/GIFT-Grab/blob/master/doc/build.md#reading-video-files From 144a5170f145e0c49f58bbddc52adbfa648e834b Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 12:00:34 +0100 Subject: [PATCH 264/277] Issue #16: added link from new RTD page to example source code on GitHub --- doc/source/complex.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/source/complex.rst b/doc/source/complex.rst index 47104d65..61ef4427 100644 --- a/doc/source/complex.rst +++ b/doc/source/complex.rst @@ -12,8 +12,10 @@ Running the example requires an `HEVC-encoded MP4 file`_, an `NVENC-capable GPU` .. _`NVENC-capable GPU`: https://github.com/gift-surg/GIFT-Grab/blob/master/doc/build.md#hevc .. _`NumPy support`: https://github.com/gift-surg/GIFT-Grab/blob/master/doc/build.md#python-api -Below is the commented full source code: +Below is the commented full source code, which is also available on GitHub_: .. literalinclude:: ../../src/tests/pipeline/complex_pipeline.py :language: python :linenos: + +.. _GitHub: https://github.com/gift-surg/GIFT-Grab/blob/master/src/tests/pipeline/complex_pipeline.py From c890e4d63a84e5ace2eca250caea85d5b2c9e4d4 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 18:47:20 +0100 Subject: [PATCH 265/277] Issue #16: made the title of the new RTD page more descriptive --- doc/source/complex.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/source/complex.rst b/doc/source/complex.rst index 61ef4427..e5702f99 100644 --- a/doc/source/complex.rst +++ b/doc/source/complex.rst @@ -1,7 +1,7 @@ .. _Complex: -Multi-threaded processing pipelines -=================================== +Multi-threaded complex processing pipelines +=========================================== This example shows how GIFT-Grab can be used for running complex pipelines with multiple intermediate processing nodes and threads. From 0bf6a100dc986c6f4f672f2079009cb5393009c4 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 18:51:26 +0100 Subject: [PATCH 266/277] Issue #16: revised the RTD page wording for clarity --- doc/source/complex.rst | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/doc/source/complex.rst b/doc/source/complex.rst index e5702f99..de681cb6 100644 --- a/doc/source/complex.rst +++ b/doc/source/complex.rst @@ -3,16 +3,19 @@ Multi-threaded complex processing pipelines =========================================== -This example shows how GIFT-Grab can be used for running complex pipelines with multiple intermediate -processing nodes and threads. -The intermediate processing nodes are built on the same principles as in the :ref:`SciPy` example. +The example below shows how GIFT-Grab can be used for running complex pipelines with multiple +intermediate processing nodes and threads. +The intermediate processing nodes in this example are built on the same principles as in the +:ref:`SciPy` example. Running the example requires an `HEVC-encoded MP4 file`_, an `NVENC-capable GPU`_, and `NumPy support`_. .. _`HEVC-encoded MP4 file`: https://github.com/gift-surg/GIFT-Grab/blob/master/doc/build.md#reading-video-files .. _`NVENC-capable GPU`: https://github.com/gift-surg/GIFT-Grab/blob/master/doc/build.md#hevc .. _`NumPy support`: https://github.com/gift-surg/GIFT-Grab/blob/master/doc/build.md#python-api -Below is the commented full source code, which is also available on GitHub_: +The full source code of the example is below. +Please follow the comments and the flow of code. +This example is also available on GitHub_: .. literalinclude:: ../../src/tests/pipeline/complex_pipeline.py :language: python From eaa67d46e88095815be554a92e568681689c1cd4 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 14 Oct 2018 18:53:21 +0100 Subject: [PATCH 267/277] Issue #16: removed line numbers from example on new RTD page --- doc/source/complex.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/source/complex.rst b/doc/source/complex.rst index de681cb6..b6ac054b 100644 --- a/doc/source/complex.rst +++ b/doc/source/complex.rst @@ -19,6 +19,5 @@ This example is also available on GitHub_: .. literalinclude:: ../../src/tests/pipeline/complex_pipeline.py :language: python - :linenos: .. _GitHub: https://github.com/gift-surg/GIFT-Grab/blob/master/src/tests/pipeline/complex_pipeline.py From c6d611ade7d832f26dbf4184a150fa21a7e82e31 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 19 Oct 2018 14:57:13 +0100 Subject: [PATCH 268/277] Issue #16: checker script now supports Blackmagic DeckLink 4K Extreme 12G --- src/tests/pipeline/complex_pipeline.py | 27 ++++++++++++++-------- src/tests/pipeline/run-complex-pipeline.sh | 10 +++++++- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/tests/pipeline/complex_pipeline.py b/src/tests/pipeline/complex_pipeline.py index 66686f1e..e3738d9b 100755 --- a/src/tests/pipeline/complex_pipeline.py +++ b/src/tests/pipeline/complex_pipeline.py @@ -12,7 +12,7 @@ import threading import numpy as np import scipy.misc -from pygiftgrab import (VideoSourceFactory, VideoFrame, +from pygiftgrab import (VideoSourceFactory, VideoFrame, Device, ColourSpace, IObservableObserver, VideoTargetFactory, Codec, IObserver) @@ -158,19 +158,26 @@ def update(self, frame): if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('-i', '--input', type=str, required=True, - metavar='VIDEO_FILE', - help='Input video file (HEVC-encoded MP4)') + metavar='VIDEO_INPUT', + help='"decklink" (for grabbing frames from a Blackmagic DeckLink 4K Extreme 12G)' + ' or a video file (HEVC-encoded MP4)') args = parser.parse_args() in_file = args.input - filename = os.path.basename(in_file) - filename, ext = os.path.splitext(filename) - assert filename - assert ext == '.mp4' - - # initialise reading of passed file sfac = VideoSourceFactory.get_instance() - reader = sfac.create_file_reader(in_file, ColourSpace.BGRA) + + if in_file == 'decklink': + reader = sfac.get_device(Device.DeckLink4KExtreme12G, ColourSpace.BGRA) + reader.set_sub_frame(640, 300, 640, 480) + else: + filename = os.path.basename(in_file) + filename, ext = os.path.splitext(filename) + assert filename + assert ext == '.mp4' + + # initialise reading of passed file + reader = sfac.create_file_reader(in_file, ColourSpace.BGRA) + frame = VideoFrame(ColourSpace.BGRA, False) reader.get_frame(frame) frame_shape = (frame.rows(), frame.cols(), 4) diff --git a/src/tests/pipeline/run-complex-pipeline.sh b/src/tests/pipeline/run-complex-pipeline.sh index 3ed9e038..5dfb083a 100755 --- a/src/tests/pipeline/run-complex-pipeline.sh +++ b/src/tests/pipeline/run-complex-pipeline.sh @@ -18,8 +18,9 @@ if [ $# -lt 1 ] || [ $# -gt 3 ]; then THIS_SCRIPT="$(basename "$(test -L "${BASH_SOURCE[0]}" && readlink "$0" || echo "$0")")" - printf "Usage: $THIS_SCRIPT video_file [ num_reps [ output_dir ] ]\n" + printf "Usage: $THIS_SCRIPT video_file|decklink [ num_reps [ output_dir ] ]\n" printf "\tvideo_file: path to an HEVC-encoded MP4 file\n" + printf "\tdecklink: Blackmagic DeckLink 4K Extreme 12G frame grabber\n" printf "\tnum_reps: how many times to run the Python script " printf "(default: once)\n" printf "\toutput_dir: where to save all the generated output " @@ -42,6 +43,13 @@ CMAKE_OPTS="-D USE_FILES=ON" CMAKE_OPTS="$CMAKE_OPTS -D USE_HEVC=ON" CMAKE_OPTS="$CMAKE_OPTS -D ENABLE_NONFREE=ON -D USE_NVENC=ON" CMAKE_OPTS="$CMAKE_OPTS -D BUILD_PYTHON=ON -D USE_NUMPY=ON" +if [ "$1" = "decklink" ]; then + if [[ -z "${BlackmagicSDK_DIR}" ]]; then + echo "Please set BlackmagicSDK_DIR to the path of the Blackmagic SDK" + exit 1 + fi + CMAKE_OPTS="$CMAKE_OPTS -D USE_BLACKMAGIC_DECKLINK_4K_EXTREME_12G=ON -D ENABLE_NONFREE=ON" +fi CMAKE_OPTS="$CMAKE_OPTS -D CMAKE_BUILD_TYPE=Debug" SESSION_DIR=$ROOT_DIR/$(date +"%Y-%m-%d-%H-%M-%S") mkdir $SESSION_DIR From 41db15f34503ae48931cceb698ab7d9c0ab07318 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 19 Oct 2018 14:59:14 +0100 Subject: [PATCH 269/277] Issue #16: revised checker script for more generic variable names --- src/tests/pipeline/complex_pipeline.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/tests/pipeline/complex_pipeline.py b/src/tests/pipeline/complex_pipeline.py index e3738d9b..1968c33a 100755 --- a/src/tests/pipeline/complex_pipeline.py +++ b/src/tests/pipeline/complex_pipeline.py @@ -159,32 +159,33 @@ def update(self, frame): parser = argparse.ArgumentParser() parser.add_argument('-i', '--input', type=str, required=True, metavar='VIDEO_INPUT', - help='"decklink" (for grabbing frames from a Blackmagic DeckLink 4K Extreme 12G)' + help='decklink (for grabbing frames from a Blackmagic DeckLink 4K Extreme 12G)' ' or a video file (HEVC-encoded MP4)') args = parser.parse_args() - in_file = args.input + video_input = args.input sfac = VideoSourceFactory.get_instance() - if in_file == 'decklink': - reader = sfac.get_device(Device.DeckLink4KExtreme12G, ColourSpace.BGRA) - reader.set_sub_frame(640, 300, 640, 480) + if video_input == 'decklink': + # start acquiring frames from a DeckLink 4K Extreme 12G + source = sfac.get_device(Device.DeckLink4KExtreme12G, ColourSpace.BGRA) + source.set_sub_frame(640, 300, 640, 480) else: - filename = os.path.basename(in_file) + filename = os.path.basename(video_input) filename, ext = os.path.splitext(filename) assert filename assert ext == '.mp4' # initialise reading of passed file - reader = sfac.create_file_reader(in_file, ColourSpace.BGRA) + source = sfac.create_file_reader(video_input, ColourSpace.BGRA) frame = VideoFrame(ColourSpace.BGRA, False) - reader.get_frame(frame) + source.get_frame(frame) frame_shape = (frame.rows(), frame.cols(), 4) # prepare for creating encoders (writers) tfac = VideoTargetFactory.get_instance() - frame_rate = reader.get_frame_rate() + frame_rate = source.get_frame_rate() # create a red and green Dyer red_dyer = Dyer(2, 128) @@ -215,7 +216,7 @@ def update(self, frame): yellow_snapshots = SnapshotSaver('.', 9) # assemble the GIFT-Grab pipeline - reader.attach(bufferer_orig) + source.attach(bufferer_orig) bufferer_orig.attach(red_dyer) red_dyer.attach(red_writer) red_dyer.attach(bufferer_red) @@ -230,7 +231,7 @@ def update(self, frame): hist_orig.stop() # disassemble the GIFT-Grab pipeline - reader.detach(bufferer_orig) + source.detach(bufferer_orig) bufferer_orig.detach(red_dyer) red_dyer.detach(red_writer) red_dyer.detach(bufferer_red) From 65b87240f431266d289b734e7b69499e8c177dbb Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 19 Oct 2018 15:21:23 +0100 Subject: [PATCH 270/277] Issue #16: added missing variable and removed cropping in checker script BM part --- src/tests/pipeline/complex_pipeline.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tests/pipeline/complex_pipeline.py b/src/tests/pipeline/complex_pipeline.py index 1968c33a..fbdf3196 100755 --- a/src/tests/pipeline/complex_pipeline.py +++ b/src/tests/pipeline/complex_pipeline.py @@ -167,9 +167,10 @@ def update(self, frame): sfac = VideoSourceFactory.get_instance() if video_input == 'decklink': + filename = 'decklink' + # start acquiring frames from a DeckLink 4K Extreme 12G source = sfac.get_device(Device.DeckLink4KExtreme12G, ColourSpace.BGRA) - source.set_sub_frame(640, 300, 640, 480) else: filename = os.path.basename(video_input) filename, ext = os.path.splitext(filename) From 9fa86408224a8e221c3ccf1300c3522db8792658 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Fri, 19 Oct 2018 15:44:04 +0100 Subject: [PATCH 271/277] Issue #16: added missing file extension specification when using DeckLink device --- src/tests/pipeline/complex_pipeline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/pipeline/complex_pipeline.py b/src/tests/pipeline/complex_pipeline.py index fbdf3196..b61e8f1c 100755 --- a/src/tests/pipeline/complex_pipeline.py +++ b/src/tests/pipeline/complex_pipeline.py @@ -167,7 +167,7 @@ def update(self, frame): sfac = VideoSourceFactory.get_instance() if video_input == 'decklink': - filename = 'decklink' + filename, ext = 'decklink', '.mp4' # start acquiring frames from a DeckLink 4K Extreme 12G source = sfac.get_device(Device.DeckLink4KExtreme12G, ColourSpace.BGRA) From 64f1e8bfdcfa467bef9a754a0448c4d2a578b169 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 21 Oct 2018 11:48:02 +0100 Subject: [PATCH 272/277] Issue #16: multi-threading reliability checker now supports Epiphan DVI2PCIe Duo DVI port --- src/tests/pipeline/complex_pipeline.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/tests/pipeline/complex_pipeline.py b/src/tests/pipeline/complex_pipeline.py index b61e8f1c..9383db13 100755 --- a/src/tests/pipeline/complex_pipeline.py +++ b/src/tests/pipeline/complex_pipeline.py @@ -159,7 +159,8 @@ def update(self, frame): parser = argparse.ArgumentParser() parser.add_argument('-i', '--input', type=str, required=True, metavar='VIDEO_INPUT', - help='decklink (for grabbing frames from a Blackmagic DeckLink 4K Extreme 12G)' + help='decklink (for grabbing frames from a Blackmagic DeckLink 4K Extreme 12G),\n' + 'dvi2pcie (for grabbing frames from an Epiphan DVI2PCIe Duo DVI port\n' ' or a video file (HEVC-encoded MP4)') args = parser.parse_args() video_input = args.input @@ -171,6 +172,11 @@ def update(self, frame): # start acquiring frames from a DeckLink 4K Extreme 12G source = sfac.get_device(Device.DeckLink4KExtreme12G, ColourSpace.BGRA) + elif video_input == 'dvi2pcie': + filename, ext = 'dvi2pcie', '.mp4' + + # start acquirigin frames from an Epiphan DVI2PCIe Duo DVI port + source = sfac.get_device(Device.DVI2PCIeDuo_DVI, ColourSpace.BGRA) else: filename = os.path.basename(video_input) filename, ext = os.path.splitext(filename) From 30a2ed99d6c89c3d6d80b24dc4c63078002beb1d Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Sun, 21 Oct 2018 11:48:42 +0100 Subject: [PATCH 273/277] Issue #16: multi-threading reliability launch script now supports Epiphan DVI2PCIe Duo as well --- src/tests/pipeline/run-complex-pipeline.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tests/pipeline/run-complex-pipeline.sh b/src/tests/pipeline/run-complex-pipeline.sh index 5dfb083a..8a016785 100755 --- a/src/tests/pipeline/run-complex-pipeline.sh +++ b/src/tests/pipeline/run-complex-pipeline.sh @@ -18,9 +18,10 @@ if [ $# -lt 1 ] || [ $# -gt 3 ]; then THIS_SCRIPT="$(basename "$(test -L "${BASH_SOURCE[0]}" && readlink "$0" || echo "$0")")" - printf "Usage: $THIS_SCRIPT video_file|decklink [ num_reps [ output_dir ] ]\n" + printf "Usage: $THIS_SCRIPT video_file|decklink|dvi2pcie [ num_reps [ output_dir ] ]\n" printf "\tvideo_file: path to an HEVC-encoded MP4 file\n" printf "\tdecklink: Blackmagic DeckLink 4K Extreme 12G frame grabber\n" + printf "\tdvi2pcie: Epiphan DVI2PCIe Duo frame grabber\n" printf "\tnum_reps: how many times to run the Python script " printf "(default: once)\n" printf "\toutput_dir: where to save all the generated output " @@ -49,6 +50,8 @@ if [ "$1" = "decklink" ]; then exit 1 fi CMAKE_OPTS="$CMAKE_OPTS -D USE_BLACKMAGIC_DECKLINK_4K_EXTREME_12G=ON -D ENABLE_NONFREE=ON" +elif [ "$1" = "dvi2pcie" ]; then + CMAKE_OPTS="$CMAKE_OPTS -D USE_EPIPHAN_DVI2PCIE_DUO=ON -D USE_I420=OFF" fi CMAKE_OPTS="$CMAKE_OPTS -D CMAKE_BUILD_TYPE=Debug" SESSION_DIR=$ROOT_DIR/$(date +"%Y-%m-%d-%H-%M-%S") From 7e355c7dd641ddde91de15ce0f8030b901ff5082 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Mon, 22 Oct 2018 08:48:14 +0100 Subject: [PATCH 274/277] Issue #16: using the SDI port of Epiphan DVI2PCIe Duo instead of the DVI port in checker --- src/tests/pipeline/complex_pipeline.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tests/pipeline/complex_pipeline.py b/src/tests/pipeline/complex_pipeline.py index 9383db13..864a2e9d 100755 --- a/src/tests/pipeline/complex_pipeline.py +++ b/src/tests/pipeline/complex_pipeline.py @@ -160,7 +160,7 @@ def update(self, frame): parser.add_argument('-i', '--input', type=str, required=True, metavar='VIDEO_INPUT', help='decklink (for grabbing frames from a Blackmagic DeckLink 4K Extreme 12G),\n' - 'dvi2pcie (for grabbing frames from an Epiphan DVI2PCIe Duo DVI port\n' + 'dvi2pcie (for grabbing frames from an Epiphan DVI2PCIe Duo SDI port\n' ' or a video file (HEVC-encoded MP4)') args = parser.parse_args() video_input = args.input @@ -175,8 +175,8 @@ def update(self, frame): elif video_input == 'dvi2pcie': filename, ext = 'dvi2pcie', '.mp4' - # start acquirigin frames from an Epiphan DVI2PCIe Duo DVI port - source = sfac.get_device(Device.DVI2PCIeDuo_DVI, ColourSpace.BGRA) + # start acquirigin frames from an Epiphan DVI2PCIe Duo SDI port + source = sfac.get_device(Device.DVI2PCIeDuo_SDI, ColourSpace.BGRA) else: filename = os.path.basename(video_input) filename, ext = os.path.splitext(filename) From c5f590facc919b7868e5ab06b59b49792f044341 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Tue, 23 Oct 2018 16:55:14 +0100 Subject: [PATCH 275/277] Issue #16: using default thread constructor with move semantics to ensure BroadcastDaemon thread does not start until it's safe to do so --- src/api/broadcastdaemon.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/api/broadcastdaemon.cpp b/src/api/broadcastdaemon.cpp index df7f7486..666655eb 100644 --- a/src/api/broadcastdaemon.cpp +++ b/src/api/broadcastdaemon.cpp @@ -10,6 +10,7 @@ namespace gg BroadcastDaemon::BroadcastDaemon(IVideoSource * source) : _source(source) , _running(false) + , _thread() { if (_source == nullptr) throw VideoSourceError("Null pointer passed" From 8bdc48c540a3edb2f4542e632dfa4b5a65c59d11 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Tue, 23 Oct 2018 19:09:40 +0100 Subject: [PATCH 276/277] Issue #35, #16: surrounded VideoSourceOpenCV colour conversion with a broad try-catch block --- src/opencv/opencv_video_source.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/opencv/opencv_video_source.cpp b/src/opencv/opencv_video_source.cpp index d41ee42a..e4fe19d4 100644 --- a/src/opencv/opencv_video_source.cpp +++ b/src/opencv/opencv_video_source.cpp @@ -121,8 +121,24 @@ bool VideoSourceOpenCV::get_frame(gg::VideoFrame & frame) _buffer_bgra.cols != _buffer.cols) { _buffer_bgra = cv::Mat::zeros(_buffer.rows, _buffer.cols, CV_8UC4); } - // Convert to BGRA - cv::cvtColor(_buffer, _buffer_bgra, CV_BGR2BGRA); + /* This too broad try-catch block is a workaround to + * https://github.com/gift-surg/GIFT-Grab/issues/35 + * as OpenCV seems to intermittently throw an assertion + * exception in the form: + * "Can't fetch data from terminated TLS container". + * To make things worse, this exception is unhandled in + * the accompanying BroadcastDaemon thread, and so leads + * to an unspecific abortion of the whole application. + */ + try + { + // Convert to BGRA + cv::cvtColor(_buffer, _buffer_bgra, CV_BGR2BGRA); + } + catch (...) + { + return false; + } unsigned char * data = nullptr; size_t data_length = 0; size_t cols = 0, rows = 0; From 03220341626cec23a8601e228b52886a02f85617 Mon Sep 17 00:00:00 2001 From: Dzhoshkun Ismail Shakir Date: Tue, 23 Oct 2018 19:24:03 +0100 Subject: [PATCH 277/277] Issue #16: build directory is now relative to calling directory, to prevent symlink problems --- src/tests/pipeline/run-complex-pipeline.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/pipeline/run-complex-pipeline.sh b/src/tests/pipeline/run-complex-pipeline.sh index 8a016785..d9bd9406 100755 --- a/src/tests/pipeline/run-complex-pipeline.sh +++ b/src/tests/pipeline/run-complex-pipeline.sh @@ -39,7 +39,7 @@ else ROOT_DIR=$CALL_DIR fi -BUILD_DIR=$ROOT_DIR/mtr-build +BUILD_DIR=$CALL_DIR/mtr-build CMAKE_OPTS="-D USE_FILES=ON" CMAKE_OPTS="$CMAKE_OPTS -D USE_HEVC=ON" CMAKE_OPTS="$CMAKE_OPTS -D ENABLE_NONFREE=ON -D USE_NVENC=ON"