From 1745f56ac7e2a4046485e012da75215c400f008f Mon Sep 17 00:00:00 2001 From: Tobias Kurze Date: Fri, 21 Feb 2020 17:10:14 +0100 Subject: [PATCH] added stream sanity checks (sound, singe color) --- Pipfile | 3 + Pipfile.lock | 120 +++++++++++----- backend/config.py | Bin 4481 -> 4652 bytes backend/cron/cron_state_checker.py | 2 +- backend/models/recorder_model.py | 3 + ...e_checker.py => recorder_state_checker.py} | 19 +++ .../tools/recorder_streams_sanity_checks.py | 132 ++++++++++++++++++ backend/tools/stream_handling.py | 15 -- 8 files changed, 246 insertions(+), 48 deletions(-) rename backend/tools/{simple_state_checker.py => recorder_state_checker.py} (92%) create mode 100644 backend/tools/recorder_streams_sanity_checks.py delete mode 100644 backend/tools/stream_handling.py diff --git a/Pipfile b/Pipfile index f7996ba..085702f 100644 --- a/Pipfile +++ b/Pipfile @@ -36,6 +36,9 @@ python-socketio = {version = "*",extras = ["client"]} socketio-client = "*" websocket-client = "*" apscheduler = "*" +pillow = "*" +pydub = "*" +simpleaudio = "*" [dev-packages] diff --git a/Pipfile.lock b/Pipfile.lock index 976b7b1..9c9b39d 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "83c5fbc0a5b6c72ecdd8842e12b7c647e6d43d94a83623a8c0268c08d8a835b7" + "sha256": "e84f3cf0b0e1452298555dc95f7493f8ec43bbff5471f088a1a9ebe64a9db44e" }, "pipfile-spec": 6, "requires": { @@ -517,6 +517,34 @@ ], "version": "==5.4.4" }, + "pillow": { + "hashes": [ + "sha256:0a628977ac2e01ca96aaae247ec2bd38e729631ddf2221b4b715446fd45505be", + "sha256:4d9ed9a64095e031435af120d3c910148067087541131e82b3e8db302f4c8946", + "sha256:54ebae163e8412aff0b9df1e88adab65788f5f5b58e625dc5c7f51eaf14a6837", + "sha256:5bfef0b1cdde9f33881c913af14e43db69815c7e8df429ceda4c70a5e529210f", + "sha256:5f3546ceb08089cedb9e8ff7e3f6a7042bb5b37c2a95d392fb027c3e53a2da00", + "sha256:5f7ae9126d16194f114435ebb79cc536b5682002a4fa57fa7bb2cbcde65f2f4d", + "sha256:62a889aeb0a79e50ecf5af272e9e3c164148f4bd9636cc6bcfa182a52c8b0533", + "sha256:7406f5a9b2fd966e79e6abdaf700585a4522e98d6559ce37fc52e5c955fade0a", + "sha256:8453f914f4e5a3d828281a6628cf517832abfa13ff50679a4848926dac7c0358", + "sha256:87269cc6ce1e3dee11f23fa515e4249ae678dbbe2704598a51cee76c52e19cda", + "sha256:875358310ed7abd5320f21dd97351d62de4929b0426cdb1eaa904b64ac36b435", + "sha256:8ac6ce7ff3892e5deaab7abaec763538ffd011f74dc1801d93d3c5fc541feee2", + "sha256:91b710e3353aea6fc758cdb7136d9bbdcb26b53cefe43e2cba953ac3ee1d3313", + "sha256:9d2ba4ed13af381233e2d810ff3bab84ef9f18430a9b336ab69eaf3cd24299ff", + "sha256:a62ec5e13e227399be73303ff301f2865bf68657d15ea50b038d25fc41097317", + "sha256:ab76e5580b0ed647a8d8d2d2daee170e8e9f8aad225ede314f684e297e3643c2", + "sha256:bf4003aa538af3f4205c5fac56eacaa67a6dd81e454ffd9e9f055fff9f1bc614", + "sha256:bf598d2e37cf8edb1a2f26ed3fb255191f5232badea4003c16301cb94ac5bdd0", + "sha256:c18f70dc27cc5d236f10e7834236aff60aadc71346a5bc1f4f83a4b3abee6386", + "sha256:c5ed816632204a2fc9486d784d8e0d0ae754347aba99c811458d69fcdfd2a2f9", + "sha256:dc058b7833184970d1248135b8b0ab702e6daa833be14035179f2acb78ff5636", + "sha256:ff3797f2f16bf9d17d53257612da84dd0758db33935777149b3334c01ff68865" + ], + "index": "pypi", + "version": "==7.0.0" + }, "pyasn1": { "hashes": [ "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d", @@ -532,38 +560,46 @@ }, "pycryptodomex": { "hashes": [ - "sha256:04646e40ef5788bad6d415e52862ffcdf2ac2d888ba4a5c82d5cb44607a042f7", - "sha256:132f1e5fa84921f25695a313a6d4988847dfaee7fb1fd0d1fbe03ef678836f58", - "sha256:17ad1ebaa00806305d34550fe5d3c776e38a27b8a2678dfb7871ef0209d64e46", - "sha256:27736fa02a2d3502e1ca4b150457e56ce3b98f132462f540073498884e5f8975", - "sha256:38050b3fd86c74c6c79e40bbe824bec6431c3e4e36f6080ed544673ba2dc133a", - "sha256:3b9306b360bddbc8e098b16eab7adacf49389d212db9c3739588ab840a1ca868", - "sha256:466e36ba74a7e725625e717fad3f36e0b9293c247b7d0439c66528026ef2834f", - "sha256:4f77360b23a21db32a4c35dacffac33dc30ac6a5a77162a34e99ab11ab631516", - "sha256:5002388178845683c330a02f4faeddfe7cd477b87824987cca4718fa0c4f2085", - "sha256:51be76756abfc1ddc97e1e2e3c38f4e62fb940161162368308ea9e5919e86c34", - "sha256:544628ae67d61c31c28a60e621dadd738b303c5266492355d5ebdb6e7dd1e78f", - "sha256:6ff9d4a06bc40211eee05cd88436740d698a01233f4aaff9eb70d8a90e578966", - "sha256:718329c6ca60260f1c27b8392e372dd51e4e691f7dcb88adc53eb3b76af6363c", - "sha256:918bc5a0170fe8ed7b72f202245b34f84a1997f5ca1520b9c7db71126e5acd62", - "sha256:a8ea72adde0d010f89abece5f024b1be95a5c52472e9a57b3ac7d59aee3c8238", - "sha256:a979d2c7bcc67282b7ec2600db384c63d37d74e250edb99168483605a380bf62", - "sha256:b350f9ad09b692aed57e669fc3f8cf918557fae9f0229c6ce9286a6fe8c1b60f", - "sha256:be838abc8557a21a60d453c5a4e64c738966b8a0b7d7f8f97eb8bb44041ca452", - "sha256:bfa99692d3c8f994c5850cc8a894cba001abd76d34069a8bfaad173dd46387d6", - "sha256:c021b66f5b3c4ea0c45422ec3241bfea4a16651e1ee5459a136639d0716ccb3c", - "sha256:c7babb64484080057a24c74a82dbf7997904b1710b74caf62e261610f989b437", - "sha256:c96b7762b601dc8a58d7712235c3c152868116f58a7ffa40dcd1c6f6cd97405e", - "sha256:d67b6e0bae0777a2c6c83275fbd7cbf53cd5f23c2028f908b0f7d996466e5b15", - "sha256:e15f39fcfb949cfd5536cc9647daba942b1a99b67e4d7211e3bdbcedbc2f823c", - "sha256:e380448f1e39736f6230ec284cd6d771956ad802d6ce5bc56947a2481080cac1", - "sha256:e5236f2171b21e704d1854fd809a7228eb22e29c894af31459e41986e6a53f87", - "sha256:ea7b48ce8dbbc86ebadcfe56ebc10d413bdd12c9a5ff0b9147a41993f12b80b3", - "sha256:f39f5b58d8fe348ed604bb44a89ca93b26130c275db2b249f718f1538cb70500", - "sha256:f545f776e45f74c41329e4020463fdd4d0cd0a7501bdf9e50251dafe7bd959a9", - "sha256:f667ac7ae29c19530f199854635f1a97e73d0bfd24163e0db6bdba7dba04eb9f" + "sha256:1537d2d15b604b303aef56e7f440895a1c81adbee786b91f1f06eddc34da5314", + "sha256:1d20ab8369b7558168fc014a0745c678613f9f486dae468cca2d68145196b8a4", + "sha256:1ecc9db7409db67765eb008e558879d298406642d33ade43a6488224d23e8081", + "sha256:37033976f72af829fe15f7fe5fe1dbed308cc43a98d9dd9d2a0a76de8ca5ee78", + "sha256:3c3dd9d4c9c1e279d3945ae422895c901f98987333acc132dc094faf52afec35", + "sha256:3c9b3fba037ea52c626060c5a87ee6de7e86c99e8a7c6ee07302539985d2bd64", + "sha256:45ee555fc5e28c119a46d44ce373f5237e54a35c61b750fb3a94446b09855dbc", + "sha256:4c93038ac011b36512cb0bf2ee3e2aec774e8bc81021d015917c89fe02bb0ee5", + "sha256:50163324834edd0c9ce3e4512ded3e221c969086e10fdd5d3fdcaadac5e24a78", + "sha256:59b0ea9cda5490f924771456912a225d8d9e678891f9f986661af718534719b2", + "sha256:5cf306a17cccc327a33cdc3845629fa13f4573a4ec620ed607c79cf6785f2e27", + "sha256:5fff8da399af16a1855f58771223acbbdac720b9969cd03fc5013d2e9a7bd9a4", + "sha256:68650ce5b9f7152b8283302a4617269f821695a612692640dd247bd12ab21c0b", + "sha256:6b3a9a562688996f760b5077714c3ab8b62ca56061b6e9ab7906841e43e19f91", + "sha256:7e938ed51a59e29431ea86fab60423ada2757728db0f78952329fa02a789bd31", + "sha256:87aa70daad6f039e814790a06422a3189311198b674b62f13933a2bdcb6b1bcc", + "sha256:99be3a1df2b2b9f731ebe1c264a2c07c465e71cee68e35e1640b645b5213a755", + "sha256:a3f2908666e6f74b8c4893f86dd02e16170f50e4a78ae7f3468b6208d54bc205", + "sha256:ae3d44a639fd11dbdeca47e35e94febb1ee8bc15daf26673331add37146e0b85", + "sha256:afb4c2fa3c6f492fd9a8b38d76e13f32d429b8e5e1e00238309391b5591cde0d", + "sha256:b1515ce3a8a2c3fa537d137c5ca5f8b7a902044d04e07d7c3aa26c3e026120fb", + "sha256:bf391b377413a197000b43ef2b74359974d8927d329a897c9f5ba7b63dca7b9c", + "sha256:c436919117c23355740c669f89720673578b9aa4569bbfe105f6c10101fc1966", + "sha256:d2c3c280975638e2a2c2fd9cb36ab111980219757fa163a2755594b9448e4138", + "sha256:e585d530764c459cbd5d460aed0288807bb881f376ca9a20e653645217895961", + "sha256:e76e6638ead4a7d93262a24218f0ff3ff74de6b6c823b7e19dccb31b6a481978", + "sha256:ebfc2f885cafda076c31ae30fa0dd81e7e919ec34059a88d3018ed66e83fcce3", + "sha256:f5797a39933a3d41526da60856735e6684b2b71a8ca99d5f79555ca121be2f4b", + "sha256:f7e5fc5e124200b19a14be33fb0099e956e6ebb5e25d287b0829ef0a78ed76c7", + "sha256:fb350e31e55211fec8ddc89fc0256f3b9bc3b44b68a8bde1cf44b3b4e80c0e42" ], - "version": "==3.9.6" + "version": "==3.9.7" + }, + "pydub": { + "hashes": [ + "sha256:c362fa02da1eebd1d08bd47aa9b0102582dff7ca2269dbe9e043d228a0c1ea93", + "sha256:d29901a486fb421c5d7b0f3d5d3a60527179204d8ffb20e74e1ae81c17e81b46" + ], + "index": "pypi", + "version": "==0.23.1" }, "pyjwkest": { "hashes": [ @@ -579,6 +615,13 @@ "index": "pypi", "version": "==1.7.1" }, + "pyreadline": { + "hashes": [ + "sha256:4530592fc2e85b25b1a9f79664433da09237c1a270e4d78ea5aa3a2c7229e2d1" + ], + "markers": "sys_platform == 'win32'", + "version": "==2.1" + }, "pyrsistent": { "hashes": [ "sha256:cdc7b5e3ed77bed61270a47d35434a30617b9becdf2478af76ad2c6ade307280" @@ -661,6 +704,19 @@ "index": "pypi", "version": "==2.4.3" }, + "simpleaudio": { + "hashes": [ + "sha256:05b63da515f5fc7c6f40e4d9673d22239c5e03e2bda200fc09fd21c185d73713", + "sha256:67348e3d3ccbae73bd126beed7f1e242976889620dbc6974c36800cd286430fc", + "sha256:691c88649243544db717e7edf6a9831df112104e1aefb5f6038a5d071e8cf41d", + "sha256:86f1b0985629852afe67259ac6c24905ca731cb202a6e96b818865c56ced0c27", + "sha256:f1a4fe3358429b2ea3181fd782e4c4fff5c123ca86ec7fc29e01ee9acd8a227a", + "sha256:f346a4eac9cdbb1b3f3d0995095b7e86c12219964c022f4d920c22f6ca05fb4c", + "sha256:f68820297ad51577e3a77369e7e9b23989d30d5ae923bf34c92cf983c04ade04" + ], + "index": "pypi", + "version": "==1.0.4" + }, "six": { "hashes": [ "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a", diff --git a/backend/config.py b/backend/config.py index e64260172f65c556039aca2ab0fa1f7e2a7f2600..fe58a30646804f66fdf13167dc9d8b1d8ca94242 100644 GIT binary patch literal 4652 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 RecorderAdapte return rec +def check_stream_sanity(recorder: Recorder, recorder_adapter: RecorderAdapter): + if recorder.archive_stream1 is None and recorder.archive_stream2 is None: # fall back to default names and rtsp + archive_stream_1_url = "rtsp://{}/{}".format(recorder_adapter.address, Config.DEFAULT_ARCHIVE_STREAM_1_NAME) + archive_stream_2_url = "rtsp://{}/{}".format(recorder_adapter.address, Config.DEFAULT_ARCHIVE_STREAM_2_NAME) + else: + archive_stream_1_url = recorder.archive_stream1 + archive_stream_2_url = recorder.archive_stream2 + + for i in range(0, Config.STREAM_SANITY_CHECK_RETRIES): + do_checks = False + if do_checks: + return True + else: + time.sleep(Config.STREAM_SANITY_CHECK_INTERVAL_SEC) + return False # stream sanity check failed! + + def check_capture_agent_state(recorder_agent: Union[Recorder, dict]): if recorder_agent.get('offline', False): logger.info("OK - Recorder {} is in offline / maintenance mode".format(recorder_agent.get('name'))) @@ -142,6 +160,7 @@ def check_capture_agent_state(recorder_agent: Union[Recorder, dict]): logger.info("OK – recorder {} is recording :)".format(recorder_agent.get('name'))) with agent_states_lock: agent_states[recorder_agent.get('name')] = 'OK - recorder is recording' + else: logger.info(rec.get_recording_status()) logger.error("FATAL - recorder {} must be recording but is not!!!!".format(recorder_agent.get('name'))) diff --git a/backend/tools/recorder_streams_sanity_checks.py b/backend/tools/recorder_streams_sanity_checks.py new file mode 100644 index 0000000..fe30817 --- /dev/null +++ b/backend/tools/recorder_streams_sanity_checks.py @@ -0,0 +1,132 @@ +import io +import sys + +import ffmpeg +import os +import tempfile +from PIL import Image +from pydub import AudioSegment +from pydub.playback import play + + +def old_test(): + file_name = tempfile.gettempdir() + os.path.sep + "test.jpg" + print(file_name) + if os.path.exists(file_name): + os.remove(file_name) + process = ( + ffmpeg + .input('rtsp://172.22.246.207/extron1') + # .input('rtsp://172.22.246.207/extron3') + .output(file_name, vframes=1) + # .output('-', format='h264') + .run(capture_stdout=True) + ) + image = Image.open(file_name) + r, g, b = image.split() + print(r.histogram()) + print(g.histogram()) + print(b.histogram()) + image.show() + + +# old_test() + +def is_single_color_image(image): + single_color_image = True + color = {} + count = 0 + color_channels = image.split() + for c in color_channels: # r, g, b + + hist = c.histogram() + num_of_non_zero_values = len([v for v in hist if v != 0]) + if num_of_non_zero_values > 1: + single_color_image = False + break + else: + color[count] = [i for i in enumerate(hist) if i[1] != 0][0][0] + count += 1 + return single_color_image, color + + +def check_frame_is_valid(stream_url, raise_errors=True): + try: + frame, _ = ( + ffmpeg + .input(stream_url) + .output('pipe:', vframes=1, format='image2', vcodec='mjpeg') + .run(capture_stdout=True, capture_stderr=True) + ) + image = Image.open(io.BytesIO(frame)) + single_color_image, color = is_single_color_image(image) + if not single_color_image: + image.show() + return True, "all good :-)" + else: + if all(map(lambda x: x == 0, color.values())): + return False, "Image is entirely black! (color: {} (RGB))".format( + ':'.join([str(x) for x in color.values()])) + return False, "Image has only one single color! (color: {} (RGB))".format( + ':'.join([str(x) for x in color.values()])) + except ffmpeg.Error as e: + msg = "Could not connect to stream URL or other error!" + try: + msg += " ({})".format(e.stderr.decode('utf-8').strip().split("\n")[-1]) + except IndexError: + pass + if raise_errors: + raise Exception(msg) + else: + return False, msg + + +# print(check_frame_is_valid('rtsp://172.22.246.207/extron2')) + +def check_if_audio_is_valid(stream_url, sample_length_sec=3, lower_alert_limit_dBFS=-40.0, raise_errors=True): + file_name = tempfile.NamedTemporaryFile(suffix='.aac').name + if os.path.exists(file_name): + os.remove(file_name) + try: + frame, _ = ( + ffmpeg + .input(stream_url, t=sample_length_sec) + .output(file_name) + .run(capture_stdout=True, capture_stderr=True) + ) + + sound = AudioSegment.from_file(file_name, "aac") + # print(sound.dBFS) + play(sound) + if sound.max_dBFS == -float('inf'): + return False, "No active audio signal detected!" + elif sound.max_dBFS < lower_alert_limit_dBFS: + return False, "Very low volume (< {} dBFS) detected! ({})".format(lower_alert_limit_dBFS, sound.max_dBFS) + + return True, "good audio signal detected! ({} max dBFS in {}s sample)".format(sound.max_dBFS, sample_length_sec) + except ffmpeg.Error as e: + msg = "Could not connect to stream URL or other error!" + try: + msg += " ({})".format(e.stderr.decode('utf-8').strip().split("\n")[-1]) + except IndexError: + pass + if raise_errors: + raise Exception(msg) + else: + return False, msg + +print(check_if_audio_is_valid('rtsp://172.22.246.207/extron1')) + + +def check_if_audio_is_valid_stream(stream_url, raise_errors=True): + audio, _ = ( + ffmpeg + .input(stream_url, t=2) + .output('pipe:', f="adts", acodec='copy') + .run(capture_stdout=False, capture_stderr=False) + ) + audio = io.BytesIO(audio) + sound = AudioSegment.from_file(audio, "aac") + play(sound) + +# check_if_audio_is_valid('rtsp://172.22.246.207/extron1') diff --git a/backend/tools/stream_handling.py b/backend/tools/stream_handling.py deleted file mode 100644 index 0a34dbd..0000000 --- a/backend/tools/stream_handling.py +++ /dev/null @@ -1,15 +0,0 @@ -import ffmpeg - -packet_size = 4096 - -process = ( - ffmpeg - .input('rtsp://172.22.246.207/extron1') - #.input('rtsp://172.22.246.207/extron3') - .output('/tmp/test.jpg', vframes=1) - #.output('-', format='h264') - .run_async(pipe_stdout=True) -) - -while process.poll() is None: - packet = process.stdout.read(packet_size)