boris-behav-obs 9.6.6__tar.gz → 9.7.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/PKG-INFO +4 -6
  2. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/README.md +3 -5
  3. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/cmd_arguments.py +2 -0
  4. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/config.py +1 -2
  5. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/connections.py +3 -0
  6. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/core.py +203 -163
  7. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/core_ui.py +6 -2
  8. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/event_operations.py +55 -0
  9. boris_behav_obs-9.7.1/boris/ipc_mpv.py +304 -0
  10. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/observation_operations.py +173 -234
  11. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/player_dock_widget.py +9 -4
  12. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/utilities.py +77 -55
  13. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/version.py +2 -2
  14. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/video_operations.py +1 -0
  15. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris_behav_obs.egg-info/PKG-INFO +4 -6
  16. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris_behav_obs.egg-info/SOURCES.txt +1 -2
  17. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/pyproject.toml +1 -8
  18. boris_behav_obs-9.6.6/boris/1.py +0 -45
  19. boris_behav_obs-9.6.6/boris/mpv-1.0.3.py +0 -2102
  20. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/LICENSE.TXT +0 -0
  21. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/MANIFEST.in +0 -0
  22. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/README.TXT +0 -0
  23. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/__init__.py +0 -0
  24. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/__main__.py +0 -0
  25. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/about.py +0 -0
  26. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/add_modifier.py +0 -0
  27. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/add_modifier_ui.py +0 -0
  28. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/advanced_event_filtering.py +0 -0
  29. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/analysis_plugins/__init__.py +0 -0
  30. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/analysis_plugins/_latency.py +0 -0
  31. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/analysis_plugins/irr_cohen_kappa.py +0 -0
  32. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/analysis_plugins/irr_cohen_kappa_with_modifiers.py +0 -0
  33. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/analysis_plugins/irr_weighted_cohen_kappa.py +0 -0
  34. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/analysis_plugins/irr_weighted_cohen_kappa_with_modifiers.py +0 -0
  35. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/analysis_plugins/list_of_dataframe_columns.py +0 -0
  36. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/analysis_plugins/number_of_occurences.py +0 -0
  37. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/analysis_plugins/number_of_occurences_by_independent_variable.py +0 -0
  38. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/analysis_plugins/time_budget.py +0 -0
  39. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/behav_coding_map_creator.py +0 -0
  40. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/behavior_binary_table.py +0 -0
  41. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/behaviors_coding_map.py +0 -0
  42. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/boris_cli.py +0 -0
  43. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/coding_pad.py +0 -0
  44. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/config_file.py +0 -0
  45. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/converters.py +0 -0
  46. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/converters_ui.py +0 -0
  47. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/cooccurence.py +0 -0
  48. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/core_qrc.py +0 -0
  49. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/db_functions.py +0 -0
  50. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/dev.py +0 -0
  51. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/dialog.py +0 -0
  52. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/duration_widget.py +0 -0
  53. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/edit_event.py +0 -0
  54. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/edit_event_ui.py +0 -0
  55. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/events_cursor.py +0 -0
  56. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/events_snapshots.py +0 -0
  57. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/exclusion_matrix.py +0 -0
  58. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/export_events.py +0 -0
  59. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/export_observation.py +0 -0
  60. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/external_processes.py +0 -0
  61. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/geometric_measurement.py +0 -0
  62. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/gui_utilities.py +0 -0
  63. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/image_overlay.py +0 -0
  64. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/import_observations.py +0 -0
  65. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/irr.py +0 -0
  66. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/latency.py +0 -0
  67. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/measurement_widget.py +0 -0
  68. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/media_file.py +0 -0
  69. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/menu_options.py +0 -0
  70. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/modifier_coding_map_creator.py +0 -0
  71. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/modifiers_coding_map.py +0 -0
  72. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/mpv.py +0 -0
  73. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/mpv2.py +0 -0
  74. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/observation.py +0 -0
  75. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/observation_ui.py +0 -0
  76. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/observations_list.py +0 -0
  77. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/otx_parser.py +0 -0
  78. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/param_panel.py +0 -0
  79. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/param_panel_ui.py +0 -0
  80. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/plot_data_module.py +0 -0
  81. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/plot_events.py +0 -0
  82. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/plot_events_rt.py +0 -0
  83. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/plot_spectrogram_rt.py +0 -0
  84. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/plot_waveform_rt.py +0 -0
  85. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/plugins.py +0 -0
  86. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/portion/__init__.py +0 -0
  87. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/portion/const.py +0 -0
  88. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/portion/dict.py +0 -0
  89. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/portion/func.py +0 -0
  90. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/portion/interval.py +0 -0
  91. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/portion/io.py +0 -0
  92. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/preferences.py +0 -0
  93. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/preferences_ui.py +0 -0
  94. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/project.py +0 -0
  95. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/project_functions.py +0 -0
  96. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/project_import_export.py +0 -0
  97. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/project_ui.py +0 -0
  98. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/qrc_boris.py +0 -0
  99. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/qrc_boris5.py +0 -0
  100. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/select_modifiers.py +0 -0
  101. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/select_observations.py +0 -0
  102. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/select_subj_behav.py +0 -0
  103. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/state_events.py +0 -0
  104. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/subjects_pad.py +0 -0
  105. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/synthetic_time_budget.py +0 -0
  106. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/time_budget_functions.py +0 -0
  107. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/time_budget_widget.py +0 -0
  108. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/transitions.py +0 -0
  109. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/video_equalizer.py +0 -0
  110. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/video_equalizer_ui.py +0 -0
  111. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/view_df.py +0 -0
  112. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/view_df_ui.py +0 -0
  113. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris/write_event.py +0 -0
  114. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris_behav_obs.egg-info/dependency_links.txt +0 -0
  115. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris_behav_obs.egg-info/entry_points.txt +0 -0
  116. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris_behav_obs.egg-info/requires.txt +0 -0
  117. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/boris_behav_obs.egg-info/top_level.txt +0 -0
  118. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/setup.cfg +0 -0
  119. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/tests/test_db_functions.py +0 -0
  120. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/tests/test_export_observation.py +0 -0
  121. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/tests/test_irr.py +0 -0
  122. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/tests/test_observation_gui.py +0 -0
  123. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/tests/test_otx_parser.py +0 -0
  124. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/tests/test_preferences_gui.py +0 -0
  125. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/tests/test_project_functions.py +0 -0
  126. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/tests/test_time_budget.py +0 -0
  127. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/tests/test_utilities.py +0 -0
  128. {boris_behav_obs-9.6.6 → boris_behav_obs-9.7.1}/tests/test_utilities2.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boris-behav-obs
3
- Version: 9.6.6
3
+ Version: 9.7.1
4
4
  Summary: BORIS - Behavioral Observation Research Interactive Software
5
5
  Author-email: Olivier Friard <olivier.friard@unito.it>
6
6
  License-Expression: GPL-3.0-only
@@ -52,13 +52,15 @@ It provides also some analysis tools like time budget and some plotting function
52
52
  <!-- The BO-RIS paper has more than [![BORIS citations counter](https://penelope.unito.it/friard/boris_scopus_citations.png) citations](https://www.boris.unito.it/citations) in peer-reviewed scientific publications. -->
53
53
 
54
54
 
55
- The BORIS paper has more than 2337 citations in peer-reviewed scientific publications.
55
+ The BORIS paper has more than 2407 citations in peer-reviewed scientific publications.
56
56
 
57
57
 
58
58
 
59
59
 
60
60
  See the official [BORIS web site](https://www.boris.unito.it).
61
61
 
62
+ <a href="https://www.boris.unito.it" target="_blank"><img alt="Website" src="https://img.shields.io/website?url=https%3A%2F%2Fwww.boris.unito.it"></a>
63
+ <a href="https://www.boris.unito.it/user_guide/" target="_blank"><img alt="User guide" src="https://img.shields.io/badge/Documentation-orange"></a>
62
64
  [![Python web site](https://img.shields.io/badge/Made%20with-Python-1f425f.svg)](https://www.python.org)
63
65
  ![Python versions](https://img.shields.io/pypi/pyversions/boris-behav-obs)
64
66
  ![BORIS license](https://img.shields.io/pypi/l/boris-behav-obs)
@@ -136,7 +138,3 @@ GNU General Public License for more details.
136
138
  Distributed with a [GPL v.3 license](LICENSE.TXT).
137
139
 
138
140
  Copyright (C) 2012-2025 Olivier Friard
139
-
140
-
141
-
142
-
@@ -14,13 +14,15 @@ It provides also some analysis tools like time budget and some plotting function
14
14
  <!-- The BO-RIS paper has more than [![BORIS citations counter](https://penelope.unito.it/friard/boris_scopus_citations.png) citations](https://www.boris.unito.it/citations) in peer-reviewed scientific publications. -->
15
15
 
16
16
 
17
- The BORIS paper has more than 2337 citations in peer-reviewed scientific publications.
17
+ The BORIS paper has more than 2407 citations in peer-reviewed scientific publications.
18
18
 
19
19
 
20
20
 
21
21
 
22
22
  See the official [BORIS web site](https://www.boris.unito.it).
23
23
 
24
+ <a href="https://www.boris.unito.it" target="_blank"><img alt="Website" src="https://img.shields.io/website?url=https%3A%2F%2Fwww.boris.unito.it"></a>
25
+ <a href="https://www.boris.unito.it/user_guide/" target="_blank"><img alt="User guide" src="https://img.shields.io/badge/Documentation-orange"></a>
24
26
  [![Python web site](https://img.shields.io/badge/Made%20with-Python-1f425f.svg)](https://www.python.org)
25
27
  ![Python versions](https://img.shields.io/pypi/pyversions/boris-behav-obs)
26
28
  ![BORIS license](https://img.shields.io/pypi/l/boris-behav-obs)
@@ -98,7 +100,3 @@ GNU General Public License for more details.
98
100
  Distributed with a [GPL v.3 license](LICENSE.TXT).
99
101
 
100
102
  Copyright (C) 2012-2025 Olivier Friard
101
-
102
-
103
-
104
-
@@ -35,6 +35,8 @@ def parse_arguments():
35
35
  parser.add_option("-n", "--nosplashscreen", action="store_true", default=False, help="No splash screen")
36
36
  parser.add_option("-p", "--project", action="store", default="", dest="project", help="Project file")
37
37
  parser.add_option("-o", "--observation", action="store", default="", dest="observation", help="Observation id")
38
+ parser.add_option("-i", "--ipc", action="store_true", default="", dest="ipc", help="MPV IPC mode")
39
+
38
40
  parser.add_option(
39
41
  "-f",
40
42
  "--no-first-launch-dialog",
@@ -22,8 +22,7 @@ This file is part of BORIS.
22
22
 
23
23
  programName: str = "BORIS"
24
24
 
25
-
26
- MACOS_CODE = "darwin"
25
+ # socket for MPV IPC mode
27
26
  MPV_SOCKET = "/tmp/mpvsocket"
28
27
 
29
28
 
@@ -120,6 +120,7 @@ def connections(self):
120
120
  self.actionSelect_observations.triggered.connect(lambda: event_operations.select_events_between_activated(self))
121
121
 
122
122
  self.actionEdit_selected_events.triggered.connect(lambda: event_operations.edit_selected_events(self))
123
+ self.action_add_comment.triggered.connect(lambda: event_operations.add_comment(self))
123
124
  self.actionEdit_event_time.triggered.connect(lambda: event_operations.edit_time_selected_events(self))
124
125
 
125
126
  self.actionCopy_events.triggered.connect(lambda: event_operations.copy_selected_events(self))
@@ -343,6 +344,8 @@ def connections(self):
343
344
 
344
345
  self.tv_events.addAction(self.actionAdd_event)
345
346
  self.tv_events.addAction(self.actionEdit_selected_events)
347
+ self.tv_events.addAction(self.action_add_comment)
348
+
346
349
  self.tv_events.addAction(self.actionEdit_event_time)
347
350
 
348
351
  self.tv_events.addAction(self.actionCopy_events)
@@ -150,7 +150,7 @@ if util.versiontuple(platform.python_version()) < util.versiontuple(MIN_PYTHON_V
150
150
  logging.critical(msg)
151
151
  sys.exit()
152
152
 
153
- if sys.platform == "darwin": # for MacOS
153
+ if sys.platform.startswith("darwin"): # for MacOS
154
154
  os.environ["LC_ALL"] = "en_US.UTF-8"
155
155
 
156
156
 
@@ -236,8 +236,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
236
236
  processes: list = [] # list of QProcess processes
237
237
  overlays: dict = {} # dict for storing video overlays
238
238
 
239
- undo_queue = deque() # queue for undoing event operations
240
- undo_description = deque() # queue for description of event operations
239
+ undo_queue = deque() # queue for undoing event operations
240
+ undo_description = deque() # queue for description of event operations
241
241
 
242
242
  current_player: int = 0 # id of the selected (left click) video player
243
243
 
@@ -400,7 +400,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
400
400
 
401
401
  # if BORIS is running on Mac lock all dockwidget features
402
402
  # because Qdockwidgets may have a strange behavior
403
- if sys.platform == "darwin":
403
+ if sys.platform.startswith("darwin"):
404
404
  self.action_block_dockwidgets.setChecked(True)
405
405
  self.block_dockwidgets()
406
406
 
@@ -1428,55 +1428,60 @@ class MainWindow(QMainWindow, Ui_MainWindow):
1428
1428
  if not self.dw_player[player].player.playlist_count:
1429
1429
  return
1430
1430
 
1431
- # one media
1432
- if self.dw_player[player].player.playlist_count == 1:
1433
- if new_time < self.dw_player[player].player.duration:
1434
- new_time_float = round(float(new_time), 3)
1435
-
1436
- self.dw_player[player].player.seek(new_time_float, "absolute+exact")
1431
+ try:
1432
+ # one media
1433
+ if self.dw_player[player].player.playlist_count == 1:
1434
+ if new_time < self.dw_player[player].player.duration:
1435
+ new_time_float = round(float(new_time), 3)
1437
1436
 
1438
- if player == 0 and not self.user_move_slider:
1439
- self.video_slider.setValue(
1440
- round(self.dw_player[0].player.time_pos / self.dw_player[0].player.duration * (cfg.SLIDER_MAXIMUM - 1))
1441
- )
1442
- return 0
1443
- else:
1444
- return 1
1437
+ self.dw_player[player].player.seek(new_time_float, "absolute+exact")
1438
+ self.mpv_timer_out()
1445
1439
 
1446
- # many media
1447
- else:
1448
- if new_time < self.dw_player[player].cumul_media_durations_sec[-1]:
1449
- for idx, d in enumerate(self.dw_player[player].cumul_media_durations_sec[:-1]):
1450
- if d <= new_time < self.dw_player[player].cumul_media_durations_sec[idx + 1]:
1451
- self.dw_player[player].player.playlist_pos = idx
1452
- time.sleep(0.5)
1453
-
1454
- self.dw_player[player].player.seek(
1455
- round(
1456
- float(new_time)
1457
- - sum(self.dw_player[player].media_durations[0 : self.dw_player[player].player.playlist_pos]) / 1000,
1458
- 3,
1459
- ),
1460
- "absolute+exact",
1440
+ if player == 0 and not self.user_move_slider:
1441
+ self.video_slider.setValue(
1442
+ round(self.dw_player[0].player.time_pos / self.dw_player[0].player.duration * (cfg.SLIDER_MAXIMUM - 1))
1461
1443
  )
1444
+ return 0
1445
+ else:
1446
+ return 1
1447
+
1448
+ # many media
1449
+ else:
1450
+ if new_time < self.dw_player[player].cumul_media_durations_sec[-1]:
1451
+ for idx, d in enumerate(self.dw_player[player].cumul_media_durations_sec[:-1]):
1452
+ if d <= new_time < self.dw_player[player].cumul_media_durations_sec[idx + 1]:
1453
+ self.dw_player[player].player.playlist_pos = idx
1454
+ time.sleep(0.5)
1455
+
1456
+ self.dw_player[player].player.seek(
1457
+ round(
1458
+ float(new_time)
1459
+ - sum(self.dw_player[player].media_durations[0 : self.dw_player[player].player.playlist_pos]) / 1000,
1460
+ 3,
1461
+ ),
1462
+ "absolute+exact",
1463
+ )
1462
1464
 
1463
- break
1465
+ break
1464
1466
 
1465
- if player == 0 and not self.user_move_slider:
1466
- self.video_slider.setValue(
1467
- round(self.dw_player[0].player.time_pos / self.dw_player[0].player.duration * (cfg.SLIDER_MAXIMUM - 1))
1467
+ if player == 0 and not self.user_move_slider:
1468
+ self.video_slider.setValue(
1469
+ round(self.dw_player[0].player.time_pos / self.dw_player[0].player.duration * (cfg.SLIDER_MAXIMUM - 1))
1470
+ )
1471
+ return 0
1472
+ else:
1473
+ QMessageBox.warning(
1474
+ self,
1475
+ cfg.programName,
1476
+ (
1477
+ "The indicated position is greater than the total media duration "
1478
+ f"({util.seconds2time(self.dw_player[player].cumul_media_durations_sec[-1])})"
1479
+ ),
1468
1480
  )
1469
- return 0
1470
- else:
1471
- QMessageBox.warning(
1472
- self,
1473
- cfg.programName,
1474
- (
1475
- "The indicated position is greater than the total media duration "
1476
- f"({util.seconds2time(self.dw_player[player].cumul_media_durations_sec[-1])})"
1477
- ),
1478
- )
1479
- return 1
1481
+ return 1
1482
+ except Exception as e:
1483
+ print(f"error in seek mediaplayer function: {e}")
1484
+ return 0
1480
1485
 
1481
1486
  def jump_to(self) -> None:
1482
1487
  """
@@ -3685,6 +3690,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
3685
3690
  if self.playerType == cfg.MEDIA:
3686
3691
  for dw in self.dw_player:
3687
3692
  dw.player.frame_step()
3693
+
3688
3694
  if self.geometric_measurements_mode:
3689
3695
  self.extract_frame(dw)
3690
3696
 
@@ -3692,6 +3698,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
3692
3698
  for idx in self.plot_data:
3693
3699
  self.timer_plot_data_out(self.plot_data[idx])
3694
3700
 
3701
+ self.mpv_timer_out()
3702
+
3695
3703
  if self.geometric_measurements_mode:
3696
3704
  geometric_measurement.redraw_measurements(self)
3697
3705
 
@@ -3709,6 +3717,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
3709
3717
  if self.playerType == cfg.MEDIA:
3710
3718
  for dw in self.dw_player:
3711
3719
  dw.player.frame_back_step()
3720
+
3712
3721
  if self.geometric_measurements_mode:
3713
3722
  self.extract_frame(dw)
3714
3723
 
@@ -3716,6 +3725,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
3716
3725
  for idx in self.plot_data:
3717
3726
  self.timer_plot_data_out(self.plot_data[idx])
3718
3727
 
3728
+ self.mpv_timer_out()
3729
+
3719
3730
  if self.geometric_measurements_mode:
3720
3731
  geometric_measurement.redraw_measurements(self)
3721
3732
 
@@ -3728,77 +3739,78 @@ class MainWindow(QMainWindow, Ui_MainWindow):
3728
3739
  QMessageBox.warning(self, cfg.programName, "Function not yet implemented")
3729
3740
  return
3730
3741
 
3731
- if not self.observationId:
3732
- self.no_observation()
3733
- return
3734
-
3735
- if self.twEvents.selectedItems():
3736
- row_s = self.twEvents.selectedItems()[0].row()
3737
- row_e = self.twEvents.selectedItems()[-1].row()
3738
- eventtime_s = self.pj[cfg.OBSERVATIONS][self.observationId][cfg.EVENTS][row_s][0]
3739
- eventtime_e = self.pj[cfg.OBSERVATIONS][self.observationId][cfg.EVENTS][row_e][0]
3740
-
3741
- durations = [] # in seconds
3742
-
3743
- # TODO: check for 2nd player
3744
- for mediaFile in self.pj[cfg.OBSERVATIONS][self.observationId][cfg.FILE][cfg.PLAYER1]:
3745
- durations.append(self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO]["length"][mediaFile])
3746
-
3747
- mediaFileIdx_s = [idx1 for idx1, x in enumerate(durations) if eventtime_s >= sum(durations[0:idx1])][-1]
3748
- media_path_s = self.pj[cfg.OBSERVATIONS][self.observationId][cfg.FILE][cfg.PLAYER1][mediaFileIdx_s]
3749
-
3750
- mediaFileIdx_e = [idx1 for idx1, x in enumerate(durations) if eventtime_e >= sum(durations[0:idx1])][-1]
3751
- media_path_e = self.pj[cfg.OBSERVATIONS][self.observationId][cfg.FILE][cfg.PLAYER1][mediaFileIdx_e]
3752
-
3753
- # calculate time for current media file in case of many queued media files
3754
-
3755
- eventtime_onmedia_s = round(eventtime_s - util.float2decimal(sum(durations[0:mediaFileIdx_s])), 3)
3756
- eventtime_onmedia_e = round(eventtime_e - util.float2decimal(sum(durations[0:mediaFileIdx_e])), 3)
3757
-
3758
- if media_path_s != media_path_e:
3759
- return
3760
-
3761
- media_path = media_path_s
3762
-
3763
- # example of external command defined in environment:
3764
- # export BORISEXTERNAL="myprog -i {MEDIA_PATH} -s {START_S} -e {END_S} {DURATION_MS} --other"
3742
+ # if not self.observationId:
3743
+ # self.no_observation()
3744
+ # return
3765
3745
 
3766
- if "BORISEXTERNAL" in os.environ:
3767
- external_command_template = os.environ["BORISEXTERNAL"]
3768
- else:
3769
- return
3770
-
3771
- external_command = external_command_template.format(
3772
- OBS_ID=self.observationId,
3773
- MEDIA_PATH=f'"{media_path}"',
3774
- MEDIA_BASENAME=f'"{os.path.basename(media_path)}"',
3775
- START_S=eventtime_onmedia_s,
3776
- END_S=eventtime_onmedia_e,
3777
- START_MS=eventtime_onmedia_s * 1000,
3778
- END_MS=eventtime_onmedia_e * 1000,
3779
- DURATION_S=eventtime_onmedia_e - eventtime_onmedia_s,
3780
- DURATION_MS=(eventtime_onmedia_e - eventtime_onmedia_s) * 1000,
3781
- )
3782
-
3783
- print(external_command)
3784
- """
3785
- p = subprocess.Popen(external_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
3786
- """
3787
- """
3788
- if eventtimeS == eventtimeE:
3789
- q = []
3790
- else:
3791
- durationsec = eventtimeE-eventtimeS
3792
- q = ["--durationmsec",str(int(durationsec*1000))]
3793
- args = [ex, "-f",os.path.abspath(fn),"--seekmsec",str(int(eventtimeS*1000)),*q,*("--size 1 --track 1 --redetect 100")
3794
- .split(" ")]
3795
- if os.path.split(fn)[1].split("_")[0] in set(["A1","A2","A3","A4","A5","A6","A7","A8","A9","A10"]):
3796
- args.append("--flip")
3797
- args.append("2")
3798
- print (os.path.split(fn)[1].split("_")[0])
3799
- print ("running",ex,"with",args,"in",os.path.split(ex)[0])
3800
- #pid = subprocess.Popen(args,executable=ex,cwd=os.path.split(ex)[0])
3801
- """
3746
+ #
3747
+ # if self.twEvents.selectedItems():
3748
+ # row_s = self.twEvents.selectedItems()[0].row()
3749
+ # row_e = self.twEvents.selectedItems()[-1].row()
3750
+ # eventtime_s = self.pj[cfg.OBSERVATIONS][self.observationId][cfg.EVENTS][row_s][0]
3751
+ # eventtime_e = self.pj[cfg.OBSERVATIONS][self.observationId][cfg.EVENTS][row_e][0]
3752
+ #
3753
+ # durations = [] # in seconds
3754
+ #
3755
+ # # TODO: check for 2nd player
3756
+ # for mediaFile in self.pj[cfg.OBSERVATIONS][self.observationId][cfg.FILE][cfg.PLAYER1]:
3757
+ # durations.append(self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO]["length"][mediaFile])
3758
+ #
3759
+ # mediaFileIdx_s = [idx1 for idx1, x in enumerate(durations) if eventtime_s >= sum(durations[0:idx1])][-1]
3760
+ # media_path_s = self.pj[cfg.OBSERVATIONS][self.observationId][cfg.FILE][cfg.PLAYER1][mediaFileIdx_s]
3761
+ #
3762
+ # mediaFileIdx_e = [idx1 for idx1, x in enumerate(durations) if eventtime_e >= sum(durations[0:idx1])][-1]
3763
+ # media_path_e = self.pj[cfg.OBSERVATIONS][self.observationId][cfg.FILE][cfg.PLAYER1][mediaFileIdx_e]
3764
+ #
3765
+ # # calculate time for current media file in case of many queued media files
3766
+ #
3767
+ # eventtime_onmedia_s = round(eventtime_s - util.float2decimal(sum(durations[0:mediaFileIdx_s])), 3)
3768
+ # eventtime_onmedia_e = round(eventtime_e - util.float2decimal(sum(durations[0:mediaFileIdx_e])), 3)
3769
+ #
3770
+ # if media_path_s != media_path_e:
3771
+ # return
3772
+ #
3773
+ # media_path = media_path_s
3774
+ #
3775
+ # # example of external command defined in environment:
3776
+ # # export BORISEXTERNAL="myprog -i {MEDIA_PATH} -s {START_S} -e {END_S} {DURATION_MS} --other"
3777
+ #
3778
+ # if "BORISEXTERNAL" in os.environ:
3779
+ # external_command_template = os.environ["BORISEXTERNAL"]
3780
+ # else:
3781
+ # return
3782
+ #
3783
+ # external_command = external_command_template.format(
3784
+ # OBS_ID=self.observationId,
3785
+ # MEDIA_PATH=f'"{media_path}"',
3786
+ # MEDIA_BASENAME=f'"{os.path.basename(media_path)}"',
3787
+ # START_S=eventtime_onmedia_s,
3788
+ # END_S=eventtime_onmedia_e,
3789
+ # START_MS=eventtime_onmedia_s * 1000,
3790
+ # END_MS=eventtime_onmedia_e * 1000,
3791
+ # DURATION_S=eventtime_onmedia_e - eventtime_onmedia_s,
3792
+ # DURATION_MS=(eventtime_onmedia_e - eventtime_onmedia_s) * 1000,
3793
+ # )
3794
+ #
3795
+ # print(external_command)
3796
+ # """
3797
+ # p = subprocess.Popen(external_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
3798
+ # """
3799
+ # """
3800
+ # if eventtimeS == eventtimeE:
3801
+ # q = []
3802
+ # else:
3803
+ # durationsec = eventtimeE-eventtimeS
3804
+ # q = ["--durationmsec",str(int(durationsec*1000))]
3805
+ # args = [ex, "-f",os.path.abspath(fn),"--seekmsec",str(int(eventtimeS*1000)),*q,*("--size 1 --track 1 --redetect 100")
3806
+ # .split(" ")]
3807
+ # if os.path.split(fn)[1].split("_")[0] in set(["A1","A2","A3","A4","A5","A6","A7","A8","A9","A10"]):
3808
+ # args.append("--flip")
3809
+ # args.append("2")
3810
+ # print (os.path.split(fn)[1].split("_")[0])
3811
+ # print ("running",ex,"with",args,"in",os.path.split(ex)[0])
3812
+ # #pid = subprocess.Popen(args,executable=ex,cwd=os.path.split(ex)[0])
3813
+ # """
3802
3814
 
3803
3815
  def no_media(self):
3804
3816
  QMessageBox.warning(self, cfg.programName, "There is no media available")
@@ -3859,10 +3871,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
3859
3871
  returns frame index for player player_idx
3860
3872
  """
3861
3873
 
3862
- if not sys.platform.startswith(cfg.MACOS_CODE):
3863
- estimated_frame_number = self.dw_player[player_idx].player.estimated_frame_number
3864
- else:
3865
- estimated_frame_number = observation_operations.send_command({"command": ["get_property", "estimated_frame_number"]})
3874
+ estimated_frame_number = self.dw_player[player_idx].player.estimated_frame_number
3875
+
3866
3876
  if estimated_frame_number is not None:
3867
3877
  return estimated_frame_number
3868
3878
  else:
@@ -3938,7 +3948,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
3938
3948
  if self.dw_player[0].player.duration is None:
3939
3949
  return
3940
3950
  video_position = slider_position * self.dw_player[0].player.duration
3941
- self.dw_player[0].player.command("seek", str(video_position), "absolute")
3951
+ # self.dw_player[0].player.command("seek", str(video_position), "absolute")
3952
+ self.dw_player[0].player.seek(video_position, "absolute")
3942
3953
 
3943
3954
  self.plot_timer_out()
3944
3955
 
@@ -4131,7 +4142,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
4131
4142
  self.dw_player[n_player].player.playlist_pos = self.dw_player[n_player].player.playlist_count - 1
4132
4143
  self.seek_mediaplayer(self.dw_player[n_player].media_durations[-1], player=n_player)
4133
4144
 
4134
- def mpv_timer_out(self, value: Union[float, None], scroll_slider=True):
4145
+ def mpv_timer_out(self, value: Union[float, None] = None, scroll_slider=True):
4135
4146
  """
4136
4147
  print the media current position and total length for MPV player
4137
4148
  scroll video slider to video position
@@ -4141,13 +4152,17 @@ class MainWindow(QMainWindow, Ui_MainWindow):
4141
4152
  if not self.observationId:
4142
4153
  return
4143
4154
 
4155
+ print("mpv timer out")
4156
+
4144
4157
  cumulative_time_pos = self.getLaps()
4158
+ print(f"{cumulative_time_pos=}")
4145
4159
  # get frame index
4146
4160
  frame_idx = self.get_frame_index()
4161
+ print(f"{frame_idx=}")
4147
4162
  # frame_idx = 0
4148
4163
 
4149
- if value is None:
4150
- current_media_time_pos = 0
4164
+ if value is None: # ipc mpv
4165
+ current_media_time_pos = self.dw_player[0].player.time_pos
4151
4166
  else:
4152
4167
  current_media_time_pos = value
4153
4168
 
@@ -4185,22 +4200,19 @@ class MainWindow(QMainWindow, Ui_MainWindow):
4185
4200
 
4186
4201
  ct0 = cumulative_time_pos
4187
4202
 
4188
- if not sys.platform.startswith(cfg.MACOS_CODE):
4189
- if self.dw_player[0].player.time_pos is not None:
4190
- for n_player in range(1, len(self.dw_player)):
4191
- ct = self.getLaps(n_player=n_player)
4203
+ if self.dw_player[0].player.time_pos is not None:
4204
+ for n_player in range(1, len(self.dw_player)):
4205
+ ct = self.getLaps(n_player=n_player)
4192
4206
 
4193
- # sync players 2..8 if time diff >= 1 s
4194
- if (
4195
- abs(ct0 - (ct + dec(self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET][str(n_player + 1)])))
4196
- >= 1
4197
- ):
4198
- self.sync_time(n_player, ct0) # self.seek_mediaplayer(ct0, n_player)
4207
+ # sync players 2..8 if time diff >= 1 s
4208
+ if abs(ct0 - (ct + dec(self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET][str(n_player + 1)]))) >= 1:
4209
+ self.sync_time(n_player, ct0) # self.seek_mediaplayer(ct0, n_player)
4199
4210
 
4200
4211
  currentTimeOffset = dec(cumulative_time_pos + self.pj[cfg.OBSERVATIONS][self.observationId][cfg.TIME_OFFSET])
4201
4212
 
4202
4213
  all_media_duration = sum(self.dw_player[0].media_durations) / 1000
4203
4214
  current_media_duration = self.dw_player[0].player.duration # mediaplayer_length
4215
+
4204
4216
  self.mediaTotalLength = current_media_duration
4205
4217
 
4206
4218
  # current state(s)
@@ -4225,6 +4237,9 @@ class MainWindow(QMainWindow, Ui_MainWindow):
4225
4237
  self.show_current_states_in_subjects_table()
4226
4238
 
4227
4239
  # current media name
4240
+ print(f"{self.dw_player[0].player.playlist_pos=}")
4241
+ print(f"{self.dw_player[0].player.playlist=}")
4242
+
4228
4243
  if self.dw_player[0].player.playlist_pos is not None:
4229
4244
  current_media_name = Path(self.dw_player[0].player.playlist[self.dw_player[0].player.playlist_pos]["filename"]).name
4230
4245
  current_playlist_index = self.dw_player[0].player.playlist_pos
@@ -4300,6 +4315,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
4300
4315
 
4301
4316
  self.actionPlay.setIcon(QIcon(f":/play_{gui_utilities.theme_mode()}"))
4302
4317
 
4318
+ print(f"{msg=}")
4319
+
4303
4320
  if msg:
4304
4321
  self.lb_current_media_time.setText(msg)
4305
4322
 
@@ -4316,14 +4333,6 @@ class MainWindow(QMainWindow, Ui_MainWindow):
4316
4333
 
4317
4334
  logging.info("Media end reached")
4318
4335
 
4319
- """
4320
- print(f"{self.dw_player[0].player.time_pos=}")
4321
- print(f"{self.dw_player[0].player.pause=}")
4322
- print(f"{self.dw_player[0].player.core_idle=}")
4323
- print(f"{self.dw_player[0].player.eof_reached=}")
4324
- print(f"{self.dw_player[0].player.playlist_pos=}")
4325
- """
4326
-
4327
4336
  if self.pj[cfg.OBSERVATIONS][self.observationId][cfg.CLOSE_BEHAVIORS_BETWEEN_VIDEOS]:
4328
4337
  if self.dw_player[0].player.eof_reached and self.dw_player[0].player.core_idle:
4329
4338
  if self.dw_player[0].player.playlist_pos == len(self.dw_player[0].player.playlist) - 1:
@@ -4593,14 +4602,9 @@ class MainWindow(QMainWindow, Ui_MainWindow):
4593
4602
 
4594
4603
  if self.playerType == cfg.MEDIA:
4595
4604
  # cumulative time
4596
- if not sys.platform.startswith(cfg.MACOS_CODE):
4597
- mem_laps = sum(self.dw_player[n_player].media_durations[0 : self.dw_player[n_player].player.playlist_pos]) + (
4598
- 0 if self.dw_player[n_player].player.time_pos is None else self.dw_player[n_player].player.time_pos * 1000
4599
- )
4600
- else:
4601
- time_pos = observation_operations.send_command({"command": ["get_property", "time-pos"]})
4602
- # TODO: fix!
4603
- return dec(time_pos)
4605
+ mem_laps = sum(self.dw_player[n_player].media_durations[0 : self.dw_player[n_player].player.playlist_pos]) + (
4606
+ 0 if self.dw_player[n_player].player.time_pos is None else self.dw_player[n_player].player.time_pos * 1000
4607
+ )
4604
4608
 
4605
4609
  return dec(str(round(mem_laps / 1000, 3)))
4606
4610
 
@@ -5388,6 +5392,18 @@ class MainWindow(QMainWindow, Ui_MainWindow):
5388
5392
  """
5389
5393
  logging.debug("function: closeEvent")
5390
5394
 
5395
+ # close MPV in IPC mode
5396
+ if self.MPV_IPC_MODE:
5397
+ try:
5398
+ for idx, p in enumerate(self.dw_player):
5399
+ p.player.process.terminate()
5400
+ try:
5401
+ p.player.process.wait(timeout=3) # wait up to 3s
5402
+ except subprocess.TimeoutExpired:
5403
+ p.player.process.kill() # force if still alive
5404
+ except Exception as e:
5405
+ logging.warning(f"Error stopping MPV process #{idx}: {e}")
5406
+
5391
5407
  # check if re-encoding
5392
5408
  if self.processes:
5393
5409
  if (
@@ -5441,6 +5457,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
5441
5457
  check if first player ended
5442
5458
  """
5443
5459
 
5460
+ print("play_video")
5461
+
5444
5462
  if self.geometric_measurements_mode:
5445
5463
  return
5446
5464
 
@@ -5462,6 +5480,9 @@ class MainWindow(QMainWindow, Ui_MainWindow):
5462
5480
 
5463
5481
  self.statusbar.showMessage("", 0)
5464
5482
 
5483
+ if self.ipc_mpv_timer is not None:
5484
+ self.ipc_mpv_timer.start()
5485
+
5465
5486
  self.plot_timer.start()
5466
5487
 
5467
5488
  # start all timer for plotting data
@@ -5493,6 +5514,10 @@ class MainWindow(QMainWindow, Ui_MainWindow):
5493
5514
  for data_timer in self.ext_data_timer_list:
5494
5515
  data_timer.stop()
5495
5516
 
5517
+ if self.ipc_mpv_timer is not None:
5518
+ self.ipc_mpv_timer.stop()
5519
+ self.mpv_timer_out()
5520
+
5496
5521
  player.player.pause = True
5497
5522
 
5498
5523
  self.lb_player_status.setText(msg)
@@ -5542,13 +5567,6 @@ class MainWindow(QMainWindow, Ui_MainWindow):
5542
5567
 
5543
5568
  self.update_visualizations()
5544
5569
 
5545
- # subtitles
5546
- """
5547
- st_track_number = 0 if self.config_param[DISPLAY_SUBTITLES] else -1
5548
- for player in self.dw_player:
5549
- player.mediaplayer.video_set_spu(st_track_number)
5550
- """
5551
-
5552
5570
  def jumpForward_activated(self):
5553
5571
  """
5554
5572
  forward from current position
@@ -5666,12 +5684,18 @@ def main():
5666
5684
  ret, msg = util.check_ffmpeg_path()
5667
5685
  if not ret:
5668
5686
  if sys.platform.startswith("win"):
5669
-
5670
5687
  import ctypes
5688
+
5671
5689
  MessageBoxTimeoutW = ctypes.windll.user32.MessageBoxTimeoutW
5672
- MessageBoxTimeoutW.argtypes = [ctypes.c_void_p, ctypes.c_wchar_p, ctypes.c_wchar_p,
5673
- ctypes.c_uint, ctypes.c_uint, ctypes.c_uint]
5674
- ctypes.windll.user32.MessageBoxTimeoutW(None, "The FFmpeg framework is not available.\nIt will be downloaded from the BORIS GitHub repository.", "FFmpeg", 0, 0, 10000) # time out
5690
+ MessageBoxTimeoutW.argtypes = [ctypes.c_void_p, ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.c_uint, ctypes.c_uint, ctypes.c_uint]
5691
+ ctypes.windll.user32.MessageBoxTimeoutW(
5692
+ None,
5693
+ "The FFmpeg framework is not available.\nIt will be downloaded from the BORIS GitHub repository.",
5694
+ "FFmpeg",
5695
+ 0,
5696
+ 0,
5697
+ 10000,
5698
+ ) # time out
5675
5699
 
5676
5700
  # if (not options.nosplashscreen):
5677
5701
  # QMessageBox.warning(
@@ -5684,7 +5708,7 @@ def main():
5684
5708
  logging.info("FFmpeg is not available. It will be downloaded from the BORIS GitHub repository")
5685
5709
 
5686
5710
  # download ffmpeg and ffprobe from https://github.com/boris-behav-obs/boris-behav-obs.github.io/releases/download/files/
5687
- url:str = "https://github.com/boris-behav-obs/boris-behav-obs.github.io/releases/download/files/"
5711
+ url: str = "https://github.com/boris-behav-obs/boris-behav-obs.github.io/releases/download/files/"
5688
5712
 
5689
5713
  # search where to download ffmpeg
5690
5714
  ffmpeg_dir = Path(__file__).parent / "misc"
@@ -5799,6 +5823,22 @@ def main():
5799
5823
  results.ptText.appendHtml(f"Some issues were found in the project<br><br>{msg}")
5800
5824
  results.show()
5801
5825
 
5826
+ # check mpv IPC mode
5827
+ window.MPV_IPC_MODE = False
5828
+ if options.ipc or sys.platform.startswith("darwin"):
5829
+ window.MPV_IPC_MODE = True
5830
+ # check if mpv is available
5831
+ if not shutil.which("mpv"):
5832
+ logging.critical("The mpv command is not available on the path")
5833
+ QMessageBox.critical(
5834
+ None,
5835
+ cfg.programName,
5836
+ ("The mpv command is not available on the path"),
5837
+ QMessageBox.Ok | QMessageBox.Default,
5838
+ QMessageBox.NoButton,
5839
+ )
5840
+ sys.exit()
5841
+
5802
5842
  window.show()
5803
5843
  window.raise_() # for overlapping widget (?)
5804
5844